Skip to content

Commit

Permalink
net_core_monitor: Make it easy to use
Browse files Browse the repository at this point in the history
The `__weak ncm_net_core_event_handler` function is used to notify
the application about the network core staus.
This repleace the periodic call of the
`ncm_net_status_check` function.
This makes it easier to use and configure.

Ref: NCSDK-23996

Signed-off-by: Marcin Jelinski <[email protected]>
  • Loading branch information
maje-emb authored and rlubos committed Oct 10, 2023
1 parent a4b6863 commit 9939469
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 66 deletions.
66 changes: 31 additions & 35 deletions doc/nrf/libraries/others/network_core_monitor.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,8 @@ The library uses two general-purpose registers of the IPC peripheral in the appl

The ``GPMEM[0]`` register is divided into two 16-bit parts.

The ``COUNTER`` value is incremented by the network core every :kconfig:option:`CONFIG_NCM_APP_FEEDING_INTERVAL_MSEC`.
The application core periodically calls the :c:func:`ncm_net_status_check` function to check the status of the network core.
The ``COUNTER`` value is incremented by the network core every :kconfig:option:`CONFIG_NCM_FEEDING_INTERVAL_MSEC`.
If the network core is suspended, the counter value is not updated.
The :c:func:`ncm_net_status_check` function returns error code ``-EBUSY``.

To correctly detect the network core status, the :c:func:`ncm_net_status_check` function should be called less frequently than the value set in the :kconfig:option:`CONFIG_NCM_APP_FEEDING_INTERVAL_MSEC` Kconfig option.

The ``FLAGS`` field has the ``Reset`` flag as the bit 0.

Expand All @@ -43,13 +39,23 @@ During the startup of the network core, the reset bit is set and the cause of th
This value is rewritten from the network core's ``RESET.RESETREAS`` register.
For a detailed description of the bits in this register, see the `RESETREAS`_ section for nRF5340.

The :c:func:`ncm_net_status_check` function returns the following error codes:
The :c:func:`ncm_net_core_event_handler` function may be implemented by your application.
On the application core, the network core monitor checks the values of IPC registers written by the network core every :kconfig:option:`CONFIG_NCM_FEEDING_INTERVAL_MSEC`.
If the network core malfunctions and fails to increment the ``COUNTER`` value, the :c:func:`ncm_net_core_event_handler` function is called on the application core.
This function is also called when the network core is restarted.
The network core monitor provides a ``__weak`` implementation of that function in the :file:`nrf/subsys/net_core_monitor/app_core.c` file.

The following events are supported and also listed in the :file:`nrf/include/net_core_monitor.h` file:

* :c:macro:`NCM_EVT_NET_CORE_RESET`

* ``-EBUSY`` if the network core is suspended
* ``-EFAULT`` if a network core reset has occurred
* Event triggered when a network core reset occurs.
* The ``reset_reas`` variable holds the reason for the reset.
It is rewritten from the ``RESET.RESETREAS`` register.

The function takes a pointer to a variable of type uint32_t as a parameter.
When a network core reset is detected, the cause of the reset is stored in this pointer.
* :c:macro:`NCM_EVT_NET_CORE_FREEZE`

* Event triggered when the network core is not responding.

Configuration
*************
Expand All @@ -68,38 +74,28 @@ Usage

To enable the Network core monitor library, set the :kconfig:option:`CONFIG_NET_CORE_MONITOR` Kconfig option.

