nRF5 SDK v15.0.0
Client
This information applies to the following SoftDevices: S132, S140

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.


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

lwIP_TCP_Client_Server.svg
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 nRF5x 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 and Button assignments.
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 Yes Scheduler is used for processing stack events.
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

Setup

You can find the source code and the project file of the example in the following folder: <InstallFolder>\examples\iot\tcp\client

See below for a 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

Button assignments

Button Mapped Action
1 TCP connection request
2 TCP data transfer start/stop
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.
  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.
  7. 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.
  8. Use a TCP Server to listen on TCP port number 9000.
    Note
    This example is designed to complement the lwIP TCP Server example, and they will work together provided that this application is modified to the address of the server application.
  9. 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.
  10. 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.
  11. Use Button 2 to stop and start the periodic Ping requests.
  12. Disconnect from the device by using the Bluetooth 6LoWPAN disconnect command.
  13. 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
SERVER_ADDR = ''
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

  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 the 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 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.
  4. 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.

Documentation feedback | Developer Zone | Subscribe | Updated