Skip to content

Commit 6f75c99

Browse files
nordicjmcarlescufi
authored andcommitted
mgmt: mcumgr: Rework event callback system
Reworks the event callback system to use a linked list to allow for chained handlers and support passing a status back to the handler to indicate if the request should be rejected or allowed. This also removes the old base callback functionality. Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
1 parent bd5eea7 commit 6f75c99

File tree

6 files changed

+284
-66
lines changed

6 files changed

+284
-66
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
* Copyright (c) 2022 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef H_MCUMGR_CALLBACKS_
8+
#define H_MCUMGR_CALLBACKS_
9+
10+
#include <inttypes.h>
11+
#include <zephyr/sys/slist.h>
12+
#include <mgmt/mgmt.h>
13+
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
/**
19+
* @brief MCUmgr callback API
20+
* @defgroup mcumgr_callback_api MCUmgr callback API
21+
* @ingroup mcumgr
22+
* @{
23+
*/
24+
25+
/** @cond INTERNAL_HIDDEN */
26+
/** Event which signfies that all event IDs for a particular group should be enabled. */
27+
#define MGMT_EVT_OP_ID_ALL 0xffff
28+
29+
/** Get event for a particular group and event ID. */
30+
#define MGMT_DEF_EVT_OP_ID(group, event_id) ((group << 16) | BIT(event_id))
31+
32+
/** Get event used for enabling all event IDs of a particular group. */
33+
#define MGMT_DEF_EVT_OP_ALL(group) ((group << 16) | MGMT_EVT_OP_ID_ALL)
34+
/** @endcond */
35+
36+
/** Get group from event. */
37+
#define MGMT_EVT_GET_GROUP(event) ((event >> 16) & MGMT_EVT_OP_ID_ALL)
38+
39+
/** Get event ID from event. */
40+
#define MGMT_EVT_GET_ID(event) (event & MGMT_EVT_OP_ID_ALL)
41+
42+
/**
43+
* @typedef mgmt_cb
44+
* @brief Function to be called on MGMT notification/event.
45+
*
46+
* This callback function is used to notify an application or system about a mcumgr mgmt event.
47+
*
48+
* @param event MGMT_EVT_OP_[...].
49+
* @param rc MGMT_ERR_[...] of the previous handler calls, if it is an error then it
50+
* will be the first error that was returned by a handler (i.e. this handler
51+
* is being called for a notification only, the return code will be ignored).
52+
* @param abort_more Set to true to abort further processing by additional handlers.
53+
* @param data Optional event argument.
54+
* @param data_size Size of optional event argument (0 if no data is provided).
55+
*
56+
* @return MGMT_ERR_[...] of the status to return to the calling code (only checked
57+
* when failed is false).
58+
*/
59+
typedef int32_t (*mgmt_cb)(uint32_t event, int32_t rc, bool *abort_more, void *data,
60+
size_t data_size);
61+
62+
/**
63+
* MGMT event callback group IDs. Note that this is not a 1:1 mapping with MGMT_GROUP_ID_[...]
64+
* values.
65+
*/
66+
enum mgmt_cb_groups {
67+
MGMT_EVT_GRP_ALL = 0,
68+
MGMT_EVT_GRP_SMP,
69+
70+
MGMT_EVT_GRP_USER_CUSTOM_START = MGMT_GROUP_ID_PERUSER,
71+
};
72+
73+
/**
74+
* MGMT event opcodes for all command processing.
75+
*/
76+
enum smp_all_events {
77+
/** Used to enable all events. */
78+
MGMT_EVT_OP_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_ALL),
79+
};
80+
81+
/**
82+
* MGMT event opcodes for base SMP command processing.
83+
*/
84+
enum smp_group_events {
85+
/** Callback when a command is received, data is mgmt_evt_op_cmd_arg. */
86+
MGMT_EVT_OP_CMD_RECV = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_SMP, 0),
87+
88+
/** Callback when a a status is updated, data is mgmt_evt_op_cmd_arg. */
89+
MGMT_EVT_OP_CMD_STATUS = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_SMP, 1),
90+
91+
/** Callback when a command has been processed, data is mgmt_evt_op_cmd_arg. */
92+
MGMT_EVT_OP_CMD_DONE = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_SMP, 2),
93+
94+
/** Used to enable all smp_group events. */
95+
MGMT_EVT_OP_CMD_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_SMP),
96+
};
97+
98+
/**
99+
* MGMT callback struct
100+
*/
101+
struct mgmt_callback {
102+
/** Entry list node. */
103+
sys_snode_t node;
104+
105+
/** Callback that will be called. */
106+
mgmt_cb callback;
107+
108+
/** MGMT_EVT_[...] Event ID for handler to be called on. */
109+
uint32_t event_id;
110+
};
111+
112+
/**
113+
* MGMT_EVT_OP_CMD_RECV, MGMT_EVT_OP_CMD_STATUS, MGMT_EVT_OP_CMD_DONE arguments
114+
*/
115+
struct mgmt_evt_op_cmd_arg {
116+
/** MGMT_GROUP_ID_[...] */
117+
uint16_t group;
118+
119+
/** Message ID within group */
120+
uint8_t id;
121+
122+
union {
123+
/** MGMT_ERR_[...], used in MGMT_EVT_OP_CMD_DONE */
124+
int err;
125+
126+
/** IMG_MGMT_ID_UPLOAD_STATUS_[...], used in MGMT_EVT_OP_CMD_STATUS */
127+
int status;
128+
};
129+
};
130+
131+
/**
132+
* @brief This function is called to notify registered callbacks about mcumgr notifications/events.
133+
*
134+
* @param event MGMT_EVT_OP_[...].
135+
* @param data Optional event argument.
136+
* @param data_size Size of optional event argument (0 if none).
137+
*
138+
* @return MGMT_ERR_[...] either MGMT_ERR_EOK if all handlers returned it, or the
139+
* error code of the first handler that returned an error.
140+
*/
141+
int32_t mgmt_callback_notify(uint32_t event, void *data, size_t data_size);
142+
143+
/**
144+
* @brief Register event callback function.
145+
*
146+
* @param callback Callback struct.
147+
*/
148+
void mgmt_callback_register(struct mgmt_callback *callback);
149+
150+
/**
151+
* @brief Unregister event callback function.
152+
*
153+
* @param callback Callback struct.
154+
*/
155+
void mgmt_callback_unregister(struct mgmt_callback *callback);
156+
157+
/**
158+
* @}
159+
*/
160+
161+
#ifdef __cplusplus
162+
}
163+
#endif
164+
165+
#endif /* H_MCUMGR_CALLBACKS_ */

