I'm trying to build a serial over radio transmitter module using two Feather M0 boards with RFM69HCW chips on board. As a test I'm trying to run a slip IP over serial session. This seems to work consistantly for UDP sessions (in my case ICMP ping requests) but fails for TCP sessions (in my case a simple HTTP request).
Here is the code:
#include <RFM69.h>
#include <RFM69_ATC.h>
#include <SPI.h>
#include <string>
// a simple off the shelf CRC8 implementation
#include <crc.h>
// defined for one of the two boards
// #define B
#ifdef B
#define NODEID 1
#define RECEIVER 2
#endif
#ifndef B
#define NODEID 2
#define RECEIVER 1
#endif
#define MAX_BYTES 56
#define NETWORKID 100
#define FREQUENCY RF69_433MHZ
#define IS_RFM69HW_HCW
RFM69_ATC radio(8, 3, true);
char buf[512];
void setup()
{
// initialize random using receiver address
// this guarantees that both nodes have different initial random values
randomSeed(RECEIVER);
Serial.begin(115200);
radio.initialize(FREQUENCY, NODEID, NETWORKID);
radio.setPowerLevel(0);
radio.setFrequency(446000000);
}
int8_t receiver_last_id = -1;
bool read_packet(bool override = false)
{
if (radio.receiveDone() || override)
{
int cnt = radio.DATALEN - 2;
int crc = radio.DATA[0];
int8_t packet_id = radio.DATA[1];
memcpy(buf, radio.DATA + 2, cnt);
uint8_t crc_data = crc8(0, (uint8_t*)buf, cnt);
if (radio.ACKRequested())
{
if (crc == crc_data)
{
radio.sendACK();
// sometimes duplicates seem to occure
// in case this happens just ignore the packet
if (packet_id != receiver_last_id)
{
Serial.write(buf, cnt);
receiver_last_id = packet_id;
return true;
}
return false;
}
else
{
radio.ACK_REQUESTED = 0;
return false;
}
}
return false;
}
return false;
}
int8_t sender_packet_id = 0;
bool send_packet()
{
int serial_cnt = Serial.available();
if (serial_cnt > 0 && radio.canSend())
{
// packet structure:
// 1. byte: CRC8 of DATA
// 2. byte: ID of packet (to prevent duplicates)
// variable length: DATA
int payload_size = min(MAX_BYTES, serial_cnt);
int total_size = payload_size + 2;
Serial.readBytes((char *)buf + 2, payload_size);
buf[0] = crc8(0, (uint8_t*)(buf + 2), payload_size);
buf[1] = sender_packet_id++;
while (!radio.sendWithRetry(RECEIVER, buf, total_size, 1, 5U))
{
// radio.receiveDone() switches the
// radio into receive mode
if (radio.receiveDone())
{
// if receive is done instantly
// process the packet and move on
read_packet(true);
continue;
}
// wait random time in case
// a collision happened
delay(random(5, 30));
read_packet();
// wait for radio to be ready to send
while (!radio.canSend()) ;
}
return true;
}
return false;
}
void loop()
{
read_packet();
send_packet();
}
I also have a network capture of both sides.
Here is the capture for the Client: https://ufile.io/v945jl8i
Here is the capture for the Server: https://ufile.io/yn36rjw4
I've figured out that it happens somewhere in the while (!radio.sendWithRetry(RECEIVER, buf, total_size, 1, 5U)) loop but I can't figure out what exactly goes wrong and how I can fix it.
Any help would be greatly appreciated!
Edit: I'm running a simple python HTTP server (python 3 -m http.server 8080). And as client i'm using curl (curl <server address>:8080)
Here are the Commands I use for starting slip:
modprobe slip
slattach -vL -s 115200 -p slip /dev/ttyACM0
ifconfig sl0 192.168.2.1 pointtopoint 192.168.2.2 up
I switched the two IP addresses for the other side.
Also interestingly it sometimes seems to randomly work for one or two requests, so i'm guessing some kind of race condition.
I also made sure that i'm connecting to the correct serial ports.
PS: i'm kind of new to C++ so any recommendations on best practices are also appreciated