mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-18 20:57:56 +00:00
added new slip.c with 7-bit-high packet encapsulation, packet length
and CRC32. Also added in-line RSSI report reception for RFD900 radios.
This commit is contained in:
parent
a42c685715
commit
fea06932e5
@ -428,6 +428,10 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr
|
||||
|
||||
if (ifconfig->socket_type==SOCK_STREAM){
|
||||
interface->slip_decode_state.dst_offset=0;
|
||||
// The encapsulation type should be configurable,
|
||||
// but for now default to the one that should be safe on the RFD900
|
||||
// radios, and that also allows us to receive RSSI reports inline
|
||||
interface->slip_decode_state.encapsulator=SLIP_FORMAT_UPPER7;
|
||||
interface->alarm.poll.events=POLLIN;
|
||||
watch(&interface->alarm);
|
||||
}else if(ifconfig->socket_type==SOCK_FILE){
|
||||
@ -721,7 +725,8 @@ overlay_broadcast_ensemble(overlay_interface *interface,
|
||||
unsigned char *buffer = interface->txbuffer;
|
||||
int out_len=0;
|
||||
|
||||
int encoded = slip_encode(bytes, len, buffer+out_len, sizeof(interface->txbuffer) - out_len);
|
||||
int encoded = slip_encode(SLIP_FORMAT_UPPER7,
|
||||
bytes, len, buffer+out_len, sizeof(interface->txbuffer) - out_len);
|
||||
if (encoded < 0)
|
||||
return WHY("Buffer overflow");
|
||||
|
||||
|
@ -38,9 +38,16 @@ int overlay_packetradio_setup_port(overlay_interface *interface)
|
||||
|
||||
tcsetattr(interface->alarm.poll.fd, TCSANOW, &t);
|
||||
|
||||
write(interface->alarm.poll.fd,"ATO\r",4);
|
||||
if (config.debug.packetradio)
|
||||
// Ask radio to report RSSI
|
||||
write(interface->alarm.poll.fd,"\r",1);
|
||||
usleep(1200000);
|
||||
write(interface->alarm.poll.fd,"+++",3);
|
||||
usleep(1200000);
|
||||
write(interface->alarm.poll.fd,"\rAT&T\rAT&T=RSSI\rATO\r",20);
|
||||
if (config.debug.packetradio) {
|
||||
DEBUGF("Enabled RSSI reporting for RFD900 radios");
|
||||
DEBUGF("Sent ATO to make sure we are in on-line mode");
|
||||
}
|
||||
|
||||
if (0){
|
||||
// dummy write of all possible ascii values
|
||||
|
17
serval.h
17
serval.h
@ -357,12 +357,24 @@ extern int overlayMode;
|
||||
// TX buffer must handle FEC encoded and encapsulated data, so needs to be
|
||||
// larger.
|
||||
#define OVERLAY_INTERFACE_TX_BUFFER_SIZE (2+2048*2)
|
||||
// buffer size for reading RFD900 RSSI reports
|
||||
// (minimum length is ~87 bytes, and includes 13 numeric fields
|
||||
// each of which may presumably end up being ~10 bytes, so 256 bytes
|
||||
// should be a safe size).
|
||||
#define RSSI_TEXT_SIZE 256
|
||||
|
||||
struct slip_decode_state{
|
||||
#define SLIP_FORMAT_SLIP 0
|
||||
#define SLIP_FORMAT_UPPER7 1
|
||||
int encapsulator;
|
||||
int state;
|
||||
unsigned char *src;
|
||||
int src_size;
|
||||
char rssi_text[RSSI_TEXT_SIZE];
|
||||
int rssi_len;
|
||||
int packet_length;
|
||||
unsigned char dst[OVERLAY_INTERFACE_RX_BUFFER_SIZE];
|
||||
unsigned long crc;
|
||||
int src_offset;
|
||||
int dst_offset;
|
||||
};
|
||||
@ -838,7 +850,10 @@ uint64_t read_uint64(unsigned char *o);
|
||||
uint32_t read_uint32(unsigned char *o);
|
||||
uint16_t read_uint16(unsigned char *o);
|
||||
|
||||
int slip_encode(unsigned char *src, int src_bytes, unsigned char *dst, int dst_len);
|
||||
int slip_encode(int format,
|
||||
unsigned char *src, int src_bytes, unsigned char *dst, int dst_len);
|
||||
int slip_decode(struct slip_decode_state *state);
|
||||
unsigned long Crc32_ComputeBuf( unsigned long inCrc32, const void *buf,
|
||||
size_t bufLen );
|
||||
|
||||
#endif // __SERVALD_SERVALD_H
|
||||
|
244
slip.c
Normal file
244
slip.c
Normal file
@ -0,0 +1,244 @@
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
|
||||
int slip_encode(int format,
|
||||
unsigned char *src, int src_bytes, unsigned char *dst, int dst_len)
|
||||
{
|
||||
switch(format) {
|
||||
case SLIP_FORMAT_SLIP:
|
||||
return WHYF("SLIP encoding not implemented",format);
|
||||
break;
|
||||
case SLIP_FORMAT_UPPER7:
|
||||
/*
|
||||
The purpose of this encoder is to work nicely with the RFD900 radios,
|
||||
including allowing the reception of RSSI information in the middle of
|
||||
packets.
|
||||
RSSI reports look like:
|
||||
L/R RSSI: 48/0 L/R noise: 62/0 pkts: 0 txe=0 rxe=0 stx=0 srx=0 ecc=0/0 temp=21 dco=0
|
||||
So we are using 0x80-0xff to hold data, and { and } to frame packets.
|
||||
*/
|
||||
{
|
||||
if (src_bytes<1) return 0;
|
||||
if (src_bytes>0x3fff)
|
||||
return WHYF("UPPER7 SLIP encoder packets must be <=0x3fff bytes");
|
||||
if (dst_len<(9+src_bytes+(src_bytes/7)+1))
|
||||
return WHYF("UPPER7 SLIP encoder requires 9+(8/7)*bytes to encode");
|
||||
int i,j;
|
||||
int out_len=0;
|
||||
|
||||
// Start of packet marker
|
||||
dst[out_len++]='{';
|
||||
// Length of (unencoded) packet
|
||||
dst[out_len++]=0x80+((src_bytes>>7)&0x7f);
|
||||
dst[out_len++]=0x80+((src_bytes>>0)&0x7f);
|
||||
// Add 32-bit CRC
|
||||
// (putting the CRC at the front allows it to be calculated progressively
|
||||
// on the receiver side, if we decide to support that)
|
||||
unsigned long crc=Crc32_ComputeBuf( 0, src, src_bytes);
|
||||
dst[out_len++]=0x80|((crc>>25)&0x7f);
|
||||
dst[out_len++]=0x80|((crc>>(25-7))&0x7f);
|
||||
dst[out_len++]=0x80|((crc>>(25-7-7))&0x7f);
|
||||
dst[out_len++]=0x80|((crc>>(25-7-7-7))&0x7f);
|
||||
dst[out_len++]=0x80|((crc>>0)&0x7f);
|
||||
|
||||
for(i=0;i<src_bytes;i+=8)
|
||||
{
|
||||
// Create 8 bytes of output consisting of 8x7 bits
|
||||
|
||||
// Generate vector of 7 bytes to encode
|
||||
unsigned char v[7];
|
||||
for(j=0;j<7&&i+j<src_bytes;j++) v[j]=src[i+j];
|
||||
for(;j<7;j++) v[j]=0;
|
||||
if (out_len+8>dst_len)
|
||||
return WHYF("Ran out of space in UPPER7 SLIP encoder (used all %d bytes after encoding %d of %d bytes)",
|
||||
dst_len,i,src_bytes);
|
||||
// We could use a nice for loop to do this, but for 8 bytes, let's
|
||||
// just do it explicitly.
|
||||
dst[out_len++]=0x80| (v[0]>>1);
|
||||
dst[out_len++]=0x80|((v[0]&0x01)<<6)|(v[1]>>2);
|
||||
dst[out_len++]=0x80|((v[1]&0x03)<<5)|(v[2]>>3);
|
||||
dst[out_len++]=0x80|((v[2]&0x07)<<4)|(v[3]>>4);
|
||||
dst[out_len++]=0x80|((v[3]&0x0f)<<3)|(v[4]>>5);
|
||||
dst[out_len++]=0x80|((v[4]&0x1f)<<2)|(v[5]>>6);
|
||||
dst[out_len++]=0x80|((v[5]&0x3f)<<1)|(v[6]>>7);
|
||||
dst[out_len++]=0x80|((v[6]&0x7f)<<0);
|
||||
}
|
||||
|
||||
// Mark end of packet
|
||||
dst[out_len++]='}';
|
||||
// Detect fatal miscalculations on byte counts
|
||||
if (out_len>dst_len) {
|
||||
FATALF("overran output buffer in SLIP UPPER7 encapsulation of packet (used %d of %d bytes)",out_len,dst_len);
|
||||
}
|
||||
return out_len;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return WHYF("Unsupported slip encoding #%d",format);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int parse_rfd900_rssi(char *s)
|
||||
{
|
||||
int lrssi,rrssi,lnoise,rnoise,temp;
|
||||
|
||||
// L/R RSSI: 48/0 L/R noise: 62/0 pkts: 0 txe=0 rxe=0 stx=0 srx=0 ecc=0/0 temp=21 dco=0
|
||||
if (sscanf(s,"L/R RSSI: %d/%d L/R noise: %d/%d pkts: %*d txe=%*d rxe=%*d stx=%*d srx=%*d ecc=%*d/%*d temp=%d dco=%*d",
|
||||
&lrssi,&rrssi,&lnoise,&rnoise,&temp)==5)
|
||||
{
|
||||
int lmargin=(lrssi-lnoise)/1.9;
|
||||
int rmargin=(lrssi-lnoise)/1.9;
|
||||
int maxmargin=lmargin; if (rmargin>maxmargin) maxmargin=rmargin;
|
||||
|
||||
if (config.debug.packetradio)
|
||||
DEBUGF("Link budget = %ddB, temperature=%dC",maxmargin,temp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define UPPER7_STATE_NOTINPACKET 0
|
||||
#define UPPER7_STATE_L1 1
|
||||
#define UPPER7_STATE_L2 2
|
||||
#define UPPER7_STATE_C1 3
|
||||
#define UPPER7_STATE_C2 4
|
||||
#define UPPER7_STATE_C3 5
|
||||
#define UPPER7_STATE_C4 6
|
||||
#define UPPER7_STATE_C5 7
|
||||
#define UPPER7_STATE_D0 8
|
||||
#define UPPER7_STATE_D1 9
|
||||
#define UPPER7_STATE_D2 10
|
||||
#define UPPER7_STATE_D3 11
|
||||
#define UPPER7_STATE_D4 12
|
||||
#define UPPER7_STATE_D5 13
|
||||
#define UPPER7_STATE_D6 14
|
||||
#define UPPER7_STATE_D7 15
|
||||
int upper7_decode(struct slip_decode_state *state,unsigned char byte)
|
||||
{
|
||||
// Parse out inline RSSI reports
|
||||
if (byte>=' '&&byte<=0x7f) {
|
||||
if (state->rssi_len<RSSI_TEXT_SIZE)
|
||||
state->rssi_text[state->rssi_len++]=byte;
|
||||
return 0;
|
||||
} else if (byte=='\r'||byte=='\n') {
|
||||
if (state->rssi_len>=RSSI_TEXT_SIZE) state->rssi_len=RSSI_TEXT_SIZE-1;
|
||||
if (state->rssi_len<0) state->rssi_len=0;
|
||||
state->rssi_text[state->rssi_len]=0;
|
||||
parse_rfd900_rssi(state->rssi_text);
|
||||
state->rssi_len=0;
|
||||
}
|
||||
|
||||
// Non-data bytes
|
||||
if (byte<0x80) {
|
||||
switch (byte) {
|
||||
case '{':
|
||||
state->state=UPPER7_STATE_L1;
|
||||
state->packet_length=0;
|
||||
return 0;
|
||||
case '}':
|
||||
// End of packet marker -- report end of received packet to caller
|
||||
// for CRC verification etc.
|
||||
state->state=UPPER7_STATE_NOTINPACKET; return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Data bytes and packet fields
|
||||
byte&=0x7f;
|
||||
switch(state->state) {
|
||||
case UPPER7_STATE_NOTINPACKET: return 0;
|
||||
case UPPER7_STATE_L1: state->packet_length=byte<<7; state->state++; return 0;
|
||||
case UPPER7_STATE_L2: state->packet_length|=byte;
|
||||
// Make sure packet length can fit in RX buffer, including that we might
|
||||
// need upto 7 bytes extra temporary space due to blocking
|
||||
if ((state->packet_length+7)<OVERLAY_INTERFACE_RX_BUFFER_SIZE) {
|
||||
state->state++;
|
||||
state->dst_offset=0;
|
||||
} else {
|
||||
if (config.debug.packetradio)
|
||||
DEBUGF("Ignoring jumbo packet of %d bytes",state->packet_length);
|
||||
state->state=UPPER7_STATE_NOTINPACKET;
|
||||
}
|
||||
return 0;
|
||||
case UPPER7_STATE_C1: state->crc=byte<<25; state->state++; return 0;
|
||||
case UPPER7_STATE_C2: state->crc|=byte<<(25-7); state->state++; return 0;
|
||||
case UPPER7_STATE_C3: state->crc|=byte<<(25-7-7); state->state++; return 0;
|
||||
case UPPER7_STATE_C4: state->crc|=byte<<(25-7-7-7); state->state++; return 0;
|
||||
case UPPER7_STATE_C5: state->crc|=byte<<0; state->state++; return 0;
|
||||
case UPPER7_STATE_D0:
|
||||
// Prevent buffer overruns
|
||||
if (state->dst_offset+7>OVERLAY_INTERFACE_RX_BUFFER_SIZE)
|
||||
state=UPPER7_STATE_NOTINPACKET;
|
||||
state->dst[state->dst_offset]=byte<<1;
|
||||
state->state++;
|
||||
return 0;
|
||||
case UPPER7_STATE_D1:
|
||||
state->dst[state->dst_offset+0]|=(byte>>6)&0x01;
|
||||
state->dst[state->dst_offset+1]=(byte<<2)&0x7f;
|
||||
state->state++;
|
||||
return 0;
|
||||
case UPPER7_STATE_D2:
|
||||
state->dst[state->dst_offset+1]|=(byte>>5)&0x03;
|
||||
state->dst[state->dst_offset+2]=(byte<<3)&0x7f;
|
||||
state->state++;
|
||||
return 0;
|
||||
case UPPER7_STATE_D3:
|
||||
state->dst[state->dst_offset+2]|=(byte>>4)&0x07;
|
||||
state->dst[state->dst_offset+3]=(byte<<4)&0x7f;
|
||||
state->state++;
|
||||
return 0;
|
||||
case UPPER7_STATE_D4:
|
||||
state->dst[state->dst_offset+3]|=(byte>>3)&0x0f;
|
||||
state->dst[state->dst_offset+4]=(byte<<5)&0x7f;
|
||||
state->state++;
|
||||
return 0;
|
||||
case UPPER7_STATE_D5:
|
||||
state->dst[state->dst_offset+4]|=(byte>>2)&0x1f;
|
||||
state->dst[state->dst_offset+5]=(byte<<6)&0x7f;
|
||||
state->state++;
|
||||
return 0;
|
||||
case UPPER7_STATE_D6:
|
||||
state->dst[state->dst_offset+5]|=(byte>>1)&0x3f;
|
||||
state->dst[state->dst_offset+6]=(byte<<7)&0x7f;
|
||||
state->state++;
|
||||
return 0;
|
||||
case UPPER7_STATE_D7:
|
||||
state->dst[state->dst_offset+6]|=(byte>>0)&0x7f;
|
||||
state->dst_offset+=7;
|
||||
state->state=UPPER7_STATE_D0;
|
||||
return 0;
|
||||
default:
|
||||
state->state=UPPER7_STATE_NOTINPACKET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* state->src and state->src_size contain the freshly read bytes
|
||||
we must accumulate any partial state between calls.
|
||||
*/
|
||||
int slip_decode(struct slip_decode_state *state)
|
||||
{
|
||||
switch(state->encapsulator) {
|
||||
case SLIP_FORMAT_SLIP:
|
||||
return WHYF("SLIP encapsulation not implemented");
|
||||
case SLIP_FORMAT_UPPER7:
|
||||
{
|
||||
while(state->src_offset<state->src_size)
|
||||
if (upper7_decode(state,state->src[state->src_offset++])==1) {
|
||||
// Check that CRC matches
|
||||
unsigned long crc=Crc32_ComputeBuf( 0, state->dst, state->packet_length);
|
||||
if (crc!=state->crc) {
|
||||
if (config.debug.packetradio)
|
||||
DEBUGF("Rejected packet of %d bytes due to CRC mis-match (%08x vs %08x)",
|
||||
state->packet_length,crc,state->crc);
|
||||
} else {
|
||||
return state->packet_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return WHYF("Unknown SLIP encapsulation format #%d",state->encapsulator);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ SERVAL_SOURCES = $(SERVAL_BASE)audiodevices.c \
|
||||
$(SERVAL_BASE)conf_om.c \
|
||||
$(SERVAL_BASE)conf_parse.c \
|
||||
$(SERVAL_BASE)conf_schema.c \
|
||||
$(SERVAL_BASE)crc32.c \
|
||||
$(SERVAL_BASE)crypto.c \
|
||||
$(SERVAL_BASE)dataformats.c \
|
||||
$(SERVAL_BASE)directory_client.c \
|
||||
|
Loading…
Reference in New Issue
Block a user