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