subsys/mgmt/mcumgr/Kconfig

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,30 @@ config MGMT_MAX_DECODING_LEVELS
101101
size of cbor_nb_reader structure by zcbor_state_t size per
102102
one unit selected here.
103103

104+
config MCUMGR_MGMT_NOTIFICATION_HOOKS
105+
bool "MCUmgr notification hook support"
106+
help
107+
With this enabled, applications and parts of code can register for MCUmgr event
108+
notifications which will result in callbacks when a registered event occurs. Note that
109+
this enables the base notification functionality but itself does not enable any
110+
notifications, which must be enabled by selecting other Kconfig options.
111+
112+
To enable notifications in code, mgmt_callback_register() must be called with the
113+
callback function and events that want to be received. Multiple handlers can be
114+
registered and will all be called when registered events occur.
115+
116+
Some callbacks support notifying the calling function of a status, in which to accept
117+
or decline the current operation, by returning false this will signal to the calling
118+
function that the request should be denied, for informal-only notifications or
119+
acceptable, true must be returned by all the registered notification handlers.
120+
121+
config MCUMGR_SMP_COMMAND_STATUS_HOOKS
122+
bool "SMP command status hooks"
123+
depends on MCUMGR_MGMT_NOTIFICATION_HOOKS
124+
help
125+
This will enable SMP command status notification hooks for when an SMP message is
126+
received or processed.
127+
104128
menu "Command Handlers"
105129

106130
rsource "lib/cmd/Kconfig"

subsys/mgmt/mcumgr/lib/cmd/img_mgmt/src/img_mgmt.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2018-2021 mcumgr authors
3+
* Copyright (c) 2022 Nordic Semiconductor ASA
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -506,8 +507,11 @@ img_mgmt_upload(struct smp_streamer *ctxt)
506507
end:
507508

508509
img_mgmt_upload_log(req.off == 0, g_img_mgmt_state.off == g_img_mgmt_state.size, rc);
509-
mgmt_evt(MGMT_EVT_OP_CMD_STATUS, MGMT_GROUP_ID_IMAGE, IMG_MGMT_ID_UPLOAD,
510-
&cmd_status_arg);
510+
511+
#if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS)
512+
(void)mgmt_callback_notify(MGMT_EVT_OP_CMD_STATUS, MGMT_GROUP_ID_IMAGE,
513+
IMG_MGMT_ID_UPLOAD, &cmd_status_arg, false);
514+
#endif
511515

