Run the Example
Project Content
The FreeRTOS Demo example is spread over two separate projects: one for the destination, the other for the source.
Projet | Folder | Description |
---|---|---|
Acklio Open-Source Example | Cloud | The Python source files of the UDP client/server application running on the Cloud side |
STM FullSDK Reference implementation | Middlewares / Third Party | The source files to build the FreeRTOS/IP/UDP client/server application to run on the board. Acklio FullSDK project folder is also in this directory. |
Dependencies
Resource | Link |
---|---|
STM32CubeIDE | IDE to load ST projects. It can be downloaded from the official website |
GitLab Repository | https://gitlab.acklio.cloud/acklio-opensource/stm-fullsdk-reference-implementation/-/tree/release/STM32CubeExpansion_LRWAN_V2.1.0 |
Build & Flash Documentation | The STM32Cube compilation page explains in detail how to build and flash the device for the FreeRTOS demo |
The IP stack library used on device-side is uIP.
The Cloud application requires Python 3 to run.
Demo Application Workflow
The messaging between the client application and the server application follows the scenario illustrated below.
During a session, four messages are transmitted between the client and the server applications. They contain the session identifier and a dummy payload.
- Message #1 – Small uplink payload (less than 50 bytes) which is not fragmented.
- Message #2 – Small downlink payload (less than 50 bytes) which is not fragmented.
- Message #3 – Large uplink payload (more than 242 bytes) which is fragmented.
- Message #4 – Large downlink payload (more than 242 bytes) which is fragmented.
The downlink message is always sent 5 seconds after the server application received the uplink message. Once it is received by the client application, it is printed in the logs.
The transmission delay between two consecutive uplinks is set to 600 seconds.
At the end of the session, a new session of transmission starts.
FreeRTOS Tasks
The device application is made of three layers, implemented as three FreeRTOS tasks as illustrated below.
The communication between the device application and the Cloud application is made by sending external messages.
The communication between layers uses queueing and internal messages. The internal message types are defined in common.h
by the message_type_e
enumeration.
Periodical Messages
External messages are transmitted periodically from one layer to the next.
From | To | Message | Description |
---|---|---|---|
task_app | task_app | SEND | Sends an external message |
task_app | task_uip | SEND | Sends an external message |
task_uip | task_uip | SEND | Sends an external message |
task_uip | task_sdk | SEND | Sends an external message |
task_sdk | task_uip | TX_RESULT | Result of the previous transmission request |
task_uip | task_app | TX_RESULT | Result of the previous transmission request |
task_sdk | task_uip | DATA_RCVD | Data has been received |
task_uip | task_app | DATA_RCVD | Data has been received |
The message that
task_app
sends to itself is generated by the timer handler function that allows the periodic transmission of the external message.The message that
task_uip
sends to itself is due to the way the uIP stack works.
task_app
task_app
is the application task. It periodically requests to send an external message to the remote Cloud application (see below).
Let's take the example of a long message that should be sent from the device application to the Cloud application. It contains the following string, terminated by a new line character.
Hello, Acklio!
On user action in the Cloud application, the application task requests to send the following external string, terminated by a new line character.
Hi, there!
When the application task receives an external message from the remote Cloud application, it displays the first 48 bytes of the message, in hexadecimal.
In the case of a short message containing the string getLocalTime
, the application task of the Cloud application replies with a message structured as follows (where nnnnnnnnnn
contains the current board time in ms, left padded with 0).
local time: nnnnnnnnnn
task_uip
task_uip
contains the uIP stack. It forwards external messages from the application layer to Acklio FullSDK layer.
When the application layer wants to send an external message to the Cloud application, it forwards it to task_uip
that wraps it in an IPv6/UDP datagram and requests task_sdk
to send it.
Conversely, when a datagram is received from the Cloud application via task_sdk
, task_uip
extracts the payload and forwards it to the application layer.
task_sdk
task_sdk
runs the FullSDK which performs IPv6/UDP compression/decompression and fragmentation when required.
Device Initialization
The main
function, in main.c
, initializes the system (peripherals, clock, etc.) then starts the tasks.
From | To | Message | Description |
---|---|---|---|
task_app | task_uip | INIT | Internal message to initialize the uIP layer |
task_uip | task_sdk | INIT | Internal message to initialize Acklio FullSDK layer |
task_sdk | task_sdk | PROCESS | Run Acklio FullSDK processing |
task_sdk | task_sdk | NETWORK_JOINED | Connectivity is up |
task_sdk | task_sdk | NETWORK_CONFIGURED | Device network interface is configured |
task_sdk | task_uip | NETWORK_CONFIGURED | Device network interface is configured |
task_uip | task_app | READY | Internal message informing on layer status |
task_uip | task_app | CAN_NOT_SEND | Internal message: The layer is busy, the transmission request cannot be fulfilled |
Cloud Application
The Cloud application can send downlink messages to the device on user action (See above, task_app).
Action for a Long Message
When the D
key is pressed and then Enter
, a long message is sent to the device that contains a timestamp, a sequence number and a text.
nnn - hh:mm:ss - text
nnn
– The sequence number, with three figures. It starts from000
and is incremented with each new downlink message. When it reaches999
it wraps around to000
.hh:mm:ss
– The timestamp.text
– The text contain enough characters to make a message of 300 bytes.
Action for a Short Message
When the T
key is pressed and then Enter
, a short message is sent to the device, requesting the local time of the device. The reply of the device is displayed.
More generally, every uplink message sent by the device is displayed.
Run the Demo Example
The Demo starts on Cloud-side.
Cloud Side
The Cloud application must run on the same machine as the VPN agent.
In the acklio-opensource-examples/examples/freertos/udp-client-server
folder, run the following command:
python3 -m cloud -dev-ip <dev_ipv6_addr> -dev-port <dev_udp_port> -app-ip <app_ipv6_addr> -app-port <app_udp_port_>
Where:
<dev_ipv6_addr>
is the IPv6 address of the device, as displayed in the device profile in Acklio IPCore.<dev_udp_port>
is the UDP port of the device, as defined in Acklio IPCore.<app_ipv6_addr>
is the IPv6 address of the application address, as defined in Acklio IPCore.<app_udp_port>
is the application UDP port, as defined in Acklio IPCore.
The server application requires an IPv6 address to start. To assign it to one of the network interfaces on your machine, run:
sudo ip -6 address add <app_ipv6_addr> dev <network_interface>
Client Side
Make sure that you flashed the board and that the board is connected to the development computer.
In the STM32 Cube IDE:
- Select the "Release" build configuration.
- Go to "Run > Run Configurations..." to create the "Run" configuration from it.
- Click the "Run" button.
View the Logs
To display trace messages generated by the device application, use one of the following commands depending on your terminal emulation application.
miniterm /dev/<usbPort> 9600
minicom -D /dev/<usbPort> -b 9600 -w