diff --git a/overlay_interface.h b/overlay_interface.h
index ce3c3d00..9c6161d9 100644
--- a/overlay_interface.h
+++ b/overlay_interface.h
@@ -119,6 +119,7 @@ typedef struct overlay_interface {
unsigned int uartbps; // set serial port speed (which might be different from link speed)
int ctsrts; // enabled hardware flow control if non-zero
+ int radiotype; // the type of radio link
struct network_destination *destination;
diff --git a/radio_link.c b/radio_link.c
index fa9aef87..bd602026 100644
--- a/radio_link.c
+++ b/radio_link.c
@@ -50,221 +50,80 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "overlay_interface.h"
#include "golay.h"
#include "radio_link.h"
-
-#define MAVLINK_MSG_ID_RADIO 166
-#define MAVLINK_MSG_ID_DATASTREAM 67
-
-// use '3D' for 3DRadio
-#define RADIO_SOURCE_SYSTEM '3'
-#define RADIO_SOURCE_COMPONENT 'D'
-
-/*
- we use a hand-crafted MAVLink packet based on the following
- message definition
-
-struct mavlink_RADIO_v10 {
- uint16_t rxerrors; // receive errors
- uint16_t fixed; // count of error corrected packets
- uint8_t rssi; // local signal strength
- uint8_t remrssi; // remote signal strength
- uint8_t txbuf; // percentage free space in transmit buffer
- uint8_t noise; // background noise level
- uint8_t remnoise; // remote background noise level
-};
-
-*/
-
-#define FEC_LENGTH 32
-#define FEC_MAX_BYTES 223
-#define RADIO_HEADER_LENGTH 6
-#define RADIO_USED_HEADER_LENGTH 4
-#define RADIO_CRC_LENGTH 2
-
-#define LINK_PAYLOAD_MTU (LINK_MTU - FEC_LENGTH - RADIO_HEADER_LENGTH - RADIO_CRC_LENGTH)
-
-struct radio_link_state{
- // next seq for transmission
- int tx_seq;
-
- // small buffer for parsing incoming bytes from the serial interface,
- // looking for recoverable link layer packets
- // should be large enough to hold at least one packet from the remote end
- // plus one heartbeat packet from the local firmware
- uint8_t payload[LINK_MTU*3];
-
- // decoded length of next link layer packet
- // including all header and footer bytes
- size_t payload_length;
- // last rx seq for reassembly
- int seq;
- // offset within payload that we have found a valid looking header
- unsigned payload_start;
- // offset after payload_start for incoming bytes
- unsigned payload_offset;
-
- // small buffer for assembling mdp payloads.
- uint8_t dst[MDP_MTU];
- // length of recovered packet
- size_t packet_length;
-
- // next firmware heartbeat
- time_ms_t next_heartbeat;
-
- time_ms_t last_packet;
-
- // parsed rssi
- int radio_rssi;
- int remote_rssi;
- // estimated firmware buffer space
- int32_t remaining_space;
-
- // next serial write
- time_ms_t next_tx_allowed;
- // partially sent packet
- struct overlay_buffer *tx_packet;
-
- // serial write buffer
- uint8_t txbuffer[LINK_MTU];
- int tx_bytes;
- int tx_pos;
-};
-
-/*
- Each mavlink frame consists of 0xfe followed by a standard 6 byte header.
- Normally the payload plus a 2-byte CRC follows.
- We are replacing the CRC check with a Reed-Solomon code to correct as well
- as detect upto 16 bytes with errors, in return for a 32-byte overhead.
-
- The nature of the particular library we are using is that the overhead is
- basically fixed, but we can shorten the data section.
-
- Note that the mavlink headers are not protected against errors. This is a
- limitation of the radio firmware at present. One day we will re-write the
- radio firmware so that we can send and receive raw radio frames, and get
- rid of the mavlink framing altogether, and just send R-S protected payloads.
-
- Not ideal, but will be fine for now.
-*/
-
-#include "fec-3.0.1/fixed.h"
-void encode_rs_8(data_t *data, data_t *parity,int pad);
-int decode_rs_8(data_t *data, int *eras_pos, int no_eras, int pad);
+#include "radio_link_rfd900.h"
+#include "radio_link_rfm69.h"
int radio_link_free(struct overlay_interface *interface)
{
- if (interface->radio_link_state){
- free(interface->radio_link_state);
- interface->radio_link_state=NULL;
- }
+ switch (interface->radiotype)
+ {
+ default:
+ case RADIO_TYPE_RFD900:
+ return radio_link_rfd900_free(interface);
+ break;
+ case RADIO_TYPE_RFM69:
+// return radio_link_rfm69_free(interface);
+ break;
+ }
return 0;
}
int radio_link_init(struct overlay_interface *interface)
{
- interface->radio_link_state = emalloc_zero(sizeof(struct radio_link_state));
+ switch (interface->radiotype)
+ {
+ default:
+ case RADIO_TYPE_RFD900:
+ return radio_link_rfd900_init(interface);
+ break;
+ case RADIO_TYPE_RFM69:
+// return radio_link_rfm69_init(interface);
+ break;
+ }
return 0;
}
void radio_link_state_html(struct strbuf *b, struct overlay_interface *interface)
{
- struct radio_link_state *state = interface->radio_link_state;
- strbuf_sprintf(b, "RSSI: %ddB
", state->radio_rssi);
- strbuf_sprintf(b, "Remote RSSI: %ddB
", state->remote_rssi);
-}
-
-// write a new link layer packet to interface->txbuffer
-// consuming more bytes from the next interface->tx_packet if required
-static int radio_link_encode_packet(struct radio_link_state *link_state)
-{
- // if we have nothing interesting left to send, don't create a packet at all
- if (!link_state->tx_packet)
- return 0;
-
- int count = ob_remaining(link_state->tx_packet);
- int startP = (ob_position(link_state->tx_packet) == 0);
- int endP = 1;
- if (count > LINK_PAYLOAD_MTU){
- count = LINK_PAYLOAD_MTU;
- endP = 0;
- }
-
- link_state->txbuffer[0]=0xfe; // mavlink v1.0 magic header
-
- // we need to add FEC_LENGTH for FEC, but the length field doesn't include the expected headers or CRC
- int len = count + FEC_LENGTH - RADIO_CRC_LENGTH;
- link_state->txbuffer[1]=len; // mavlink payload length
- link_state->txbuffer[2]=(len & 0xF);
- link_state->txbuffer[3]=0;
-
- // add golay encoding so that decoding the actual length is more reliable
- golay_encode(&link_state->txbuffer[1]);
-
-
- link_state->txbuffer[4]=(link_state->tx_seq++) & 0x3f;
- if (startP) link_state->txbuffer[4]|=0x40;
- if (endP) link_state->txbuffer[4]|=0x80;
- link_state->txbuffer[5]=MAVLINK_MSG_ID_DATASTREAM;
-
- ob_get_bytes(link_state->tx_packet, &link_state->txbuffer[6], count);
-
- encode_rs_8(&link_state->txbuffer[4], &link_state->txbuffer[6+count], FEC_MAX_BYTES - (count+2));
- link_state->tx_bytes=len + RADIO_CRC_LENGTH + RADIO_HEADER_LENGTH;
- if (endP){
- ob_free(link_state->tx_packet);
- link_state->tx_packet=NULL;
- overlay_queue_schedule_next(gettime_ms());
- }
- return 0;
+ switch (interface->radiotype)
+ {
+ default:
+ case RADIO_TYPE_RFD900:
+ radio_link_rfd900_state_html(b, interface);
+ break;
+ case RADIO_TYPE_RFM69:
+// radio_link_rfm69_state_html(b, interface);
+ break;
+ }
}
int radio_link_is_busy(struct overlay_interface *interface)
{
- if (interface->radio_link_state && interface->radio_link_state->tx_packet)
- return 1;
+ switch (interface->radiotype)
+ {
+ default:
+ case RADIO_TYPE_RFD900:
+ return radio_link_rfd900_is_busy(interface);
+ break;
+ case RADIO_TYPE_RFM69:
+// return radio_link_rfm69_is_busy(interface);
+ break;
+ }
return 0;
}
int radio_link_queue_packet(struct overlay_interface *interface, struct overlay_buffer *buffer)
{
- struct radio_link_state *link_state = interface->radio_link_state;
-
- if (link_state->tx_packet){
- ob_free(buffer);
- return WHYF("Cannot send two packets to a stream at the same time");
- }
-
- // prepare the buffer for reading
- ob_flip(buffer);
- link_state->tx_packet = buffer;
- radio_link_tx(interface);
-
- return 0;
-}
-
-static int build_heartbeat(struct radio_link_state *link_state)
-{
- int count=9;
- bzero(link_state->txbuffer, count + RADIO_CRC_LENGTH + RADIO_HEADER_LENGTH);
-
- link_state->txbuffer[0]=0xfe; // mavlink v1.0 link_state->txbuffer
- // Must be 9 to indicate heartbeat
- link_state->txbuffer[1]=count; // payload len, excluding 6 byte header and 2 byte CRC
- link_state->txbuffer[2]=(count & 0xF); // packet sequence
- link_state->txbuffer[3]=0x00; // system ID of sender (MAV_TYPE_GENERIC)
- // we're golay encoding the length to improve the probability of skipping it correctly
- golay_encode(&link_state->txbuffer[1]);
- link_state->txbuffer[4]=0xf1; // component ID of sender (MAV_COMP_ID_UART_BRIDGE)
- // Must be zero to indicate heartbeat
- link_state->txbuffer[5]=0; // message ID type of this link_state->txbuffer: DATA_STREAM
-
- // extra magic number to help correctly detect remote heartbeat requests
- link_state->txbuffer[14]=0x55;
- link_state->txbuffer[15]=0x05;
- golay_encode(&link_state->txbuffer[14]);
- link_state->tx_bytes = count + RADIO_CRC_LENGTH + RADIO_HEADER_LENGTH;
- if (config.debug.radio_link)
- DEBUGF("Produced heartbeat");
-
+ switch (interface->radiotype)
+ {
+ default:
+ case RADIO_TYPE_RFD900:
+ return radio_link_rfd900_queue_packet(interface, buffer);
+ break;
+ case RADIO_TYPE_RFM69:
+// return radio_link_rfm69_queue_packet(interface, buffer);
+ break;
+ }
return 0;
}
@@ -272,191 +131,16 @@ static int build_heartbeat(struct radio_link_state *link_state)
// consuming more bytes from the next interface->tx_packet if required
int radio_link_tx(struct overlay_interface *interface)
{
- struct radio_link_state *link_state = interface->radio_link_state;
-
- unschedule(&interface->alarm);
- interface->alarm.alarm = 0;
- time_ms_t next_tick = interface->destination->last_tx+interface->destination->tick_ms;
- time_ms_t now = gettime_ms();
-
- while(1){
-
- if (link_state->tx_bytes){
- if (link_state->next_tx_allowed > now){
- interface->alarm.alarm = link_state->next_tx_allowed;
- break;
- }
-
- int written=write(interface->alarm.poll.fd, &link_state->txbuffer[link_state->tx_pos], link_state->tx_bytes);
- if (written<=0){
- interface->alarm.poll.events|=POLLOUT;
- break;
- }
- link_state->remaining_space-=written;
- link_state->tx_bytes-=written;
- if (link_state->tx_bytes)
- link_state->tx_pos+=written;
- else
- link_state->tx_pos=0;
- continue;
- }
-
- interface->alarm.poll.events&=~POLLOUT;
-
- if (link_state->next_heartbeat<=now){
- build_heartbeat(link_state);
- link_state->next_heartbeat = now + 1000;
- continue;
- }
-
- // out of space? Don't bother to send anything interesting
- // until we hear the next heartbeat response
- if (link_state->remaining_space < LINK_MTU + HEARTBEAT_SIZE){
- interface->alarm.alarm = link_state->next_heartbeat;
+ switch (interface->radiotype)
+ {
+ default:
+ case RADIO_TYPE_RFD900:
+ return radio_link_rfd900_tx(interface);
break;
- }
-
- if (link_state->remaining_space < LINK_MTU + HEARTBEAT_SIZE)
- link_state->next_heartbeat = now;
-
- if (!link_state->tx_packet){
- // finished current packet, wait for more.
- interface->alarm.alarm = next_tick;
+ case RADIO_TYPE_RFM69:
+// return radio_link_rfm69_callback(interface);
break;
}
-
- // encode another packet fragment
- radio_link_encode_packet(link_state);
- link_state->last_packet = now;
- }
-
- watch(&interface->alarm);
- if (interface->alarm.alarmalarm.alarm=now;
- if (interface->alarm.alarm){
- interface->alarm.deadline = interface->alarm.alarm+100;
- schedule(&interface->alarm);
- }
-
- return 0;
-}
-
-static int parse_heartbeat(struct radio_link_state *state, const unsigned char *payload)
-{
- if (payload[0]==0xFE
- && payload[1]==9
- && payload[3]==RADIO_SOURCE_SYSTEM
- && payload[4]==RADIO_SOURCE_COMPONENT
- && payload[5]==MAVLINK_MSG_ID_RADIO){
-
- // we can assume that radio status packets arrive without corruption
- state->radio_rssi=(1.0*payload[10]-payload[13])/1.9;
- state->remote_rssi=(1.0*payload[11] - payload[14])/1.9;
- int free_space = payload[12];
- int free_bytes = (free_space * 1280) / 100 - 30;
- state->remaining_space = free_bytes;
- if (free_bytes>0)
- state->next_tx_allowed = gettime_ms();
- if (free_bytes>720)
- state->next_heartbeat=gettime_ms()+1000;
- if (config.debug.packetradio)
- INFOF("Link budget = %+ddB, remote link budget = %+ddB, buffer space = %d%% (approx %d)",
- state->radio_rssi,
- state->remote_rssi,
- free_space, free_bytes);
- return 1;
- }
- return 0;
-}
-
-static int radio_link_parse(struct overlay_interface *interface, struct radio_link_state *state,
- size_t packet_length, uint8_t *payload, int *backtrack)
-{
- *backtrack=0;
- if (packet_length==17){
- // if we've heard the start and end of a remote heartbeat request
- // we can skip it without checking anything else
- int errs=0;
- int tail = golay_decode(&errs, &payload[14]);
- if (tail == 0x555){
- if (config.debug.radio_link)
- DEBUGF("Decoded remote heartbeat request");
- return 1;
- }
- return 0;
- }
-
- size_t data_bytes = packet_length - (RADIO_USED_HEADER_LENGTH + FEC_LENGTH);
-
- int errors=decode_rs_8(&payload[4], NULL, 0, FEC_MAX_BYTES - data_bytes);
- if (errors==-1){
- if (config.debug.radio_link)
- DEBUGF("Reed-Solomon error correction failed");
- return 0;
- }
- *backtrack=errors;
- data_bytes -= 2;
- int seq=payload[4]&0x3f;
-
- if (config.debug.radio_link){
- DEBUGF("Received RS protected message, len: %zd, errors: %d, seq: %d, flags:%s%s",
- data_bytes,
- errors,
- seq,
- payload[4]&0x40?" start":"",
- payload[4]&0x80?" end":"");
- }
-
- if (seq != ((state->seq+1)&0x3f)){
- // reject partial packet if we missed a sequence number
- if (config.debug.radio_link)
- DEBUGF("Rejecting packet, sequence jumped from %d to %d", state->seq, seq);
- state->packet_length=sizeof(state->dst)+1;
- }
-
- if (payload[4]&0x40){
- // start a new packet
- state->packet_length=0;
- }
-
- state->seq=payload[4]&0x3f;
- if (state->packet_length + data_bytes > sizeof(state->dst)){
- if (config.debug.radio_link)
- DEBUG("Fragmented packet is too long or a previous piece was missed - discarding");
- state->packet_length=sizeof(state->dst)+1;
- return 1;
- }
-
- bcopy(&payload[RADIO_HEADER_LENGTH], &state->dst[state->packet_length], data_bytes);
- state->packet_length+=data_bytes;
-
- if (payload[4]&0x80) {
- if (config.debug.radio_link)
- DEBUGF("PDU Complete (length=%zd)",state->packet_length);
-
- packetOkOverlay(interface, state->dst, state->packet_length, NULL);
- state->packet_length=sizeof(state->dst)+1;
- }
- return 1;
-}
-
-static int decode_length(struct radio_link_state *state, unsigned char *p)
-{
- // look for a valid golay encoded length
- int errs=0;
- int gd = golay_decode(&errs, p);
- if (gd<0 || ((gd >>8) & 0xF) != (gd&0xF))
- return -1;
- size_t length = gd&0xFF;
- length += RADIO_HEADER_LENGTH + RADIO_CRC_LENGTH;
-
- if (length!=17 && (length <= FEC_LENGTH || length > LINK_MTU))
- return -1;
-
- if (config.debug.radio_link && (errs || state->payload_length!=*p))
- DEBUGF("Decoded length %u to %zu with %d errs", *p, length, errs);
-
- state->payload_length=length;
return 0;
}
@@ -464,84 +148,15 @@ static int decode_length(struct radio_link_state *state, unsigned char *p)
int radio_link_decode(struct overlay_interface *interface, uint8_t c)
{
IN();
- struct radio_link_state *state=interface->radio_link_state;
-
- if (state->payload_start + state->payload_offset >= sizeof state->payload){
- // drop one byte if we run out of space
- if (config.debug.radio_link)
- DEBUGF("Dropped %02x, buffer full", state->payload[0]);
- bcopy(state->payload+1, state->payload, sizeof(state->payload) -1);
- state->payload_start--;
- }
-
- unsigned char *p = &state->payload[state->payload_start];
- p[state->payload_offset++]=c;
-
- while(1){
- // look for packet length headers
- p = &state->payload[state->payload_start];
- while(state->payload_length==0 && state->payload_offset>=6){
- if (p[0]==0xFE
- && p[1]==9
- && p[3]==RADIO_SOURCE_SYSTEM
- && p[4]==RADIO_SOURCE_COMPONENT
- && p[5]==MAVLINK_MSG_ID_RADIO){
- //looks like a valid heartbeat response header, read the rest and process it
- state->payload_length=17;
- break;
- }
-
- if (decode_length(state, &p[1])==0)
- break;
-
- state->payload_start++;
- state->payload_offset--;
- p++;
- }
-
- // wait for a whole packet
- if (!state->payload_length || state->payload_offset < state->payload_length)
- RETURN(0);
-
- if (parse_heartbeat(state, p)){
- // cut the bytes of the heartbeat out of the buffer
- state->payload_offset -= state->payload_length;
- if (state->payload_offset){
- // shuffle bytes backwards
- bcopy(&p[state->payload_length], p, state->payload_offset);
- }
- // restart parsing for a valid header from the beginning of out buffer
- state->payload_offset+=state->payload_start;
- state->payload_start=0;
- state->payload_length=0;
- continue;
- }
-
- // is this a well formed packet?
- int backtrack=0;
- if (radio_link_parse(interface, state, state->payload_length, p, &backtrack)==1){
- // Since we know we've synced with the remote party,
- // and there's nothing we can do about any earlier data
- // throw away everything before the end of this packet
- if (state->payload_start && config.debug.radio_link)
- dump("Skipped", state->payload, state->payload_start);
-
- // If the packet is truncated by less than 16 bytes, RS protection should be enough to recover the packet,
- // but we may need to examine the last few bytes to find the start of the next packet.
- state->payload_offset -= state->payload_length - backtrack;
- if (state->payload_offset){
- // shuffle all remaining bytes back to the start of the buffer
- bcopy(&state->payload[state->payload_start + state->payload_length - backtrack],
- state->payload, state->payload_offset);
- }
- state->payload_start=0;
- }else{
- // ignore the first byte for now and start looking for another packet header
- // we may find a heartbeat in the middle that we need to cut out first
- state->payload_start++;
- state->payload_offset--;
+ switch (interface->radiotype)
+ {
+ default:
+ case RADIO_TYPE_RFD900:
+ return radio_link_rfd900_decode(interface, c);
+ break;
+ case RADIO_TYPE_RFM69:
+// return radio_link_rfm69_decode(interface, c);
+ break;
}
- state->payload_length=0;
- };
RETURN(0);
}
diff --git a/radio_link.h b/radio_link.h
index f1da9bf9..5ff45af2 100644
--- a/radio_link.h
+++ b/radio_link.h
@@ -19,9 +19,55 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __SERVAL_DNA___RADIO_LINK_H
#define __SERVAL_DNA___RADIO_LINK_H
-#define HEARTBEAT_SIZE (8+9)
#define LINK_MTU 255
+struct radio_link_state {
+ // next seq for transmission
+ int tx_seq;
+
+ // small buffer for parsing incoming bytes from the serial interface,
+ // looking for recoverable link layer packets
+ // should be large enough to hold at least one packet from the remote end
+ // plus one heartbeat packet from the local firmware
+ uint8_t payload[LINK_MTU * 3];
+
+ // decoded length of next link layer packet
+ // including all header and footer bytes
+ size_t payload_length;
+ // last rx seq for reassembly
+ int seq;
+ // offset within payload that we have found a valid looking header
+ unsigned payload_start;
+ // offset after payload_start for incoming bytes
+ unsigned payload_offset;
+
+ // small buffer for assembling mdp payloads.
+ uint8_t dst[MDP_MTU];
+ // length of recovered packet
+ size_t packet_length;
+
+ // next firmware heartbeat
+ time_ms_t next_heartbeat;
+
+ time_ms_t last_packet;
+
+ // parsed rssi
+ int radio_rssi;
+ int remote_rssi;
+ // estimated firmware buffer space
+ int32_t remaining_space;
+
+ // next serial write
+ time_ms_t next_tx_allowed;
+ // partially sent packet
+ struct overlay_buffer *tx_packet;
+
+ // serial write buffer
+ uint8_t txbuffer[LINK_MTU];
+ int tx_bytes;
+ int tx_pos;
+};
+
int radio_link_free(struct overlay_interface *interface);
int radio_link_init(struct overlay_interface *interface);
int radio_link_decode(struct overlay_interface *interface, uint8_t c);
diff --git a/radio_link_rfd900.c b/radio_link_rfd900.c
new file mode 100644
index 00000000..54eecbf4
--- /dev/null
+++ b/radio_link_rfd900.c
@@ -0,0 +1,501 @@
+// -*- Mode: C; c-basic-offset: 2; -*-
+//
+// Copyright (c) 2012 Andrew Tridgell, All Rights Reserved
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// o Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// o Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+/*
+Portions Copyright (C) 2013 Paul Gardner-Stephen
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "serval.h"
+#include "conf.h"
+#include "overlay_buffer.h"
+#include "overlay_interface.h"
+#include "golay.h"
+#include "radio_link.h"
+#include "radio_link_rfd900.h"
+
+#define RFD900_MAVLINK_MSG_ID_RADIO 166
+#define RFD900_MAVLINK_MSG_ID_DATASTREAM 67
+
+// use '3D' for 3DRadio
+#define RFD900_RADIO_SOURCE_SYSTEM '3'
+#define RFD900_RADIO_SOURCE_COMPONENT 'D'
+
+/*
+ we use a hand-crafted MAVLink packet based on the following
+ message definition
+
+struct mavlink_RADIO_v10 {
+ uint16_t rxerrors; // receive errors
+ uint16_t fixed; // count of error corrected packets
+ uint8_t rssi; // local signal strength
+ uint8_t remrssi; // remote signal strength
+ uint8_t txbuf; // percentage free space in transmit buffer
+ uint8_t noise; // background noise level
+ uint8_t remnoise; // remote background noise level
+};
+
+*/
+
+#define RFD900_FEC_LENGTH 32
+#define RFD900_FEC_MAX_BYTES 223
+#define RFD900_RADIO_HEADER_LENGTH 6
+#define RFD900_RADIO_USED_HEADER_LENGTH 4
+#define RFD900_RADIO_CRC_LENGTH 2
+
+#define RFD900_LINK_PAYLOAD_MTU (RFD900_LINK_MTU - RFD900_FEC_LENGTH - RFD900_RADIO_HEADER_LENGTH - RFD900_RADIO_CRC_LENGTH)
+
+/*
+ Each mavlink frame consists of 0xfe followed by a standard 6 byte header.
+ Normally the payload plus a 2-byte CRC follows.
+ We are replacing the CRC check with a Reed-Solomon code to correct as well
+ as detect upto 16 bytes with errors, in return for a 32-byte overhead.
+
+ The nature of the particular library we are using is that the overhead is
+ basically fixed, but we can shorten the data section.
+
+ Note that the mavlink headers are not protected against errors. This is a
+ limitation of the radio firmware at present. One day we will re-write the
+ radio firmware so that we can send and receive raw radio frames, and get
+ rid of the mavlink framing altogether, and just send R-S protected payloads.
+
+ Not ideal, but will be fine for now.
+*/
+
+#include "fec-3.0.1/fixed.h"
+void encode_rs_8(data_t *data, data_t *parity,int pad);
+int decode_rs_8(data_t *data, int *eras_pos, int no_eras, int pad);
+
+int radio_link_rfd900_free(struct overlay_interface *interface)
+{
+ if (interface->radio_link_state){
+ free(interface->radio_link_state);
+ interface->radio_link_state=NULL;
+ }
+ return 0;
+}
+
+int radio_link_rfd900_init(struct overlay_interface *interface)
+{
+ interface->radio_link_state = emalloc_zero(sizeof(struct radio_link_state));
+ return 0;
+}
+
+void radio_link_rfd900_state_html(struct strbuf *b, struct overlay_interface *interface)
+{
+ struct radio_link_state *state = interface->radio_link_state;
+ strbuf_sprintf(b, "RSSI: %ddB
", state->radio_rssi);
+ strbuf_sprintf(b, "Remote RSSI: %ddB
", state->remote_rssi);
+}
+
+// write a new link layer packet to interface->txbuffer
+// consuming more bytes from the next interface->tx_packet if required
+static int radio_link_rfd900_encode_packet(struct radio_link_state *link_state)
+{
+ // if we have nothing interesting left to send, don't create a packet at all
+ if (!link_state->tx_packet)
+ return 0;
+
+ int count = ob_remaining(link_state->tx_packet);
+ int startP = (ob_position(link_state->tx_packet) == 0);
+ int endP = 1;
+ if (count > RFD900_LINK_PAYLOAD_MTU){
+ count = RFD900_LINK_PAYLOAD_MTU;
+ endP = 0;
+ }
+
+ link_state->txbuffer[0]=0xfe; // mavlink v1.0 magic header
+
+ // we need to add FEC_LENGTH for FEC, but the length field doesn't include the expected headers or CRC
+ int len = count + RFD900_FEC_LENGTH - RFD900_RADIO_CRC_LENGTH;
+ link_state->txbuffer[1]=len; // mavlink payload length
+ link_state->txbuffer[2]=(len & 0xF);
+ link_state->txbuffer[3]=0;
+
+ // add golay encoding so that decoding the actual length is more reliable
+ golay_encode(&link_state->txbuffer[1]);
+
+
+ link_state->txbuffer[4]=(link_state->tx_seq++) & 0x3f;
+ if (startP) link_state->txbuffer[4]|=0x40;
+ if (endP) link_state->txbuffer[4]|=0x80;
+ link_state->txbuffer[5]=RFD900_MAVLINK_MSG_ID_DATASTREAM;
+
+ ob_get_bytes(link_state->tx_packet, &link_state->txbuffer[6], count);
+
+ encode_rs_8(&link_state->txbuffer[4], &link_state->txbuffer[6+count], RFD900_FEC_MAX_BYTES - (count+2));
+ link_state->tx_bytes=len + RFD900_RADIO_CRC_LENGTH + RFD900_RADIO_HEADER_LENGTH;
+ if (endP){
+ ob_free(link_state->tx_packet);
+ link_state->tx_packet=NULL;
+ overlay_queue_schedule_next(gettime_ms());
+ }
+ return 0;
+}
+
+int radio_link_rfd900_is_busy(struct overlay_interface *interface)
+{
+ if (interface->radio_link_state && interface->radio_link_state->tx_packet)
+ return 1;
+ return 0;
+}
+
+int radio_link_rfd900_queue_packet(struct overlay_interface *interface, struct overlay_buffer *buffer)
+{
+ struct radio_link_state *link_state = interface->radio_link_state;
+
+ if (link_state->tx_packet){
+ ob_free(buffer);
+ return WHYF("Cannot send two packets to a stream at the same time");
+ }
+
+ // prepare the buffer for reading
+ ob_flip(buffer);
+ link_state->tx_packet = buffer;
+ radio_link_rfd900_tx(interface);
+
+ return 0;
+}
+
+static int build_heartbeat(struct radio_link_state *link_state)
+{
+ int count=9;
+ bzero(link_state->txbuffer, count + RFD900_RADIO_CRC_LENGTH + RFD900_RADIO_HEADER_LENGTH);
+
+ link_state->txbuffer[0]=0xfe; // mavlink v1.0 link_state->txbuffer
+ // Must be 9 to indicate heartbeat
+ link_state->txbuffer[1]=count; // payload len, excluding 6 byte header and 2 byte CRC
+ link_state->txbuffer[2]=(count & 0xF); // packet sequence
+ link_state->txbuffer[3]=0x00; // system ID of sender (MAV_TYPE_GENERIC)
+ // we're golay encoding the length to improve the probability of skipping it correctly
+ golay_encode(&link_state->txbuffer[1]);
+ link_state->txbuffer[4]=0xf1; // component ID of sender (MAV_COMP_ID_UART_BRIDGE)
+ // Must be zero to indicate heartbeat
+ link_state->txbuffer[5]=0; // message ID type of this link_state->txbuffer: DATA_STREAM
+
+ // extra magic number to help correctly detect remote heartbeat requests
+ link_state->txbuffer[14]=0x55;
+ link_state->txbuffer[15]=0x05;
+ golay_encode(&link_state->txbuffer[14]);
+ link_state->tx_bytes = count + RFD900_RADIO_CRC_LENGTH + RFD900_RADIO_HEADER_LENGTH;
+ if (config.debug.radio_link)
+ DEBUGF("Produced heartbeat");
+
+ return 0;
+}
+
+// write a new link layer packet to interface->txbuffer
+// consuming more bytes from the next interface->tx_packet if required
+int radio_link_rfd900_tx(struct overlay_interface *interface)
+{
+ struct radio_link_state *link_state = interface->radio_link_state;
+
+ unschedule(&interface->alarm);
+ interface->alarm.alarm = 0;
+ time_ms_t next_tick = interface->destination->last_tx+interface->destination->tick_ms;
+ time_ms_t now = gettime_ms();
+
+ while(1){
+
+ if (link_state->tx_bytes){
+ if (link_state->next_tx_allowed > now){
+ interface->alarm.alarm = link_state->next_tx_allowed;
+ break;
+ }
+
+ int written=write(interface->alarm.poll.fd, &link_state->txbuffer[link_state->tx_pos], link_state->tx_bytes);
+ if (written<=0){
+ interface->alarm.poll.events|=POLLOUT;
+ break;
+ }
+ link_state->remaining_space-=written;
+ link_state->tx_bytes-=written;
+ if (link_state->tx_bytes)
+ link_state->tx_pos+=written;
+ else
+ link_state->tx_pos=0;
+ continue;
+ }
+
+ interface->alarm.poll.events&=~POLLOUT;
+
+ if (link_state->next_heartbeat<=now){
+ build_heartbeat(link_state);
+ link_state->next_heartbeat = now + 1000;
+ continue;
+ }
+
+ // out of space? Don't bother to send anything interesting
+ // until we hear the next heartbeat response
+ if (link_state->remaining_space < RFD900_LINK_MTU + RFD900_HEARTBEAT_SIZE){
+ interface->alarm.alarm = link_state->next_heartbeat;
+ break;
+ }
+
+ if (link_state->remaining_space < RFD900_LINK_MTU + RFD900_HEARTBEAT_SIZE)
+ link_state->next_heartbeat = now;
+
+ if (!link_state->tx_packet){
+ // finished current packet, wait for more.
+ interface->alarm.alarm = next_tick;
+ break;
+ }
+
+ // encode another packet fragment
+ radio_link_rfd900_encode_packet(link_state);
+ link_state->last_packet = now;
+ }
+
+ watch(&interface->alarm);
+ if (interface->alarm.alarmalarm.alarm=now;
+ if (interface->alarm.alarm){
+ interface->alarm.deadline = interface->alarm.alarm+100;
+ schedule(&interface->alarm);
+ }
+
+ return 0;
+}
+
+static int parse_heartbeat(struct radio_link_state *state, const unsigned char *payload)
+{
+ if (payload[0]==0xFE
+ && payload[1]==9
+ && payload[3]==RFD900_RADIO_SOURCE_SYSTEM
+ && payload[4]==RFD900_RADIO_SOURCE_COMPONENT
+ && payload[5]==RFD900_MAVLINK_MSG_ID_RADIO){
+
+ // we can assume that radio status packets arrive without corruption
+ state->radio_rssi=(1.0*payload[10]-payload[13])/1.9;
+ state->remote_rssi=(1.0*payload[11] - payload[14])/1.9;
+ int free_space = payload[12];
+ int free_bytes = (free_space * 1280) / 100 - 30;
+ state->remaining_space = free_bytes;
+ if (free_bytes>0)
+ state->next_tx_allowed = gettime_ms();
+ if (free_bytes>720)
+ state->next_heartbeat=gettime_ms()+1000;
+ if (config.debug.packetradio)
+ INFOF("Link budget = %+ddB, remote link budget = %+ddB, buffer space = %d%% (approx %d)",
+ state->radio_rssi,
+ state->remote_rssi,
+ free_space, free_bytes);
+ return 1;
+ }
+ return 0;
+}
+
+static int radio_link_rfd900_parse(struct overlay_interface *interface, struct radio_link_state *state,
+ size_t packet_length, uint8_t *payload, int *backtrack)
+{
+ *backtrack=0;
+ if (packet_length==17){
+ // if we've heard the start and end of a remote heartbeat request
+ // we can skip it without checking anything else
+ int errs=0;
+ int tail = golay_decode(&errs, &payload[14]);
+ if (tail == 0x555){
+ if (config.debug.radio_link)
+ DEBUGF("Decoded remote heartbeat request");
+ return 1;
+ }
+ return 0;
+ }
+
+ size_t data_bytes = packet_length - (RFD900_RADIO_USED_HEADER_LENGTH + RFD900_FEC_LENGTH);
+
+ int errors=decode_rs_8(&payload[4], NULL, 0, RFD900_FEC_MAX_BYTES - data_bytes);
+ if (errors==-1){
+ if (config.debug.radio_link)
+ DEBUGF("Reed-Solomon error correction failed");
+ return 0;
+ }
+ *backtrack=errors;
+ data_bytes -= 2;
+ int seq=payload[4]&0x3f;
+
+ if (config.debug.radio_link){
+ DEBUGF("Received RS protected message, len: %zd, errors: %d, seq: %d, flags:%s%s",
+ data_bytes,
+ errors,
+ seq,
+ payload[4]&0x40?" start":"",
+ payload[4]&0x80?" end":"");
+ }
+
+ if (seq != ((state->seq+1)&0x3f)){
+ // reject partial packet if we missed a sequence number
+ if (config.debug.radio_link)
+ DEBUGF("Rejecting packet, sequence jumped from %d to %d", state->seq, seq);
+ state->packet_length=sizeof(state->dst)+1;
+ }
+
+ if (payload[4]&0x40){
+ // start a new packet
+ state->packet_length=0;
+ }
+
+ state->seq=payload[4]&0x3f;
+ if (state->packet_length + data_bytes > sizeof(state->dst)){
+ if (config.debug.radio_link)
+ DEBUG("Fragmented packet is too long or a previous piece was missed - discarding");
+ state->packet_length=sizeof(state->dst)+1;
+ return 1;
+ }
+
+ bcopy(&payload[RFD900_RADIO_HEADER_LENGTH], &state->dst[state->packet_length], data_bytes);
+ state->packet_length+=data_bytes;
+
+ if (payload[4]&0x80) {
+ if (config.debug.radio_link)
+ DEBUGF("PDU Complete (length=%zd)",state->packet_length);
+
+ packetOkOverlay(interface, state->dst, state->packet_length, NULL);
+ state->packet_length=sizeof(state->dst)+1;
+ }
+ return 1;
+}
+
+static int decode_length(struct radio_link_state *state, unsigned char *p)
+{
+ // look for a valid golay encoded length
+ int errs=0;
+ int gd = golay_decode(&errs, p);
+ if (gd<0 || ((gd >>8) & 0xF) != (gd&0xF))
+ return -1;
+ size_t length = gd&0xFF;
+ length += RFD900_RADIO_HEADER_LENGTH + RFD900_RADIO_CRC_LENGTH;
+
+ if (length!=17 && (length <= RFD900_FEC_LENGTH || length > RFD900_LINK_MTU))
+ return -1;
+
+ if (config.debug.radio_link && (errs || state->payload_length!=*p))
+ DEBUGF("Decoded length %u to %zu with %d errs", *p, length, errs);
+
+ state->payload_length=length;
+ return 0;
+}
+
+// add one byte at a time from the serial link, and attempt to decode packets
+int radio_link_rfd900_decode(struct overlay_interface *interface, uint8_t c)
+{
+ IN();
+ struct radio_link_state *state=interface->radio_link_state;
+
+ if (state->payload_start + state->payload_offset >= sizeof state->payload){
+ // drop one byte if we run out of space
+ if (config.debug.radio_link)
+ DEBUGF("Dropped %02x, buffer full", state->payload[0]);
+ bcopy(state->payload+1, state->payload, sizeof(state->payload) -1);
+ state->payload_start--;
+ }
+
+ unsigned char *p = &state->payload[state->payload_start];
+ p[state->payload_offset++]=c;
+
+ while(1){
+ // look for packet length headers
+ p = &state->payload[state->payload_start];
+ while(state->payload_length==0 && state->payload_offset>=6){
+ if (p[0]==0xFE
+ && p[1]==9
+ && p[3]==RFD900_RADIO_SOURCE_SYSTEM
+ && p[4]==RFD900_RADIO_SOURCE_COMPONENT
+ && p[5]==RFD900_MAVLINK_MSG_ID_RADIO){
+ //looks like a valid heartbeat response header, read the rest and process it
+ state->payload_length=17;
+ break;
+ }
+
+ if (decode_length(state, &p[1])==0)
+ break;
+
+ state->payload_start++;
+ state->payload_offset--;
+ p++;
+ }
+
+ // wait for a whole packet
+ if (!state->payload_length || state->payload_offset < state->payload_length)
+ RETURN(0);
+
+ if (parse_heartbeat(state, p)){
+ // cut the bytes of the heartbeat out of the buffer
+ state->payload_offset -= state->payload_length;
+ if (state->payload_offset){
+ // shuffle bytes backwards
+ bcopy(&p[state->payload_length], p, state->payload_offset);
+ }
+ // restart parsing for a valid header from the beginning of out buffer
+ state->payload_offset+=state->payload_start;
+ state->payload_start=0;
+ state->payload_length=0;
+ continue;
+ }
+
+ // is this a well formed packet?
+ int backtrack=0;
+ if (radio_link_rfd900_parse(interface, state, state->payload_length, p, &backtrack)==1){
+ // Since we know we've synced with the remote party,
+ // and there's nothing we can do about any earlier data
+ // throw away everything before the end of this packet
+ if (state->payload_start && config.debug.radio_link)
+ dump("Skipped", state->payload, state->payload_start);
+
+ // If the packet is truncated by less than 16 bytes, RS protection should be enough to recover the packet,
+ // but we may need to examine the last few bytes to find the start of the next packet.
+ state->payload_offset -= state->payload_length - backtrack;
+ if (state->payload_offset){
+ // shuffle all remaining bytes back to the start of the buffer
+ bcopy(&state->payload[state->payload_start + state->payload_length - backtrack],
+ state->payload, state->payload_offset);
+ }
+ state->payload_start=0;
+ }else{
+ // ignore the first byte for now and start looking for another packet header
+ // we may find a heartbeat in the middle that we need to cut out first
+ state->payload_start++;
+ state->payload_offset--;
+ }
+ state->payload_length=0;
+ };
+ RETURN(0);
+}
diff --git a/radio_link_rfd900.h b/radio_link_rfd900.h
new file mode 100644
index 00000000..6e799e1e
--- /dev/null
+++ b/radio_link_rfd900.h
@@ -0,0 +1,33 @@
+/*
+Copyright (C) 2013 Paul Gardner-Stephen
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __SERVAL_DNA___RADIO_LINK_RFD900_H
+#define __SERVAL_DNA___RADIO_LINK_RFD900_H
+
+#define RFD900_HEARTBEAT_SIZE (8+9)
+#define RFD900_LINK_MTU 255
+
+int radio_link_rfd900_free(struct overlay_interface *interface);
+int radio_link_rfd900_init(struct overlay_interface *interface);
+int radio_link_rfd900_decode(struct overlay_interface *interface, uint8_t c);
+int radio_link_rfd900_tx(struct overlay_interface *interface);
+void radio_link_rfd900_state_html(struct strbuf *b, struct overlay_interface *interface);
+int radio_link_rfd900_is_busy(struct overlay_interface *interface);
+int radio_link_rfd900_queue_packet(struct overlay_interface *interface, struct overlay_buffer *buffer);
+
+#endif //__SERVAL_DNA___RADIO_LINK_RFD900_H
diff --git a/radio_link_rfm69.c b/radio_link_rfm69.c
new file mode 100644
index 00000000..8bf09fdf
--- /dev/null
+++ b/radio_link_rfm69.c
@@ -0,0 +1,150 @@
+// -*- Mode: C; c-basic-offset: 2; -*-
+//
+// Copyright (c) 2014 Ulf Mueller-Baumgart, All Rights Reserved
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// o Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// o Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+/*
+ Portions Copyright (C) 2013 Paul Gardner-Stephen
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "serval.h"
+#include "conf.h"
+#include "overlay_buffer.h"
+#include "overlay_interface.h"
+#include "golay.h"
+#include "radio_link.h"
+#include "radio_link_rfm69.h"
+
+#define STATE_RECEIVE 0
+#define STATE_SEND 1
+#define STATE_WAIT_OK 2
+#define suppress_warning(X) if(X){}
+
+int state;
+
+int radio_link_rfm69_free(struct overlay_interface *interface)
+{
+ if (interface->radio_link_state)
+ {
+ free(interface->radio_link_state);
+ interface->radio_link_state = NULL;
+ }
+ return 0;
+}
+
+int radio_link_rfm69_init(struct overlay_interface *interface)
+{
+ interface->radio_link_state = emalloc_zero(sizeof(struct radio_link_state));
+
+ return 0;
+}
+
+void radio_link_rfm69_state_html(struct strbuf *b, struct overlay_interface *interface)
+{
+ struct radio_link_state *state = interface->radio_link_state;
+ strbuf_sprintf(b, "RSSI: %ddB
", state->radio_rssi);
+}
+
+int radio_link_rfm69_is_busy(struct overlay_interface *interface)
+{
+ if (interface->radio_link_state && interface->radio_link_state->tx_packet)
+ return 1;
+ return 0;
+}
+
+int radio_link_rfm69_queue_packet(struct overlay_interface *interface, struct overlay_buffer *buffer)
+{
+ struct radio_link_state *link_state = interface->radio_link_state;
+
+ if (link_state->tx_packet)
+ {
+ ob_free(buffer);
+ return WHYF("Cannot send two packets to a stream at the same time");
+ }
+
+ // prepare the buffer for reading
+ ob_flip(buffer);
+ link_state->tx_packet = buffer;
+ radio_link_rfm69_callback(interface);
+
+ return 0;
+}
+
+void radio_link_rfm69_receive_packet(struct overlay_interface *interface)
+{
+ suppress_warning(interface);
+}
+
+void radio_link_rfm69_process_ok(struct overlay_interface *interface)
+{
+ suppress_warning(interface);
+}
+
+void radio_link_rfm69_send_packet(struct overlay_interface *interface)
+{
+ suppress_warning(interface);
+}
+
+// write a new link layer packet to interface->txbuffer
+// consuming more bytes from the next interface->tx_packet if required
+int radio_link_rfm69_callback(struct overlay_interface *interface)
+{
+ switch (state)
+ {
+ default:
+ case STATE_RECEIVE:
+ radio_link_rfm69_receive_packet(interface);
+ break;
+ case STATE_WAIT_OK:
+ radio_link_rfm69_process_ok(interface);
+ break;
+ case STATE_SEND:
+ radio_link_rfm69_send_packet(interface);
+ break;
+ }
+ return 0;
+}
+
+int radio_link_rfm69_decode(struct overlay_interface *interface, uint8_t c) {
+ IN();
+ suppress_warning(interface);
+ suppress_warning(c);
+ RETURN(0);
+}
diff --git a/radio_link_rfm69.h b/radio_link_rfm69.h
new file mode 100644
index 00000000..841303a5
--- /dev/null
+++ b/radio_link_rfm69.h
@@ -0,0 +1,60 @@
+// -*- Mode: C; c-basic-offset: 2; -*-
+//
+// Copyright (c) 2014 Ulf Mueller-Baumgart, All Rights Reserved
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// o Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// o Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+/*
+Copyright (C) 2013 Paul Gardner-Stephen
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __SERVAL_DNA___RADIO_LINK_RFM69_H
+#define __SERVAL_DNA___RADIO_LINK_RFM69_H
+
+#define RFM69_LINK_MTU 60
+
+int radio_link_rfm69_free(struct overlay_interface *interface);
+int radio_link_rfm69_init(struct overlay_interface *interface);
+int radio_link_rfm69_decode(struct overlay_interface *interface, uint8_t c);
+int radio_link_rfm69_callback(struct overlay_interface *interface);
+void radio_link_rfm69_state_html(struct strbuf *b, struct overlay_interface *interface);
+int radio_link_rfm69_is_busy(struct overlay_interface *interface);
+int radio_link_rfm69_queue_packet(struct overlay_interface *interface, struct overlay_buffer *buffer);
+
+#endif //__SERVAL_DNA___RADIO_LINK_RFM69_H
diff --git a/sourcefiles.mk b/sourcefiles.mk
index 2b74fdb3..e0e4b165 100644
--- a/sourcefiles.mk
+++ b/sourcefiles.mk
@@ -61,6 +61,8 @@ SERVAL_DAEMON_SOURCES = \
lsif.c \
main.c \
radio_link.c \
+ radio_link_rfd900.c \
+ radio_link_rfm69.c \
meshms.c \
meshms_restful.c \
msp_client.c \