1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdlib.h>
8 #include <zephyr/shell/shell.h>
9 #include <zephyr/bluetooth/mesh.h>
10
11 #include "mesh/net.h"
12 #include "mesh/access.h"
13 #include "utils.h"
14 #include <zephyr/bluetooth/mesh/shell.h>
15
16 static const struct bt_mesh_model *mod;
17
show_faults(const struct shell * sh,uint8_t test_id,uint16_t cid,uint8_t * faults,size_t fault_count)18 static void show_faults(const struct shell *sh, uint8_t test_id, uint16_t cid, uint8_t *faults,
19 size_t fault_count)
20 {
21 size_t i;
22
23 if (!fault_count) {
24 shell_print(sh, "Health Test ID 0x%02x Company ID 0x%04x: no faults\n", test_id,
25 cid);
26 return;
27 }
28
29 shell_print(sh, "Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu:\n", test_id, cid,
30 fault_count);
31
32 for (i = 0; i < fault_count; i++) {
33 shell_print(sh, "\t0x%02x\n", faults[i]);
34 }
35 }
36
cmd_fault_get(const struct shell * sh,size_t argc,char * argv[])37 static int cmd_fault_get(const struct shell *sh, size_t argc, char *argv[])
38 {
39 if (!mod && !bt_mesh_shell_mdl_first_get(BT_MESH_MODEL_ID_HEALTH_CLI, &mod)) {
40 return -ENODEV;
41 }
42
43 struct bt_mesh_health_cli *cli = mod->rt->user_data;
44 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx,
45 bt_mesh_shell_target_ctx.dst);
46 uint8_t faults[32];
47 size_t fault_count;
48 uint8_t test_id;
49 uint16_t cid;
50 int err = 0;
51
52 cid = shell_strtoul(argv[1], 0, &err);
53 if (err) {
54 shell_warn(sh, "Unable to parse input string argument");
55 return err;
56 }
57
58 fault_count = sizeof(faults);
59
60 err = bt_mesh_health_cli_fault_get(cli, ctx.addr ? &ctx : NULL, cid, &test_id, faults,
61 &fault_count);
62 if (err) {
63 shell_error(sh, "Failed to send Health Fault Get (err %d)", err);
64 } else {
65 show_faults(sh, test_id, cid, faults, fault_count);
66 }
67
68 return 0;
69 }
70
fault_clear(const struct shell * sh,size_t argc,char * argv[],bool acked)71 static int fault_clear(const struct shell *sh, size_t argc, char *argv[], bool acked)
72 {
73 if (!mod && !bt_mesh_shell_mdl_first_get(BT_MESH_MODEL_ID_HEALTH_CLI, &mod)) {
74 return -ENODEV;
75 }
76
77 struct bt_mesh_health_cli *cli = mod->rt->user_data;
78 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx,
79 bt_mesh_shell_target_ctx.dst);
80 uint8_t test_id;
81 uint16_t cid;
82 int err = 0;
83
84 cid = shell_strtoul(argv[1], 0, &err);
85 if (err) {
86 shell_warn(sh, "Unable to parse input string argument");
87 return err;
88 }
89
90 if (acked) {
91 uint8_t faults[32];
92 size_t fault_count = sizeof(faults);
93
94 err = bt_mesh_health_cli_fault_clear(cli, ctx.addr ? &ctx : NULL, cid, &test_id,
95 faults, &fault_count);
96 if (err) {
97 shell_error(sh, "Failed to send Health Fault Clear (err %d)", err);
98 } else {
99 show_faults(sh, test_id, cid, faults, fault_count);
100 }
101
102 return err;
103 }
104
105 err = bt_mesh_health_cli_fault_clear_unack(cli, ctx.addr ? &ctx : NULL, cid);
106 if (err) {
107 shell_error(sh, "Health Fault Clear Unacknowledged failed (err %d)", err);
108 }
109
110 return err;
111 }
112
cmd_fault_clear(const struct shell * sh,size_t argc,char * argv[])113 static int cmd_fault_clear(const struct shell *sh, size_t argc, char *argv[])
114 {
115 return fault_clear(sh, argc, argv, true);
116 }
117
cmd_fault_clear_unack(const struct shell * sh,size_t argc,char * argv[])118 static int cmd_fault_clear_unack(const struct shell *sh, size_t argc, char *argv[])
119 {
120 return fault_clear(sh, argc, argv, false);
121 }
122
fault_test(const struct shell * sh,size_t argc,char * argv[],bool acked)123 static int fault_test(const struct shell *sh, size_t argc, char *argv[], bool acked)
124 {
125 if (!mod && !bt_mesh_shell_mdl_first_get(BT_MESH_MODEL_ID_HEALTH_CLI, &mod)) {
126 return -ENODEV;
127 }
128
129 struct bt_mesh_health_cli *cli = mod->rt->user_data;
130 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx,
131 bt_mesh_shell_target_ctx.dst);
132 uint8_t test_id;
133 uint16_t cid;
134 int err = 0;
135
136 cid = shell_strtoul(argv[1], 0, &err);
137 test_id = shell_strtoul(argv[2], 0, &err);
138 if (err) {
139 shell_warn(sh, "Unable to parse input string argument");
140 return err;
141 }
142
143 if (acked) {
144 uint8_t faults[32];
145 size_t fault_count = sizeof(faults);
146
147 err = bt_mesh_health_cli_fault_test(cli, ctx.addr ? &ctx : NULL, cid, test_id,
148 faults, &fault_count);
149 if (err) {
150 shell_error(sh, "Failed to send Health Fault Test (err %d)", err);
151 } else {
152 show_faults(sh, test_id, cid, faults, fault_count);
153 }
154
155 return err;
156 }
157
158 err = bt_mesh_health_cli_fault_test_unack(cli, ctx.addr ? &ctx : NULL, cid, test_id);
159 if (err) {
160 shell_error(sh, "Health Fault Test Unacknowledged failed (err %d)", err);
161 }
162
163 return err;
164 }
165
cmd_fault_test(const struct shell * sh,size_t argc,char * argv[])166 static int cmd_fault_test(const struct shell *sh, size_t argc, char *argv[])
167 {
168 return fault_test(sh, argc, argv, true);
169 }
170
cmd_fault_test_unack(const struct shell * sh,size_t argc,char * argv[])171 static int cmd_fault_test_unack(const struct shell *sh, size_t argc, char *argv[])
172 {
173 return fault_test(sh, argc, argv, false);
174 }
175
cmd_period_get(const struct shell * sh,size_t argc,char * argv[])176 static int cmd_period_get(const struct shell *sh, size_t argc, char *argv[])
177 {
178 if (!mod && !bt_mesh_shell_mdl_first_get(BT_MESH_MODEL_ID_HEALTH_CLI, &mod)) {
179 return -ENODEV;
180 }
181
182 struct bt_mesh_health_cli *cli = mod->rt->user_data;
183 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx,
184 bt_mesh_shell_target_ctx.dst);
185 uint8_t divisor;
186 int err;
187
188 err = bt_mesh_health_cli_period_get(cli, ctx.addr ? &ctx : NULL, &divisor);
189 if (err) {
190 shell_error(sh, "Failed to send Health Period Get (err %d)", err);
191 } else {
192 shell_print(sh, "Health FastPeriodDivisor: %u", divisor);
193 }
194
195 return 0;
196 }
197
period_set(const struct shell * sh,size_t argc,char * argv[],bool acked)198 static int period_set(const struct shell *sh, size_t argc, char *argv[], bool acked)
199 {
200 if (!mod && !bt_mesh_shell_mdl_first_get(BT_MESH_MODEL_ID_HEALTH_CLI, &mod)) {
201 return -ENODEV;
202 }
203
204 struct bt_mesh_health_cli *cli = mod->rt->user_data;
205 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx,
206 bt_mesh_shell_target_ctx.dst);
207 uint8_t divisor;
208 int err = 0;
209
210 divisor = shell_strtoul(argv[1], 0, &err);
211 if (err) {
212 shell_warn(sh, "Unable to parse input string argument");
213 return err;
214 }
215
216 if (acked) {
217 uint8_t updated_divisor;
218
219 err = bt_mesh_health_cli_period_set(cli, ctx.addr ? &ctx : NULL, divisor,
220 &updated_divisor);
221 if (err) {
222 shell_error(sh, "Failed to send Health Period Set (err %d)", err);
223 } else {
224 shell_print(sh, "Health FastPeriodDivisor: %u", updated_divisor);
225 }
226
227 return err;
228 }
229
230 err = bt_mesh_health_cli_period_set_unack(cli, ctx.addr ? &ctx : NULL, divisor);
231 if (err) {
232 shell_print(sh, "Failed to send Health Period Set (err %d)", err);
233 }
234
235 return err;
236 }
237
cmd_period_set(const struct shell * sh,size_t argc,char * argv[])238 static int cmd_period_set(const struct shell *sh, size_t argc, char *argv[])
239 {
240 return period_set(sh, argc, argv, true);
241 }
242
cmd_period_set_unack(const struct shell * sh,size_t argc,char * argv[])243 static int cmd_period_set_unack(const struct shell *sh, size_t argc, char *argv[])
244 {
245 return period_set(sh, argc, argv, false);
246 }
247
cmd_attention_get(const struct shell * sh,size_t argc,char * argv[])248 static int cmd_attention_get(const struct shell *sh, size_t argc, char *argv[])
249 {
250 if (!mod && !bt_mesh_shell_mdl_first_get(BT_MESH_MODEL_ID_HEALTH_CLI, &mod)) {
251 return -ENODEV;
252 }
253
254 struct bt_mesh_health_cli *cli = mod->rt->user_data;
255 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx,
256 bt_mesh_shell_target_ctx.dst);
257 uint8_t attention;
258 int err;
259
260 err = bt_mesh_health_cli_attention_get(cli, ctx.addr ? &ctx : NULL, &attention);
261 if (err) {
262 shell_error(sh, "Failed to send Health Attention Get (err %d)", err);
263 } else {
264 shell_print(sh, "Health Attention Timer: %u", attention);
265 }
266
267 return 0;
268 }
269
attention_set(const struct shell * sh,size_t argc,char * argv[],bool acked)270 static int attention_set(const struct shell *sh, size_t argc, char *argv[], bool acked)
271 {
272 if (!mod && !bt_mesh_shell_mdl_first_get(BT_MESH_MODEL_ID_HEALTH_CLI, &mod)) {
273 return -ENODEV;
274 }
275
276 struct bt_mesh_health_cli *cli = mod->rt->user_data;
277 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx,
278 bt_mesh_shell_target_ctx.dst);
279 uint8_t attention;
280 int err = 0;
281
282 attention = shell_strtoul(argv[1], 0, &err);
283 if (err) {
284 shell_warn(sh, "Unable to parse input string argument");
285 return err;
286 }
287
288 if (acked) {
289 uint8_t updated_attention;
290
291 err = bt_mesh_health_cli_attention_set(cli, ctx.addr ? &ctx : NULL, attention,
292 &updated_attention);
293 if (err) {
294 shell_error(sh, "Failed to send Health Attention Set (err %d)", err);
295 } else {
296 shell_print(sh, "Health Attention Timer: %u", updated_attention);
297 }
298
299 return err;
300 }
301
302 err = bt_mesh_health_cli_attention_set_unack(cli, ctx.addr ? &ctx : NULL, attention);
303 if (err) {
304 shell_error(sh, "Failed to send Health Attention Set (err % d) ", err);
305 }
306
307 return err;
308 }
309
cmd_attention_set(const struct shell * sh,size_t argc,char * argv[])310 static int cmd_attention_set(const struct shell *sh, size_t argc, char *argv[])
311 {
312 return attention_set(sh, argc, argv, true);
313 }
314
cmd_attention_set_unack(const struct shell * sh,size_t argc,char * argv[])315 static int cmd_attention_set_unack(const struct shell *sh, size_t argc, char *argv[])
316 {
317 return attention_set(sh, argc, argv, false);
318 }
319
320 BT_MESH_SHELL_MDL_INSTANCE_CMDS(instance_cmds, BT_MESH_MODEL_ID_HEALTH_CLI, mod);
321
322 SHELL_STATIC_SUBCMD_SET_CREATE(
323 health_cli_cmds,
324 /* Health Client Model Operations */
325 SHELL_CMD_ARG(fault-get, NULL, "<CID>", cmd_fault_get, 2, 0),
326 SHELL_CMD_ARG(fault-clear, NULL, "<CID>", cmd_fault_clear, 2, 0),
327 SHELL_CMD_ARG(fault-clear-unack, NULL, "<CID>", cmd_fault_clear_unack, 2, 0),
328 SHELL_CMD_ARG(fault-test, NULL, "<CID> <TestID>", cmd_fault_test, 3, 0),
329 SHELL_CMD_ARG(fault-test-unack, NULL, "<CID> <TestID>", cmd_fault_test_unack, 3,
330 0),
331 SHELL_CMD_ARG(period-get, NULL, NULL, cmd_period_get, 1, 0),
332 SHELL_CMD_ARG(period-set, NULL, "<Divisor>", cmd_period_set, 2, 0),
333 SHELL_CMD_ARG(period-set-unack, NULL, "<Divisor>", cmd_period_set_unack, 2, 0),
334 SHELL_CMD_ARG(attention-get, NULL, NULL, cmd_attention_get, 1, 0),
335 SHELL_CMD_ARG(attention-set, NULL, "<Time(s)>", cmd_attention_set, 2, 0),
336 SHELL_CMD_ARG(attention-set-unack, NULL, "<Time(s)>", cmd_attention_set_unack, 2, 0),
337 SHELL_CMD(instance, &instance_cmds, "Instance commands", bt_mesh_shell_mdl_cmds_help),
338 SHELL_SUBCMD_SET_END);
339
340 SHELL_SUBCMD_ADD((mesh, models), health, &health_cli_cmds, "Health Cli commands",
341 bt_mesh_shell_mdl_cmds_help, 1, 1);
342