1 /*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdlib.h>
8 #include <ctype.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/sys/printk.h>
11 #include <zephyr/sys/util.h>
12
13 #include <zephyr/shell/shell.h>
14 #include <zephyr/settings/settings.h>
15
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/mesh.h>
18 #include <zephyr/bluetooth/mesh/shell.h>
19
20 /* Private includes for raw Network & Transport layer access */
21 #include "mesh/mesh.h"
22 #include "mesh/net.h"
23 #include "mesh/rpl.h"
24 #include "mesh/transport.h"
25 #include "mesh/foundation.h"
26 #include "mesh/settings.h"
27 #include "mesh/access.h"
28 #include "common/bt_shell_private.h"
29 #include "utils.h"
30 #include "dfu.h"
31 #include "blob.h"
32
33 #define CID_NVAL 0xffff
34 #define COMPANY_ID_LF 0x05F1
35 #define COMPANY_ID_NORDIC_SEMI 0x05F9
36
37 struct bt_mesh_shell_target bt_mesh_shell_target_ctx = {
38 .dst = BT_MESH_ADDR_UNASSIGNED,
39 };
40
41 /* Default net, app & dev key values, unless otherwise specified */
42 const uint8_t bt_mesh_shell_default_key[16] = {
43 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
44 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
45 };
46
47 #if defined(CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE)
48 static uint8_t cur_faults[BT_MESH_SHELL_CUR_FAULTS_MAX];
49 static uint8_t reg_faults[BT_MESH_SHELL_CUR_FAULTS_MAX * 2];
50
get_faults(uint8_t * faults,uint8_t faults_size,uint8_t * dst,uint8_t * count)51 static void get_faults(uint8_t *faults, uint8_t faults_size, uint8_t *dst, uint8_t *count)
52 {
53 uint8_t i, limit = *count;
54
55 for (i = 0U, *count = 0U; i < faults_size && *count < limit; i++) {
56 if (faults[i]) {
57 *dst++ = faults[i];
58 (*count)++;
59 }
60 }
61 }
62
fault_get_cur(const struct bt_mesh_model * model,uint8_t * test_id,uint16_t * company_id,uint8_t * faults,uint8_t * fault_count)63 static int fault_get_cur(const struct bt_mesh_model *model, uint8_t *test_id,
64 uint16_t *company_id, uint8_t *faults, uint8_t *fault_count)
65 {
66 bt_shell_print("Sending current faults");
67
68 *test_id = 0x00;
69 *company_id = BT_COMP_ID_LF;
70
71 get_faults(cur_faults, sizeof(cur_faults), faults, fault_count);
72
73 return 0;
74 }
75
fault_get_reg(const struct bt_mesh_model * model,uint16_t cid,uint8_t * test_id,uint8_t * faults,uint8_t * fault_count)76 static int fault_get_reg(const struct bt_mesh_model *model, uint16_t cid,
77 uint8_t *test_id, uint8_t *faults, uint8_t *fault_count)
78 {
79 if (cid != CONFIG_BT_COMPANY_ID) {
80 bt_shell_print("Faults requested for unknown Company ID 0x%04x", cid);
81 return -EINVAL;
82 }
83
84 bt_shell_print("Sending registered faults");
85
86 *test_id = 0x00;
87
88 get_faults(reg_faults, sizeof(reg_faults), faults, fault_count);
89
90 return 0;
91 }
92
fault_clear(const struct bt_mesh_model * model,uint16_t cid)93 static int fault_clear(const struct bt_mesh_model *model, uint16_t cid)
94 {
95 if (cid != CONFIG_BT_COMPANY_ID) {
96 return -EINVAL;
97 }
98
99 (void)memset(reg_faults, 0, sizeof(reg_faults));
100
101 return 0;
102 }
103
fault_test(const struct bt_mesh_model * model,uint8_t test_id,uint16_t cid)104 static int fault_test(const struct bt_mesh_model *model, uint8_t test_id,
105 uint16_t cid)
106 {
107 if (cid != CONFIG_BT_COMPANY_ID) {
108 return -EINVAL;
109 }
110
111 if (test_id != 0x00) {
112 return -EINVAL;
113 }
114
115 return 0;
116 }
117
attention_on(const struct bt_mesh_model * model)118 static void attention_on(const struct bt_mesh_model *model)
119 {
120 bt_shell_print("Attention On");
121 }
122
attention_off(const struct bt_mesh_model * model)123 static void attention_off(const struct bt_mesh_model *model)
124 {
125 bt_shell_print("Attention Off");
126 }
127
128 static const struct bt_mesh_health_srv_cb health_srv_cb = {
129 .fault_get_cur = fault_get_cur,
130 .fault_get_reg = fault_get_reg,
131 .fault_clear = fault_clear,
132 .fault_test = fault_test,
133 .attn_on = attention_on,
134 .attn_off = attention_off,
135 };
136 #endif /* CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE */
137
138 #if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)
139 static const uint8_t health_tests[] = {
140 BT_MESH_HEALTH_TEST_INFO(COMPANY_ID_LF, 6, 0x01, 0x02, 0x03, 0x04, 0x34, 0x15),
141 BT_MESH_HEALTH_TEST_INFO(COMPANY_ID_NORDIC_SEMI, 3, 0x01, 0x02, 0x03),
142 };
143
144 const struct bt_mesh_models_metadata_entry health_srv_meta[] = {
145 BT_MESH_HEALTH_TEST_INFO_METADATA(health_tests),
146 BT_MESH_MODELS_METADATA_END,
147 };
148 #endif
149
150 struct bt_mesh_health_srv bt_mesh_shell_health_srv = {
151 #if defined(CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE)
152 .cb = &health_srv_cb,
153 #endif
154 };
155
156 #if defined(CONFIG_BT_MESH_SHELL_HEALTH_CLI)
show_faults(uint8_t test_id,uint16_t cid,uint8_t * faults,size_t fault_count)157 static void show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count)
158 {
159 size_t i;
160
161 if (!fault_count) {
162 bt_shell_print("Health Test ID 0x%02x Company ID 0x%04x: no faults",
163 test_id, cid);
164 return;
165 }
166
167 bt_shell_print("Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu:",
168 test_id, cid, fault_count);
169
170 for (i = 0; i < fault_count; i++) {
171 bt_shell_print("\t0x%02x", faults[i]);
172 }
173 }
174
health_current_status(struct bt_mesh_health_cli * cli,uint16_t addr,uint8_t test_id,uint16_t cid,uint8_t * faults,size_t fault_count)175 static void health_current_status(struct bt_mesh_health_cli *cli, uint16_t addr,
176 uint8_t test_id, uint16_t cid, uint8_t *faults,
177 size_t fault_count)
178 {
179 bt_shell_print("Health Current Status from 0x%04x", addr);
180 show_faults(test_id, cid, faults, fault_count);
181 }
182
health_fault_status(struct bt_mesh_health_cli * cli,uint16_t addr,uint8_t test_id,uint16_t cid,uint8_t * faults,size_t fault_count)183 static void health_fault_status(struct bt_mesh_health_cli *cli, uint16_t addr,
184 uint8_t test_id, uint16_t cid, uint8_t *faults,
185 size_t fault_count)
186 {
187 bt_shell_print("Health Fault Status from 0x%04x", addr);
188 show_faults(test_id, cid, faults, fault_count);
189 }
190
health_attention_status(struct bt_mesh_health_cli * cli,uint16_t addr,uint8_t attention)191 static void health_attention_status(struct bt_mesh_health_cli *cli,
192 uint16_t addr, uint8_t attention)
193 {
194 bt_shell_print("Health Attention Status from 0x%04x: %u", addr, attention);
195 }
196
health_period_status(struct bt_mesh_health_cli * cli,uint16_t addr,uint8_t period)197 static void health_period_status(struct bt_mesh_health_cli *cli, uint16_t addr,
198 uint8_t period)
199 {
200 bt_shell_print("Health Fast Period Divisor Status from 0x%04x: %u", addr, period);
201 }
202
203 struct bt_mesh_health_cli bt_mesh_shell_health_cli = {
204 .current_status = health_current_status,
205 .fault_status = health_fault_status,
206 .attention_status = health_attention_status,
207 .period_status = health_period_status,
208 };
209 #endif /* CONFIG_BT_MESH_SHELL_HEALTH_CLI */
210
cmd_init(const struct shell * sh,size_t argc,char * argv[])211 static int cmd_init(const struct shell *sh, size_t argc, char *argv[])
212 {
213 shell_print(sh, "Mesh shell initialized");
214
215 #if defined(CONFIG_BT_MESH_SHELL_DFU_CLI) || defined(CONFIG_BT_MESH_SHELL_DFU_SRV)
216 bt_mesh_shell_dfu_cmds_init();
217 #endif
218 #if defined(CONFIG_BT_MESH_SHELL_BLOB_CLI) || defined(CONFIG_BT_MESH_SHELL_BLOB_SRV) || \
219 defined(CONFIG_BT_MESH_SHELL_BLOB_IO_FLASH)
220 bt_mesh_shell_blob_cmds_init();
221 #endif
222
223 if (IS_ENABLED(CONFIG_BT_MESH_RPR_SRV)) {
224 bt_mesh_prov_enable(BT_MESH_PROV_REMOTE);
225 }
226
227 return 0;
228 }
229
cmd_reset(const struct shell * sh,size_t argc,char * argv[])230 static int cmd_reset(const struct shell *sh, size_t argc, char *argv[])
231 {
232 #if defined(CONFIG_BT_MESH_CDB)
233 bt_mesh_cdb_clear();
234 #endif
235 bt_mesh_reset();
236 shell_print(sh, "Local node reset complete");
237
238 return 0;
239 }
240
241 #if defined(CONFIG_BT_MESH_SHELL_LOW_POWER)
cmd_lpn(const struct shell * sh,size_t argc,char * argv[])242 static int cmd_lpn(const struct shell *sh, size_t argc, char *argv[])
243 {
244 static bool enabled;
245 bool onoff;
246 int err = 0;
247
248 if (argc < 2) {
249 shell_print(sh, "%s", enabled ? "enabled" : "disabled");
250 return 0;
251 }
252
253 onoff = shell_strtobool(argv[1], 0, &err);
254 if (err) {
255 shell_warn(sh, "Unable to parse input string argument");
256 return err;
257 }
258
259 if (onoff) {
260 if (enabled) {
261 shell_print(sh, "LPN already enabled");
262 return 0;
263 }
264
265 err = bt_mesh_lpn_set(true);
266 if (err) {
267 shell_error(sh, "Enabling LPN failed (err %d)", err);
268 } else {
269 enabled = true;
270 }
271 } else {
272 if (!enabled) {
273 shell_print(sh, "LPN already disabled");
274 return 0;
275 }
276
277 err = bt_mesh_lpn_set(false);
278 if (err) {
279 shell_error(sh, "Enabling LPN failed (err %d)", err);
280 } else {
281 enabled = false;
282 }
283 }
284
285 return 0;
286 }
287
cmd_poll(const struct shell * sh,size_t argc,char * argv[])288 static int cmd_poll(const struct shell *sh, size_t argc, char *argv[])
289 {
290 int err;
291
292 err = bt_mesh_lpn_poll();
293 if (err) {
294 shell_error(sh, "Friend Poll failed (err %d)", err);
295 }
296
297 return 0;
298 }
299
lpn_established(uint16_t net_idx,uint16_t friend_addr,uint8_t queue_size,uint8_t recv_win)300 static void lpn_established(uint16_t net_idx, uint16_t friend_addr,
301 uint8_t queue_size, uint8_t recv_win)
302 {
303 bt_shell_print("Friendship (as LPN) established to "
304 "Friend 0x%04x Queue Size %d Receive Window %d",
305 friend_addr, queue_size, recv_win);
306 }
307
lpn_terminated(uint16_t net_idx,uint16_t friend_addr)308 static void lpn_terminated(uint16_t net_idx, uint16_t friend_addr)
309 {
310 bt_shell_print("Friendship (as LPN) lost with Friend 0x%04x", friend_addr);
311 }
312
313 BT_MESH_LPN_CB_DEFINE(lpn_cb) = {
314 .established = lpn_established,
315 .terminated = lpn_terminated,
316 };
317 #endif /* CONFIG_BT_MESH_SHELL_LOW_POWER */
318
319 #if defined(CONFIG_BT_MESH_SHELL_GATT_PROXY)
320 #if defined(CONFIG_BT_MESH_GATT_PROXY)
cmd_ident(const struct shell * sh,size_t argc,char * argv[])321 static int cmd_ident(const struct shell *sh, size_t argc, char *argv[])
322 {
323 int err;
324
325 err = bt_mesh_proxy_identity_enable();
326 if (err) {
327 shell_error(sh, "Failed advertise using Node Identity (err "
328 "%d)", err);
329 }
330
331 return 0;
332 }
333 #endif /* CONFIG_BT_MESH_GATT_PROXY */
334
335 #if defined(CONFIG_BT_MESH_PROXY_CLIENT)
cmd_proxy_connect(const struct shell * sh,size_t argc,char * argv[])336 static int cmd_proxy_connect(const struct shell *sh, size_t argc,
337 char *argv[])
338 {
339 uint16_t net_idx;
340 int err = 0;
341
342 net_idx = shell_strtoul(argv[1], 0, &err);
343 if (err) {
344 shell_warn(sh, "Unable to parse input string argument");
345 return err;
346 }
347
348 err = bt_mesh_proxy_connect(net_idx);
349 if (err) {
350 shell_error(sh, "Proxy connect failed (err %d)", err);
351 }
352
353 return 0;
354 }
355
cmd_proxy_disconnect(const struct shell * sh,size_t argc,char * argv[])356 static int cmd_proxy_disconnect(const struct shell *sh, size_t argc,
357 char *argv[])
358 {
359 uint16_t net_idx;
360 int err = 0;
361
362 net_idx = shell_strtoul(argv[1], 0, &err);
363 if (err) {
364 shell_warn(sh, "Unable to parse input string argument");
365 return err;
366 }
367
368 err = bt_mesh_proxy_disconnect(net_idx);
369 if (err) {
370 shell_error(sh, "Proxy disconnect failed (err %d)", err);
371 }
372
373 return 0;
374 }
375 #endif /* CONFIG_BT_MESH_PROXY_CLIENT */
376
377 #if defined(CONFIG_BT_MESH_PROXY_SOLICITATION)
cmd_proxy_solicit(const struct shell * sh,size_t argc,char * argv[])378 static int cmd_proxy_solicit(const struct shell *sh, size_t argc,
379 char *argv[])
380 {
381 uint16_t net_idx;
382 int err = 0;
383
384 net_idx = shell_strtoul(argv[1], 0, &err);
385 if (err) {
386 shell_warn(sh, "Unable to parse input string argument");
387 return err;
388 }
389
390 err = bt_mesh_proxy_solicit(net_idx);
391 if (err) {
392 shell_error(sh, "Failed to advertise solicitation PDU (err %d)",
393 err);
394 }
395
396 return err;
397 }
398 #endif /* CONFIG_BT_MESH_PROXY_SOLICITATION */
399 #endif /* CONFIG_BT_MESH_SHELL_GATT_PROXY */
400
401 #if defined(CONFIG_BT_MESH_SHELL_PROV)
cmd_input_num(const struct shell * sh,size_t argc,char * argv[])402 static int cmd_input_num(const struct shell *sh, size_t argc, char *argv[])
403 {
404 int err = 0;
405 uint32_t val;
406
407 val = shell_strtoul(argv[1], 10, &err);
408 if (err) {
409 shell_warn(sh, "Unable to parse input string argument");
410 return err;
411 }
412
413 err = bt_mesh_input_number(val);
414 if (err) {
415 shell_error(sh, "Numeric input failed (err %d)", err);
416 }
417
418 return 0;
419 }
420
cmd_input_str(const struct shell * sh,size_t argc,char * argv[])421 static int cmd_input_str(const struct shell *sh, size_t argc, char *argv[])
422 {
423 int err = bt_mesh_input_string(argv[1]);
424
425 if (err) {
426 shell_error(sh, "String input failed (err %d)", err);
427 }
428
429 return 0;
430 }
431
bearer2str(bt_mesh_prov_bearer_t bearer)432 static const char *bearer2str(bt_mesh_prov_bearer_t bearer)
433 {
434 switch (bearer) {
435 case BT_MESH_PROV_ADV:
436 return "PB-ADV";
437 case BT_MESH_PROV_GATT:
438 return "PB-GATT";
439 case BT_MESH_PROV_REMOTE:
440 return "PB-REMOTE";
441 default:
442 return "unknown";
443 }
444 }
445
446 #if defined(CONFIG_BT_MESH_SHELL_PROV_CTX_INSTANCE)
447 static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
448
prov_complete(uint16_t net_idx,uint16_t addr)449 static void prov_complete(uint16_t net_idx, uint16_t addr)
450 {
451
452 bt_shell_print("Local node provisioned, net_idx 0x%04x address 0x%04x", net_idx, addr);
453
454 bt_mesh_shell_target_ctx.net_idx = net_idx;
455 bt_mesh_shell_target_ctx.dst = addr;
456 }
457
reprovisioned(uint16_t addr)458 static void reprovisioned(uint16_t addr)
459 {
460 bt_shell_print("Local node re-provisioned, new address 0x%04x", addr);
461
462 if (bt_mesh_shell_target_ctx.dst == bt_mesh_primary_addr()) {
463 bt_mesh_shell_target_ctx.dst = addr;
464 }
465 }
466
prov_node_added(uint16_t net_idx,uint8_t uuid[16],uint16_t addr,uint8_t num_elem)467 static void prov_node_added(uint16_t net_idx, uint8_t uuid[16], uint16_t addr,
468 uint8_t num_elem)
469 {
470 bt_shell_print("Node provisioned, net_idx 0x%04x address 0x%04x elements %d",
471 net_idx, addr, num_elem);
472
473 bt_mesh_shell_target_ctx.net_idx = net_idx;
474 bt_mesh_shell_target_ctx.dst = addr;
475 }
476
477 #if defined(CONFIG_BT_MESH_PROVISIONER)
478 static const char * const output_meth_string[] = {
479 "Blink",
480 "Beep",
481 "Vibrate",
482 "Display Number",
483 "Display String",
484 };
485
486 static const char *const input_meth_string[] = {
487 "Push",
488 "Twist",
489 "Enter Number",
490 "Enter String",
491 };
492
capabilities(const struct bt_mesh_dev_capabilities * cap)493 static void capabilities(const struct bt_mesh_dev_capabilities *cap)
494 {
495 bt_shell_print("Provisionee capabilities:");
496 bt_shell_print("\tStatic OOB is %ssupported", cap->oob_type & 1 ? "" : "not ");
497
498 bt_shell_print("\tAvailable output actions (%d bytes max):%s", cap->output_size,
499 cap->output_actions ? "" : "\n\t\tNone");
500 for (int i = 0; i < ARRAY_SIZE(output_meth_string); i++) {
501 if (cap->output_actions & BIT(i)) {
502 bt_shell_print("\t\t%s", output_meth_string[i]);
503 }
504 }
505
506 bt_shell_print("\tAvailable input actions (%d bytes max):%s", cap->input_size,
507 cap->input_actions ? "" : "\n\t\tNone");
508 for (int i = 0; i < ARRAY_SIZE(input_meth_string); i++) {
509 if (cap->input_actions & BIT(i)) {
510 bt_shell_print("\t\t%s", input_meth_string[i]);
511 }
512 }
513 }
514 #endif
515
prov_input_complete(void)516 static void prov_input_complete(void)
517 {
518 bt_shell_print("Input complete");
519 }
520
prov_reset(void)521 static void prov_reset(void)
522 {
523 bt_shell_print("The local node has been reset and needs reprovisioning");
524 }
525
output_number(bt_mesh_output_action_t action,uint32_t number)526 static int output_number(bt_mesh_output_action_t action, uint32_t number)
527 {
528 switch (action) {
529 case BT_MESH_BLINK:
530 bt_shell_print("OOB blink Number: %u", number);
531 break;
532 case BT_MESH_BEEP:
533 bt_shell_print("OOB beep Number: %u", number);
534 break;
535 case BT_MESH_VIBRATE:
536 bt_shell_print("OOB vibrate Number: %u", number);
537 break;
538 case BT_MESH_DISPLAY_NUMBER:
539 bt_shell_print("OOB display Number: %u", number);
540 break;
541 default:
542 bt_shell_error("Unknown Output action %u (number %u) requested!",
543 action, number);
544 return -EINVAL;
545 }
546
547 return 0;
548 }
549
output_string(const char * str)550 static int output_string(const char *str)
551 {
552 bt_shell_print("OOB String: %s", str);
553 return 0;
554 }
555
input(bt_mesh_input_action_t act,uint8_t size)556 static int input(bt_mesh_input_action_t act, uint8_t size)
557 {
558
559 switch (act) {
560 case BT_MESH_ENTER_NUMBER:
561 bt_shell_print("Enter a number (max %u digits) with: Input-num <num>", size);
562 break;
563 case BT_MESH_ENTER_STRING:
564 bt_shell_print("Enter a string (max %u chars) with: Input-str <str>", size);
565 break;
566 case BT_MESH_TWIST:
567 bt_shell_print("\"Twist\" a number (max %u digits) with: Input-num <num>", size);
568 break;
569 case BT_MESH_PUSH:
570 bt_shell_print("\"Push\" a number (max %u digits) with: Input-num <num>", size);
571 break;
572 default:
573 bt_shell_error("Unknown Input action %u (size %u) requested!", act, size);
574 return -EINVAL;
575 }
576
577 return 0;
578 }
579
link_open(bt_mesh_prov_bearer_t bearer)580 static void link_open(bt_mesh_prov_bearer_t bearer)
581 {
582 bt_shell_print("Provisioning link opened on %s", bearer2str(bearer));
583 }
584
link_close(bt_mesh_prov_bearer_t bearer)585 static void link_close(bt_mesh_prov_bearer_t bearer)
586 {
587 bt_shell_print("Provisioning link closed on %s", bearer2str(bearer));
588 }
589
590 static uint8_t static_val[32];
591
592 struct bt_mesh_prov bt_mesh_shell_prov = {
593 .uuid = dev_uuid,
594 .link_open = link_open,
595 .link_close = link_close,
596 .complete = prov_complete,
597 .reprovisioned = reprovisioned,
598 .node_added = prov_node_added,
599 .reset = prov_reset,
600 .static_val = NULL,
601 .static_val_len = 0,
602 .output_size = 6,
603 .output_actions = (BT_MESH_BLINK | BT_MESH_BEEP | BT_MESH_VIBRATE | BT_MESH_DISPLAY_NUMBER |
604 BT_MESH_DISPLAY_STRING),
605 .output_number = output_number,
606 .output_string = output_string,
607 .input_size = 6,
608 .input_actions =
609 (BT_MESH_ENTER_NUMBER | BT_MESH_ENTER_STRING | BT_MESH_TWIST | BT_MESH_PUSH),
610 .input = input,
611 .input_complete = prov_input_complete,
612 #if defined(CONFIG_BT_MESH_PROVISIONER)
613 .capabilities = capabilities
614 #endif
615 };
616
cmd_static_oob(const struct shell * sh,size_t argc,char * argv[])617 static int cmd_static_oob(const struct shell *sh, size_t argc, char *argv[])
618 {
619 if (argc < 2) {
620 bt_mesh_shell_prov.static_val = NULL;
621 bt_mesh_shell_prov.static_val_len = 0U;
622 } else {
623 bt_mesh_shell_prov.static_val_len = hex2bin(argv[1], strlen(argv[1]),
624 static_val, 32);
625 if (bt_mesh_shell_prov.static_val_len) {
626 bt_mesh_shell_prov.static_val = static_val;
627 } else {
628 bt_mesh_shell_prov.static_val = NULL;
629 }
630 }
631
632 if (bt_mesh_shell_prov.static_val) {
633 shell_print(sh, "Static OOB value set (length %u)",
634 bt_mesh_shell_prov.static_val_len);
635 } else {
636 shell_print(sh, "Static OOB value cleared");
637 }
638
639 return 0;
640 }
641
cmd_uuid(const struct shell * sh,size_t argc,char * argv[])642 static int cmd_uuid(const struct shell *sh, size_t argc, char *argv[])
643 {
644 uint8_t uuid[16];
645 size_t len;
646
647 if (argc < 2) {
648 char uuid_hex_str[32 + 1];
649
650 bin2hex(dev_uuid, 16, uuid_hex_str, sizeof(uuid_hex_str));
651
652 bt_shell_print("Device UUID: %s", uuid_hex_str);
653 return 0;
654 }
655
656 len = hex2bin(argv[1], strlen(argv[1]), uuid, sizeof(uuid));
657 if (len < 1) {
658 return -EINVAL;
659 }
660
661 memcpy(dev_uuid, uuid, len);
662 (void)memset(dev_uuid + len, 0, sizeof(dev_uuid) - len);
663
664 shell_print(sh, "Device UUID set");
665
666 return 0;
667 }
668
print_unprovisioned_beacon(uint8_t uuid[16],bt_mesh_prov_oob_info_t oob_info,uint32_t * uri_hash)669 static void print_unprovisioned_beacon(uint8_t uuid[16],
670 bt_mesh_prov_oob_info_t oob_info,
671 uint32_t *uri_hash)
672 {
673 char uuid_hex_str[32 + 1];
674
675 bin2hex(uuid, 16, uuid_hex_str, sizeof(uuid_hex_str));
676
677 bt_shell_print("PB-ADV UUID %s, OOB Info 0x%04x, URI Hash 0x%x",
678 uuid_hex_str, oob_info,
679 (uri_hash == NULL ? 0 : *uri_hash));
680 }
681
682 #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
pb_gatt_unprovisioned(uint8_t uuid[16],bt_mesh_prov_oob_info_t oob_info)683 static void pb_gatt_unprovisioned(uint8_t uuid[16],
684 bt_mesh_prov_oob_info_t oob_info)
685 {
686 char uuid_hex_str[32 + 1];
687
688 bin2hex(uuid, 16, uuid_hex_str, sizeof(uuid_hex_str));
689
690 bt_shell_print("PB-GATT UUID %s, OOB Info 0x%04x", uuid_hex_str, oob_info);
691 }
692 #endif
693
cmd_beacon_listen(const struct shell * sh,size_t argc,char * argv[])694 static int cmd_beacon_listen(const struct shell *sh, size_t argc,
695 char *argv[])
696 {
697 int err = 0;
698 bool val = shell_strtobool(argv[1], 0, &err);
699
700 if (err) {
701 shell_warn(sh, "Unable to parse input string argument");
702 return err;
703 }
704
705 if (!bt_mesh_is_provisioned()) {
706 shell_error(sh, "Not yet provisioned");
707 return -EINVAL;
708 }
709
710 if (val) {
711 bt_mesh_shell_prov.unprovisioned_beacon = print_unprovisioned_beacon;
712 #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
713 bt_mesh_shell_prov.unprovisioned_beacon_gatt = pb_gatt_unprovisioned;
714 #endif
715 } else {
716 bt_mesh_shell_prov.unprovisioned_beacon = NULL;
717 bt_mesh_shell_prov.unprovisioned_beacon_gatt = NULL;
718 }
719
720 return 0;
721 }
722 #endif /* CONFIG_BT_MESH_SHELL_PROV_CTX_INSTANCE */
723
724 #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
cmd_provision_gatt(const struct shell * sh,size_t argc,char * argv[])725 static int cmd_provision_gatt(const struct shell *sh, size_t argc,
726 char *argv[])
727 {
728 static uint8_t uuid[16];
729 uint8_t attention_duration;
730 uint16_t net_idx;
731 uint16_t addr;
732 size_t len;
733 int err = 0;
734
735 len = hex2bin(argv[1], strlen(argv[1]), uuid, sizeof(uuid));
736 (void)memset(uuid + len, 0, sizeof(uuid) - len);
737
738 net_idx = shell_strtoul(argv[2], 0, &err);
739 addr = shell_strtoul(argv[3], 0, &err);
740 attention_duration = shell_strtoul(argv[4], 0, &err);
741 if (err) {
742 shell_warn(sh, "Unable to parse input string argument");
743 return err;
744 }
745
746 err = bt_mesh_provision_gatt(uuid, net_idx, addr, attention_duration);
747 if (err) {
748 shell_error(sh, "Provisioning failed (err %d)", err);
749 }
750
751 return 0;
752 }
753 #endif /* CONFIG_BT_MESH_PB_GATT_CLIENT */
754
755 #if defined(CONFIG_BT_MESH_PROVISIONEE)
cmd_pb(bt_mesh_prov_bearer_t bearer,const struct shell * sh,size_t argc,char * argv[])756 static int cmd_pb(bt_mesh_prov_bearer_t bearer, const struct shell *sh,
757 size_t argc, char *argv[])
758 {
759 int err = 0;
760 bool onoff;
761
762 if (argc < 2) {
763 return -EINVAL;
764 }
765
766 onoff = shell_strtobool(argv[1], 0, &err);
767 if (err) {
768 shell_warn(sh, "Unable to parse input string argument");
769 return err;
770 }
771
772 if (onoff) {
773 err = bt_mesh_prov_enable(bearer);
774 if (err) {
775 shell_error(sh, "Failed to enable %s (err %d)",
776 bearer2str(bearer), err);
777 } else {
778 shell_print(sh, "%s enabled", bearer2str(bearer));
779 }
780 } else {
781 err = bt_mesh_prov_disable(bearer);
782 if (err) {
783 shell_error(sh, "Failed to disable %s (err %d)",
784 bearer2str(bearer), err);
785 } else {
786 shell_print(sh, "%s disabled", bearer2str(bearer));
787 }
788 }
789
790 return 0;
791 }
792
793 #if defined(CONFIG_BT_MESH_PB_ADV)
cmd_pb_adv(const struct shell * sh,size_t argc,char * argv[])794 static int cmd_pb_adv(const struct shell *sh, size_t argc, char *argv[])
795 {
796 return cmd_pb(BT_MESH_PROV_ADV, sh, argc, argv);
797 }
798 #endif /* CONFIG_BT_MESH_PB_ADV */
799
800 #if defined(CONFIG_BT_MESH_PB_GATT)
cmd_pb_gatt(const struct shell * sh,size_t argc,char * argv[])801 static int cmd_pb_gatt(const struct shell *sh, size_t argc, char *argv[])
802 {
803 return cmd_pb(BT_MESH_PROV_GATT, sh, argc, argv);
804 }
805 #endif /* CONFIG_BT_MESH_PB_GATT */
806 #endif /* CONFIG_BT_MESH_PROVISIONEE */
807
808 #if defined(CONFIG_BT_MESH_PROVISIONER)
cmd_remote_pub_key_set(const struct shell * sh,size_t argc,char * argv[])809 static int cmd_remote_pub_key_set(const struct shell *sh, size_t argc, char *argv[])
810 {
811 size_t len;
812 uint8_t pub_key[64];
813 int err = 0;
814
815 len = hex2bin(argv[1], strlen(argv[1]), pub_key, sizeof(pub_key));
816 if (len < 1) {
817 shell_warn(sh, "Unable to parse input string argument");
818 return -EINVAL;
819 }
820
821 err = bt_mesh_prov_remote_pub_key_set(pub_key);
822
823 if (err) {
824 shell_error(sh, "Setting remote pub key failed (err %d)", err);
825 }
826
827 return 0;
828 }
829
cmd_auth_method_set_input(const struct shell * sh,size_t argc,char * argv[])830 static int cmd_auth_method_set_input(const struct shell *sh, size_t argc, char *argv[])
831 {
832 int err = 0;
833 bt_mesh_input_action_t action = shell_strtoul(argv[1], 10, &err);
834 uint8_t size = shell_strtoul(argv[2], 10, &err);
835
836 if (err) {
837 shell_warn(sh, "Unable to parse input string argument");
838 return err;
839 }
840
841 err = bt_mesh_auth_method_set_input(action, size);
842 if (err) {
843 shell_error(sh, "Setting input OOB authentication action failed (err %d)", err);
844 }
845
846 return 0;
847 }
848
cmd_auth_method_set_output(const struct shell * sh,size_t argc,char * argv[])849 static int cmd_auth_method_set_output(const struct shell *sh, size_t argc, char *argv[])
850 {
851 int err = 0;
852 bt_mesh_output_action_t action = shell_strtoul(argv[1], 10, &err);
853 uint8_t size = shell_strtoul(argv[2], 10, &err);
854
855 if (err) {
856 shell_warn(sh, "Unable to parse input string argument");
857 return err;
858 }
859
860 err = bt_mesh_auth_method_set_output(action, size);
861 if (err) {
862 shell_error(sh, "Setting output OOB authentication action failed (err %d)", err);
863 }
864 return 0;
865 }
866
cmd_auth_method_set_static(const struct shell * sh,size_t argc,char * argv[])867 static int cmd_auth_method_set_static(const struct shell *sh, size_t argc, char *argv[])
868 {
869 size_t len;
870 uint8_t static_oob_auth[32];
871 int err = 0;
872
873 len = hex2bin(argv[1], strlen(argv[1]), static_oob_auth, sizeof(static_oob_auth));
874 if (len < 1) {
875 shell_warn(sh, "Unable to parse input string argument");
876 return -EINVAL;
877 }
878
879 err = bt_mesh_auth_method_set_static(static_oob_auth, len);
880 if (err) {
881 shell_error(sh, "Setting static OOB authentication failed (err %d)", err);
882 }
883 return 0;
884 }
885
cmd_auth_method_set_none(const struct shell * sh,size_t argc,char * argv[])886 static int cmd_auth_method_set_none(const struct shell *sh, size_t argc, char *argv[])
887 {
888 int err = bt_mesh_auth_method_set_none();
889
890 if (err) {
891 shell_error(sh, "Disabling authentication failed (err %d)", err);
892 }
893 return 0;
894 }
895
cmd_provision_adv(const struct shell * sh,size_t argc,char * argv[])896 static int cmd_provision_adv(const struct shell *sh, size_t argc,
897 char *argv[])
898 {
899 uint8_t uuid[16];
900 uint8_t attention_duration;
901 uint16_t net_idx;
902 uint16_t addr;
903 size_t len;
904 int err = 0;
905
906 len = hex2bin(argv[1], strlen(argv[1]), uuid, sizeof(uuid));
907 (void)memset(uuid + len, 0, sizeof(uuid) - len);
908
909 net_idx = shell_strtoul(argv[2], 0, &err);
910 addr = shell_strtoul(argv[3], 0, &err);
911 attention_duration = shell_strtoul(argv[4], 0, &err);
912 if (err) {
913 shell_warn(sh, "Unable to parse input string argument");
914 return err;
915 }
916
917 err = bt_mesh_provision_adv(uuid, net_idx, addr, attention_duration);
918 if (err) {
919 shell_error(sh, "Provisioning failed (err %d)", err);
920 }
921
922 return 0;
923 }
924 #endif /* CONFIG_BT_MESH_PROVISIONER */
925
cmd_provision_local(const struct shell * sh,size_t argc,char * argv[])926 static int cmd_provision_local(const struct shell *sh, size_t argc, char *argv[])
927 {
928 uint8_t net_key[16];
929 uint16_t net_idx, addr;
930 uint32_t iv_index;
931 int err = 0;
932
933 net_idx = shell_strtoul(argv[1], 0, &err);
934 addr = shell_strtoul(argv[2], 0, &err);
935
936 if (argc > 3) {
937 iv_index = shell_strtoul(argv[3], 0, &err);
938 } else {
939 iv_index = 0U;
940 }
941
942 if (err) {
943 shell_warn(sh, "Unable to parse input string argument");
944 return err;
945 }
946
947 memcpy(net_key, bt_mesh_shell_default_key, sizeof(net_key));
948
949 if (IS_ENABLED(CONFIG_BT_MESH_CDB)) {
950 struct bt_mesh_cdb_subnet *sub;
951
952 sub = bt_mesh_cdb_subnet_get(net_idx);
953 if (!sub) {
954 shell_error(sh, "No cdb entry for subnet 0x%03x", net_idx);
955 return 0;
956 }
957
958 if (bt_mesh_cdb_subnet_key_export(sub, SUBNET_KEY_TX_IDX(sub), net_key)) {
959 shell_error(sh, "Unable to export key for subnet 0x%03x", net_idx);
960 return 0;
961 }
962 }
963
964 err = bt_mesh_provision(net_key, net_idx, 0, iv_index, addr, bt_mesh_shell_default_key);
965 if (err) {
966 shell_error(sh, "Provisioning failed (err %d)", err);
967 }
968
969 return 0;
970 }
971
cmd_comp_change(const struct shell * sh,size_t argc,char * argv[])972 static int cmd_comp_change(const struct shell *sh, size_t argc, char *argv[])
973 {
974 bt_mesh_comp_change_prepare();
975 return 0;
976 }
977 #endif /* CONFIG_BT_MESH_SHELL_PROV */
978
979 #if defined(CONFIG_BT_MESH_SHELL_TEST)
cmd_net_send(const struct shell * sh,size_t argc,char * argv[])980 static int cmd_net_send(const struct shell *sh, size_t argc, char *argv[])
981 {
982 NET_BUF_SIMPLE_DEFINE(msg, 32);
983
984 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT(bt_mesh_shell_target_ctx.net_idx,
985 bt_mesh_shell_target_ctx.app_idx,
986 bt_mesh_shell_target_ctx.dst,
987 BT_MESH_TTL_DEFAULT);
988 struct bt_mesh_net_tx tx = {
989 .ctx = &ctx,
990 .src = bt_mesh_primary_addr(),
991 };
992
993 size_t len;
994 int err;
995
996 len = hex2bin(argv[1], strlen(argv[1]),
997 msg.data, net_buf_simple_tailroom(&msg) - 4);
998 net_buf_simple_add(&msg, len);
999
1000 err = bt_mesh_trans_send(&tx, &msg, NULL, NULL);
1001 if (err) {
1002 shell_error(sh, "Failed to send (err %d)", err);
1003 }
1004
1005 return 0;
1006 }
1007
1008 #if defined(CONFIG_BT_MESH_IV_UPDATE_TEST)
cmd_iv_update(const struct shell * sh,size_t argc,char * argv[])1009 static int cmd_iv_update(const struct shell *sh, size_t argc, char *argv[])
1010 {
1011 if (bt_mesh_iv_update()) {
1012 shell_print(sh, "Transitioned to IV Update In Progress "
1013 "state");
1014 } else {
1015 shell_print(sh, "Transitioned to IV Update Normal state");
1016 }
1017
1018 shell_print(sh, "IV Index is 0x%08x", bt_mesh.iv_index);
1019
1020 return 0;
1021 }
1022
cmd_iv_update_test(const struct shell * sh,size_t argc,char * argv[])1023 static int cmd_iv_update_test(const struct shell *sh, size_t argc,
1024 char *argv[])
1025 {
1026 int err = 0;
1027 bool enable;
1028
1029 enable = shell_strtobool(argv[1], 0, &err);
1030 if (err) {
1031 shell_warn(sh, "Unable to parse input string argument");
1032 return err;
1033 }
1034
1035 if (enable) {
1036 shell_print(sh, "Enabling IV Update test mode");
1037 } else {
1038 shell_print(sh, "Disabling IV Update test mode");
1039 }
1040
1041 bt_mesh_iv_update_test(enable);
1042
1043 return 0;
1044 }
1045 #endif /* CONFIG_BT_MESH_IV_UPDATE_TEST */
1046
cmd_rpl_clear(const struct shell * sh,size_t argc,char * argv[])1047 static int cmd_rpl_clear(const struct shell *sh, size_t argc, char *argv[])
1048 {
1049 bt_mesh_rpl_clear();
1050 return 0;
1051 }
1052
1053 #if defined(CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE)
primary_element(void)1054 static const struct bt_mesh_elem *primary_element(void)
1055 {
1056 const struct bt_mesh_comp *comp = bt_mesh_comp_get();
1057
1058 if (comp) {
1059 return &comp->elem[0];
1060 }
1061
1062 return NULL;
1063 }
1064
cmd_add_fault(const struct shell * sh,size_t argc,char * argv[])1065 static int cmd_add_fault(const struct shell *sh, size_t argc, char *argv[])
1066 {
1067 uint8_t fault_id;
1068 uint8_t i;
1069 const struct bt_mesh_elem *elem;
1070 int err = 0;
1071
1072 elem = primary_element();
1073 if (elem == NULL) {
1074 shell_print(sh, "Element not found!");
1075 return -EINVAL;
1076 }
1077
1078 fault_id = shell_strtoul(argv[1], 0, &err);
1079 if (err) {
1080 shell_warn(sh, "Unable to parse input string argument");
1081 return err;
1082 }
1083
1084 if (!fault_id) {
1085 shell_print(sh, "The Fault ID must be non-zero!");
1086 return -EINVAL;
1087 }
1088
1089 for (i = 0U; i < sizeof(cur_faults); i++) {
1090 if (!cur_faults[i]) {
1091 cur_faults[i] = fault_id;
1092 break;
1093 }
1094 }
1095
1096 if (i == sizeof(cur_faults)) {
1097 shell_print(sh, "Fault array is full. Use \"del-fault\" to "
1098 "clear it");
1099 return 0;
1100 }
1101
1102 for (i = 0U; i < sizeof(reg_faults); i++) {
1103 if (!reg_faults[i]) {
1104 reg_faults[i] = fault_id;
1105 break;
1106 }
1107 }
1108
1109 if (i == sizeof(reg_faults)) {
1110 shell_print(sh, "No space to store more registered faults");
1111 }
1112
1113 bt_mesh_health_srv_fault_update(elem);
1114
1115 return 0;
1116 }
1117
cmd_del_fault(const struct shell * sh,size_t argc,char * argv[])1118 static int cmd_del_fault(const struct shell *sh, size_t argc, char *argv[])
1119 {
1120 uint8_t fault_id;
1121 uint8_t i;
1122 const struct bt_mesh_elem *elem;
1123 int err = 0;
1124
1125 elem = primary_element();
1126 if (elem == NULL) {
1127 shell_print(sh, "Element not found!");
1128 return -EINVAL;
1129 }
1130
1131 if (argc < 2) {
1132 (void)memset(cur_faults, 0, sizeof(cur_faults));
1133 shell_print(sh, "All current faults cleared");
1134 bt_mesh_health_srv_fault_update(elem);
1135 return 0;
1136 }
1137
1138 fault_id = shell_strtoul(argv[1], 0, &err);
1139 if (err) {
1140 shell_warn(sh, "Unable to parse input string argument");
1141 return err;
1142 }
1143
1144 if (!fault_id) {
1145 shell_print(sh, "The Fault ID must be non-zero!");
1146 return -EINVAL;
1147 }
1148
1149 for (i = 0U; i < sizeof(cur_faults); i++) {
1150 if (cur_faults[i] == fault_id) {
1151 cur_faults[i] = 0U;
1152 shell_print(sh, "Fault cleared");
1153 }
1154 }
1155
1156 bt_mesh_health_srv_fault_update(elem);
1157
1158 return 0;
1159 }
1160 #endif /* CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE */
1161 #endif /* CONFIG_BT_MESH_SHELL_TEST */
1162
1163 #if defined(CONFIG_BT_MESH_SHELL_CDB)
cmd_cdb_create(const struct shell * sh,size_t argc,char * argv[])1164 static int cmd_cdb_create(const struct shell *sh, size_t argc,
1165 char *argv[])
1166 {
1167 uint8_t net_key[16];
1168 size_t len;
1169 int err;
1170
1171 if (argc < 2) {
1172 bt_rand(net_key, 16);
1173 } else {
1174 len = hex2bin(argv[1], strlen(argv[1]), net_key,
1175 sizeof(net_key));
1176 memset(net_key + len, 0, sizeof(net_key) - len);
1177 }
1178
1179 err = bt_mesh_cdb_create(net_key);
1180 if (err < 0) {
1181 shell_print(sh, "Failed to create CDB (err %d)", err);
1182 }
1183
1184 return 0;
1185 }
1186
cmd_cdb_clear(const struct shell * sh,size_t argc,char * argv[])1187 static int cmd_cdb_clear(const struct shell *sh, size_t argc,
1188 char *argv[])
1189 {
1190 bt_mesh_cdb_clear();
1191
1192 shell_print(sh, "Cleared CDB");
1193
1194 return 0;
1195 }
1196
cdb_print_nodes(const struct shell * sh)1197 static void cdb_print_nodes(const struct shell *sh)
1198 {
1199 char key_hex_str[32 + 1], uuid_hex_str[32 + 1];
1200 struct bt_mesh_cdb_node *node;
1201 int i, total = 0;
1202 bool configured;
1203 uint8_t dev_key[16];
1204
1205 shell_print(sh, "Address Elements Flags %-32s DevKey", "UUID");
1206
1207 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) {
1208 node = &bt_mesh_cdb.nodes[i];
1209 if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
1210 continue;
1211 }
1212
1213 configured = atomic_test_bit(node->flags,
1214 BT_MESH_CDB_NODE_CONFIGURED);
1215
1216 total++;
1217 bin2hex(node->uuid, 16, uuid_hex_str, sizeof(uuid_hex_str));
1218 if (bt_mesh_cdb_node_key_export(node, dev_key)) {
1219 shell_error(sh, "Unable to export key for node 0x%04x", node->addr);
1220 continue;
1221 }
1222 bin2hex(dev_key, 16, key_hex_str, sizeof(key_hex_str));
1223 shell_print(sh, "0x%04x %-8d %-5s %s %s", node->addr,
1224 node->num_elem, configured ? "C" : "-",
1225 uuid_hex_str, key_hex_str);
1226 }
1227
1228 shell_print(sh, "> Total nodes: %d", total);
1229 }
1230
cdb_print_subnets(const struct shell * sh)1231 static void cdb_print_subnets(const struct shell *sh)
1232 {
1233 struct bt_mesh_cdb_subnet *subnet;
1234 char key_hex_str[32 + 1];
1235 int i, total = 0;
1236 uint8_t net_key[16];
1237
1238 shell_print(sh, "NetIdx NetKey");
1239
1240 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
1241 subnet = &bt_mesh_cdb.subnets[i];
1242 if (subnet->net_idx == BT_MESH_KEY_UNUSED) {
1243 continue;
1244 }
1245
1246 if (bt_mesh_cdb_subnet_key_export(subnet, 0, net_key)) {
1247 shell_error(sh, "Unable to export key for subnet 0x%03x",
1248 subnet->net_idx);
1249 continue;
1250 }
1251
1252 total++;
1253 bin2hex(net_key, 16, key_hex_str, sizeof(key_hex_str));
1254 shell_print(sh, "0x%03x %s", subnet->net_idx, key_hex_str);
1255 }
1256
1257 shell_print(sh, "> Total subnets: %d", total);
1258 }
1259
cdb_print_app_keys(const struct shell * sh)1260 static void cdb_print_app_keys(const struct shell *sh)
1261 {
1262 struct bt_mesh_cdb_app_key *key;
1263 char key_hex_str[32 + 1];
1264 int i, total = 0;
1265 uint8_t app_key[16];
1266
1267 shell_print(sh, "NetIdx AppIdx AppKey");
1268
1269 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) {
1270 key = &bt_mesh_cdb.app_keys[i];
1271 if (key->net_idx == BT_MESH_KEY_UNUSED) {
1272 continue;
1273 }
1274
1275 if (bt_mesh_cdb_app_key_export(key, 0, app_key)) {
1276 shell_error(sh, "Unable to export app key 0x%03x", key->app_idx);
1277 continue;
1278 }
1279
1280 total++;
1281 bin2hex(app_key, 16, key_hex_str, sizeof(key_hex_str));
1282 shell_print(sh, "0x%03x 0x%03x %s", key->net_idx, key->app_idx, key_hex_str);
1283 }
1284
1285 shell_print(sh, "> Total app-keys: %d", total);
1286 }
1287
cmd_cdb_show(const struct shell * sh,size_t argc,char * argv[])1288 static int cmd_cdb_show(const struct shell *sh, size_t argc,
1289 char *argv[])
1290 {
1291 if (!atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID)) {
1292 shell_print(sh, "No valid networks");
1293 return 0;
1294 }
1295
1296 shell_print(sh, "Mesh Network Information");
1297 shell_print(sh, "========================");
1298
1299 cdb_print_nodes(sh);
1300 shell_print(sh, "---");
1301 cdb_print_subnets(sh);
1302 shell_print(sh, "---");
1303 cdb_print_app_keys(sh);
1304
1305 return 0;
1306 }
1307
cmd_cdb_node_add(const struct shell * sh,size_t argc,char * argv[])1308 static int cmd_cdb_node_add(const struct shell *sh, size_t argc,
1309 char *argv[])
1310 {
1311 struct bt_mesh_cdb_node *node;
1312 uint8_t uuid[16], dev_key[16];
1313 uint16_t addr, net_idx;
1314 uint8_t num_elem;
1315 size_t len;
1316 int err = 0;
1317
1318 len = hex2bin(argv[1], strlen(argv[1]), uuid, sizeof(uuid));
1319 memset(uuid + len, 0, sizeof(uuid) - len);
1320
1321 addr = shell_strtoul(argv[2], 0, &err);
1322 num_elem = shell_strtoul(argv[3], 0, &err);
1323 net_idx = shell_strtoul(argv[4], 0, &err);
1324 if (err) {
1325 shell_warn(sh, "Unable to parse input string argument");
1326 return err;
1327 }
1328
1329 if (argc < 6) {
1330 bt_rand(dev_key, 16);
1331 } else {
1332 len = hex2bin(argv[5], strlen(argv[5]), dev_key,
1333 sizeof(dev_key));
1334 memset(dev_key + len, 0, sizeof(dev_key) - len);
1335 }
1336
1337 node = bt_mesh_cdb_node_alloc(uuid, addr, num_elem, net_idx);
1338 if (node == NULL) {
1339 shell_print(sh, "Failed to allocate node");
1340 return 0;
1341 }
1342
1343 err = bt_mesh_cdb_node_key_import(node, dev_key);
1344 if (err) {
1345 shell_warn(sh, "Unable to import device key into cdb");
1346 return err;
1347 }
1348
1349 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1350 bt_mesh_cdb_node_store(node);
1351 }
1352
1353 shell_print(sh, "Added node 0x%04x", node->addr);
1354
1355 return 0;
1356 }
1357
cmd_cdb_node_del(const struct shell * sh,size_t argc,char * argv[])1358 static int cmd_cdb_node_del(const struct shell *sh, size_t argc,
1359 char *argv[])
1360 {
1361 struct bt_mesh_cdb_node *node;
1362 uint16_t addr;
1363 int err = 0;
1364
1365 addr = shell_strtoul(argv[1], 0, &err);
1366 if (err) {
1367 shell_warn(sh, "Unable to parse input string argument");
1368 return err;
1369 }
1370
1371 node = bt_mesh_cdb_node_get(addr);
1372 if (node == NULL) {
1373 shell_print(sh, "No node with address 0x%04x", addr);
1374 return 0;
1375 }
1376
1377 bt_mesh_cdb_node_del(node, true);
1378
1379 shell_print(sh, "Deleted node 0x%04x", addr);
1380
1381 return 0;
1382 }
1383
cmd_cdb_subnet_add(const struct shell * sh,size_t argc,char * argv[])1384 static int cmd_cdb_subnet_add(const struct shell *sh, size_t argc,
1385 char *argv[])
1386 {
1387 struct bt_mesh_cdb_subnet *sub;
1388 uint8_t net_key[16];
1389 uint16_t net_idx;
1390 size_t len;
1391 int err = 0;
1392
1393 net_idx = shell_strtoul(argv[1], 0, &err);
1394 if (err) {
1395 shell_warn(sh, "Unable to parse input string argument");
1396 return err;
1397 }
1398
1399 if (argc < 3) {
1400 bt_rand(net_key, 16);
1401 } else {
1402 len = hex2bin(argv[2], strlen(argv[2]), net_key,
1403 sizeof(net_key));
1404 memset(net_key + len, 0, sizeof(net_key) - len);
1405 }
1406
1407 sub = bt_mesh_cdb_subnet_alloc(net_idx);
1408 if (sub == NULL) {
1409 shell_print(sh, "Could not add subnet");
1410 return 0;
1411 }
1412
1413 if (bt_mesh_cdb_subnet_key_import(sub, 0, net_key)) {
1414 shell_error(sh, "Unable to import key for subnet 0x%03x", net_idx);
1415 return 0;
1416 }
1417
1418 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1419 bt_mesh_cdb_subnet_store(sub);
1420 }
1421
1422 shell_print(sh, "Added Subnet 0x%03x", net_idx);
1423
1424 return 0;
1425 }
1426
cmd_cdb_subnet_del(const struct shell * sh,size_t argc,char * argv[])1427 static int cmd_cdb_subnet_del(const struct shell *sh, size_t argc,
1428 char *argv[])
1429 {
1430 struct bt_mesh_cdb_subnet *sub;
1431 uint16_t net_idx;
1432 int err = 0;
1433
1434 net_idx = shell_strtoul(argv[1], 0, &err);
1435 if (err) {
1436 shell_warn(sh, "Unable to parse input string argument");
1437 return err;
1438 }
1439
1440 sub = bt_mesh_cdb_subnet_get(net_idx);
1441 if (sub == NULL) {
1442 shell_print(sh, "No subnet with NetIdx 0x%03x", net_idx);
1443 return 0;
1444 }
1445
1446 bt_mesh_cdb_subnet_del(sub, true);
1447
1448 shell_print(sh, "Deleted subnet 0x%03x", net_idx);
1449
1450 return 0;
1451 }
1452
cmd_cdb_app_key_add(const struct shell * sh,size_t argc,char * argv[])1453 static int cmd_cdb_app_key_add(const struct shell *sh, size_t argc,
1454 char *argv[])
1455 {
1456 struct bt_mesh_cdb_app_key *key;
1457 uint16_t net_idx, app_idx;
1458 uint8_t app_key[16];
1459 size_t len;
1460 int err = 0;
1461
1462 net_idx = shell_strtoul(argv[1], 0, &err);
1463 app_idx = shell_strtoul(argv[2], 0, &err);
1464 if (err) {
1465 shell_warn(sh, "Unable to parse input string argument");
1466 return err;
1467 }
1468
1469 if (argc < 4) {
1470 bt_rand(app_key, 16);
1471 } else {
1472 len = hex2bin(argv[3], strlen(argv[3]), app_key,
1473 sizeof(app_key));
1474 memset(app_key + len, 0, sizeof(app_key) - len);
1475 }
1476
1477 key = bt_mesh_cdb_app_key_alloc(net_idx, app_idx);
1478 if (key == NULL) {
1479 shell_print(sh, "Could not add AppKey");
1480 return 0;
1481 }
1482
1483 if (bt_mesh_cdb_app_key_import(key, 0, app_key)) {
1484 shell_error(sh, "Unable to import app key 0x%03x", app_idx);
1485 return 0;
1486 }
1487
1488 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1489 bt_mesh_cdb_app_key_store(key);
1490 }
1491
1492 shell_print(sh, "Added AppKey 0x%03x", app_idx);
1493
1494 return 0;
1495 }
1496
cmd_cdb_app_key_del(const struct shell * sh,size_t argc,char * argv[])1497 static int cmd_cdb_app_key_del(const struct shell *sh, size_t argc,
1498 char *argv[])
1499 {
1500 struct bt_mesh_cdb_app_key *key;
1501 uint16_t app_idx;
1502 int err = 0;
1503
1504 app_idx = shell_strtoul(argv[1], 0, &err);
1505 if (err) {
1506 shell_warn(sh, "Unable to parse input string argument");
1507 return err;
1508 }
1509
1510 key = bt_mesh_cdb_app_key_get(app_idx);
1511 if (key == NULL) {
1512 shell_print(sh, "No AppKey 0x%03x", app_idx);
1513 return 0;
1514 }
1515
1516 bt_mesh_cdb_app_key_del(key, true);
1517
1518 shell_print(sh, "Deleted AppKey 0x%03x", app_idx);
1519
1520 return 0;
1521 }
1522 #endif /* CONFIG_BT_MESH_SHELL_CDB */
1523
cmd_dst(const struct shell * sh,size_t argc,char * argv[])1524 static int cmd_dst(const struct shell *sh, size_t argc, char *argv[])
1525 {
1526 int err = 0;
1527
1528 if (argc < 2) {
1529 shell_print(sh, "Destination address: 0x%04x%s", bt_mesh_shell_target_ctx.dst,
1530 bt_mesh_shell_target_ctx.dst == bt_mesh_primary_addr()
1531 ? " (local)"
1532 : "");
1533 return 0;
1534 }
1535
1536 if (!strcmp(argv[1], "local")) {
1537 bt_mesh_shell_target_ctx.dst = bt_mesh_primary_addr();
1538 } else {
1539 bt_mesh_shell_target_ctx.dst = shell_strtoul(argv[1], 0, &err);
1540 if (err) {
1541 shell_warn(sh, "Unable to parse input string argument");
1542 return err;
1543 }
1544 }
1545
1546 shell_print(sh, "Destination address set to 0x%04x%s", bt_mesh_shell_target_ctx.dst,
1547 bt_mesh_shell_target_ctx.dst == bt_mesh_primary_addr() ? " (local)"
1548 : "");
1549 return 0;
1550 }
1551
cmd_netidx(const struct shell * sh,size_t argc,char * argv[])1552 static int cmd_netidx(const struct shell *sh, size_t argc, char *argv[])
1553 {
1554 int err = 0;
1555
1556 if (argc < 2) {
1557 shell_print(sh, "NetIdx: 0x%04x", bt_mesh_shell_target_ctx.net_idx);
1558 return 0;
1559 }
1560
1561 bt_mesh_shell_target_ctx.net_idx = shell_strtoul(argv[1], 0, &err);
1562 if (err) {
1563 shell_warn(sh, "Unable to parse input string argument");
1564 return err;
1565 }
1566
1567 shell_print(sh, "NetIdx set to 0x%04x", bt_mesh_shell_target_ctx.net_idx);
1568 return 0;
1569 }
1570
cmd_appidx(const struct shell * sh,size_t argc,char * argv[])1571 static int cmd_appidx(const struct shell *sh, size_t argc, char *argv[])
1572 {
1573 int err = 0;
1574
1575 if (argc < 2) {
1576 shell_print(sh, "AppIdx: 0x%04x", bt_mesh_shell_target_ctx.app_idx);
1577 return 0;
1578 }
1579
1580 bt_mesh_shell_target_ctx.app_idx = shell_strtoul(argv[1], 0, &err);
1581 if (err) {
1582 shell_warn(sh, "Unable to parse input string argument");
1583 return err;
1584 }
1585
1586 shell_print(sh, "AppIdx set to 0x%04x", bt_mesh_shell_target_ctx.app_idx);
1587 return 0;
1588 }
1589
1590 #if defined(CONFIG_BT_MESH_STATISTIC)
cmd_stat_get(const struct shell * sh,size_t argc,char * argv[])1591 static int cmd_stat_get(const struct shell *sh, size_t argc, char *argv[])
1592 {
1593 struct bt_mesh_statistic st;
1594
1595 bt_mesh_stat_get(&st);
1596
1597 shell_print(sh, "Received frames over:");
1598 shell_print(sh, "adv: %d", st.rx_adv);
1599 shell_print(sh, "loopback: %d", st.rx_loopback);
1600 shell_print(sh, "proxy: %d", st.rx_proxy);
1601 shell_print(sh, "unknown: %d", st.rx_uknown);
1602
1603 shell_print(sh, "Transmitted frames: <planned> - <succeeded>");
1604 shell_print(sh, "relay adv: %d - %d", st.tx_adv_relay_planned, st.tx_adv_relay_succeeded);
1605 shell_print(sh, "local adv: %d - %d", st.tx_local_planned, st.tx_local_succeeded);
1606 shell_print(sh, "friend: %d - %d", st.tx_friend_planned, st.tx_friend_succeeded);
1607
1608 return 0;
1609 }
1610
cmd_stat_clear(const struct shell * sh,size_t argc,char * argv[])1611 static int cmd_stat_clear(const struct shell *sh, size_t argc, char *argv[])
1612 {
1613 bt_mesh_stat_reset();
1614
1615 return 0;
1616 }
1617 #endif
1618
1619 #if defined(CONFIG_BT_MESH_SHELL_CDB)
1620 SHELL_STATIC_SUBCMD_SET_CREATE(
1621 cdb_cmds,
1622 /* Mesh Configuration Database Operations */
1623 SHELL_CMD_ARG(create, NULL, "[NetKey(1-16 hex)]", cmd_cdb_create, 1, 1),
1624 SHELL_CMD_ARG(clear, NULL, NULL, cmd_cdb_clear, 1, 0),
1625 SHELL_CMD_ARG(show, NULL, NULL, cmd_cdb_show, 1, 0),
1626 SHELL_CMD_ARG(node-add, NULL,
1627 "<UUID(1-16 hex)> <Addr> <ElemCnt> <NetKeyIdx> [DevKey(1-16 hex)]",
1628 cmd_cdb_node_add, 5, 1),
1629 SHELL_CMD_ARG(node-del, NULL, "<Addr>", cmd_cdb_node_del, 2, 0),
1630 SHELL_CMD_ARG(subnet-add, NULL, "<NetKeyIdx> [<NetKey(1-16 hex)>]", cmd_cdb_subnet_add, 2,
1631 1),
1632 SHELL_CMD_ARG(subnet-del, NULL, "<NetKeyIdx>", cmd_cdb_subnet_del, 2, 0),
1633 SHELL_CMD_ARG(app-key-add, NULL, "<NetKeyIdx> <AppKeyIdx> [<AppKey(1-16 hex)>]",
1634 cmd_cdb_app_key_add, 3, 1),
1635 SHELL_CMD_ARG(app-key-del, NULL, "<AppKeyIdx>", cmd_cdb_app_key_del, 2, 0),
1636 SHELL_SUBCMD_SET_END);
1637 #endif
1638
1639 #if defined(CONFIG_BT_MESH_SHELL_PROV)
1640 #if defined(CONFIG_BT_MESH_PROVISIONER)
1641 SHELL_STATIC_SUBCMD_SET_CREATE(auth_cmds,
1642 SHELL_CMD_ARG(input, NULL, "<Action> <Size>",
1643 cmd_auth_method_set_input, 3, 0),
1644 SHELL_CMD_ARG(output, NULL, "<Action> <Size>",
1645 cmd_auth_method_set_output, 3, 0),
1646 SHELL_CMD_ARG(static, NULL, "<Val(1-16 hex)>", cmd_auth_method_set_static, 2,
1647 0),
1648 SHELL_CMD_ARG(none, NULL, NULL, cmd_auth_method_set_none, 1, 0),
1649 SHELL_SUBCMD_SET_END);
1650 #endif
1651
1652 SHELL_STATIC_SUBCMD_SET_CREATE(
1653 prov_cmds, SHELL_CMD_ARG(input-num, NULL, "<Number>", cmd_input_num, 2, 0),
1654 SHELL_CMD_ARG(input-str, NULL, "<String>", cmd_input_str, 2, 0),
1655 SHELL_CMD_ARG(local, NULL, "<NetKeyIdx> <Addr> [IVI]", cmd_provision_local, 3, 1),
1656 #if defined(CONFIG_BT_MESH_SHELL_PROV_CTX_INSTANCE)
1657 SHELL_CMD_ARG(static-oob, NULL, "[Val]", cmd_static_oob, 2, 1),
1658 SHELL_CMD_ARG(uuid, NULL, "[UUID(1-16 hex)]", cmd_uuid, 1, 1),
1659 SHELL_CMD_ARG(beacon-listen, NULL, "<Val(off, on)>", cmd_beacon_listen, 2, 0),
1660 #endif
1661
1662 SHELL_CMD_ARG(comp-change, NULL, NULL, cmd_comp_change, 1, 0),
1663
1664 /* Provisioning operations */
1665 #if defined(CONFIG_BT_MESH_PROVISIONEE)
1666 #if defined(CONFIG_BT_MESH_PB_GATT)
1667 SHELL_CMD_ARG(pb-gatt, NULL, "<Val(off, on)>", cmd_pb_gatt, 2, 0),
1668 #endif
1669 #if defined(CONFIG_BT_MESH_PB_ADV)
1670 SHELL_CMD_ARG(pb-adv, NULL, "<Val(off, on)>", cmd_pb_adv, 2, 0),
1671 #endif
1672 #endif /* CONFIG_BT_MESH_PROVISIONEE */
1673
1674 #if defined(CONFIG_BT_MESH_PROVISIONER)
1675 SHELL_CMD(auth-method, &auth_cmds, "Authentication methods", bt_mesh_shell_mdl_cmds_help),
1676 SHELL_CMD_ARG(remote-pub-key, NULL, "<PubKey>", cmd_remote_pub_key_set, 2, 0),
1677 SHELL_CMD_ARG(remote-adv, NULL,
1678 "<UUID(1-16 hex)> <NetKeyIdx> <Addr> "
1679 "<AttDur(s)>",
1680 cmd_provision_adv, 5, 0),
1681 #endif
1682
1683 #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
1684 SHELL_CMD_ARG(remote-gatt, NULL,
1685 "<UUID(1-16 hex)> <NetKeyIdx> <Addr> "
1686 "<AttDur(s)>",
1687 cmd_provision_gatt, 5, 0),
1688 #endif
1689 SHELL_SUBCMD_SET_END);
1690 #endif /* CONFIG_BT_MESH_SHELL_PROV */
1691
1692 #if defined(CONFIG_BT_MESH_SHELL_TEST)
1693 #if defined(CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE)
1694 SHELL_STATIC_SUBCMD_SET_CREATE(health_srv_cmds,
1695 /* Health Server Model Operations */
1696 SHELL_CMD_ARG(add-fault, NULL, "<FaultID>", cmd_add_fault, 2, 0),
1697 SHELL_CMD_ARG(del-fault, NULL, "[FaultID]", cmd_del_fault, 1, 1),
1698 SHELL_SUBCMD_SET_END);
1699 #endif
1700
1701 SHELL_STATIC_SUBCMD_SET_CREATE(test_cmds,
1702 /* Commands which access internal APIs, for testing only */
1703 SHELL_CMD_ARG(net-send, NULL, "<HexString>", cmd_net_send,
1704 2, 0),
1705 #if defined(CONFIG_BT_MESH_IV_UPDATE_TEST)
1706 SHELL_CMD_ARG(iv-update, NULL, NULL, cmd_iv_update, 1, 0),
1707 SHELL_CMD_ARG(iv-update-test, NULL, "<Val(off, on)>", cmd_iv_update_test, 2, 0),
1708 #endif
1709 SHELL_CMD_ARG(rpl-clear, NULL, NULL, cmd_rpl_clear, 1, 0),
1710 #if defined(CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE)
1711 SHELL_CMD(health-srv, &health_srv_cmds, "Health Server test", bt_mesh_shell_mdl_cmds_help),
1712 #endif
1713 SHELL_SUBCMD_SET_END);
1714 #endif /* CONFIG_BT_MESH_SHELL_TEST */
1715
1716 #if defined(CONFIG_BT_MESH_SHELL_GATT_PROXY)
1717 SHELL_STATIC_SUBCMD_SET_CREATE(proxy_cmds,
1718 #if defined(CONFIG_BT_MESH_GATT_PROXY)
1719 SHELL_CMD_ARG(identity-enable, NULL, NULL, cmd_ident, 1, 0),
1720 #endif
1721
1722 #if defined(CONFIG_BT_MESH_PROXY_CLIENT)
1723 SHELL_CMD_ARG(connect, NULL, "<NetKeyIdx>", cmd_proxy_connect, 2, 0),
1724 SHELL_CMD_ARG(disconnect, NULL, "<NetKeyIdx>", cmd_proxy_disconnect, 2, 0),
1725 #endif
1726
1727 #if defined(CONFIG_BT_MESH_PROXY_SOLICITATION)
1728 SHELL_CMD_ARG(solicit, NULL, "<NetKeyIdx>",
1729 cmd_proxy_solicit, 2, 0),
1730 #endif
1731 SHELL_SUBCMD_SET_END);
1732 #endif /* CONFIG_BT_MESH_SHELL_GATT_PROXY */
1733
1734 #if defined(CONFIG_BT_MESH_SHELL_LOW_POWER)
1735 SHELL_STATIC_SUBCMD_SET_CREATE(low_pwr_cmds,
1736 SHELL_CMD_ARG(set, NULL, "<Val(off, on)>", cmd_lpn, 2, 0),
1737 SHELL_CMD_ARG(poll, NULL, NULL, cmd_poll, 1, 0),
1738 SHELL_SUBCMD_SET_END);
1739 #endif
1740
1741 SHELL_STATIC_SUBCMD_SET_CREATE(target_cmds,
1742 SHELL_CMD_ARG(dst, NULL, "[DstAddr]", cmd_dst, 1, 1),
1743 SHELL_CMD_ARG(net, NULL, "[NetKeyIdx]", cmd_netidx, 1, 1),
1744 SHELL_CMD_ARG(app, NULL, "[AppKeyIdx]", cmd_appidx, 1, 1),
1745 SHELL_SUBCMD_SET_END);
1746
1747 #if defined(CONFIG_BT_MESH_STATISTIC)
1748 SHELL_STATIC_SUBCMD_SET_CREATE(stat_cmds,
1749 SHELL_CMD_ARG(get, NULL, NULL, cmd_stat_get, 1, 0),
1750 SHELL_CMD_ARG(clear, NULL, NULL, cmd_stat_clear, 1, 0),
1751 SHELL_SUBCMD_SET_END);
1752 #endif
1753
1754 /* Placeholder for model shell modules that is configured in the application */
1755 SHELL_SUBCMD_SET_CREATE(model_cmds, (mesh, models));
1756
1757 /* List of Mesh subcommands.
1758 *
1759 * Each command is documented in doc/reference/bluetooth/mesh/shell.rst.
1760 *
1761 * Please keep the documentation up to date by adding any new commands to the
1762 * list.
1763 */
1764 SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds,
1765 SHELL_CMD_ARG(init, NULL, NULL, cmd_init, 1, 0),
1766 SHELL_CMD_ARG(reset-local, NULL, NULL, cmd_reset, 1, 0),
1767
1768 SHELL_CMD(models, &model_cmds, "Model commands", bt_mesh_shell_mdl_cmds_help),
1769
1770 #if defined(CONFIG_BT_MESH_SHELL_LOW_POWER)
1771 SHELL_CMD(lpn, &low_pwr_cmds, "Low Power commands", bt_mesh_shell_mdl_cmds_help),
1772 #endif
1773
1774 #if defined(CONFIG_BT_MESH_SHELL_CDB)
1775 SHELL_CMD(cdb, &cdb_cmds, "Configuration Database", bt_mesh_shell_mdl_cmds_help),
1776 #endif
1777
1778 #if defined(CONFIG_BT_MESH_SHELL_GATT_PROXY)
1779 SHELL_CMD(proxy, &proxy_cmds, "Proxy commands", bt_mesh_shell_mdl_cmds_help),
1780 #endif
1781
1782 #if defined(CONFIG_BT_MESH_SHELL_PROV)
1783 SHELL_CMD(prov, &prov_cmds, "Provisioning commands", bt_mesh_shell_mdl_cmds_help),
1784 #endif
1785
1786 #if defined(CONFIG_BT_MESH_SHELL_TEST)
1787 SHELL_CMD(test, &test_cmds, "Test commands", bt_mesh_shell_mdl_cmds_help),
1788 #endif
1789 SHELL_CMD(target, &target_cmds, "Target commands", bt_mesh_shell_mdl_cmds_help),
1790
1791 #if defined(CONFIG_BT_MESH_STATISTIC)
1792 SHELL_CMD(stat, &stat_cmds, "Statistic commands", bt_mesh_shell_mdl_cmds_help),
1793 #endif
1794
1795 SHELL_SUBCMD_SET_END
1796 );
1797
1798 SHELL_CMD_ARG_REGISTER(mesh, &mesh_cmds, "Bluetooth Mesh shell commands",
1799 bt_mesh_shell_mdl_cmds_help, 1, 1);
1800