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 the sections TCP Request Format and TCP Response Format respectively.
A TCP connection to the remote server can be requested by pushing Button 1.
Once the connection is successfully established (LED 3 lights up), the user can request periodic sending of requests by pushing Button 2. This button is also used to stop the data when in transfer state. Therefore, Button 2, based on state, can be used to both start and stop the sending of 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
- Note
- The TCP server's IPv6 address to which the requests are sent is assumed to be 2004::02AA:BBFF:FECC:DD:EEFF. The example must be modified to match the address of the server in use. For example, if the lwIP TCP server application is used as the server that the client is sending requests to, and it has public Bluetooth device address 00:DA:BB:C9:A4:E9 and the prefix assigned to the server by the router is 2003::/64, then the client must use the servers global address 2003::02DA:BBFF:FEC9:A4E9. See Creating IPv6 addresses for details.
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 back to a request with a 8-byte response packet with 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 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 lwip_tcp_client. The source code and project file of the example can be found at: <InstallFolder>/Nordic/nrf51/examples/iot/lwip_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 Linux commands for 6LoWPAN 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.
- An ICMP ping can be used 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 compliment the lwIP UDP Server example, and they will work together provided 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 BD address to be 00: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::02AA:BBFF:FECC:DDEE.
SERVER_ADDR = '2004::02AA: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]
rx_sequence_number = ~rx_sequence_number
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 takes 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. This can be done 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.