1 /* main.c - Application main entry point */
2 
3 /*
4  * Copyright (c) 2017 Intel Corporation
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /*
10  * This application is specific to the Nordic nRF52840-PDK board.
11  *
12  * It supports the 4 buttons and 4 LEDs as mesh clients and servers.
13  *
14  * Prior to provisioning, a button inverts the state of the
15  * corresponding LED.
16  *
17  * The unprovisioned beacon uses the device address set by Nordic
18  * in the FICR as its UUID and is presumed unique.
19  *
20  * Button and LED 1 are in the root node.
21  * The 3 remaining button/LED pairs are in element 1 through 3.
22  * Assuming the provisioner assigns 0x100 to the root node,
23  * the secondary elements will appear at 0x101, 0x102 and 0x103.
24  *
25  * It's anticipated that after provisioning, the button clients would
26  * be configured to publish and the LED servers to subscribe.
27  *
28  * If a LED server is provided with a publish address, it will
29  * also publish its status on a state change.
30  *
31  * Messages from a button to its corresponding LED are ignored as
32  * the LED's state has already been changed locally by the button client.
33  *
34  * The buttons are debounced at a nominal 250ms. That value can be
35  * changed as needed.
36  *
37  */
38 
39 #include <zephyr/sys/printk.h>
40 #include <zephyr/settings/settings.h>
41 #include <zephyr/sys/byteorder.h>
42 #include <zephyr/device.h>
43 #include <zephyr/drivers/gpio.h>
44 #include <zephyr/bluetooth/bluetooth.h>
45 #include <zephyr/bluetooth/conn.h>
46 #include <zephyr/bluetooth/l2cap.h>
47 #include <zephyr/bluetooth/hci.h>
48 #include <zephyr/bluetooth/mesh.h>
49 #include <stdio.h>
50 
51 /* Model Operation Codes */
52 #define BT_MESH_MODEL_OP_GEN_ONOFF_GET		BT_MESH_MODEL_OP_2(0x82, 0x01)
53 #define BT_MESH_MODEL_OP_GEN_ONOFF_SET		BT_MESH_MODEL_OP_2(0x82, 0x02)
54 #define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK	BT_MESH_MODEL_OP_2(0x82, 0x03)
55 #define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS	BT_MESH_MODEL_OP_2(0x82, 0x04)
56 
57 static int gen_onoff_set(const struct bt_mesh_model *model,
58 			 struct bt_mesh_msg_ctx *ctx,
59 			 struct net_buf_simple *buf);
60 
61 static int gen_onoff_set_unack(const struct bt_mesh_model *model,
62 			       struct bt_mesh_msg_ctx *ctx,
63 			       struct net_buf_simple *buf);
64 
65 static int gen_onoff_get(const struct bt_mesh_model *model,
66 			 struct bt_mesh_msg_ctx *ctx,
67 			 struct net_buf_simple *buf);
68 
69 static int gen_onoff_status(const struct bt_mesh_model *model,
70 			    struct bt_mesh_msg_ctx *ctx,
71 			    struct net_buf_simple *buf);
72 
73 /*
74  * Client Configuration Declaration
75  */
76 
77 static struct bt_mesh_cfg_cli cfg_cli = {
78 };
79 
80 /*
81  * Health Server Declaration
82  */
83 
84 static struct bt_mesh_health_srv health_srv = {
85 };
86 
87 /*
88  * Publication Declarations
89  *
90  * The publication messages are initialized to
91  * the size of the opcode + content
92  *
93  * For publication, the message must be in static or global as
94  * it is re-transmitted several times. This occurs
95  * after the function that called bt_mesh_model_publish() has
96  * exited and the stack is no longer valid.
97  *
98  * Note that the additional 4 bytes for the AppMIC is not needed
99  * because it is added to a stack variable at the time a
100  * transmission occurs.
101  *
102  */
103 
104 BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
105 
106 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_srv, NULL, 2 + 2);
107 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_cli, NULL, 2 + 2);
108 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_srv_s_0, NULL, 2 + 2);
109 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_cli_s_0, NULL, 2 + 2);
110 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_srv_s_1, NULL, 2 + 2);
111 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_cli_s_1, NULL, 2 + 2);
112 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_srv_s_2, NULL, 2 + 2);
113 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_cli_s_2, NULL, 2 + 2);
114 
115 /*
116  * Models in an element must have unique op codes.
117  *
118  * The mesh stack dispatches a message to the first model in an element
119  * that is also bound to an app key and supports the op code in the
120  * received message.
121  *
122  */
123 
124 /*
125  * OnOff Model Server Op Dispatch Table
126  *
127  */
128 
129 static const struct bt_mesh_model_op gen_onoff_srv_op[] = {
130 	{ BT_MESH_MODEL_OP_GEN_ONOFF_GET,       BT_MESH_LEN_EXACT(0), gen_onoff_get },
131 	{ BT_MESH_MODEL_OP_GEN_ONOFF_SET,       BT_MESH_LEN_EXACT(2), gen_onoff_set },
132 	{ BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, BT_MESH_LEN_EXACT(2), gen_onoff_set_unack },
133 	BT_MESH_MODEL_OP_END,
134 };
135 
136 /*
137  * OnOff Model Client Op Dispatch Table
138  */
139 
140 static const struct bt_mesh_model_op gen_onoff_cli_op[] = {
141 	{ BT_MESH_MODEL_OP_GEN_ONOFF_STATUS, BT_MESH_LEN_EXACT(1), gen_onoff_status },
142 	BT_MESH_MODEL_OP_END,
143 };
144 
145 struct led_onoff_state {
146 	const struct gpio_dt_spec led_device;
147 	uint8_t current;
148 	uint8_t previous;
149 };
150 
151 /*
152  * Declare and Initialize Element Contexts
153  * Change to select different GPIO output pins
154  */
155 
156 static struct led_onoff_state led_onoff_states[] = {
157 	{ .led_device = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios), },
158 	{ .led_device = GPIO_DT_SPEC_GET(DT_ALIAS(led1), gpios), },
159 	{ .led_device = GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios), },
160 	{ .led_device = GPIO_DT_SPEC_GET(DT_ALIAS(led3), gpios), },
161 };
162 
163 /*
164  *
165  * Element Model Declarations
166  *
167  * Element 0 Root Models
168  */
169 
170 static const struct bt_mesh_model root_models[] = {
171 	BT_MESH_MODEL_CFG_SRV,
172 	BT_MESH_MODEL_CFG_CLI(&cfg_cli),
173 	BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
174 	BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
175 		      &gen_onoff_pub_srv, &led_onoff_states[0]),
176 	BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
177 		      &gen_onoff_pub_cli, &led_onoff_states[0]),
178 };
179 
180 /*
181  * Element 1 Models
182  */
183 
184 static const struct bt_mesh_model secondary_0_models[] = {
185 	BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
186 		      &gen_onoff_pub_srv_s_0, &led_onoff_states[1]),
187 	BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
188 		      &gen_onoff_pub_cli_s_0, &led_onoff_states[1]),
189 };
190 
191 /*
192  * Element 2 Models
193  */
194 
195 static const struct bt_mesh_model secondary_1_models[] = {
196 	BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
197 		      &gen_onoff_pub_srv_s_1, &led_onoff_states[2]),
198 	BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
199 		      &gen_onoff_pub_cli_s_1, &led_onoff_states[2]),
200 };
201 
202 /*
203  * Element 3 Models
204  */
205 
206 static const struct bt_mesh_model secondary_2_models[] = {
207 	BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
208 		      &gen_onoff_pub_srv_s_2, &led_onoff_states[3]),
209 	BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
210 		      &gen_onoff_pub_cli_s_2, &led_onoff_states[3]),
211 };
212 
213 /*
214  * Button to Client Model Assignments
215  */
216 
217 const struct bt_mesh_model *mod_cli_sw[] = {
218 		&root_models[4],
219 		&secondary_0_models[1],
220 		&secondary_1_models[1],
221 		&secondary_2_models[1],
222 };
223 
224 /*
225  * LED to Server Model Assignments
226  */
227 
228 const struct bt_mesh_model *mod_srv_sw[] = {
229 		&root_models[3],
230 		&secondary_0_models[0],
231 		&secondary_1_models[0],
232 		&secondary_2_models[0],
233 };
234 
235 /*
236  * Root and Secondary Element Declarations
237  */
238 
239 static const struct bt_mesh_elem elements[] = {
240 	BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
241 	BT_MESH_ELEM(0, secondary_0_models, BT_MESH_MODEL_NONE),
242 	BT_MESH_ELEM(0, secondary_1_models, BT_MESH_MODEL_NONE),
243 	BT_MESH_ELEM(0, secondary_2_models, BT_MESH_MODEL_NONE),
244 };
245 
246 static const struct bt_mesh_comp comp = {
247 	.cid = BT_COMP_ID_LF,
248 	.elem = elements,
249 	.elem_count = ARRAY_SIZE(elements),
250 };
251 
252 static const struct gpio_dt_spec sw_device[4] = {
253 	GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios),
254 	GPIO_DT_SPEC_GET(DT_ALIAS(sw1), gpios),
255 	GPIO_DT_SPEC_GET(DT_ALIAS(sw2), gpios),
256 	GPIO_DT_SPEC_GET(DT_ALIAS(sw3), gpios),
257 };
258 
259 struct switch_data {
260 	uint8_t sw_num;
261 	uint8_t onoff_state;
262 	struct k_work button_work;
263 	struct k_timer button_timer;
264 };
265 
266 
267 static uint8_t button_press_cnt;
268 static struct switch_data sw;
269 
270 static struct gpio_callback button_cb;
271 
272 static uint8_t trans_id;
273 static uint32_t time, last_time;
274 static uint16_t primary_addr;
275 static uint16_t primary_net_idx;
276 
277 /*
278  * Generic OnOff Model Server Message Handlers
279  *
280  * Mesh Model Specification 3.1.1
281  *
282  */
283 
gen_onoff_get(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)284 static int gen_onoff_get(const struct bt_mesh_model *model,
285 			 struct bt_mesh_msg_ctx *ctx,
286 			 struct net_buf_simple *buf)
287 {
288 	NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4);
289 	struct led_onoff_state *onoff_state = model->rt->user_data;
290 
291 	printk("addr 0x%04x onoff 0x%02x\n",
292 	       bt_mesh_model_elem(model)->rt->addr, onoff_state->current);
293 	bt_mesh_model_msg_init(&msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
294 	net_buf_simple_add_u8(&msg, onoff_state->current);
295 
296 	if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
297 		printk("Unable to send On Off Status response\n");
298 	}
299 
300 	return 0;
301 }
302 
gen_onoff_set_unack(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)303 static int gen_onoff_set_unack(const struct bt_mesh_model *model,
304 			       struct bt_mesh_msg_ctx *ctx,
305 			       struct net_buf_simple *buf)
306 {
307 	struct net_buf_simple *msg = model->pub->msg;
308 	struct led_onoff_state *onoff_state = model->rt->user_data;
309 	int err;
310 
311 	onoff_state->current = net_buf_simple_pull_u8(buf);
312 	printk("addr 0x%02x state 0x%02x\n",
313 	       bt_mesh_model_elem(model)->rt->addr, onoff_state->current);
314 
315 	gpio_pin_set_dt(&onoff_state->led_device, onoff_state->current);
316 
317 	/*
318 	 * If a server has a publish address, it is required to
319 	 * publish status on a state change
320 	 *
321 	 * See Mesh Profile Specification 3.7.6.1.2
322 	 *
323 	 * Only publish if there is an assigned address
324 	 */
325 
326 	if (onoff_state->previous != onoff_state->current &&
327 	    model->pub->addr != BT_MESH_ADDR_UNASSIGNED) {
328 		printk("publish last 0x%02x cur 0x%02x\n",
329 		       onoff_state->previous, onoff_state->current);
330 		onoff_state->previous = onoff_state->current;
331 		bt_mesh_model_msg_init(msg,
332 				       BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
333 		net_buf_simple_add_u8(msg, onoff_state->current);
334 		err = bt_mesh_model_publish(model);
335 		if (err) {
336 			printk("bt_mesh_model_publish err %d\n", err);
337 		}
338 	}
339 
340 	return 0;
341 }
342 
gen_onoff_set(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)343 static int gen_onoff_set(const struct bt_mesh_model *model,
344 			 struct bt_mesh_msg_ctx *ctx,
345 			 struct net_buf_simple *buf)
346 {
347 	printk("gen_onoff_set\n");
348 
349 	(void)gen_onoff_set_unack(model, ctx, buf);
350 	(void)gen_onoff_get(model, ctx, buf);
351 
352 	return 0;
353 }
354 
gen_onoff_status(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)355 static int gen_onoff_status(const struct bt_mesh_model *model,
356 			    struct bt_mesh_msg_ctx *ctx,
357 			    struct net_buf_simple *buf)
358 {
359 	uint8_t	state;
360 
361 	state = net_buf_simple_pull_u8(buf);
362 
363 	printk("Node 0x%04x OnOff status from 0x%04x with state 0x%02x\n",
364 	       bt_mesh_model_elem(model)->rt->addr, ctx->addr, state);
365 
366 	return 0;
367 }
368 
output_number(bt_mesh_output_action_t action,uint32_t number)369 static int output_number(bt_mesh_output_action_t action, uint32_t number)
370 {
371 	printk("OOB Number %06u\n", number);
372 	return 0;
373 }
374 
output_string(const char * str)375 static int output_string(const char *str)
376 {
377 	printk("OOB String %s\n", str);
378 	return 0;
379 }
380 
prov_complete(uint16_t net_idx,uint16_t addr)381 static void prov_complete(uint16_t net_idx, uint16_t addr)
382 {
383 	printk("provisioning complete for net_idx 0x%04x addr 0x%04x\n",
384 	       net_idx, addr);
385 	primary_addr = addr;
386 	primary_net_idx = net_idx;
387 }
388 
prov_reset(void)389 static void prov_reset(void)
390 {
391 	bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
392 }
393 
394 static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
395 
396 #define BUTTON_DEBOUNCE_DELAY_MS 250
397 
398 /*
399  * Map GPIO pins to button number
400  * Change to select different GPIO input pins
401  */
402 
pin_to_sw(uint32_t pin_pos)403 static uint8_t pin_to_sw(uint32_t pin_pos)
404 {
405 	switch (pin_pos) {
406 	case BIT(DT_GPIO_PIN(DT_ALIAS(sw0), gpios)): return 0;
407 	case BIT(DT_GPIO_PIN(DT_ALIAS(sw1), gpios)): return 1;
408 	case BIT(DT_GPIO_PIN(DT_ALIAS(sw2), gpios)): return 2;
409 	case BIT(DT_GPIO_PIN(DT_ALIAS(sw3), gpios)): return 3;
410 	}
411 
412 	printk("No match for GPIO pin 0x%08x\n", pin_pos);
413 	return 0;
414 }
415 
button_pressed(const struct device * dev,struct gpio_callback * cb,uint32_t pin_pos)416 static void button_pressed(const struct device *dev, struct gpio_callback *cb,
417 			   uint32_t pin_pos)
418 {
419 	/*
420 	 * One button press within a 1 second interval sends an on message
421 	 * More than one button press sends an off message
422 	 */
423 
424 	time = k_uptime_get_32();
425 
426 	/* debounce the switch */
427 	if (time < last_time + BUTTON_DEBOUNCE_DELAY_MS) {
428 		last_time = time;
429 		return;
430 	}
431 
432 	if (button_press_cnt == 0U) {
433 		k_timer_start(&sw.button_timer, K_SECONDS(1), K_NO_WAIT);
434 	}
435 
436 	printk("button_press_cnt 0x%02x\n", button_press_cnt);
437 	button_press_cnt++;
438 
439 	/* The variable pin_pos is the pin position in the GPIO register,
440 	 * not the pin number. It's assumed that only one bit is set.
441 	 */
442 
443 	sw.sw_num = pin_to_sw(pin_pos);
444 	last_time = time;
445 }
446 
447 /*
448  * Button Count Timer Worker
449  */
450 
button_cnt_timer(struct k_timer * work)451 static void button_cnt_timer(struct k_timer *work)
452 {
453 	struct switch_data *button_sw = CONTAINER_OF(work, struct switch_data, button_timer);
454 
455 	button_sw->onoff_state = button_press_cnt == 1U ? 1 : 0;
456 	printk("button_press_cnt 0x%02x onoff_state 0x%02x\n",
457 	       button_press_cnt, button_sw->onoff_state);
458 	button_press_cnt = 0U;
459 	k_work_submit(&sw.button_work);
460 }
461 
462 /*
463  * Button Pressed Worker Task
464  */
465 
button_pressed_worker(struct k_work * work)466 static void button_pressed_worker(struct k_work *work)
467 {
468 	const struct bt_mesh_model *mod_cli, *mod_srv;
469 	struct bt_mesh_model_pub *pub_cli, *pub_srv;
470 	struct switch_data *button_sw = CONTAINER_OF(work, struct switch_data, button_work);
471 	int err;
472 	uint8_t sw_idx = button_sw->sw_num;
473 
474 	mod_cli = mod_cli_sw[sw_idx];
475 	pub_cli = mod_cli->pub;
476 
477 	mod_srv = mod_srv_sw[sw_idx];
478 	pub_srv = mod_srv->pub;
479 
480 	/* If unprovisioned, just call the set function.
481 	 * The intent is to have switch-like behavior
482 	 * prior to provisioning. Once provisioned,
483 	 * the button and its corresponding led are no longer
484 	 * associated and act independently. So, if a button is to
485 	 * control its associated led after provisioning, the button
486 	 * must be configured to either publish to the led's unicast
487 	 * address or a group to which the led is subscribed.
488 	 */
489 
490 	if (primary_addr == BT_MESH_ADDR_UNASSIGNED) {
491 		NET_BUF_SIMPLE_DEFINE(msg, 1);
492 		struct bt_mesh_msg_ctx ctx = {
493 			.addr = sw_idx + primary_addr,
494 		};
495 
496 		/* This is a dummy message sufficient
497 		 * for the led server
498 		 */
499 
500 		net_buf_simple_add_u8(&msg, button_sw->onoff_state);
501 		(void)gen_onoff_set_unack(mod_srv, &ctx, &msg);
502 		return;
503 	}
504 
505 	if (pub_cli->addr == BT_MESH_ADDR_UNASSIGNED) {
506 		return;
507 	}
508 
509 	printk("publish to 0x%04x onoff 0x%04x sw_idx 0x%04x\n",
510 	       pub_cli->addr, button_sw->onoff_state, sw_idx);
511 	bt_mesh_model_msg_init(pub_cli->msg,
512 			       BT_MESH_MODEL_OP_GEN_ONOFF_SET);
513 	net_buf_simple_add_u8(pub_cli->msg, button_sw->onoff_state);
514 	net_buf_simple_add_u8(pub_cli->msg, trans_id++);
515 	err = bt_mesh_model_publish(mod_cli);
516 	if (err) {
517 		printk("bt_mesh_model_publish err %d\n", err);
518 	}
519 }
520 
521 /* Disable OOB security for SILabs Android app */
522 
523 static const struct bt_mesh_prov prov = {
524 	.uuid = dev_uuid,
525 #if 1
526 	.output_size = 6,
527 	.output_actions = (BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING),
528 	.output_number = output_number,
529 	.output_string = output_string,
530 #else
531 	.output_size = 0,
532 	.output_actions = 0,
533 	.output_number = 0,
534 #endif
535 	.complete = prov_complete,
536 	.reset = prov_reset,
537 };
538 
539 /*
540  * Bluetooth Ready Callback
541  */
542 
bt_ready(int err)543 static void bt_ready(int err)
544 {
545 	struct bt_le_oob oob;
546 
547 	if (err) {
548 		printk("Bluetooth init failed (err %d)\n", err);
549 		return;
550 	}
551 
552 	printk("Bluetooth initialized\n");
553 
554 	err = bt_mesh_init(&prov, &comp);
555 	if (err) {
556 		printk("Initializing mesh failed (err %d)\n", err);
557 		return;
558 	}
559 
560 	if (IS_ENABLED(CONFIG_SETTINGS)) {
561 		settings_load();
562 	}
563 
564 	/* Use identity address as device UUID */
565 	if (bt_le_oob_get_local(BT_ID_DEFAULT, &oob)) {
566 		printk("Identity Address unavailable\n");
567 	} else {
568 		memcpy(dev_uuid, oob.addr.a.val, 6);
569 	}
570 
571 	bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV);
572 
573 	printk("Mesh initialized\n");
574 }
575 
main(void)576 int main(void)
577 {
578 	int err, i;
579 
580 	printk("Initializing...\n");
581 
582 	/* Initialize the button debouncer */
583 	last_time = k_uptime_get_32();
584 
585 	/* Initialize button worker task*/
586 	k_work_init(&sw.button_work, button_pressed_worker);
587 
588 	/* Initialize button count timer */
589 	k_timer_init(&sw.button_timer, button_cnt_timer, NULL);
590 
591 	gpio_init_callback(&button_cb, button_pressed,
592 			   BIT(sw_device[0].pin) | BIT(sw_device[1].pin) |
593 			   BIT(sw_device[2].pin) | BIT(sw_device[3].pin));
594 
595 	for (i = 0; i < ARRAY_SIZE(sw_device); i++) {
596 		if (!gpio_is_ready_dt(&sw_device[i])) {
597 			printk("SW%d GPIO controller device is not ready\n", i);
598 			return 0;
599 		}
600 		gpio_pin_configure_dt(&sw_device[i], GPIO_INPUT);
601 		gpio_pin_interrupt_configure_dt(&sw_device[i], GPIO_INT_EDGE_TO_ACTIVE);
602 		gpio_add_callback(sw_device[i].port, &button_cb);
603 	}
604 
605 
606 	/* Initialize LED's */
607 	for (i = 0; i < ARRAY_SIZE(led_onoff_states); i++) {
608 		if (!gpio_is_ready_dt(&led_onoff_states[i].led_device)) {
609 			printk("LED%d GPIO controller device is not ready\n", i);
610 			return 0;
611 		}
612 		gpio_pin_configure_dt(&led_onoff_states[i].led_device, GPIO_OUTPUT_INACTIVE);
613 	}
614 
615 	/* Initialize the Bluetooth Subsystem */
616 	err = bt_enable(bt_ready);
617 	if (err) {
618 		printk("Bluetooth init failed (err %d)\n", err);
619 	}
620 	return 0;
621 }
622