From 190a5e693f0ffd3858a8d1b8c5c7b98d8cafa289 Mon Sep 17 00:00:00 2001 From: gardners Date: Tue, 5 Feb 2013 05:42:50 +1030 Subject: [PATCH] refactored packet radio code mostly into separate file. began writing stateful packet decoder. --- conf_schema.h | 1 + overlay_interface.c | 67 +++++-------------- overlay_packetradio.c | 149 ++++++++++++++++++++++++++++++++++++++++++ serval.h | 12 +++- sourcefiles.mk | 1 + 5 files changed, 176 insertions(+), 54 deletions(-) create mode 100644 overlay_packetradio.c diff --git a/conf_schema.h b/conf_schema.h index 1a606e3a..90acbe2f 100644 --- a/conf_schema.h +++ b/conf_schema.h @@ -200,6 +200,7 @@ ATOM(char, overlayinterfaces, 0, cf_opt_char_boolean,, "") ATOM(char, broadcasts, 0, cf_opt_char_boolean,, "") ATOM(char, packettx, 0, cf_opt_char_boolean,, "") ATOM(char, packetrx, 0, cf_opt_char_boolean,, "") +ATOM(char, packetradio, 0, cf_opt_char_boolean,, "") ATOM(char, packetconstruction, 0, cf_opt_char_boolean,, "") ATOM(char, rhizome, 0, cf_opt_char_boolean,, "") ATOM(char, rhizome_tx, 0, cf_opt_char_boolean,, "") diff --git a/overlay_interface.c b/overlay_interface.c index 1ddeaeb1..ce31580e 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -412,7 +412,7 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr return WHYF("dummy or packet radio interface file name overrun: %s", alloca_str_toprint(strbuf_str(d))); } if ((interface->alarm.poll.fd = open(dummyfile,O_APPEND|O_RDWR)) < 1) { - return WHYF("could not open dummy or packet radio interface file %s for append", dummyfile); + return WHYF("could not open dummy or packet radio interface file %s for append (errno=%d)", dummyfile,errno); } bzero(&interface->address, sizeof(interface->address)); @@ -548,59 +548,22 @@ struct dummy_packet{ int payload_length; /* TODO ? ; - half-power beam height (uint16) - half-power beam width (uint16) - range in metres, centre beam (uint32) - latitude (uint32) - longitude (uint32) - X/Z direction (uint16) - Y direction (uint16) - speed in metres per second (uint16) - TX frequency in Hz, uncorrected for doppler (which must be done at the receiving end to take into account - relative motion) - coding method (use for doppler response etc) null terminated string + half-power beam height (uint16) + half-power beam width (uint16) + range in metres, centre beam (uint32) + latitude (uint32) + longitude (uint32) + X/Z direction (uint16) + Y direction (uint16) + speed in metres per second (uint16) + TX frequency in Hz, uncorrected for doppler (which must be done at the receiving end to take into account + relative motion) + coding method (use for doppler response etc) null terminated string */ unsigned char payload[1400]; }; -void overlay_packetradio_poll(struct sched_ent *alarm) -{ - overlay_interface *interface = (overlay_interface *)alarm; - time_ms_t now = gettime_ms(); - - // We will almost certainly support more than one type of packet radio - // so lets parameterise this. - switch(1) { - case 1: - // Read data from the serial port - break; - } - - // tick the interface - if (interface->tick_ms>0 && - (interface->last_tick_ms == -1 || now >= interface->last_tick_ms + interface->tick_ms)) { - // tick the interface - overlay_route_queue_advertisements(interface); - interface->last_tick_ms=now; - } - - unsigned char buffer[8192]; - ssize_t nread = read(alarm->poll.fd, buffer,8192); - if (nread == -1){ - WHY_perror("read"); - return; - } - if (nread>0) { - buffer[8191]=0; - if (nread<8192) buffer[nread]=0; - DEBUGF("Read '%s'",buffer); - } - - schedule(alarm); - - return ; -} void overlay_dummy_poll(struct sched_ent *alarm) { @@ -618,8 +581,8 @@ void overlay_dummy_poll(struct sched_ent *alarm) if (interface->recv_offset >= length) { /* if there's no input, while we want to check for more soon, - we need to allow all other low priority alarms to fire first, - otherwise we'll dominate the scheduler without accomplishing anything */ + we need to allow all other low priority alarms to fire first, + otherwise we'll dominate the scheduler without accomplishing anything */ alarm->alarm = gettime_ms() + 5; if (interface->last_tick_ms != -1 && alarm->alarm > interface->last_tick_ms + interface->tick_ms) alarm->alarm = interface->last_tick_ms + interface->tick_ms; @@ -648,7 +611,7 @@ void overlay_dummy_poll(struct sched_ent *alarm) if (((!interface->drop_unicasts) && memcmp(&packet.dst_addr, &interface->address, sizeof(packet.dst_addr))==0) || ((!interface->drop_broadcasts) && - memcmp(&packet.dst_addr, &interface->broadcast_address, sizeof(packet.dst_addr))==0)){ + memcmp(&packet.dst_addr, &interface->broadcast_address, sizeof(packet.dst_addr))==0)){ if (packetOkOverlay(interface, packet.payload, packet.payload_length, -1, (struct sockaddr*)&packet.src_addr, sizeof(packet.src_addr))) { diff --git a/overlay_packetradio.c b/overlay_packetradio.c new file mode 100644 index 00000000..e15796d4 --- /dev/null +++ b/overlay_packetradio.c @@ -0,0 +1,149 @@ +#include "serval.h" +#include "conf.h" + +/* interface decoder states. broadly based on RFC1055 */ +#define DC_NORMAL 0 +#define DC_ESC 1 +#define DC_END 2 + +/* SLIP-style escape characters used for serial packet radio interfaces */ +#define SLIP_END 0300 +#define SLIP_ESC 0333 +#define SLIP_ESC_END 0334 +#define SLIP_ESC_ESC 0335 + +int overlay_rx_packet_complete(overlay_interface *interface) +{ + if (interface->recv_offset) { + // dispatch received packet + if (packetOkOverlay(interface, interface->buffer, interface->recv_offset, -1, + NULL,0)) { + if (config.debug.packetradio) + WARN("Corrupted or unsupported packet from packet radio interface"); + } + } + interface->recv_offset=0; + return 0; +} + +int overlay_rx_packet_append_byte(overlay_interface *interface,unsigned char byte) +{ + // Make sure we don't put the data outside the RX buffer + if (interface->recv_offset<0 + ||interface->recv_offset>=OVERLAY_INTERFACE_RX_BUFFER_SIZE) + interface->recv_offset=0; + + interface->buffer[interface->recv_offset++]=byte; + if (interface->recv_offset==OVERLAY_INTERFACE_RX_BUFFER_SIZE) { + // packet fills buffer. Who knows, we might be able to decode what we + // have of it. + return overlay_rx_packet_complete(interface); + } + + if (config.debug.packetradio) DEBUGF("RXd %d bytes",interface->recv_offset); + return 0; +} + +void overlay_packetradio_poll(struct sched_ent *alarm) +{ + overlay_interface *interface = (overlay_interface *)alarm; + time_ms_t now = gettime_ms(); + + // Read data from the serial port + // We will almost certainly support more than one type of packet radio + // so lets parameterise this. + switch(1) { + case 1: + { + unsigned char buffer[OVERLAY_INTERFACE_RX_BUFFER_SIZE]; + ssize_t nread = read(alarm->poll.fd, buffer, OVERLAY_INTERFACE_RX_BUFFER_SIZE); + if (nread == -1){ + WHY_perror("read"); + return; + } + if (nread>0) { + /* + Examine received bytes for end of packet marker. + The challenge is that we need to make sure that the packet encapsulation + is self-synchronising in the event that a data error occurs (including + failure to receive an arbitrary number of bytes). + For now we will reuse the antiquated and sub-optimal method described in + RFC1055 for SLIP, but with a couple of tweaks to reduce byte wastage when + encountering ESC and END characters in packets. + */ + int i; + for(i=0;idecoder_state) { + case DC_ESC: + // escaped character + switch(buffer[i]) { + case SLIP_ESC_END: // escaped END byte + overlay_rx_packet_append_byte(interface,SLIP_END); break; + case SLIP_ESC_ESC: // escaped escape character + overlay_rx_packet_append_byte(interface,SLIP_ESC); break; + default: /* unknown escape character + This is where the inefficiency comes, because + we don't use the spare bits. + We can reduce the inefficiency by making ESC + mean literally that. */ + overlay_rx_packet_append_byte(interface,SLIP_ESC); + overlay_rx_packet_append_byte(interface,buffer[i]); + break; + } + break; + case DC_END: + // character preceeded by END character + switch(buffer[i]) { + case SLIP_ESC_END: + overlay_rx_packet_complete(interface); + break; + default: + overlay_rx_packet_append_byte(interface,SLIP_END); + overlay_rx_packet_append_byte(interface,buffer[i]); + break; + } + break; + default: + // non-escape character + switch(buffer[i]) { + case SLIP_ESC: + interface->decoder_state=DC_ESC; break; + case SLIP_END: + interface->decoder_state=DC_END; break; + default: + overlay_rx_packet_append_byte(interface,buffer[i]); + } + break; + } + } + } + } + break; + } + + // tick the interface + if (interface->tick_ms>0 && + (interface->last_tick_ms == -1 || now >= interface->last_tick_ms + interface->tick_ms)) { + // tick the interface + overlay_route_queue_advertisements(interface); + interface->last_tick_ms=now; + } + + unsigned char buffer[8192]; + ssize_t nread = read(alarm->poll.fd, buffer,8192); + if (nread == -1){ + WHY_perror("read"); + return; + } + if (nread>0) { + buffer[8191]=0; + if (nread<8192) buffer[nread]=0; + DEBUGF("Read '%s'",buffer); + } + + schedule(alarm); + + return ; +} + diff --git a/serval.h b/serval.h index 3ec6700a..a1499a2d 100644 --- a/serval.h +++ b/serval.h @@ -350,11 +350,19 @@ extern int overlayMode; #define INTERFACE_STATE_DOWN 2 #define INTERFACE_STATE_DETECTING 3 +// Specify the size of the receive buffer. +// This effectively sets the MRU for packet radio interfaces +// where we have to buffer packets on the receive side +#define OVERLAY_INTERFACE_RX_BUFFER_SIZE 2048 + typedef struct overlay_interface { struct sched_ent alarm; char name[256]; - int recv_offset; - int fileP; // dummyP + unsigned char buffer[OVERLAY_INTERFACE_RX_BUFFER_SIZE]; + int recv_offset; /* either dummy file offset or number of bytes in RX buffer + for packet radio interfaces */ + char decoder_state; // decoder state for packet radio interfaces + int fileP; // non-zero for dummy and packet radio serial interfaces char drop_broadcasts; char drop_unicasts; int port; diff --git a/sourcefiles.mk b/sourcefiles.mk index 8a9f842c..15314b7a 100644 --- a/sourcefiles.mk +++ b/sourcefiles.mk @@ -31,6 +31,7 @@ SERVAL_SOURCES = $(SERVAL_BASE)audiodevices.c \ $(SERVAL_BASE)overlay_buffer.c \ $(SERVAL_BASE)overlay_interface.c \ $(SERVAL_BASE)overlay_link.c \ + $(SERVAL_BASE)overlay_packetradio.c \ $(SERVAL_BASE)overlay_queue.c \ $(SERVAL_BASE)overlay_mdp.c \ $(SERVAL_BASE)overlay_mdp_services.c \