Using NetServices and forcing an immediate tcp transmit

11 May 2012

I have an interesting problem where I need to transmit TCP packets deterministically rather than whenever the tcp/ip stack gets around to sending the packet. I haven't been able to accomplish this using Netservices but I would really like to. I have used the lwip library directly and I am able to send tcp packets at 10hz exactly with the data I need in each packet using the tcp_write followed by a tcp_output. However in Netservices there is no access to tcp_write and tcp_output directly. Does anyone know where I can start to modify the Netservices library to gain direct access to tcp_write and tcp_output ? I have tried hard at this and just can't figure it out. I have played with options in lwipopts.h and the best I could do was set the TCP_MSS to 10 (my max packet size) which kind of works, the packets are no larger than 10 bytes but they don't get transmitted immediately, they are still queued up somewhere.

I would really like to use Netservices for this project, I just need access to tcp_write and tcp_output.

Thanks,

Errol

11 May 2012

Sounds like you are trying to an URGENT tcp message (see http://en.wikipedia.org/wiki/Transmission_Control_Protocol skip to the "Out of band data" section). Just googling a bit does show that urgent TCP has been implemented in LWIP in some places - but I don't know if MBED's port has it. Search for it in the source. If that exists, it skips the data queue and xmits immediately.

To do truly deterministic Ethernet, you need a different physical layer, because Ethernet was built around collisions and retries. See http://en.wikipedia.org/wiki/Ethercat if you really want deterministic TCP or UDP.

Another idea - often you can get the same job done by sending the data to your target ahead of time, and then have him wait for a deterministic "trigger" signal that you just pulse with a digital output pin, when you want him to "go".

Another another idea - CANbus has deterministic timing, and MBED has CANbus.

12 May 2012

Errol, can you not just #include <lwip/tcp.h> from your code which includes the NetServices library and then make calls to tcp_write() and tcp_output().

14 May 2012

Thanks for the responses!

I haven't tried just including lwip/tcp.h yet, I'll give it a shot and let you know how it goes. I have however used lwip directly without the Netservices wrapper and have been able to get everything to work the way I need but I would like to use Netservices at the same time for other things that it helps with (http, etc.).

I am aware that Ethernet is not a very deterministic architecture but I have to use it unfortunately for this project. Basically we have to push vehicle speed data that is converted from an analog signal to a tcp packet to another system that I don't have control of. Their system must have this in the form of separate tcp packets at a 10hz rate. I guess they already know that there are going to be occasional hiccups. The good thing is that its a very small network, one router and 2 nodes so the bandwidth is all mine..

14 May 2012

Errol Burrow wrote:

Basically we have to push vehicle speed data that is converted from an analog signal to a tcp packet to another system that I don't have control of. Their system must have this in the form of separate tcp packets at a 10hz rate.

Errol - Attach a timestamp to each speed value, so that you are sending time/speed pairs that can be graphed. It doesn't sound like you need to deliver the speed values at deterministic times, it just sounds like your client needs to know exactly when the speed values were sampled. This is a really common situation.

14 May 2012

Unfortunately their packet structure is already defined and they don't include a timestamp.. go figure. I believe this is because the system that uses the vehicle speed data needs to make immediate use of it and if its at all delayed then it won't use it. This is a real time system but not a safety system...

Anyway. I got this working with Netservices finally.

I modified lwip/include/lwip/tcp_impl.h

I changed:

TCP_TMR_INTERVAL 250

to this:

TCP_TMR_INTERVAL 40

this is the tcp fast timer value in milliseconds.

I also modified lwip/core/tcp_out.c

added lines of "apiflags |= TF_NODELAY" to the tcp_write and tcp_pbuf_prealloc functions.

Granted this fix is more of a temporary hack that would only work for my specific situation and probably would not be suitable for anything else.

15 May 2012

I think I found a better way to do this.

At the bottom of the tcp_write() function (just before return ERR_OK;) in tcp_out.c I simply added this line:

tcp_output(pcb);

This basically makes every single call to tcp_write force an immediate output of the packet. In effect a tcp_write() tcp_output() combined into one function. It might even be better to create a new function in tcp_out.c called something like "tcp_immediate_write()" instead to maintain backwards compatibility with code that relies on the standard behavior. However, this solves my problem and allows me to continue to use the Netservices wrapper and all its goodness.

Thanks, Errol

15 May 2012

You will probably want to remove the network switch from your setup and just directly cable the two devices to eliminate any latency the switch might add (I run my mbed ethernet directly cabled to my PC).

It seems to me (from reading between the lines of your additional info) that what you are really after is just the instant delivery of very small packets of data. TCP/IP is really designed to do the opposite - to reliably deliver large volumes data with an acceptable delay.

You seem to have gotten where you need to go, so nice work, but - CAN or UDP would have been better suited, if you had the whole thing to do over again :)

15 May 2012

Dave,

I completely agree. I use CAN (J1939 specifically) for many things around here and I have actually made a CAN->Ethernet gateway that uses UDP and Multicast utilizing the mBed platform which works great. Unfortunately on this project I am forced to use TCP but it's definitely not the right choice for lowest latency.