Overview
This example demonstrates how the lwIP stack can be used on Nordic's 6lowpan interface to send data on a remote TCP port. Remote port number 9000 is assumed in this example. Local port number 9001 is used to send requests and receive responses. Request and response formats used for this example are described in sections TCP Request Format and TCP Response Format, respectively.
To request a TCP connection to the remote server, push Button 1.
Once the connection is successfully established (LED 3 lights up), you can request periodic sending of requests by pushing Button 2. This button is also used to stop the data when in transfer state. Therefore, depending on the state, you can use Button 2 to both start and stop sending the data.
The TCP server could be a PC application communicating to the TCP client on the kit, as shown in Figure 1 below.
Figure 1: Setup of the lwIP based IPv6 TCP client application
Or, the TCP server could be the example server application included in the SDK responding to requests from this example application in Figure 2.
Figure 2: Setup of the lwIP based IPv6 TCP client with TCP server application
TCP Request Format
In order to demonstrate data exchange on the TCP port, the application is designed to expect an 8-byte echo request in the following format from the TCP Client.
Field | Sequence number in uint32 format | 'P' | 'i' | 'n' | 'g' |
Size (octets) | 4 (Network Order) | 1 | 1 | 1 | 1 |
TCP Response Format
In response to a request from the client, this application responds to a request with an 8-byte response packet in the following format:
Field | Requested Sequence number in uint32 format | 'P' | 'o' | 'n' | 'g' |
Size (octets) | 4 (Network Order) | 1 | 1 | 1 | 1 |
Common Modules Dependency and Usage
This section summarizes the usage of nRF51 resources and common modules in the examples apart from the IoT 6lowpan and lwIP stack library.
Module | Inclusion/Usage | Description |
Timer | 3 | Timer for lwIP, button module, and application timer to send data periodically. |
Button | 2 | Buttons are used to control the application. See the Overview section. |
LEDs | 2 | LEDs are used to indicate the application states. See LED assignments. |
Adv Data Encoder | Yes | The device name used is 'lwIPTCPClient', IPSP Service UUID is included in the UUID list. |
Scheduler | No | Scheduler is not used for processing stack events. |
UART Trace | Included not enabled | Tracing is included but not enabled by default. |
- Note
- The lwIP library used for this example is under BSD-style license; this is different from the Nordic SDK license. The license text can be found at <InstallFolder>/Nordic/nrf51/external/lwip/license.txt
Setup
The name of the example is iot_lwip_tcp_client. The source code and project file of the example can be found at: <InstallFolder>/Nordic/nrf51/examples/iot/tcp/client
See below for a state diagram that describes the application states.
Figure 3: Application State Diagram.
LED assignments
Application State | LED 1 State | LED 2 State | LED 3 State | LED 4 State |
Idle | OFF | OFF | OFF | OFF |
Advertising | ON | OFF | OFF | OFF |
IPv6 Interface Up | OFF | ON | OFF | OFF |
IPv6 Interface Down | ON | OFF | OFF | OFF |
TCP Connected | OFF | OFF | ON | OFF |
TCP Ping | Refer to table below | Refer to table below | Refer to table below | Refer to table below |
ASSERT | ON | ON | ON | ON |
By using the LEDs on the board, the remainder after division of the received Sequence number by 16 is displayed in the following manner.
Value | Binary | LED 1 State | LED 2 State | LED 3 State | LED 4 State |
0 | 00000000 | OFF | OFF | OFF | OFF |
1 | 00000001 | ON | OFF | OFF | OFF |
2 | 00000010 | OFF | ON | OFF | OFF |
3 | 00000011 | ON | ON | OFF | OFF |
4 | 00000100 | OFF | OFF | ON | OFF |
5 | 00000101 | ON | OFF | ON | OFF |
6 | 00000110 | OFF | ON | ON | OFF |
7 | 00000111 | ON | ON | ON | OFF |
8 | 00001000 | OFF | OFF | OFF | ON |
9 | 00001001 | ON | OFF | OFF | ON |
A | 00001010 | OFF | ON | OFF | ON |
B | 00001011 | ON | ON | OFF | ON |
C | 00001100 | OFF | OFF | ON | ON |
D | 00001101 | ON | OFF | ON | ON |
E | 00001110 | OFF | ON | ON | ON |
F | 00001111 | ON | ON | ON | ON |
Button assignments
Button | Mapped Action |
1 | TCP connection request |
2 | TCP data transfer start/stop |
- Note
- If the application asserts, it is halted.
-
This application is not power optimized!
Testing
See Connecting devices to the router for a list of relevant Linux commands.
- Compile and program the application. Observe that the advertising LED is lit.
- Prepare the Linux router device by initializing the 6LoWPAN module.
- Discover the advertising device by using the hcitool lescan command.
- Connect to the discovered device from the Linux console by using the Bluetooth 6LoWPAN connect command.
- Now the advertising LED is turned off and the connected LED is lit.
- Run the Wireshark or hcidump program and observe the btX interface.
- You can use an ICMP ping on the link-local and on the global IPv6 address assigned to the device to ensure that the device is reachable.
- Note
- To find the global address, use the prefix assigned to the interface in Router Advertisement.
- Use a TCP Server to listen on TCP port number 9000.
- Note
- This example is designed to complement the lwIP UDP Server example, and they will work together provided that this application is modified to the address of the server application.
- Press Button 1 to request TCP connection to the server. To see if the connection was successful, check the LED pattern that indicates the TCP Connected state, as described in the LED assignments.
- In TCP Connected state, press Button 2 to initiate periodic sending of requests. Observe the LED pattern to see if a response is received.
- Note
- Attempts to send requests every 50 ms is made by the application irrespective of whether the server responded or not.
- Use Button 2 to stop and start the periodic Ping requests.
- Disconnect from the device by using the Bluetooth 6LoWPAN disconnect command.
- Observe that only the advertising LED is lit.
Python TCP Server Example
Below is a python server example that listens on port 9000 and sends back responses for requests received on the port. Request and response structure are according to the format specified in sections TCP Request Format and TCP Response Format respectively.
import socket
import struct
#This example assumes the server's random static BD address to be C0:AA:BB:CC:DD:EE and the global prefix used to be 2004::/64.
#Therefore the global IPv6 address of the server will be 2004::C0AA:BBFF:FECC:DDEE.
SERVER_ADDR = '2004::C0AA:BBFF:FECC:DDEE'
SERVER_PORT = 9000
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
server_addr = (SERVER_ADDR, SERVER_PORT, 0, 0)
sock.bind(server_addr)
sock.listen(1)
client, addr = sock.accept()
print 'Connected'
while 1:
recv_data = client.recv(128)
recv_len = len(recv_data)
if recv_len >= 8:
rx_sequence_number = 0
rx_sequence_number = struct.unpack("!I", recv_data[:4])[0]
data = struct.pack("!i", (rx_sequence_number))
data += 'Pong'
client.send(data)
sock.close()
del sock
Troubleshooting guide
- It is possible that the global address is not immediately available on the connection as the Neighbor Discovery, Router Advertisement, and Duplicate Address Detection procedures take a few seconds to complete.
- In case no global address is assigned to the nRF51, the lwIP stack does not permit sending packets to a global address. This means that if a TCP request packet was received from a global address, the response will not be sent, as there is no global address available for this application.
- If you observe that the server responses are received at the btX interface but the client never receives them, it is possible that the forwarding between networks is not enabled. You can do this on Linux by using the command
sysctl -w net.ipv6.conf.all.forwarding=1
.
- In case this example is reachable and sending requests every 200 ms, but these requests do not make it to the listening server, it is possible that the application is not configured with the correct remote server address. Verify that the address m_remote_addr in the application matches the server address.