Go Down

Topic: Reliable UDP (Read 5410 times) previous topic - next topic

wbcrisman

Dec 15, 2013, 09:52 pm Last Edit: Dec 15, 2013, 10:01 pm by wbcrisman Reason: 1
Hello,

I want to stream data from my arduino uno/w Ethernet shield using a more reliable version of UDP. I don't care to lose some packets (as long as i get about 80%) but i would like for them to arrive in order and be dropped if they come in late. Is there a way to add a time stamp and sequence number to the current UDP library? Or could I write this a function in my sketch?

robtillaart

#1
Dec 15, 2013, 10:00 pm Last Edit: Dec 16, 2013, 07:19 pm by robtillaart Reason: 1
hello, this is the shortest most cryptic post of the day! (update, there was only hello and a title)

Guessing:
UDP is not reliable by design.
Routers, switches and netwerk cards are allowed to drop UDP packets (after a best effort).
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

wbcrisman

Yes i know it is not reliable by design, but there are protocols out there like RTP that do what im asking, however i dont want to use 2 sockets. I have also found a library for RUDP but i don't know how to make the header or if it will work with he arduino because I dont know how different normal C is from arduino c.

pYro_65

There is no special Arduino C, the IDE uses a real C/C++ compiler and the Arduino project only provides the hardware and an extensive set of libraries and code to use on them ( API ). The library might have come with examples or search the net for someone else that may have posted info on using it.
Forum Mod anyone?
https://arduino.land/Moduino/

msssltd

#4
Dec 16, 2013, 09:16 am Last Edit: Dec 16, 2013, 09:24 am by MattS-UK Reason: 1
Quote from: wbcrisman

I want to stream data from my arduino uno/w Ethernet shield using a more reliable version of UDP.

Theoretically, UDP is unreliable.  Pragmatically, in many real World applications UDP proves no less reliable than TCP.  For UDP to be unreliable, the failure modes which cause UDP to be unreliable, must be present within the usage scenario.

Quote
I don't care to lose some packets (as long as i get about 80%) but i would like for them to arrive in order and be dropped if they come in late. Is there a way to add a time stamp and sequence number to the current UDP library? Or could I write this a function in my sketch?


Fundamentally, the answer is yes.  You can add whatever you want to a UDP packet, subject to a packet length limitation specific to the Arduino.  Obviously the receiving application needs to be able to decode the packet it has been sent.  You may need to check  endianess and reorder bytes accordingly.

Here is some code I wrote a few weeks ago to answer a different forum question, which may help to get you started.  A sequence field can be easily added to the DCB structure and populated with a global counter.   It would make sense to move the guts of the loop() function to your own function.

Code: [Select]

#include <Streaming.h>

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

//#define _DEBUG

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
IPAddress ip(192, 168, 200, 64);
EthernetUDP udp;

void setup()
{
Serial.begin(9600);
Ethernet.begin(mac);
}

typedef struct DCB {
int pinA0;
int pinA1;
int pinA2;
int pinA3;
int pinA4;
int pinA5;
       uint32_t timeStamp;
char stringData[32];
byte endData;
} DCB;

uint32_t period = 0L;
uint32_t periodStart = 0L;

void loop()
{

periodStart = millis();

//grab some memory from the heap
DCB* dcbData = (DCB*) malloc(sizeof(DCB));

// populate device control block
dcbData->pinA0 = analogRead(A0);
dcbData->pinA1 = analogRead(A1);
dcbData->pinA2 = analogRead(A2);
dcbData->pinA3 = analogRead(A3);
dcbData->pinA4 = analogRead(A4);
dcbData->pinA5 = analogRead(A5);
dcbData->timeStamp = millis();

strcpy(dcbData->stringData, "Matt's Uno\r\n\0");
dcbData->endData = 0;

//send once every 40 ms
period += millis() - periodStart;
if (period >= 40) {

udp.begin(2000);
udp.beginPacket(ip, 2000);
udp.write( (byte*) dcbData, sizeof(DCB) );
udp.endPacket();
udp.stop();

period = 0;
};

//always free memory grabbed from the heap
free(dcbData);
}


I provided a more sophisticated example of doing roughly the same thing using class inheritance, on this thread
http://forum.arduino.cc/index.php?topic=201523.msg1485490#msg1485490

HTH

wbcrisman

