1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/kernel.h>
7 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
8 #include <zephyr/mgmt/mcumgr/smp/smp.h>
9 #include <zephyr/mgmt/mcumgr/mgmt/handlers.h>
10 /* The below should be updated with the real name of the file */
11 #include <example_mgmt.h>
12 #include <zephyr/logging/log.h>
13 #include <assert.h>
14 #include <limits.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <zcbor_common.h>
18 #include <zcbor_decode.h>
19 #include <zcbor_encode.h>
20 #include <mgmt/mcumgr/util/zcbor_bulk.h>
21
22 #if defined(CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS)
23 #include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
24 #if defined(CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK)
25 /* The below should be updated with the real name of the file */
26 #include <example_mgmt_callbacks.h>
27 #endif
28 #endif
29
30 LOG_MODULE_REGISTER(mcumgr_example_grp, CONFIG_MCUMGR_GRP_EXAMPLE_LOG_LEVEL);
31 /* Example function with "read" command support, requires both parameters are supplied */
example_mgmt_test(struct smp_streamer * ctxt)32 static int example_mgmt_test(struct smp_streamer *ctxt)
33 {
34 uint32_t uint_value = 0;
35 zcbor_state_t *zse = ctxt->writer->zs;
36 zcbor_state_t *zsd = ctxt->reader->zs;
37 bool ok;
38 struct zcbor_string string_value = { 0 };
39 size_t decoded;
40 struct zcbor_map_decode_key_val example_test_decode[] = {
41 ZCBOR_MAP_DECODE_KEY_DECODER("uint_key", zcbor_uint32_decode, &uint_value),
42 ZCBOR_MAP_DECODE_KEY_DECODER("string_key", zcbor_tstr_decode, &string_value),
43 };
44
45 LOG_DBG("Example test function called");
46
47 ok = zcbor_map_decode_bulk(zsd, example_test_decode, ARRAY_SIZE(example_test_decode),
48 &decoded) == 0;
49 /* Check that both parameters were supplied and that the value of "string_key" is not
50 * empty
51 */
52 if (!ok || string_value.len == 0 || !zcbor_map_decode_bulk_key_found(
53 example_test_decode, ARRAY_SIZE(example_test_decode), "uint_key")) {
54 return MGMT_ERR_EINVAL;
55 }
56
57 /* If the value of "uint_key" is over 50, return an error of "not wanted" */
58 if (uint_value > 50) {
59 ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_EXAMPLE, EXAMPLE_MGMT_ERR_NOT_WANTED);
60 goto end;
61 }
62
63 /* Otherwise, return an integer value of 4691 */
64 ok = zcbor_tstr_put_lit(zse, "return_int") &&
65 zcbor_int32_put(zse, 4691);
66
67 end:
68 /* If "ok" is false, then there was an error processing the output cbor message, which
69 * likely indicates a lack of available memory
70 */
71 return (ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE);
72 }
73
74 /* Example function with "write" command support */
example_mgmt_other(struct smp_streamer * ctxt)75 static int example_mgmt_other(struct smp_streamer *ctxt)
76 {
77 uint32_t user_value = 0;
78 zcbor_state_t *zse = ctxt->writer->zs;
79 zcbor_state_t *zsd = ctxt->reader->zs;
80 bool ok;
81 size_t decoded;
82 struct zcbor_map_decode_key_val example_other_decode[] = {
83 ZCBOR_MAP_DECODE_KEY_DECODER("user_value", zcbor_uint32_decode, &user_value),
84 };
85
86 #if defined(CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK)
87 struct example_mgmt_other_data other_data;
88 enum mgmt_cb_return status;
89 int32_t err_rc;
90 uint16_t err_group;
91 #endif
92
93 LOG_DBG("Example other function called");
94
95 ok = zcbor_map_decode_bulk(zsd, example_other_decode, ARRAY_SIZE(example_other_decode),
96 &decoded) == 0;
97
98 /* The supplied value is optional, therefore do not return an error if it was not
99 * provided
100 */
101 if (!ok) {
102 return MGMT_ERR_EINVAL;
103 }
104
105 #if defined(CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK)
106 /* Send request to application to check what to do */
107 other_data.user_value = user_value;
108 status = mgmt_callback_notify(MGMT_EVT_OP_EXAMPLE_OTHER, &other_data, sizeof(other_data),
109 &err_rc, &err_group);
110 if (status != MGMT_CB_OK) {
111 /* If a callback returned an RC error, exit out, if it returned a group error
112 * code, add the error code to the response and return to the calling function to
113 * have it sent back to the client
114 */
115 if (status == MGMT_CB_ERROR_RC) {
116 return err_rc;
117 }
118
119 ok = smp_add_cmd_err(zse, err_group, (uint16_t)err_rc);
120 goto end;
121 }
122 #endif
123 /* Return some dummy data to the client */
124 ok = zcbor_tstr_put_lit(zse, "return_string") &&
125 zcbor_tstr_put_lit(zse, "some dummy data!");
126
127 #if defined(CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK)
128 end:
129 #endif
130 /* If "ok" is false, then there was an error processing the output cbor message, which
131 * likely indicates a lack of available memory
132 */
133 return (ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE);
134 }
135
136 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
137 /* This is a lookup function that converts from SMP version 2 group error codes to legacy
138 * MCUmgr error codes, it is only included if support for the original protocol is enabled.
139 * Note that in SMP version 2, MCUmgr error codes can still be returned, but are to be used
140 * only for general SMP/MCUmgr errors. The success/OK error code is not used in translation
141 * functions as it is automatically handled by the base SMP code.
142 */
example_mgmt_translate_error_code(uint16_t err)143 static int example_mgmt_translate_error_code(uint16_t err)
144 {
145 int rc;
146
147 switch (err) {
148 case EXAMPLE_MGMT_ERR_NOT_WANTED:
149 rc = MGMT_ERR_ENOENT;
150 break;
151
152 case EXAMPLE_MGMT_ERR_REJECTED_BY_HOOK:
153 rc = MGMT_ERR_EBADSTATE;
154 break;
155
156 case EXAMPLE_MGMT_ERR_UNKNOWN:
157 default:
158 rc = MGMT_ERR_EUNKNOWN;
159 }
160
161 return rc;
162 }
163 #endif
164
165 static const struct mgmt_handler example_mgmt_handlers[] = {
166 [EXAMPLE_MGMT_ID_TEST] = {
167 .mh_read = example_mgmt_test,
168 .mh_write = NULL,
169 },
170 [EXAMPLE_MGMT_ID_OTHER] = {
171 .mh_read = NULL,
172 .mh_write = example_mgmt_other,
173 },
174 };
175
176 static struct mgmt_group example_mgmt_group = {
177 .mg_handlers = example_mgmt_handlers,
178 .mg_handlers_count = ARRAY_SIZE(example_mgmt_handlers),
179 .mg_group_id = MGMT_GROUP_ID_EXAMPLE,
180 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
181 .mg_translate_error = example_mgmt_translate_error_code,
182 #endif
183 };
184
example_mgmt_register_group(void)185 static void example_mgmt_register_group(void)
186 {
187 /* This function is called during system init before main() is invoked, if the
188 * handler needs to set anything up before it can be used, it should do it here.
189 * This register the group so that clients can call the function handlers.
190 */
191 mgmt_register_group(&example_mgmt_group);
192 }
193
194 MCUMGR_HANDLER_DEFINE(example_mgmt, example_mgmt_register_group);
195