512516
if (rc != 0) {
513517
img_mgmt_dfu_stopped();

subsys/mgmt/mcumgr/lib/mgmt/include/mgmt/mgmt.h

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2018-2021 mcumgr authors
3+
* Copyright (c) 2022 Nordic Semiconductor ASA
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -55,39 +56,6 @@ extern "C" {
5556

5657
#define MGMT_HDR_SIZE 8
5758

58-
/*
59-
* MGMT event opcodes.
60-
*/
61-
#define MGMT_EVT_OP_CMD_RECV 0x01
62-
#define MGMT_EVT_OP_CMD_STATUS 0x02
63-
#define MGMT_EVT_OP_CMD_DONE 0x03
64-
65-
/*
66-
* MGMT_EVT_OP_CMD_STATUS argument
67-
*/
68-
struct mgmt_evt_op_cmd_status_arg {
69-
int status;
70-
};
71-
72-
/*
73-
* MGMT_EVT_OP_CMD_DONE argument
74-
*/
75-
struct mgmt_evt_op_cmd_done_arg {
76-
int err; /* MGMT_ERR_[...] */
77-
};
78-
79-
/** @typedef mgmt_on_evt_cb
80-
* @brief Function to be called on MGMT event.
81-
*
82-
* This callback function is used to notify application about mgmt event.
83-
*
84-
* @param opcode MGMT_EVT_OP_[...].
85-
* @param group MGMT_GROUP_ID_[...].
86-
* @param id Message ID within group.
87-
* @param arg Optional event argument.
88-
*/
89-
typedef void (*mgmt_on_evt_cb)(uint8_t opcode, uint16_t group, uint8_t id, void *arg);
90-
9159
/** @typedef mgmt_alloc_rsp_fn
9260
* @brief Allocates a buffer suitable for holding a response.
9361
*
@@ -177,23 +145,6 @@ void mgmt_unregister_group(struct mgmt_group *group);
177145
*/
178146
const struct mgmt_handler *mgmt_find_handler(uint16_t group_id, uint16_t command_id);
179147

180-
/**
181-
* @brief Register event callback function.
182-
*
183-
* @param cb Callback function.
184-
*/
185-
void mgmt_register_evt_cb(mgmt_on_evt_cb cb);
186-
187-
/**
188-
* @brief This function is called to notify about mgmt event.
189-
*
190-
* @param opcode MGMT_EVT_OP_[...].
191-
* @param group MGMT_GROUP_ID_[...].
192-
* @param id Message ID within group.
193-
* @param arg Optional event argument.
194-
*/
195-
void mgmt_evt(uint8_t opcode, uint16_t group, uint8_t id, void *arg);
196-
197148
#ifdef __cplusplus
198149
}
199150
#endif

subsys/mgmt/mcumgr/lib/mgmt/src/mgmt.c

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,18 @@
99
#include "mgmt/mgmt.h"
1010
#include "smp/smp.h"
1111

12-
static mgmt_on_evt_cb evt_cb;
12+
#ifdef CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS
13+
#include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
14+
#endif
15+
1316
static sys_slist_t mgmt_group_list =
1417
SYS_SLIST_STATIC_INIT(&mgmt_group_list);
1518

19+
#if defined(CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS)
20+
static sys_slist_t mgmt_callback_list =
21+
SYS_SLIST_STATIC_INIT(&mgmt_callback_list);
22+
#endif
23+
1624
void
1725
mgmt_unregister_group(struct mgmt_group *group)
1826
{
@@ -62,16 +70,55 @@ mgmt_register_group(struct mgmt_group *group)
6270
sys_slist_append(&mgmt_group_list, &group->node);
6371
}
6472

65-
void
66-
mgmt_register_evt_cb(mgmt_on_evt_cb cb)
73+
#if defined(CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS)
74+
void mgmt_callback_register(struct mgmt_callback *callback)
6775
{
68-
evt_cb = cb;
76+
sys_slist_append(&mgmt_callback_list, &callback->node);
6977
}
7078

71-
void
72-
mgmt_evt(uint8_t opcode, uint16_t group, uint8_t id, void *arg)
79+
void mgmt_callback_unregister(struct mgmt_callback *callback)
80+
{
81+
(void)sys_slist_find_and_remove(&mgmt_callback_list, &callback->node);
82+
}
83+
84+
int32_t mgmt_callback_notify(uint32_t event, void *data, size_t data_size)
7385
{
74-
if (evt_cb) {
75-
evt_cb(opcode, group, id, arg);
86+
sys_snode_t *snp, *sns;
87+
bool failed = false;
88+
bool abort_more = false;
89+
int32_t rc;
90+
int32_t return_rc = MGMT_ERR_EOK;
91+
uint16_t group = MGMT_EVT_GET_GROUP(event);
92+
93+
/*
94+
* Search through the linked list for entries that have registered for this event and
95+
* notify them, the first handler to return an error code will have this error returned
96+
* to the calling function, errors returned by additional handlers will be ignored. If
97+
* all notification handlers return MGMT_ERR_EOK then access will be allowed and no error
98+
* will be returned to the calling function. The status of if a previous handler has
99+
* returned an error is provided to the functions through the failed variable, and a
100+
* handler function can set abort_more to true to prevent calling any further handlers.
101+
*/
102+
SYS_SLIST_FOR_EACH_NODE_SAFE(&mgmt_callback_list, snp, sns) {
103+
struct mgmt_callback *loop_group =
104+
CONTAINER_OF(snp, struct mgmt_callback, node);
105+
106+
if (loop_group->event_id == event || loop_group->event_id == MGMT_EVT_OP_ALL ||
107+
(MGMT_EVT_GET_GROUP(loop_group->event_id) == group &&
108+
MGMT_EVT_GET_ID(loop_group->event_id) == MGMT_EVT_OP_ID_ALL)) {
109+
rc = loop_group->callback(event, return_rc, &abort_more, data, data_size);
110+
111+
if (rc != MGMT_ERR_EOK && failed == false) {
112+
failed = true;
113+
return_rc = rc;
114+
}
115+
116+
if (abort_more == true) {
117+
break;
118+
}
119+
}
76120
}
121+
122+
return return_rc;
77123
}
124+
#endif

0 commit comments

Comments
 (0)