diff --git a/overlay_interface.c b/overlay_interface.c index 9a241a11..32aab87e 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -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"); diff --git a/overlay_packetradio.c b/overlay_packetradio.c index 786b54a8..b5ef7c52 100644 --- a/overlay_packetradio.c +++ b/overlay_packetradio.c @@ -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 diff --git a/serval.h b/serval.h index da7521ea..d8bf24db 100644 --- a/serval.h +++ b/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 diff --git a/slip.c b/slip.c new file mode 100644 index 00000000..aa7c5e95 --- /dev/null +++ b/slip.c @@ -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;idst_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_lenrssi_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)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_offsetsrc_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); + } +} diff --git a/sourcefiles.mk b/sourcefiles.mk index 44d5251c..75061c10 100644 --- a/sourcefiles.mk +++ b/sourcefiles.mk @@ -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 \