Hi All!
I've got 2 Arduinos, each with it's own Nrf2401a (Nordic RF Transciever). There's a nifty (but a bit too simple) library for them out on the Arduino Playground.
I've gotten them working with the very simple blocking communication style.
ie: A sends to B, changes to RX mode and waits for B to respond. When B receive's A's message, it changes to TX mode and esponds, and then changes to RX mode and waits for A again. etc, etc...
That works fairly well, until A or B misses a packet. Then they both end up in RX mode and quit talking to eachother.
However, I'd love to implement something a bit more complex. Something more like TCP that guarantees packet delivery (ie: that detects lost packets and re-sends). I'm trying to expand upon the library, using it for sending and receiving, and then implementing the TCP protocol on top of that.
Has anyone done something similar that would like to share their experience, tips, or code?
My first attempt didn't work quite right The receiver doesn't detect the SYN-ACK for some reason.
Here's the code:
#include <ByteBuffer.h>
#include "Nrf2401.h"
Nrf2401 Radio;
byte PacketData[256];
ByteBuffer CircularBuffer;
// 0 = CLOSED
// 1 = LISTEN
// 2 = SYN SENT
// 3 = SYN RECEIVED
// 4 = ESTABLISHED
// 5 = FIN WAIT 1
// 6 = FIN WAIT 2
// 7 = CLOSE WAIT
// 8 = CLOSING
// 9 = LAST ACK
// 10 = TIME WAIT
int ConnectionState=0;
int TCPHeaderSize=6;
typedef struct {
byte SequenceNumber;
byte AcknowledgementNumber;
byte Flags;
byte WindowSize;
byte Checksum;
byte DataLength;
}
TCPHeader;
TCPHeader TCPSendHeader;
TCPHeader TCPReceiveHeader;
void setup(void)
{
TCPSendHeader.SequenceNumber=0x00;
TCPSendHeader.AcknowledgementNumber=0x00;
TCPSendHeader.Flags=0x00;
TCPSendHeader.WindowSize=0x00;
TCPSendHeader.Checksum=0x00;
TCPSendHeader.DataLength=0x00;
TCPReceiveHeader.SequenceNumber=0x00;
TCPReceiveHeader.AcknowledgementNumber=0x00;
TCPReceiveHeader.Flags=0x00;
TCPReceiveHeader.WindowSize=0x00;
TCPReceiveHeader.Checksum=0x00;
TCPReceiveHeader.DataLength=0x00;
CircularBuffer.init(512);
Serial.begin(9600);
pinMode(13, OUTPUT);
randomSeed(analogRead(7)); // start the random number generator
attachInterrupt(0, messageReceived, RISING); // look for rising edges on digital pin 2
ConnectionState=0;
Radio.rxMode(1);
}
void loop(void)
{
digitalWrite(13, !digitalRead(13));
//Wait 1-2 seconds
delay(random(2000)+1000);
if (ConnectionState )
if (ConnectionState<3)
{
Connect();
}
else if (ConnectionState==8)
{
Disconnect();
}
else
{
Serial.print("Connection State = ");
Serial.println(ConnectionState,DEC);
}
}//End RequestData
void Connect()
{
Serial.println("Sending Connect...");
TCPSendHeader.SequenceNumber = (byte)random(0,256);
TCPSendHeader.AcknowledgementNumber=0x00;
TCPSendHeader.Flags=0x02; // 00000010 = SYN
TCPSendHeader.WindowSize=0x00;
TCPSendHeader.Checksum=0x00;
TCPSendHeader.DataLength=0x00;
SendPacket();
ConnectionState=2; //SYN SENT
}
void Disconnect()
{
Serial.println("Sending Disconnect...");
TCPSendHeader.SequenceNumber=TCPSendHeader.SequenceNumber+1;
TCPSendHeader.AcknowledgementNumber=0x00;
TCPSendHeader.Flags=0x01; // 0000 0001 = FIN
TCPSendHeader.WindowSize=0x00;
TCPSendHeader.Checksum=0x00;
TCPSendHeader.DataLength=0x00;
SendPacket();
ConnectionState=0; //CLOSED
}
void SendPacket()
{
Serial.println("Sending Packet...");
Radio.txMode(1);
Radio.write(TCPSendHeader.SequenceNumber);
delay(50);
Radio.write(TCPSendHeader.AcknowledgementNumber);
delay(50);
Radio.write(TCPSendHeader.Flags);
delay(50);
Radio.write(TCPSendHeader.WindowSize);
delay(50);
Radio.write(TCPSendHeader.Checksum);
delay(50);
Radio.write(TCPSendHeader.DataLength);
delay(50);
Radio.rxMode(1);
}
void messageReceived(void)
{
Serial.println("Received:");
while(Radio.available())
{
Radio.read();
CircularBuffer.put(Radio.data[0]);
Serial.print("CircularBuffer[");
Serial.print(CircularBuffer.getSize()-1,DEC);
Serial.print("] = ");
Serial.println(CircularBuffer.peek(CircularBuffer.getSize()-1),DEC);
}//End Copy Bytes from Receive Buffer.
if (CircularBuffer.getSize()>=TCPHeaderSize)
{
Serial.println("Buffer has enough data to be TCP Header.");
TCPReceiveHeader.SequenceNumber=CircularBuffer.get();
TCPReceiveHeader.AcknowledgementNumber=CircularBuffer.get();
TCPReceiveHeader.Flags=CircularBuffer.get();
TCPReceiveHeader.WindowSize=CircularBuffer.get();
TCPReceiveHeader.Checksum=CircularBuffer.get();
TCPReceiveHeader.DataLength=CircularBuffer.get();
Serial.print("TCPReceiveHeader.SequenceNumber=");
Serial.println(TCPReceiveHeader.SequenceNumber,DEC);
Serial.print("TCPReceiveHeader.AcknowledgementNumber=");
Serial.println(TCPReceiveHeader.AcknowledgementNumber,DEC);
Serial.print("TCPReceiveHeader.Flags=");
Serial.println(TCPReceiveHeader.Flags,DEC);
Serial.print("TCPReceiveHeader.WindowSize=");
Serial.println(TCPReceiveHeader.WindowSize,DEC);
Serial.print("TCPReceiveHeader.Checksum=");
Serial.println(TCPReceiveHeader.Checksum,DEC);
Serial.print("TCPReceiveHeader.DataLength=");
Serial.println(TCPReceiveHeader.DataLength,DEC);
if (ConnectionState==0)
{
//Received a SYN Packet
if ((TCPReceiveHeader.Flags & 0x02)==0x02)
{
Serial.println("Received a SYN Packet.");
ConnectionState=3; //SYN RECEIVED
//Reply with SYN-ACK
TCPSendHeader.SequenceNumber=(byte)random(0,255);
TCPSendHeader.AcknowledgementNumber=TCPReceiveHeader.SequenceNumber+1;
TCPSendHeader.Flags=0x12; // 00010010 = ACK,SYN
TCPSendHeader.WindowSize=0x00;
TCPSendHeader.Checksum=0x00;
TCPSendHeader.DataLength=0x00;
Serial.println("Sending SYN ACK...");
SendPacket();
ConnectionState=4; //CONNECTED
}
}
if (ConnectionState==2)
{
//Received SYN ACK Packet
if ((TCPReceiveHeader.Flags & 0x12)==0x12)
{
Serial.println("Received SYN ACK Packet.");
ConnectionState=4; //CONNECTED
}
}
if (ConnectionState==4)
{
//Received an ACK Packet
if ((TCPReceiveHeader.Flags & 0x10)==0x10)
{
Serial.println("Received an ACK Packet.");
TCPSendHeader.SequenceNumber=TCPReceiveHeader.AcknowledgementNumber;
TCPSendHeader.AcknowledgementNumber=TCPReceiveHeader.SequenceNumber+1;
}
}
//Received a FIN Packet
if ((TCPReceiveHeader.Flags & 0x01)==0x01)
{
Serial.println("Received FIN Packet.");
ConnectionState=0; //CLOSED
}
}//End Has whole header
}//End messageReceived