1 /** @file
2  *  @brief Interactive Bluetooth LE shell application
3  *
4  *  Application allows implement Bluetooth LE functional commands performing
5  *  simple diagnostic interaction between LE host stack and LE controller
6  */
7 
8 /*
9  * Copyright (c) 2017 Nordic Semiconductor ASA
10  * Copyright (c) 2015-2016 Intel Corporation
11  *
12  * SPDX-License-Identifier: Apache-2.0
13  */
14 
15 #include <errno.h>
16 #include <zephyr/types.h>
17 #include <stddef.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <zephyr/sys/printk.h>
21 #include <zephyr/sys/byteorder.h>
22 #include <zephyr/kernel.h>
23 #include <zephyr/usb/usb_device.h>
24 #include <zephyr/drivers/uart.h>
25 
26 #include <zephyr/shell/shell.h>
27 
28 #include <zephyr/bluetooth/hci.h>
29 #include <zephyr/bluetooth/bluetooth.h>
30 #include <zephyr/bluetooth/uuid.h>
31 #include <zephyr/bluetooth/services/hrs.h>
32 
33 #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
34 
35 #if defined(CONFIG_BT_HRS)
36 static bool hrs_simulate;
37 
38 static const struct bt_data ad[] = {
39 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
40 	BT_DATA_BYTES(BT_DATA_UUID16_ALL,
41 		      BT_UUID_16_ENCODE(BT_UUID_HRS_VAL),
42 		      BT_UUID_16_ENCODE(BT_UUID_BAS_VAL),
43 		      BT_UUID_16_ENCODE(BT_UUID_DIS_VAL)),
44 };
45 
cmd_hrs_simulate(const struct shell * sh,size_t argc,char * argv[])46 static int cmd_hrs_simulate(const struct shell *sh,
47 			    size_t argc, char *argv[])
48 {
49 	static bool hrs_registered;
50 	int err;
51 
52 	if (!strcmp(argv[1], "on")) {
53 		if (!hrs_registered && IS_ENABLED(CONFIG_BT_BROADCASTER)) {
54 			shell_print(sh, "Registering HRS Service");
55 			hrs_registered = true;
56 			err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad,
57 					      ARRAY_SIZE(ad), NULL, 0);
58 			if (err) {
59 				shell_error(sh, "Advertising failed to start"
60 					    " (err %d)\n", err);
61 				return -ENOEXEC;
62 			}
63 
64 			printk("Advertising successfully started\n");
65 		}
66 
67 		shell_print(sh, "Start HRS simulation");
68 		hrs_simulate = true;
69 	} else if (!strcmp(argv[1], "off")) {
70 		shell_print(sh, "Stop HRS simulation");
71 
72 		if (hrs_registered && IS_ENABLED(CONFIG_BT_BROADCASTER)) {
73 			bt_le_adv_stop();
74 		}
75 
76 		hrs_simulate = false;
77 	} else {
78 		shell_print(sh, "Incorrect value: %s", argv[1]);
79 		shell_help(sh);
80 		return -ENOEXEC;
81 	}
82 
83 	return 0;
84 }
85 #endif /* CONFIG_BT_HRS */
86 
87 #define HELP_NONE "[none]"
88 #define HELP_ADDR_LE "<address: XX:XX:XX:XX:XX:XX> <type: (public|random)>"
89 
90 SHELL_STATIC_SUBCMD_SET_CREATE(hrs_cmds,
91 #if defined(CONFIG_BT_HRS)
92 	SHELL_CMD_ARG(simulate, NULL,
93 		"register and simulate Heart Rate Service <value: on, off>",
94 		cmd_hrs_simulate, 2, 0),
95 #endif /* CONFIG_BT_HRS*/
96 	SHELL_SUBCMD_SET_END
97 );
98 
cmd_hrs(const struct shell * sh,size_t argc,char ** argv)99 static int cmd_hrs(const struct shell *sh, size_t argc, char **argv)
100 {
101 	shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
102 
103 	return -ENOEXEC;
104 }
105 
106 SHELL_CMD_ARG_REGISTER(hrs, &hrs_cmds, "Heart Rate Service shell commands",
107 		       cmd_hrs, 2, 0);
108 
109 #if defined(CONFIG_BT_HRS)
hrs_notify(void)110 static void hrs_notify(void)
111 {
112 	static uint8_t heartrate = 90U;
113 
114 	/* Heartrate measurements simulation */
115 	heartrate++;
116 	if (heartrate == 160U) {
117 		heartrate = 90U;
118 	}
119 
120 	bt_hrs_notify(heartrate);
121 }
122 #endif /* CONFIG_BT_HRS */
123 
main(void)124 int main(void)
125 {
126 #if DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_shell_uart), zephyr_cdc_acm_uart)
127 	const struct device *dev;
128 	uint32_t dtr = 0;
129 
130 	dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart));
131 	if (!device_is_ready(dev) || usb_enable(NULL)) {
132 		return 0;
133 	}
134 
135 	while (!dtr) {
136 		uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr);
137 		k_sleep(K_MSEC(100));
138 	}
139 #endif
140 
141 	printk("Type \"help\" for supported commands.");
142 	printk("Before any Bluetooth commands you must `bt init` to initialize"
143 	       " the stack.\n");
144 
145 	while (1) {
146 		k_sleep(K_SECONDS(1));
147 
148 #if defined(CONFIG_BT_HRS)
149 		/* Heartrate measurements simulation */
150 		if (hrs_simulate) {
151 			hrs_notify();
152 		}
153 #endif /* CONFIG_BT_HRS */
154 	}
155 }
156