Yes thank you. I know C pretty well but im not very creative so when i need to come up with things examples really help me out and i guess Reliable UDP is a bad choice of words since i don't need it to and more reliability just some added functions.  Also if you don't mid or you have time an example of a sequence number function would be much appreciated.

haniabidi

wbcrisman,

I think a simple way might be to append a number at the end of each packet seperated by a % sign. Let's say for example you are sending information with 10 packets:

0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

And if your receiving machine misses the 4th packet, the receiving machine can request for it again?

For my senior project, I forced the receiving machine to send an acknowledgement for the packet received before transmission of the next packet. That was my way of figuring out if packet was sent successfully and I didn't had to worry about the order. You might have to take into account some delay.

Hani Abidi

robtillaart


wbcrisman,

I think a simple way might be to append a number at the end of each packet seperated by a % sign. Let's say for example you are sending information with 10 packets:

0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

And if your receiving machine misses the 4th packet, the receiving machine can request for it again?
...
Hani Abidi

A very similar kind of algorithm is implemented in TCP to improve the throughput, and not to wait for every ACK/NACK which takes time due to network latency.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

haniabidi


[/quote]
A very similar kind of algorithm is implemented in TCP to improve the throughput, and not to wait for every ACK/NACK which takes time due to network latency.
[/quote]

You are right.. ! That might defeat the purpose. When I was working on my project few years back, I couldn't find the TCP library for Arduino and thus used UDP and ack to verify data transmission.

msssltd

Here is an example based on the class example I linked to in my earlier post.  I have added a static member to the message base class and auto increment the sequence number in the derived class constructor.  The sequence value will rollover at 255, which should be enough to detect dropped packets within the receiving application. I learnt a few things about C++ static members in the process. so thank you for that.

The message will arrive at the receiving end as an array of bytes with the sequence number in the first byte, value1 in the 2nd and 3rd bytes, so and so forth.

Code: [Select]

#include <stdio.h>
#include <stdlib.h>
#include <Streaming.h>

#include <SPI.h>
#include <w5100.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

// our message structure, the data we want to transmit
class SequencedMessage {
protected:
static byte seq_;   //note the static member is not stored contiguously
byte sequence;    // so we need a property to hold the value when we send
public:
uint16_t value1;  // just some values
uint16_t value2;
uint16_t value3;
};

//add the methods to serialise the data onto the network, in a derived class
class SUDPMessage : public SequencedMessage {
public:
SUDPMessage(void);
byte getSequence(void) { return seq_; }
void send(UDP*, IPAddress*, uint16_t);
};

//initialise the static member
byte SequencedMessage::seq_= 0;

//constructor increments the sequence
SUDPMessage::SUDPMessage(void) {
SequencedMessage::seq_++;
}

//send the message to the network
void SUDPMessage::send(UDP* udp, IPAddress* dstIP, uint16_t dstPort) {
       //remember to copy the static member into the message
sequence = seq_;

      //send the packet
udp->beginPacket(*dstIP, dstPort);
udp->write((byte*) this, sizeof(SequencedMessage));
udp->endPacket();
}

IPAddress dstIP(192, 168, 200, 64);
const uint16_t srcPort = 2000;
const uint16_t dstPort = 2000;

EthernetUDP udp;

void setup(void) {
Serial.begin(9600);
Serial << F("Setup...\r\n");
udp.begin(srcPort);
Serial << F("UDP bound to port ") << srcPort << "\r\n"
}

void loop(void) {
SUDPMessage* sMessage = new SUDPMessage;

sMessage->value1 = 10;
sMessage->value2 = 20;
sMessage->value3 = 30;
sMessage->send(&udp, &dstIP, dstPort);
Serial << "Sent msg seq=" << sMessage->getSequence() << "\r\n";

delete sMessage;
delay(1000);
}



SurferTim

Do your specifications require the sender to know if the packet was delivered to the receiver? Or will the Arduino just stream packets even if the receiver is offline?

wbcrisman


Do your specifications require the sender to know if the packet was delivered to the receiver? Or will the Arduino just stream packets even if the receiver is offline?




Not at the moment, if I do end up having packets that i cant do with out ill see about flagging certain packets to ensure they get there.

SurferTim

Those do appear to be pointers. Where did you get that declaration? It is not in the ethernet library udp code.

SurferTim


Scroll up MattS-UK Posted the code

That explains it in more than one way.

Go Up