refactored packet radio code mostly into separate file.

began writing stateful packet decoder.
This commit is contained in:
gardners 2013-02-05 05:42:50 +10:30 committed by Jeremy Lakeman
parent 70af7fae0d
commit 190a5e693f
5 changed files with 176 additions and 54 deletions

View File

@ -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,, "")

View File

@ -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))) {

149
overlay_packetradio.c Normal file
View File

@ -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;i<nread;i++)
{
switch (interface->decoder_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 <otherbyte>
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 ;
}

View File

@ -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;

View File

@ -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 \