Note: This application uses glib and graphics functionalities. To better understand how to use them, please refer to Enable LCD screen on WSTK KBA about how to setup graphics easily (used on sensor) and this KBA for a better knowledge on the glib library usage (used on sink).
Introduction
In this article we will learn about the Connect API and create a simple sensor-sink network. The purpose is to understand the basic functionalities of Connect through a simple RF sensor application and to integrate LCD screen printing into Connect, which is not presented yet in any example.
Specification
To create a somewhat real network, three wireless starter kits should be used – one sink and two sensors – however, it will work with two WSTKs as well. We will use Connect to create the network with encryption enabled, using a 2.4 GHz 802.15.4 radio profile.
The sensors will be sleepy-end devices (configurable), running one “task” (called Event in Connect) after the network is up, which sends out the sensor information to the sink every second. The sensor should print the sent values and basic information on its screen.
The sink upon receiving the packets should update its screen accordingly, while also should show basics network status info.
Quick introduction to Connect
Connect is a network stack on RAIL's 15.4 specific API. It does not allow accessing lower layers, every message should go through the upmost network layer, which is the Connect messaging API. It is a production-quality wireless networking stack and development environment for broad based proprietary applications, full-featured, easily customizable wireless connectivity solution for the Sub-GHz and 2.4 GHz proprietary market. It is based on 802.15.4 like MAC. By taking care of the low-level details of network formation and radio configuration, the customer can focus on application development.
The main functionality of a Connect application is written in the Callbacks source file. There are several built-in events – like message received, child has joined etc. – named “Callbacks”, and optionally create-able, user customizable Events. The Callback functions will run when their tied trigger occur (e.g. a message was received), and the so called “Event handlers” will run whenever we start or schedule their Events. These Events can be considered as tasks in an embedded operating system. They are round-robin scheduled without pre-emption, therefore their handler functions will run until not stopped (or interrupted).
In this stack the main.c source file is part of the SDK, it should not be edited, user defined code should only go into the callbacks.c file. In Connect, setting up a network is rather easy, it is done by writing a few Callbacks. We must initialize the network and set the security keys in the MainInitCallback function – which will run only once upon init – then using an appropriate Callback let children join or start the joining process (depends on the node type). With this the network should be up, from this point we can modify the application behavior with the rest of the Callback functions or Event handlers.
Setting up the projects
There are several examples available for Connect. Our application will be very similar to the sensor-sink examples, but much simpler. Let’s start and build the application therefore from a blank flex project. The AppBuilder will guide us through the project setup and will be able to generate the application frame, even if we start from scratch. Our job will be to find a simple way to configure Connect to achieve the basic functionality, and to – fulfilling our specifications – include the graphics handling.
Sensor project
Create a new blank application for the Flex SDK. After the project was created, the AppBuilder should come up with the General tab open. Make sure the architecture listed here is correct, especially if the toolchain is set. As you can see on the picture below, we are using a Mighty Gecko board, SDK version 2.4.0.0 and the GNU ARM compiler for this example.
General settings
Under the “Radio Configuration” tab select the Connect 2.4 GHz 802154 radio profile. You can also select any of the profiles compatible with your board, however in this example we are using the 802154 one.
Radio configuration
Under the “Printing” tab disable the Command line interface. We won't use the CLI, we would like to rely on the LCD screen of the WSTKs and automatic network buildup in this example.
Printing setup
On the “Plugins” tab, make sure to set the tick next to the following options only:
Connect Common
Main
Connect Debug
Debug Print
Diagnostic Stub
Stack Packet Counters Stub
Connect HAL
HAL Library
Simulated EEPROM version 1 Library
Connect I/O
Serial
WSTK Sensors (sensor project only)
Connect PHY
PHY Library
Connect Stack
Form and Join
Frequency Hopping stub
MAC Packet Queue
Parent Support
Security AES
Security XXTEA Stub
Stack Common
RAIL
RAIL Library
RAIL Utility
Application Graphics
After you enable Application Graphics, a warning will pop up that this action will also enable the SPIDISPLAY. This is something that we want, so go ahead and click OK.
Disabling EXTCOMIN pin
If you click on the Application Graphics plugin, the Hardware Configurator Dependent Module Options will show on the right. It's important to turn off setting "Use EXTCOMIN pin for polarity inversion" here, as this option was reported to cause issues with Connect. We will take care of this polarity inversion from our code instead.
The next step is to configure the Callbacks under the Callbacks tab. As mentioned before, these are the built-in events for which we can determine a functionality through a Callback function. If we do not want to use a specific Callback, here we can disable them. From the user configurable Callbacks, we will only need the MainInitCallback and the StackStatusCallback callbacks for the sensor application. Turn them on by checking the box next to them under the "Is used?" column.
Callbacks configuration - sensor
To finish the AppBuilder configuration, go to the “Other” tab. Under this tab you can configure additional macros and includes, but most importantly for a Connect application, here you can configure the Events, the user-defined “tasks”. Add a new Event in the "Event Configuration" and edit its command, by clicking on the automatically generated name, to “reportControl” and its callback function to “reportHandler”. This Event will be responsible for the sensor data reporting. Add another one with “connectControl” and “connectCallback” command and callback names, respectively. This Event will be responsible for reconnecting whenever the network connection is lost.
Event configuration - sensor
Save the *.isc file and generate the project.
Unfortunately the WSTK Sensors plugin does not enable the Sensor in the hardware configurator, therefore it has to be done manually. Open up the *.hwconf file in the project and under the DefaultMode Peripherals make sure to enable the I2C Sensor.
Hardware configurator
Sink project
Create another blank project for the Sink. Make sure to set up everything the same as you did for the sensor on the “Radio Configuration”, “Printing” and “Plugins” tabs. One exception is under the “Plugins” tab: “WSTK Sensors” under “Connect I/O” should not be enabled, as for the Sink we won’t need the sensors on the WSTK.
Under the Callbacks tab we will need the following to be enabled: MainInitCallback for the initializations, StackStatusCallback and ChildJoinCallback for creating the network, and IncomingMessageCallback so we can process and show the data on the display.
Callbacks configuration - sink
As no Event will be used for the sink application – we can handle everything from the Callbacks – we've got no configuration to change on the "Other" tab.
Save the *.isc file and generate the project.
Callbacks and Events – Sensor
It’s time to write the main functionality of the sensor application – in the callbacks source file as mentioned before.
Please note, not all necessary code snippets will be presented here. You can find the rest of the code, such as definitions and includes in the attached source files.
For the sensor we turned two callbacks on, let’s start with one of those.
MainInitCallback
void emberAfMainInitCallback(void) {
//Start with one-time configurations
emberSetSecurityKey(&securityKey);
//try to restore the networks state from NVM
EmberStatus initStatus = emberNetworkInit();
if (initStatus != EMBER_SUCCESS) {
//start the connectControl event ASAP
emberEventControlSetActive(connectControl);
}
//Initializes graphics
GRAPHICS_Init();
}
In the MainInitCallback function we first set the security key, then try to restore the network state from the Non-Volatile Memory. As the child table is not deleted after a device reset, this can be a quick way to initialize the network. If the device was just set up or the table is not available, we start our connectControl Event to initialize the network connections from scratch. In the end of this Callback, the graphics is initialized, as all kind of one-time-run initialization like this should be put in this Callback.
connectHandler
Since it was just mentioned it, let's continue with the connectControl Event's Handler, the connectHandler.
void connectHandler(void) {
// Put disconnected message on screen
...
// Set parameters and join the network
EmberNetworkParameters parameters;
parameters.radioTxPower = MAX_TX_POWER;
parameters.radioChannel = RADIO_CHANNEL;
parameters.panId = PAN_ID;
#ifdef SLEEPY_MODE
emberJoinNetwork(EMBER_STAR_SLEEPY_END_DEVICE, ¶meters);
#else
emberJoinNetwork(EMBER_STAR_END_DEVICE, ¶meters);
#endif
emberEventControlSetInactive(connectControl); //we'll re-enable it if join has failed
}
This Event puts the “disconnected” message on the screen, as it only runs when there’s no network connection. After setting necessary radio parameters it tries to connect to the network – as a sleepy end device or a regular device, based on the configuration. As a last step, we set this Event inactive; if we didn’t do this, the Event would run endlessly.
StackStatusCallback
The StackStatusCallback function will run whenever the stack status changes. This can mean a good thing, like the network is up, or something worse, like it got disconnected, or the join failed, etc. Based on the status it carries, we will start the reportControl Event – sending out the sensor data – or schedule the connectControl Event with a retry interval to try connecting again.
void emberAfStackStatusCallback(EmberStatus status) {
if (status == EMBER_NETWORK_UP) {
//network is up, start the reportControl event ASAP
emberEventControlSetActive(reportControl);
} else
if (status == EMBER_NETWORK_DOWN || status == EMBER_JOIN_FAILED
|| status == EMBER_NO_VALID_BEACONS) {
//network or joining failure, try to reconnect with delay
emberEventControlSetDelayMS(connectControl, CONNECT_RETRY_INTERVAL);
}
}
reportHandler
If the network is up, the reportHandler function will run immediately. The Handler consists of four main steps: first, we need to get the sensor data through calling PluginWstkSensorsGetSample(). With emberMessageSend() we can send the data. Using the sink’s node ID, it will be sent to the right node. We wouldn’t want this function to run as fast it can, but every 1000 ms, so we schedule the Event with the report interval. As a last step, the LCD screen is refreshed with the help of the graphics library.
void reportHandler(void) {
// Get sensor data
emberAfPluginWstkSensorsGetSample(&(txBuffer.humidity),
&(txBuffer.temperature));
//Send message
emberMessageSend(SINK_NODE_ID, DATA_ENDPOINT, 0, sizeof(dataMsg_t),
(uint8_t*) &txBuffer, EMBER_OPTIONS_ACK_REQUESTED);
//Schedule task run in 1000 ms
emberEventControlSetDelayMS(reportControl, REPORT_INTERVAL);
//Refresh sensor data on screen
...
}
With this the sensor should be able to connect to the network, send its sensor data to the sink and use the LCD screen to provide basic information of its state and the sensor information. To try it however, we will need the sink to work as well.
Callbacks and Events – Sink
The sink is the coordinator in the network. Its responsibilities are to create the network and receive the data from the nodes – the sensors in our case – and print it on its screen. Three Callbacks will be needed to create this simple functionality in the application. MainInitCallback and StackStatusCallback for inits and creating the network – just as we used these for the sensor – and additionally, the IncomingMessageCallback.
In the source file you can see an additional function implemented here, the ChildJoinCallback. It is used for diagnostic purposes only, therefore not mentioned here.With the help of an auxiliary function called printChildTable, upon every new node detect and connection, some information and the full child table – the list of devices connected to the coordinator – will be printed using this Callback and function to the USART console.
MainInitCallback
The main initialization Callback is very similar to the one that we saw during discussing the sensor application. First, we need to set the security key, then initialize the network with the appropriate parameters. As a last step, we call the FormNetwork() function to start the network forming. In this Callback the display and graphics initializations are also done but removed from this code snippet for better readability.
void emberAfMainInitCallback(void) {
//Start with one time configurations
emberSetSecurityKey(&securityKey);
//try to restore the networks state from NVM
EmberStatus initStatus = emberNetworkInit();
if (initStatus != EMBER_SUCCESS) {
EmberNetworkParameters parameters;
parameters.radioTxPower = MAX_TX_POWER;
parameters.radioChannel = RADIO_CHANNEL;
parameters.panId = PAN_ID;
emberFormNetwork(¶meters);
}
// ... display-specific functions were cut out
}
StackStatusCallback
After the initializations ran, we should have our network up. This status change will invoke the StackStatusCallback function. In this function all we need to do is to permit joining to the network. Anything else except this below is for diagnostic purposes only, as you can see we also print out the child table to the console – as it is stored in the non volatile memory, from earlier it actually can contain devices.
void emberAfStackStatusCallback(EmberStatus status) {
if (status == EMBER_NETWORK_UP) {
//network is up, enable joining indefinitely
emberPermitJoining(0xff);
emberAfAppPrintln("Network is up");
printChildTable();
}
}
IncomingMessageCallback
Any time a message was received, this Callback will be invoked. The passed parameter will contain all the information of the message we need, like where it came from, RSSI and the data of course. Using all this information, we process and print the sensor data on the console, then on the LCD screen.
Writing these three Callbacks should provide the minimal functionality for the sink to be operating. As you could see, this time we didn’t use any Events, relying on the Callbacks alone could resolve the main functionality of the coordinator.
With the project set up and callbacks written, we can test our Connect network. After flashing, the network should set itself up, however it might need some time to do so. If connection doesn't want to happen, try resetting the sensors and the sink as well.
Conclusion
The intent of this article was to show through a basic application the initial steps of development in Connect. We could see how easy and automatic it is to form a network from any number of nodes, then transmit messages between them. Using the Callbacks and Events it was demonstrated how to schedule tasks and transfer useful data over the air. We made the application independent from the console and the command line interface by automating the network forming and utilizing the display modules on the wireless starter kits under Connect.
Proprietary Knowledge Base
Simple wireless sensor application in Connect with LCD support
Introduction
In this article we will learn about the Connect API and create a simple sensor-sink network. The purpose is to understand the basic functionalities of Connect through a simple RF sensor application and to integrate LCD screen printing into Connect, which is not presented yet in any example.
Specification
To create a somewhat real network, three wireless starter kits should be used – one sink and two sensors – however, it will work with two WSTKs as well. We will use Connect to create the network with encryption enabled, using a 2.4 GHz 802.15.4 radio profile.
The sensors will be sleepy-end devices (configurable), running one “task” (called Event in Connect) after the network is up, which sends out the sensor information to the sink every second. The sensor should print the sent values and basic information on its screen.
The sink upon receiving the packets should update its screen accordingly, while also should show basics network status info.
Quick introduction to Connect
Connect is a network stack on RAIL's 15.4 specific API. It does not allow accessing lower layers, every message should go through the upmost network layer, which is the Connect messaging API. It is a production-quality wireless networking stack and development environment for broad based proprietary applications, full-featured, easily customizable wireless connectivity solution for the Sub-GHz and 2.4 GHz proprietary market. It is based on 802.15.4 like MAC. By taking care of the low-level details of network formation and radio configuration, the customer can focus on application development.
The main functionality of a Connect application is written in the Callbacks source file. There are several built-in events – like message received, child has joined etc. – named “Callbacks”, and optionally create-able, user customizable Events. The Callback functions will run when their tied trigger occur (e.g. a message was received), and the so called “Event handlers” will run whenever we start or schedule their Events. These Events can be considered as tasks in an embedded operating system. They are round-robin scheduled without pre-emption, therefore their handler functions will run until not stopped (or interrupted).
In this stack the main.c source file is part of the SDK, it should not be edited, user defined code should only go into the callbacks.c file. In Connect, setting up a network is rather easy, it is done by writing a few Callbacks. We must initialize the network and set the security keys in the MainInitCallback function – which will run only once upon init – then using an appropriate Callback let children join or start the joining process (depends on the node type). With this the network should be up, from this point we can modify the application behavior with the rest of the Callback functions or Event handlers.
Setting up the projects
There are several examples available for Connect. Our application will be very similar to the sensor-sink examples, but much simpler. Let’s start and build the application therefore from a blank flex project. The AppBuilder will guide us through the project setup and will be able to generate the application frame, even if we start from scratch. Our job will be to find a simple way to configure Connect to achieve the basic functionality, and to – fulfilling our specifications – include the graphics handling.
Sensor project
Create a new blank application for the Flex SDK. After the project was created, the AppBuilder should come up with the General tab open. Make sure the architecture listed here is correct, especially if the toolchain is set. As you can see on the picture below, we are using a Mighty Gecko board, SDK version 2.4.0.0 and the GNU ARM compiler for this example.
Under the “Radio Configuration” tab select the Connect 2.4 GHz 802154 radio profile. You can also select any of the profiles compatible with your board, however in this example we are using the 802154 one.
Under the “Printing” tab disable the Command line interface. We won't use the CLI, we would like to rely on the LCD screen of the WSTKs and automatic network buildup in this example.
On the “Plugins” tab, make sure to set the tick next to the following options only:
If you click on the Application Graphics plugin, the Hardware Configurator Dependent Module Options will show on the right. It's important to turn off setting "Use EXTCOMIN pin for polarity inversion" here, as this option was reported to cause issues with Connect. We will take care of this polarity inversion from our code instead.
The next step is to configure the Callbacks under the Callbacks tab. As mentioned before, these are the built-in events for which we can determine a functionality through a Callback function. If we do not want to use a specific Callback, here we can disable them. From the user configurable Callbacks, we will only need the MainInitCallback and the StackStatusCallback callbacks for the sensor application. Turn them on by checking the box next to them under the "Is used?" column.
To finish the AppBuilder configuration, go to the “Other” tab. Under this tab you can configure additional macros and includes, but most importantly for a Connect application, here you can configure the Events, the user-defined “tasks”. Add a new Event in the "Event Configuration" and edit its command, by clicking on the automatically generated name, to “reportControl” and its callback function to “reportHandler”. This Event will be responsible for the sensor data reporting. Add another one with “connectControl” and “connectCallback” command and callback names, respectively. This Event will be responsible for reconnecting whenever the network connection is lost.
Save the *.isc file and generate the project.
Unfortunately the WSTK Sensors plugin does not enable the Sensor in the hardware configurator, therefore it has to be done manually. Open up the *.hwconf file in the project and under the DefaultMode Peripherals make sure to enable the I2C Sensor.
Sink project
Create another blank project for the Sink. Make sure to set up everything the same as you did for the sensor on the “Radio Configuration”, “Printing” and “Plugins” tabs. One exception is under the “Plugins” tab: “WSTK Sensors” under “Connect I/O” should not be enabled, as for the Sink we won’t need the sensors on the WSTK.
Under the Callbacks tab we will need the following to be enabled: MainInitCallback for the initializations, StackStatusCallback and ChildJoinCallback for creating the network, and IncomingMessageCallback so we can process and show the data on the display.
As no Event will be used for the sink application – we can handle everything from the Callbacks – we've got no configuration to change on the "Other" tab.
Save the *.isc file and generate the project.
Callbacks and Events – Sensor
It’s time to write the main functionality of the sensor application – in the callbacks source file as mentioned before.
For the sensor we turned two callbacks on, let’s start with one of those.
MainInitCallback
In the MainInitCallback function we first set the security key, then try to restore the network state from the Non-Volatile Memory. As the child table is not deleted after a device reset, this can be a quick way to initialize the network. If the device was just set up or the table is not available, we start our connectControl Event to initialize the network connections from scratch. In the end of this Callback, the graphics is initialized, as all kind of one-time-run initialization like this should be put in this Callback.
connectHandler
Since it was just mentioned it, let's continue with the connectControl Event's Handler, the connectHandler.
This Event puts the “disconnected” message on the screen, as it only runs when there’s no network connection. After setting necessary radio parameters it tries to connect to the network – as a sleepy end device or a regular device, based on the configuration. As a last step, we set this Event inactive; if we didn’t do this, the Event would run endlessly.
StackStatusCallback
The StackStatusCallback function will run whenever the stack status changes. This can mean a good thing, like the network is up, or something worse, like it got disconnected, or the join failed, etc. Based on the status it carries, we will start the reportControl Event – sending out the sensor data – or schedule the connectControl Event with a retry interval to try connecting again.
reportHandler
If the network is up, the reportHandler function will run immediately. The Handler consists of four main steps: first, we need to get the sensor data through calling PluginWstkSensorsGetSample(). With emberMessageSend() we can send the data. Using the sink’s node ID, it will be sent to the right node. We wouldn’t want this function to run as fast it can, but every 1000 ms, so we schedule the Event with the report interval. As a last step, the LCD screen is refreshed with the help of the graphics library.
With this the sensor should be able to connect to the network, send its sensor data to the sink and use the LCD screen to provide basic information of its state and the sensor information. To try it however, we will need the sink to work as well.
Callbacks and Events – Sink
The sink is the coordinator in the network. Its responsibilities are to create the network and receive the data from the nodes – the sensors in our case – and print it on its screen. Three Callbacks will be needed to create this simple functionality in the application. MainInitCallback and StackStatusCallback for inits and creating the network – just as we used these for the sensor – and additionally, the IncomingMessageCallback.
MainInitCallback
The main initialization Callback is very similar to the one that we saw during discussing the sensor application. First, we need to set the security key, then initialize the network with the appropriate parameters. As a last step, we call the FormNetwork() function to start the network forming. In this Callback the display and graphics initializations are also done but removed from this code snippet for better readability.
StackStatusCallback
After the initializations ran, we should have our network up. This status change will invoke the StackStatusCallback function. In this function all we need to do is to permit joining to the network. Anything else except this below is for diagnostic purposes only, as you can see we also print out the child table to the console – as it is stored in the non volatile memory, from earlier it actually can contain devices.
IncomingMessageCallback
Any time a message was received, this Callback will be invoked. The passed parameter will contain all the information of the message we need, like where it came from, RSSI and the data of course. Using all this information, we process and print the sensor data on the console, then on the LCD screen.
Writing these three Callbacks should provide the minimal functionality for the sink to be operating. As you could see, this time we didn’t use any Events, relying on the Callbacks alone could resolve the main functionality of the coordinator.
With the project set up and callbacks written, we can test our Connect network. After flashing, the network should set itself up, however it might need some time to do so. If connection doesn't want to happen, try resetting the sensors and the sink as well.
Conclusion
The intent of this article was to show through a basic application the initial steps of development in Connect. We could see how easy and automatic it is to form a network from any number of nodes, then transmit messages between them. Using the Callbacks and Events it was demonstrated how to schedule tasks and transfer useful data over the air. We made the application independent from the console and the command line interface by automating the network forming and utilizing the display modules on the wireless starter kits under Connect.