Important notice: This post is about integrating the legacy Nabto 4/Micro (uNabto) platform which is no longer supported for new designs. Instead, it is highly recommended to look at the modern Nabto 5/Edge platform. CC3200 is not yet supported by Nabto 5/Edge – but you can follow the general integration guide for integrating Nabto 5/Edge to new platforms, including a step-by-step test-harness to simplify the integration. Also, take a look at the embedded platforms currently supported by Nabto 5/Edge.
…or Love at Second Sight
But let’s start in the beginning. TI’s CC3200 wireless Wi-Fi MCU is an interesting platform for a range of IoT applications. Many customers were asking us for a reference implementation of the uNabto Platform Adapter – some reported performance problems with their own. Huh? Performance problems? We need to investigate that!
The goal was a state-of-the-art Nabto streaming implementation with FreeRTOS and hardware accelerated encryption. After working my way through the Code Composer Studio IDE, Uniflash and the CC3200 SDK this seemed like a rather straightforward task.
After implementing the uNabto Platform Adapter for the CC3200, uNabto was running on the CC3200 and echoing streaming data coming from our stream_tester application. But it was REALLY SLOW (28.8k dial up modem slow).
Let the debugging begin…
Armed with stream_tester, tcpdump and a serial terminal I started to fiddle around using different stream window and segment sizes, specified in unabto_config.h
#define NABTO_STREAM_RECEIVE_SEGMENT_SIZE 500 #define NABTO_STREAM_RECEIVE_WINDOW_SIZE 2
After some tries, I got the impression that the transmission starts to stutter with segment sizes greater than ~500 bytes. Smaller window sizes made it slightly better but that could be a side effect. First idea: Network buffers full or overflowing.
To rule out low-level problems, I decided to create a simple UDP echo server and flood the CC3200 with messages. But even at bit rates much higher than what the Nabto stream achieved there were no substantial packet losses. The CC3200’s socket implementation seems to work. So, back to uNabto.
uNabto’s default log level doesn’t give much information on what’s going on under the hood. Changing it to DEBUG in unabto_config.h with
#define NABTO_ENABLE_LOGGING 1 #define NABTO_LOG_SEVERITY_FILTER NABTO_LOG_SEVERITY_DEBUG
should uncover a little bit more. I ran the stream_tester again with stream window and segment sizes set back to default values (4 and 1247 respectively). A short peek into the debug logs in the serial terminal:
4097, <-- [32,12] DATA, 0 bytes (xmitFirst/Count=30/2)
(.-1146771279.) STREAM EVENT, dlen: 0
4097 --> [12,31] DATA, 0 bytes
Invalid request message length: 1368
Invalid request message length: 1368
Invalid request message length: 896
(.-1146771279.) STREAM EVENT, dlen: 801
4097 --> [15,32] DATA, 801 bytes
4097 Data=801 bytes, seq=15 inserted into slot=3
4097, <-- [32,12] DATA, 0 bytes (xmitFirst/Count=32/0)
(.-1146771279.) STREAM EVENT, dlen: 1247
4097 --> [12,32] DATA, 1247 bytes
4097 Data=1247 bytes, seq=12 inserted into slot=0
4097, <-- [32,12] DATA, 0 bytes (xmitFirst/Count=32/0)
Invalid request message length: 1368
Invalid request message length: 1368
Invalid request message length: 372
Ha! Quite some Invalid request message length in there. This log message is printed shortly before the uNabto framework drops our messages in unabto_message.c. Not good. What does tcpdump tell us?
09:41:40.946054 IP 192.168.1.18.51211 > 192.168.1.128.49331: UDP, length 92
09:41:41.561571 IP 192.168.1.128.49331 > 192.168.1.18.51211: UDP, length 1324
09:41:41.561692 IP 192.168.1.128.49331 > 192.168.1.18.51211: UDP, length 892
09:41:41.561798 IP 192.168.1.128.49331 > 192.168.1.18.51211: UDP, length 1324
Biggest message sent to the CC3200 is 1324 bytes long. This is smaller than the invalid 1368 bytes messages. But where do they come from? Back to the UDP echo server…
Last time I just echoed the received data and counted the number of received and sent bytes. Let’s also print the message sizes this time. These are returned by the CC3200 SDK’s sl_RecvFrom funcion (equivalent to the POSIX socket recvfrom) when reading from the socket. Sending UDP messages of size 1024 from my UDP client resulted in the following terminal printouts:
read: 2048 bytes
read: 2048 bytes
read: 2048 bytes
read: 1024 bytes
read: 1024 bytes
read: 1024 bytes
Woops. What happened there? Apparently sl_RecvFrom doesn’t necessarily return one message at a time. This behavior differs from the POSIX socket standard. After some tests I found that message lengths < 540 bytes work as expected. Everything ≥ 540 bytes causes concatenation. This correlates with the oberservations on the ~500 bytes segment size threshold (considering the additional Nabto stream payload).
So how to prevent shoveling concatenated packets from sl_RecvFrom to the uNabto framework, which eventually will drop those? Well, we heave the message header. If we read the 16 header bytes first, we get to know the message length. Having this information, we can read exactly the remaining bytes of the current message from sl_RecvFrom, even if it goes wild and would give us more.
ssize_t nabto_read(nabto_socket_t sock, uint8_t* buf, size_t len, uint32_t* addr, uint16_t* port) { struct SlSockAddrIn_t sa; SlSocklen_t addrlen = sizeof(sa); // read the header first ssize_t bytesRecvd = sl_RecvFrom(sock, buf, 16, 0, (struct SlSockAddr_t*)&sa, &addrlen); if (bytesRecvd < 16) { return 0; } // get actual message length from header uint16_t msgLen; READ_U16(msgLen , buf + 14); if(msgLen > len) { msgLen = len; } // read the remaining message bytesRecvd += sl_RecvFrom(sock, buf + 16, msgLen - 16, 0, (struct SlSockAddr_t*)&sa, &addrlen); if (bytesRecvd < 16) { return 0; } *addr = sl_Htonl(sa.sin_addr.s_addr); *port = sl_Htons(sa.sin_port); return bytesRecvd; }
I tested the performance of the workaround with stream_tester and 1 MB of data. The transmission to the C3200 and back took less then 10 seconds using a local connection. Looks very good! Using a mobile phone connection the encrypted transmission took 30 seconds on the first shot. Nice!
CC3200 <3 uNabto
The Code Composer Studio project for the Nabto echo server including the reference implementation of the uNabto Platform Adapter is now available here on github.