System Integration¶
Review MiraMesh hardware requirements here and here.
Bare metal system¶
Using MiraMesh in a bare metal environment is straight forward. Call miramesh_init (with the wakeup callbacks doing nothing), configure the memory usage (see mem_usage API), implement miramesh_lock/miramesh_unlock as two empty functions and call your application logic as well as miramesh_run_once in a loop.
For power saving, the loop and wakeup-callbacks have to cooperate so miramesh_run_once is only called when really needed (after the wakeup functions have run) and otherwise call __WFE
in the loop. This can be implemented with a simple flag.
There is an example of this in the examples/miramesh
folder.
An operating system with preemptive threads¶
An OS integrating MiraMesh must implement the functions miramesh_lock and miramesh_unlock, they are used to prevent simultanious access to MiraMesh's internal data. The lock need to support recursive calls. For FreeRTOS a RecursiveMutex is a good choice.
As with a bare metal system, miramesh_init needs to be called before any other mira function. The wakeup callbacks are used to wake up the thread/task that should call the miramesh_run_once function. For FreeRTOS a good strategy is to have a task wait with xTaskNotifyWait and the wakeup callbacks call xTaskNotify/xTaskNotifyFromISR to wake it up. When the task wakes up it calls miramesh_run_once before sleeping again.
The priority of the task running miramesh_run_once need to be such that it gets a chance to run once for every packet that the system wants to send or receive. For network rate 0, that means once every 10ms.
There is an example of using MiraMesh with FreeRTOS in the examples/miramesh
folder and on GitHub.
An operating system with cooprative threading¶
When using an OS with cooperative threading a lock is not needed, otherwise it works more or less like an integration on a system with preemtive threads. When miramesh_run_once has run, the thread should yield control to the other threads.
How to verify a working integration.¶
Connect the node to a known working node, i.e. the examples/miraos/network_receiver or network_sender examples. See that the mesh node connects with the mira_net_get_state function within a few minutes.
Measure the time between the wakeup callbacks being called and when miramesh_run_once is called. When it takes longer than 10ms, packets risk being dropped and the network performance becomes worse so it shouldn't happen frequently.
Monitor the tx_dropped/tx_failed/rx_missed_slots values of the result from mira_diag_mac_get_statistics. If those values often increase, it indicates that something blocks miramesh' IRQs too much.
Defines¶
MIRAMESH_SYS_NUM_PPIS_USED¶
How many PPIs used by MiraMesh
MIRAMESH_SYS_NUM_PPI_GROUPS_USED¶
How many PPI groups used by MiraMesh
Types¶
miramesh_certificate_cfg_t¶
Alias for backwards compability
Structs¶
miramesh_callback_cfg_t¶
Name | Type | Description |
---|---|---|
api_lock |
void(*)(void) |
Take the big lock before running MiraMesh code. The function needs to be reentrant by the same thread and the lock should not be released until miramesh_unlock has been called just as many times. |
api_unlock |
void(*)(void) |
Release the big lock after running MiraMesh code. The function needs to be reentrant by the same thread and the lock should not be released until miramesh_unlock has been called just as many times as miramesh_lock has been called. |
wakeup_from_app_callback |
void(*)(void) |
Called when MiraMesh wants miramesh_run_once to be called. This callback is called from app/task context. !!! note miramesh_run_once can not be called from the callback. |
wakeup_from_irq_callback |
void(*)(void) |
Called when MiraMesh wants miramesh_run_once to be called. This callback is called from IRQ context. Callbacks may occur from any IRQ level, including highest used by radio. This may be higher than maximum allowed IRQ level for RTOS calls, and measures may need to be taken to properly call RTOS API. In case of FreeRTOS, an example is available at GitHub !!! note miramesh_run_once can't be called from the callback. |
miramesh_rng_cfg_t¶
Name | Type | Description |
---|---|---|
rng_gen_init |
void(*)(void) |
Initializatoin of the RNG. !!! note If initialization is not required, set this to NULL |
rng_gen_u16 |
uint16_t(*)(void) |
This function will be called when MiraMesh requires random numbers. !!! note Numbers generated by the provided generator needs to be cryptographically secure. |
miramesh_hardware_cfg_t¶
Name | Type | Description |
---|---|---|
ppi_idx |
uint8_t[MIRAMESH_SYS_NUM_PPIS_USED] |
The PPIs to use |
ppi_group_idx |
uint8_t[MIRAMESH_SYS_NUM_PPI_GROUPS_USED] |
The PPI groups to use |
rtc |
uint8_t |
The RTC to use, 2 for RTC2 |
rtc_irq_prio |
uint8_t |
The prio of the RTC IRQ to use |
swi |
uint8_t |
The SWI/EGU to use beside SWI1 |
swi_irq_prio |
uint8_t |
The SWI prio. Should be of higher priority than rtc_irq_prio |
miramesh_factory_config_t¶
Name | Type | Description |
---|---|---|
start |
const uint8_t * |
pointer to the certificate/license pool |
end |
const uint8_t * |
pointer to the end of the certificate/license pool |
miramesh_config_t¶
Note
The struct miramesh_config_t can be updated with more fields in future versions. Therefore, it is recommended that the entire memory block of the structure is zeroed out before setting the desired fields.
Name | Type | Description |
---|---|---|
callback |
miramesh_callback_cfg_t |
Needed callbacks for OS integration |
rng |
miramesh_rng_cfg_t |
Optional custom rng function, set both struct members to NULL to use internal rng |
hardware |
miramesh_hardware_cfg_t |
Describes needed hardware resources |
factory_config |
miramesh_factory_config_t |
Describes the factory_config location |
certificate |
miramesh_certificate_cfg_t |
Backwards compatible alias to factory_config |
@5 |
union miramesh_config_t::@4 |
Functions¶
miramesh_init¶
mira_status_t miramesh_init(const miramesh_config_t *config, const mira_net_frontend_config_t *frontend_cfg);
Init the MiraMesh system.
This function must be called before any other MiraMesh functions are called. It must also be called before any SoftDevice protocol is used on nrf52 platforms.
During the call it will use the api_lock/api_unlock callbacks multiple times to verify that they can be used recusively.
Parameters¶
Name | Description |
---|---|
config | The system configuration |
frontend_cfg | Frontend configuration, NULL means no frontend config |
Return value¶
Name | Description |
---|---|
MIRA_SUCCESS | Successfully initialized MiraMesh. |
MIRA_RADIO_ERROR | A softdevice protocol has already been started or invalid frontend cfg. |
MIRA_ERROR_INVALID_VALUE | Incorrect config values. |
miramesh_is_init¶
Is MiraMesh initialized.
Return value¶
Name | Description |
---|---|
MIRA_TRUE | MiraMesh is initialized |
MIRA_FALSE | MiraMesh is not initialzied |
Return value¶
mira_bool_t
miramesh_handle_sd_event¶
Routes events from SoftDevice to MiraMesh.
This function is used by nRF52 targets to process recieved events.
Normally used like this:
#include "miramesh.h"
#include "miramesh_sys.h"
#include "nrf_sdh_soc.h"
static void sd_evt_observer(uint32_t evt_id, void *ctx) {
miramesh_handle_sd_event(evt_id);
}
NRF_SDH_SOC_OBSERVER(m_sd_evt_miramesh, 0, sd_evt_observer, 0);
nrf_sdh_soc.c
file needs to be part of the build.
miramesh_rtc_irq_handler¶
The IRQ handler for the RTC events.
This function should be called from the RTCx_IRQHandler
miramesh_swi_irq_handler¶
The IRQ handler for the configurable SWI events.
This function should be called from the SWIx_EGUx_IRQHandler or put in the isr_vector directly.
miramesh_swi1_irq_handler¶
The IRQ handler for the SWI1 events.
This function should be called from the SWI1_EGU1_IRQHandler or put in the isr_vector directly.
miramesh_run_once¶
Run the system once.
This function should be called repeatedly. After running once the thread should sleep until miramesh_wakeup_from_IRQ or miramesh_wakeup_from_API have been called.
Example: