Sunday, 4 November 2012

Steady data transmission over WIFI - Part 2 - Unexpected oversleeping

The first puzzling thing to show up on the transmission graphs was the amount of time one of the machine  appeared to be sleeping. Sleeping occurs in the test application as part of the main-loop: when it's not yet time to send (every 20ms in the example) or check for incoming packets (every 2ms), the application simply goes to sleep. Instead of sleeping for a "long" time (for example 19ms if it took 1ms to send the packet), it sleeps multiple times by a small amount (2ms).

All this appears OK on the bottom line of the graph (the Raspberry PI playing the "client" role) but on the top  (the Windows 7 netbook), the blue blocks representing the Sleep calls are far too big! They should be the same size as the bottom ones.


As a result, in this particular test, the receive packet operation on the server side is running at longer intervals (16ms) than specified (2ms).

Weirdly enough, the problem didn't show when doing the same test using a Windows 7 desktop PC instead of the netbook.

It turns out that on some Windows machines, the granularity of the Sleep() function can be quite substantial, basically not less than 16ms (not sure if it has anything to do with 32-bit vs 64-bit Windows).

Anyway, this granularity can reduced using the Multimedia function timeBeginPeriod (this requires the app to link against Winmm.lib though):


This is more like it!

Saturday, 3 November 2012

Steady data transmission over WIFI - Part 1 - The set-up

As part of a “bricolage” project, I’m investigating replacing the 2.4Ghz RC transmitter of my tricopter with a WIFI-based system. I believe using WIFI could open the door to a lot of other interesting things... More on that later, if the whole thing ever works!

So I’ve started some experiments at home between my old netbook and a Raspberry PI equipped with a USB 
WIFI adapter.



My goal is to transmit packets of data very regularly. I totally accept packet loss every now and then and I expect it to increase as I approach the limit of the transmission range. However, I really need the transmission to be as steady as possible: no transitory lag, no bursts of data and if possible a reasonable (few milliseconds) and fairly constant latency.

In terms of software, I’ve decided to go for the UDP protocol with non blocking sockets checked at a constant rate (basically a main-loop running at a fixed frequency). To study this approach, I’ve developed a command line test application, running on the two distant computers. The app sends packets, or receives them, or do both and log everything into a file.

Each of these data-exchange session is what I call a “test”. The app can go through a series of these tests (each with its own settings), one after the other at specified times. This is the “test schedule”. It is described in a text file that gets read by the application at startup (both end must have the same file). Here’s an example:
# Test #1 (name;starttime;duration;sleepDuration)
Test1;15000;8000;2
    # Server (role, packetSize, sendInterval)
    SENDER;1024;20
    # Client (role, receiveInterval)
    RECEIVER;10

# Test #2
Test2;25000;8000;2
    # Server 
    RECEIVER;10
    # Client 
    SENDER;1024;20
    
# Test #3
Test3;35000;8000;2
    TRANSCEIVER
        SENDER;1024;20
        RECEIVER;10
    TRANSCEIVER
        SENDER;1024;20
        RECEIVER;10
A machine is arbitrarily defined as the “server” (initially I wanted it to send the test-schedule to the other one at startup, but didn’t go that far) and the other one is the “client”. Depending on the role, the application will look at the appropriate sections in the file.

For each test, a log is created. For the test named “Test1” in the example above, I get two files “Test1.server.csv” and “Test1.client.csv”. Here are first few lines of one these files:
#timestamp;duration;action;...
35000;2;SLEEP
35002;3;SLEEP
35005;3;SLEEP
35008;3;SLEEP
35011;0;RECEIVE;0;379;1024
35011;0;RECEIVE;0;-1;-1
35011;3;SLEEP
35014;3;SLEEP
35017;2;SLEEP
35019;3;SLEEP
35022;1;SEND;0;0;1024
35023;0;RECEIVE;0;0;1024
35024;0;RECEIVE;0;-1;-1
And now, the fun part! Once I collect all these files, I can visualize the result graphically with another application (using QT of course!):
Example of a rather nice full-duplex session. Packet 128 got lost!
Being able to analyze graphically what happens in a test is tremendously useful. I toyed with network programming in the past, and making sense of text logs was pretty hard. By contrast, a glimpse at a graph like the one above and you instantly see if something’s wrong.

Needless to say, something did appear wrong right from the first tests...