Wirepas SDK
|
The Single-MCU feature allows an application to be executed on the same chip as the Wirepas Connectivity stack. Wirepas provides an SDK containing multiple applications examples. Each application describes a different aspect and can be used as a starting point.
This document will focus on a practical approach of writing an application. This document will highlight some crucial point like the minimal steps to follow in the initialization of an application and will give some practical guidance to correctly write an application.
This page contains following sections:
In order to develop the software with SDK, you need to have a license for Wirepas Mesh. Then, you have access to the firmware image according to your architecture. If you don't have a license, contact Wirepas sales.
This page contains following sections:
In order to debug the devices with JTAG debugger, you need to use unprotected bootloader. Whereas normal licensed Wirepas Mesh has JTAG debugging capabilities prevented, this one has JTAG debugging active. It is intended to be used during development phase to speed up application software development. If you don't yet have an access to unlocked bootloader, contact Wirepas sales.
If you have licensed Wirepas Mesh, you have access to the firmware image. In order to link that with the SDK, you have to unzip the firmware delivery to image/
folder.
In this chapter we will create a new application named new_app
.
It describes the initial steps to start writing a new application.
This page contains following sections:
The provided SDK contains several example applications. They can be used as a starting point (Here, custom_app is used as an reference).
To quickly start the development of a new application you can copy an already existing application and use it as a template. Any application from source/
folder can be used as a starting point.
To start developing the new application, copy folder custom_app
to a new folder named new_app
in source/
directory.
address and channel
To form a network, all nodes must share the same network address and network channel.
These information can come from multiple sources like NFC, provisioned in persistent memory during production,... In order to ease the setup, build system allows to set those settings at build time of an application from the application config.mk file.
In custom_app
application example, this information can be seen in file config.mk
In the new application folder created, you can modified these variables default_network_address
and default_network_channel
to arbitrary values that feat your needs. For example:
These variables are then automatically assigned to constants NETWORK_ADDRESS
and NETWORK_CHANNEL
and accessible from the code.
Additionally, you can define network keys the same way. Those keys are 16 bytes long and must be kept secret. It is very important to set them to protect your network.
Those settings are used with configureNodeFromBuildParameters utility function.
It is mandatory to have unique app_area_id in order to update specific application independently on other applications. Thus, modify file config.mk
following by using new arbitrary area id specific for this application:
The App_Init() function is the entry point for the application. It is called by the stack after each boot.
The Wirepas Connectivity stack is in the stopped state during this call. All the API calls that require the stack to be in the stopped state, like configuring node settings, must be done in this function.
The code below shows the minimal steps for an application to configure a node and start the stack.
A newly flashed device starts with its role set to APP_LIB_SETTINGS_ROLE_AUTOROLE_LE by default.
To be able to join a network, the application must set at least a unique node address, a common network address and a common network channel. Consequently, it is important to check if a node setting (role, node address, etc.) is already set before updating it from application initialization code. Otherwise it would break the Remote API, as the remotely updated value would be overwritten in App_Init().
This is the role of the configureNode() function. It sets the node address, network address and network channel, but ONLY if these settings are missing from the node. This is the case on first boot after flashing but not after any reboots after that, unless the settings are explicitly cleared by the application.
Note that the lib_state->stopStack() function will cause a reboot of the device and the App_Init() function will be called again.
Once the node is correctly configured, the stack must be started.
This initialization is just an example and can be something different, depending on the use case. For example, the application can wait for configuration via another interface (UART, SPI, NFC, ...). This is the case with the dualmcu_app
application, for example.
Building is done in root of the SDK file structure. It is done by calling the makefile
. There can be many options for building but necessary ones are in application makefile
. For example by using pca10040
as a target board, following build command can be issued:
For detailed information on build process, see here.
To practically test the application, a minimum of two boards is needed. One of them must be configured as a sink Low Energy or a sink Low Latency and the other as a node (i.e. something else than sink). In a first step, the sink can be connected to a PC running the Wirepas Terminal.
The application runs on the board configured as a node. Even if it is technically possible to run the application on a sink, it implies that the board has another network connection (WiFi, Ethernet,...) and everything is managed by the same MCU. In this basic configuration, it is assumed that it is not the case.
To program the sink, application dualmcu_app
can be flashed and then configured by using Wirepas Terminal.
Now when application has been compiled, next step is to program that to the device. The generated binary is located in following path (based on the makefile
options used):
For example:
To flash the image to the device, see here.
For more information about OTAP, see [1].
OTAP images can be found in following paths (based on the makefile
options used):
To update application image only:
To update both application and stack images:
For example:
Many times application requires custom board definition when application is intended to be executed on board not defined in existing board definitions. Albeit it is totally possible to discard the board definition altogether and hard-code all board-specific definitions (such as GPIO pin numbers) directly in application source code, it is still recommended to define board properly. This allows many benefits, such as:
To implement new board, check out the documentation of board definitions and modify existing board template (according to processor architecture).
The Wirepas Mesh Single-MCU SDK low-level initialization code sets up the application environment to run C code. The low-level setup is outside the scope of this document, but once the setup is done, the application initialization function App_init()
will be run::
functions
parameter is a global list of function pointers for the application. Normally this is not needed at all and is mainly needed for backwards compatibility of the applications.
The stack is not yet running when App_init()
is called. Depending on the stored settings and stack state, the stack may start right after returning from App_init()
.
For better code readability and organization, the application can be split in to multiple source files. Adding a new source file is as simple as declaring it in application specific source files in makefile
, for example:
The file named new_source.c
is created alongside app.c
in this example.
By default, the <app_folder>/include
folder is added to the list of paths to check for header files. Any additional folders can be added to the INCLUDES
variable in the application makefile
.
This chapter contains various recommendations and best practices to use with application development.
This page contains following sections:
The throughput of a Wirepas Connectivity network is expressed in packet per seconds. To optimize this throughput, it is important to fill the packet to the maximum available PDU size when possible.
It is even more important when operating in time-slotted mode. The network will handle the same number of packets independently of its payload size.
All hardware resources that are not used by the Wirepas Connectivity stack can be used freely by the application.
For example, unused GPIOs must be properly configured by the application, to avoid unnecessary power consumption due to pull-up or pull-down resistors.
The Wirepas Connectivity stack will try to enter the deepest possible sleep state of the platform, to optimize power consumption.
But as the application may require staying in a higher power state (to keep a peripheral clock enabled for example), the application can ask the stack to prevent entering the deep sleep state.
Please see the lib_system->disableDeepSleep() function in the System library.
It is often necessary to store data from an application to persistent memory in order to still have access to it across reboots of the node. The different methods to achieve it and their pros and cons are described in this section.
This page contains following sections:
Wirepas Mesh Stack uses reserved areas for its own usage in internal flash. To avoid reserving too much flash, this area is kept as small as possible. However, a small amount of this area is reserved for the application.
This application area can be accessed through the storage library handle.
Most of the platforms supported by Wirepas have their own specific persistent area to store persistent data.
To use it, users must refer to platform specific reference manual. For NRF52 users, Wirepas developed a wrapper to use it. You can find it persistent.h here.
The internal flash is partitioned in multiple areas. Some of these areas are used for Wirepas usage like the bootloader or the firmware that cannot be moved. But the remaining part of flash can be freely partitioned by the application. Each area has a dedicated area ID and a given size. More information about area ids and its usage can be found in [2]
The steps to realize are:
An example can be found from the provisioning joining node with the code to access the memory area in storage_memarea.c and example of modified ini file in the scratchpad_ini folder
[1] https://developer.wirepas.com/support/solutions/articles/77000496639
[2] https://developer.wirepas.com/support/solutions/articles/77000496582
[4] https://github.com/wirepas/wm-sdk/blob/master/source/reference_apps/dualmcu_app/api/DualMcuAPI.md Manual
[7] https://developer.wirepas.com/support/solutions/articles/77000407101