nRF5 IoT SDK  v0.9.0
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
Server

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.


lwIP_TCP_Server.svg
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.

lwIP_TCP_Client_Server.svg
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 nRF5x 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 enabledTracing 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>external/lwip/license.txt
This example requires more than 16k RAM and is supported only for the PCA10040 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>/examples/iot/tcp/server

See below for a short state diagram that describes the application states.

LwIP_TCP_ApplicationStateDiagram.png
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 commissioning is enabled, additional LED and Button assignments are made.
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.

  1. Compile and program the application. Observe that the advertising LED is lit. Ensure the custom SoftDevice located at <InstallFolder>components/softdevice/s110_for_ipv6 is used.
  2. Prepare the Linux router device by initializing the 6LoWPAN module.
  3. Discover the advertising device by using the hcitool lescan command.
  4. Connect to the discovered device from the Linux console by using the Bluetooth 6LoWPAN connect command.
  5. Now the advertising LED is turned off and the connected LED is lit.
  6. Run the Wireshark or hcidump program and observe the btX interface. Observe the periodic Neighbor Solicitation messages sent by the lwIP stack.
  7. 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.
  8. Use a TCP client to send request packets as described in the section TCP Request Format on the global address of the nRF5x and TCP port number 9000. The TCP client application can be another nRF5x running the lwIP TCP client application or a local TCP client that connects to the server and sends data to the application.
  9. Disconnect from the device by using the Bluetooth 6LoWPAN disconnect command.
  10. Observe that only the advertising LED is lit.

Example Python Client

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 nRF5x 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

  1. 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.
  2. In case no global address is assigned to nRF5x, 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.
  3. If you observe that the client requests are initiated on Ethernet but not sent on the Bluetooth network interface to the nRF5x 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.