On the application core, periodically call the :c:func:`ncm_net_status_check` function to monitor the state of the network core.
The :c:func:`ncm_net_core_event_handler` function can be used to notify the application about the status of the network core.
To define the user action for the event, you must override the ``__weak`` function definition of :c:func:`ncm_net_core_event_handler`.
Otherwise, the ``__weak``` definition is called and it prints information about the event.

See the following usage example.

.. code-block::
#include "net_core_monitor.h"
...
static void print_reset(uint32_t reset_reas)
{
if (reset_reas & NRF_RESET_RESETREAS_RESETPIN_MASK) {
printk("Reset by pin-reset\n");
} else if (reset_reas & NRF_RESET_RESETREAS_DOG0_MASK) {
printk("Reset by application watchdog timer 0 \n");
} else if (reset_reas & NRF_RESET_RESETREAS_SREQ_MASK) {
printk("Reset by soft-reset\n");
} else if (reset_reas) {
printk("Reset by a different source (0x%08X)\n", reset_reas);
}
}
int main(void)
/* This is the override for the __weak handler. */
void ncm_net_core_event_handler(enum ncm_event_type event, uint32_t reset_reas)
{
uint32_t reset_reas;
...
for (;;) {
ret = ncm_net_status_check(&reset_reas);
if (ret == -EBUSY) {
/* do something*/
} else if (ret == -EFAULT) {
print_reset(reset_reas);
}
k_sleep(K_MSEC(1000));
switch (event) {
case NCM_EVT_NET_CORE_RESET:
printk("The network core reset.\n");
/* do something */
break;
case NCM_EVT_NET_CORE_FREEZE:
printk("The network core is not responding.\n");
/* do something */
break;
}
}
Expand Down
32 changes: 20 additions & 12 deletions include/net_core_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,29 @@
extern "C" {
#endif

/** @brief Check the status of the network core.
*
* The function should be called less frequently than
* @kconfig{CONFIG_NCM_APP_FEEDING_INTERVAL_MSEC} to correctly detect the network core status.
/** @brief Network core monitor event types, used to signal the application. */
enum ncm_event_type {
/** Event triggered when a network core reset occurs.
* The ``reset_reas`` variable holds the reason for the reset.
* It is rewritten from the RESET.RESETREAS register.
*/
NCM_EVT_NET_CORE_RESET,

/** Event triggered when the network core is not responding. */
NCM_EVT_NET_CORE_FREEZE
};

/** @brief Event handler that is called by the Network core monitor library when an event occurs.
*
* @param[out] reset_reas Reason for network core reset.
* When the -EFAULT code is returned, the variable is set.
* This value is rewritten from the network core's RESET.RESETREAS
* register.
* @note This function should be defined by the application.
* Otherwise, `__weak` definition will called and it prints information about the event.
*
* @retval 0 If network core works properly.
* @retval -EBUSY If network core failure occurred.
* @retval -EFAULT If network core restart occurred.
* @param[out] event Event occurring.
* @param[out] reset_reas Reason for network core reset.
* When the NCM_EVT_NET_CORE_RESET event was triggered the variable is set.
* This value is rewritten from the network core's RESET.RESETREAS register.
*/
int ncm_net_status_check(uint32_t * const reset_reas);
extern void ncm_net_core_event_handler(enum ncm_event_type event, uint32_t reset_reas);

#ifdef __cplusplus
}
Expand Down
13 changes: 10 additions & 3 deletions subsys/net_core_monitor/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,21 @@ config NET_CORE_MONITOR
depends on (SOC_NRF5340_CPUAPP || SOC_NRF5340_CPUNET)
help
Enable the Network Core Monitor module.
To define the user action for event, you need to override the
weak function definition of the ncm_net_core_event_handler.

if NET_CORE_MONITOR

menu "Net Core Monitor"

config NCM_APP_FEEDING_INTERVAL_MSEC
default 500
int "Application core feeding interval (in ms)"
config NCM_FEEDING_INTERVAL_MSEC
default 500 if SOC_NRF5340_CPUNET
default 1000 if SOC_NRF5340_CPUAPP
int "Feeding interval in milliseconds"
help
The value of this parameter on the application core must be greater
than the value on the network core. Otherwise the network core monitor
will report false positive network code malfunctions.

config NCM_RESET_INIT_PRIORITY
int "Reset init priority"
Expand Down
61 changes: 60 additions & 1 deletion subsys/net_core_monitor/app_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include <zephyr/init.h>
#include <zephyr/types.h>
#include <errno.h>
#include <zephyr/kernel.h>
#include <nrfx_ipc.h>
#include "common.h"
#include <helpers/nrfx_reset_reason.h>
#include "net_core_monitor.h"

#include <zephyr/logging/log.h>

Expand All @@ -17,7 +20,12 @@ LOG_MODULE_REGISTER(net_core_monitor, CONFIG_NET_CORE_MONITOR_LOG_LEVEL);
#define IPC_MEM_CNT_IDX 0
#define IPC_MEM_REAS_IDX 1

int ncm_net_status_check(uint32_t * const reset_reas)
#define NET_CORE_CHECK_INTERVAL_MSEC CONFIG_NCM_FEEDING_INTERVAL_MSEC

static void ncm_work_handler(struct k_work *work);
static K_WORK_DELAYABLE_DEFINE(ncm_work, ncm_work_handler);

static int ncm_net_status_check(uint32_t * const reset_reas)
{
uint32_t gpmem;
uint16_t cnt;
Expand Down Expand Up @@ -49,3 +57,54 @@ int ncm_net_status_check(uint32_t * const reset_reas)
prv_cnt = cnt;
return 0;
}

static void ncm_work_handler(struct k_work *work)
{
int ret;
uint32_t reset_reas;

ret = ncm_net_status_check(&reset_reas);

if (ret == -EBUSY) {
ncm_net_core_event_handler(NCM_EVT_NET_CORE_FREEZE, 0);
} else if (ret == -EFAULT) {
ncm_net_core_event_handler(NCM_EVT_NET_CORE_RESET, reset_reas);
} else {
/* Nothing to do. */
}

k_work_reschedule(&ncm_work, K_MSEC(NET_CORE_CHECK_INTERVAL_MSEC));
}

__weak void ncm_net_core_event_handler(enum ncm_event_type event, uint32_t reset_reas)
{
switch (event) {
case NCM_EVT_NET_CORE_RESET:
LOG_DBG("The network core reset.");
if (reset_reas & NRF_RESET_RESETREAS_RESETPIN_MASK) {
LOG_DBG("Reset by pin-reset.");
} else if (reset_reas & NRF_RESET_RESETREAS_DOG0_MASK) {
LOG_DBG("Reset by application watchdog timer 0.");
} else if (reset_reas & NRF_RESET_RESETREAS_SREQ_MASK) {
LOG_DBG("Reset by soft-reset");
} else if (reset_reas) {
LOG_DBG("Reset by a different source (0x%08X).", reset_reas);
} else {
/* Nothing to do. */
}

break;
case NCM_EVT_NET_CORE_FREEZE:
LOG_DBG("The network core is not responding.");
break;
}
}

static int app_init(void)
{
LOG_DBG("Network Core Monitor Init");
k_work_schedule(&ncm_work, K_MSEC(NET_CORE_CHECK_INTERVAL_MSEC));
return 0;
}

SYS_INIT(app_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
7 changes: 5 additions & 2 deletions subsys/net_core_monitor/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ extern "C" {
#define CNT_MSK (0xFFFF << CNT_POS) /* Bit mask of Counter field. */
#define FLAGS_POS (16UL) /* Position of Flags field. */
#define FLAGS_MSK (0xFFFF << FLAGS_POS) /* Bit mask of Flags field. */
#define FLAGS_RESET BIT(0) /* Reset bit */
#define CNT_INIT_VAL (0x0055) /* Initialization value for counter */
#define FLAGS_RESET BIT(0) /* Reset bit. */
#define CNT_INIT_VAL (0x0055) /* Initialization value for counter. */

#define IPC_MEM_CNT_IDX 0 /** Index of the memory cell that stores the counter. */
#define IPC_MEM_REAS_IDX 1 /** Index of the memory cell that stores the reset reason. */

#ifdef __cplusplus
}
Expand Down
24 changes: 11 additions & 13 deletions subsys/net_core_monitor/net_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,23 @@ LOG_MODULE_REGISTER(net_core_monitor, CONFIG_NET_CORE_MONITOR_LOG_LEVEL);
/* General purpose memory IPC of the application core.
* Access possible only through the memory address.
*/
#define APP_IPC_GPMEM_0_S (*(volatile uint32_t *)(0x5002A610))
#define APP_IPC_GPMEM_0_NS (*(volatile uint32_t *)(0x4002A610))
#define APP_IPC_GPMEM_1_S (*(volatile uint32_t *)(0x5002A614))
#define APP_IPC_GPMEM_1_NS (*(volatile uint32_t *)(0x4002A614))
#define APP_IPC_GPMEM_0 APP_IPC_GPMEM_0_S
#define APP_IPC_GPMEM_1 APP_IPC_GPMEM_1_S
#define APP_IPC_GPMEM_0_S ((volatile uint32_t *)(0x5002A610))
#define APP_IPC_GPMEM_0_NS ((volatile uint32_t *)(0x4002A610))
#define APP_IPC_GPMEM APP_IPC_GPMEM_0_S

static void ncm_work_handler(struct k_work *work);
static K_WORK_DELAYABLE_DEFINE(ncm_work, ncm_work_handler);

static void ncm_work_handler(struct k_work *work)
{
static uint16_t live_cnt = CNT_INIT_VAL;
uint32_t gpmem = APP_IPC_GPMEM_0;
uint32_t gpmem = APP_IPC_GPMEM[IPC_MEM_CNT_IDX];

live_cnt++;
gpmem = (gpmem & (~CNT_MSK)) | (live_cnt << CNT_POS);
APP_IPC_GPMEM_0 = gpmem;
APP_IPC_GPMEM[IPC_MEM_CNT_IDX] = gpmem;

k_work_reschedule(&ncm_work, K_MSEC(CONFIG_NCM_APP_FEEDING_INTERVAL_MSEC));
k_work_reschedule(&ncm_work, K_MSEC(CONFIG_NCM_FEEDING_INTERVAL_MSEC));
}

static int reset(void)
Expand All @@ -50,11 +47,12 @@ static int reset(void)
/* A notification that a core reset has occurred.
* And set the non-zero value of the counter.
*/
APP_IPC_GPMEM_0 = (APP_IPC_GPMEM_0 & FLAGS_MSK)
| (FLAGS_RESET << FLAGS_POS)
| (CNT_INIT_VAL << CNT_POS);
APP_IPC_GPMEM[IPC_MEM_CNT_IDX] = (APP_IPC_GPMEM[IPC_MEM_CNT_IDX] & FLAGS_MSK)
| (FLAGS_RESET << FLAGS_POS)
| (CNT_INIT_VAL << CNT_POS);

/* Save the reason for the reset. */
APP_IPC_GPMEM_1 = reas;
APP_IPC_GPMEM[IPC_MEM_REAS_IDX] = reas;

return 0;
}
Expand Down

0 comments on commit 9939469

Please sign in to comment.