Overview
This example demonstrates how the lwIP stack can be used on Nordic's 6lowpan interface to listen on a TCP port. Port number 9000 is used in this example. The TCP listen port is not bound to a particular address and hence it is possible to connect on the TCP port on a link-local or on global address(es). Once the TCP connection is established, the server waits for requests from the client in the format specified in section TCP Request Format. When receiving a request, the response is sent in the TCP Response Format format.
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 the request with a 8-byte response packet of following format:
Field | Requested Sequence number in uint32 format | 'P' | 'o' | 'n' | 'g' |
Size (octets) | 4 (Network Order) | 1 | 1 | 1 | 1 |
The TCP client could be a PC application communicating to the UDP server on the kit as, shown in Figure 1 below.
Figure 1: Setup of the lwIP based IPv6 TCP server application
Or, the UDP client could be the example client application included in the SDK sending requests to the server, as shown in Figure 2.
Figure 2: Setup of the lwIP based IPv6 TCP client with TCP server application
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 | 1 | One timer is used to periodically service the lwIP, the interval is 200 ms. |
Button | 0 | No buttons are used in the example. |
LEDs | 4 | LEDs are used as an indicator of the application states. See LED assignments. |
Adv Data Encoder | Yes | The device name used is 'LwIPTCPServer', IPSP Service UUID is included in the UUID list. |
Scheduler | Yes | Scheduler is 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
-
This example requires more than 16k RAM and is supported only for the PCA10028 board.
Setup
The name of the example is iot_lwip_tcp_server. The source code and project file for this example can be found at: <InstallFolder>/Nordic/nrf51/examples/iot/tcp/server
See below for a short 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 |
- 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. Ensure the custom SoftDevice located at <InstallFolder>/Nordic/nrf51/components/softdevice/s110_for_ipv6 is used.
- 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. Observe the periodic Neighbor Solicitation messages sent by the lwIP stack.
- You can use an ICMP ping on the link-local and on the global IPv6 address assigned to the device to ensure the device is reachable.
- Note
- To find the global address, use the prefix assigned to the interface in Router Advertisement.
- Use a TCP client to send request packets as described in the section TCP Request Format on the global address of the nRF51 and TCP port number 9000. The TCP client application can be another nRF51 running the lwIP TCP client application or a local TCP client that connects to the server and sends data to the application.
- Disconnect from the device by using the Bluetooth 6LoWPAN disconnect command.
- Observe that only the advertising LED is lit.
Python Client Example
Below is a Python client example that connects to the server application, sends 100 ping requests and then exits. The server address used here is an example address and will need to be modified based on the server address of the nRF51 that runs the lwIP TCP server application.
import socket
import struct
#This example assumes the server BD address to be 00:AA:BB:CC:DD:EE and the used global prefix 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
sequence_number = 1
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.connect((SERVER_ADDR, SERVER_PORT))
while sequence_number < 101 :
data = struct.pack("!I", sequence_number)
data += 'Ping'
sock.sendto(data, (SERVER_ADDR, SERVER_PORT, 0, 0))
recv_data = sock.recvfrom(8)
print recv_data
rx_sequence_number = struct.unpack("!I", recv_data[0][:4])[0]
if sequence_number is not rx_sequence_number:
print "Sequence number mismatch!"
sequence_number+= 1
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 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 client requests are initiated on Ethernet but not sent on the Bluetooth network interface to the nRF51 running the TCP server, it is possible that the forwarding between networks is not enabled. You can do this on Linux using the command
sysctl -w net.ipv6.conf.all.forwarding=1
.