MiraMesh 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, ie 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¶
#define MIRAMESH_SYS_NUM_PPIS_USED
How many PPIs used by MiraMesh
MIRAMESH_SYS_NUM_PPI_GROUPS_USED¶
#define MIRAMESH_SYS_NUM_PPI_GROUPS_USED
How many PPI groups used by MiraMesh
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. !!! note miramesh_run_once can't be called from the callback. |
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_certificate_cfg_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¶
Name | Type | Description |
---|---|---|
callback |
miramesh_callback_cfg_t |
Needed callbacks for OS integration |
hardware |
miramesh_hardware_cfg_t |
Describes needed hardware resources |
certificate |
miramesh_certificate_cfg_t |
Describes the certificate location |
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 |
miramesh_handle_sd_event¶
void miramesh_handle_sd_event(uint32_t evt_id);
Routes events from Softdevice to MiraMesh.
This function is used by nRF52 targets with Softdevice 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);
miramesh_rtc_irq_handler¶
void miramesh_rtc_irq_handler(void);
The IRQ Handler for the RTC events.
This function should be called from the RTCx_IRQHandler
miramesh_swi_irq_handler¶
void miramesh_swi_irq_handler(void);
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¶
void miramesh_swi1_irq_handler(void);
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¶
void miramesh_run_once(void);
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:
while(1) {
if(xTaskNotifyWait(0, 1, NULL, portMAX_DELAY) == pdPASS) {
miramesh_run_once();
}
}