1*042d53a7SEvalZero /* main.c - Application main entry point */
2*042d53a7SEvalZero
3*042d53a7SEvalZero /*
4*042d53a7SEvalZero * Copyright (c) 2017 Intel Corporation
5*042d53a7SEvalZero *
6*042d53a7SEvalZero * SPDX-License-Identifier: Apache-2.0
7*042d53a7SEvalZero */
8*042d53a7SEvalZero
9*042d53a7SEvalZero /*
10*042d53a7SEvalZero * This application is specific to the Nordic nRF52840-PDK board.
11*042d53a7SEvalZero *
12*042d53a7SEvalZero * It supports the 4 buttons and 4 LEDs as mesh clients and servers.
13*042d53a7SEvalZero *
14*042d53a7SEvalZero * Prior to provisioning, a button inverts the state of the
15*042d53a7SEvalZero * corresponding LED.
16*042d53a7SEvalZero *
17*042d53a7SEvalZero * Button and LED 1 are in the root node.
18*042d53a7SEvalZero * The 3 remaining button/LED pairs are in element 1 through 3.
19*042d53a7SEvalZero * Assuming the provisioner assigns 0x100 to the root node,
20*042d53a7SEvalZero * the secondary elements will appear at 0x101, 0x102 and 0x103.
21*042d53a7SEvalZero *
22*042d53a7SEvalZero * It's anticipated that after provisioning, the button clients would
23*042d53a7SEvalZero * be configured to publish and the LED servers to subscribe.
24*042d53a7SEvalZero *
25*042d53a7SEvalZero * If a LED server is provided with a publish address, it will
26*042d53a7SEvalZero * also publish its status on a state change.
27*042d53a7SEvalZero *
28*042d53a7SEvalZero * Messages from a button to its corresponding LED are ignored as
29*042d53a7SEvalZero * the LED's state has already been changed locally by the button client.
30*042d53a7SEvalZero *
31*042d53a7SEvalZero * The buttons are debounced at a nominal 250ms. That value can be
32*042d53a7SEvalZero * changed as needed.
33*042d53a7SEvalZero *
34*042d53a7SEvalZero */
35*042d53a7SEvalZero
36*042d53a7SEvalZero #include "os/mynewt.h"
37*042d53a7SEvalZero #include "bsp/bsp.h"
38*042d53a7SEvalZero #include "console/console.h"
39*042d53a7SEvalZero #include "hal/hal_gpio.h"
40*042d53a7SEvalZero #include "host/ble_hs.h"
41*042d53a7SEvalZero #include "mesh/glue.h"
42*042d53a7SEvalZero #include "mesh/mesh.h"
43*042d53a7SEvalZero
44*042d53a7SEvalZero #define CID_RUNTIME 0x05C3
45*042d53a7SEvalZero
46*042d53a7SEvalZero /* Model Operation Codes */
47*042d53a7SEvalZero #define BT_MESH_MODEL_OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01)
48*042d53a7SEvalZero #define BT_MESH_MODEL_OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02)
49*042d53a7SEvalZero #define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03)
50*042d53a7SEvalZero #define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04)
51*042d53a7SEvalZero
52*042d53a7SEvalZero static void gen_onoff_set(struct bt_mesh_model *model,
53*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
54*042d53a7SEvalZero struct os_mbuf *buf);
55*042d53a7SEvalZero
56*042d53a7SEvalZero static void gen_onoff_set_unack(struct bt_mesh_model *model,
57*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
58*042d53a7SEvalZero struct os_mbuf *buf);
59*042d53a7SEvalZero
60*042d53a7SEvalZero static void gen_onoff_get(struct bt_mesh_model *model,
61*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
62*042d53a7SEvalZero struct os_mbuf *buf);
63*042d53a7SEvalZero
64*042d53a7SEvalZero static void gen_onoff_status(struct bt_mesh_model *model,
65*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
66*042d53a7SEvalZero struct os_mbuf *buf);
67*042d53a7SEvalZero
68*042d53a7SEvalZero /*
69*042d53a7SEvalZero * Server Configuration Declaration
70*042d53a7SEvalZero */
71*042d53a7SEvalZero
72*042d53a7SEvalZero static struct bt_mesh_cfg_srv cfg_srv = {
73*042d53a7SEvalZero .relay = BT_MESH_RELAY_DISABLED,
74*042d53a7SEvalZero .beacon = BT_MESH_BEACON_ENABLED,
75*042d53a7SEvalZero #if defined(CONFIG_BT_MESH_FRIEND)
76*042d53a7SEvalZero .frnd = BT_MESH_FRIEND_ENABLED,
77*042d53a7SEvalZero #else
78*042d53a7SEvalZero .frnd = BT_MESH_FRIEND_NOT_SUPPORTED,
79*042d53a7SEvalZero #endif
80*042d53a7SEvalZero #if defined(CONFIG_BT_MESH_GATT_PROXY)
81*042d53a7SEvalZero .gatt_proxy = BT_MESH_GATT_PROXY_ENABLED,
82*042d53a7SEvalZero #else
83*042d53a7SEvalZero .gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
84*042d53a7SEvalZero #endif
85*042d53a7SEvalZero .default_ttl = 7,
86*042d53a7SEvalZero
87*042d53a7SEvalZero /* 3 transmissions with 20ms interval */
88*042d53a7SEvalZero .net_transmit = BT_MESH_TRANSMIT(2, 20),
89*042d53a7SEvalZero .relay_retransmit = BT_MESH_TRANSMIT(2, 20),
90*042d53a7SEvalZero };
91*042d53a7SEvalZero
92*042d53a7SEvalZero /*
93*042d53a7SEvalZero * Client Configuration Declaration
94*042d53a7SEvalZero */
95*042d53a7SEvalZero
96*042d53a7SEvalZero static struct bt_mesh_cfg_cli cfg_cli = {
97*042d53a7SEvalZero };
98*042d53a7SEvalZero
99*042d53a7SEvalZero /*
100*042d53a7SEvalZero * Health Server Declaration
101*042d53a7SEvalZero */
102*042d53a7SEvalZero
103*042d53a7SEvalZero static struct bt_mesh_health_srv health_srv = {
104*042d53a7SEvalZero };
105*042d53a7SEvalZero
106*042d53a7SEvalZero /*
107*042d53a7SEvalZero * Publication Declarations
108*042d53a7SEvalZero *
109*042d53a7SEvalZero * The publication messages are initialized to the
110*042d53a7SEvalZero * the size of the opcode + content
111*042d53a7SEvalZero *
112*042d53a7SEvalZero * For publication, the message must be in static or global as
113*042d53a7SEvalZero * it is re-transmitted several times. This occurs
114*042d53a7SEvalZero * after the function that called bt_mesh_model_publish() has
115*042d53a7SEvalZero * exited and the stack is no longer valid.
116*042d53a7SEvalZero *
117*042d53a7SEvalZero * Note that the additional 4 bytes for the AppMIC is not needed
118*042d53a7SEvalZero * because it is added to a stack variable at the time a
119*042d53a7SEvalZero * transmission occurs.
120*042d53a7SEvalZero *
121*042d53a7SEvalZero */
122*042d53a7SEvalZero
123*042d53a7SEvalZero static struct bt_mesh_model_pub health_pub;
124*042d53a7SEvalZero static struct bt_mesh_model_pub gen_onoff_pub_srv;
125*042d53a7SEvalZero static struct bt_mesh_model_pub gen_onoff_pub_cli;
126*042d53a7SEvalZero static struct bt_mesh_model_pub gen_onoff_pub_srv_s_0;
127*042d53a7SEvalZero static struct bt_mesh_model_pub gen_onoff_pub_cli_s_0;
128*042d53a7SEvalZero static struct bt_mesh_model_pub gen_onoff_pub_srv_s_1;
129*042d53a7SEvalZero static struct bt_mesh_model_pub gen_onoff_pub_cli_s_1;
130*042d53a7SEvalZero static struct bt_mesh_model_pub gen_onoff_pub_srv_s_2;
131*042d53a7SEvalZero static struct bt_mesh_model_pub gen_onoff_pub_cli_s_2;
132*042d53a7SEvalZero
133*042d53a7SEvalZero static struct os_mbuf *bt_mesh_pub_msg_health_pub;
134*042d53a7SEvalZero static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv;
135*042d53a7SEvalZero static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli;
136*042d53a7SEvalZero static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_0;
137*042d53a7SEvalZero static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_0;
138*042d53a7SEvalZero static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_1;
139*042d53a7SEvalZero static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_1;
140*042d53a7SEvalZero static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_2;
141*042d53a7SEvalZero static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_2;
142*042d53a7SEvalZero
init_pub(void)143*042d53a7SEvalZero void init_pub(void)
144*042d53a7SEvalZero {
145*042d53a7SEvalZero bt_mesh_pub_msg_health_pub = NET_BUF_SIMPLE(1 + 3 + 0);
146*042d53a7SEvalZero bt_mesh_pub_msg_gen_onoff_pub_srv = NET_BUF_SIMPLE(2 + 2);
147*042d53a7SEvalZero bt_mesh_pub_msg_gen_onoff_pub_cli = NET_BUF_SIMPLE(2 + 2);
148*042d53a7SEvalZero bt_mesh_pub_msg_gen_onoff_pub_srv_s_0 = NET_BUF_SIMPLE(2 + 2);
149*042d53a7SEvalZero bt_mesh_pub_msg_gen_onoff_pub_cli_s_0 = NET_BUF_SIMPLE(2 + 2);
150*042d53a7SEvalZero bt_mesh_pub_msg_gen_onoff_pub_srv_s_1 = NET_BUF_SIMPLE(2 + 2);
151*042d53a7SEvalZero bt_mesh_pub_msg_gen_onoff_pub_cli_s_1 = NET_BUF_SIMPLE(2 + 2);
152*042d53a7SEvalZero bt_mesh_pub_msg_gen_onoff_pub_srv_s_2 = NET_BUF_SIMPLE(2 + 2);
153*042d53a7SEvalZero bt_mesh_pub_msg_gen_onoff_pub_cli_s_2 = NET_BUF_SIMPLE(2 + 2);
154*042d53a7SEvalZero
155*042d53a7SEvalZero health_pub.msg = bt_mesh_pub_msg_health_pub;
156*042d53a7SEvalZero gen_onoff_pub_srv.msg = bt_mesh_pub_msg_gen_onoff_pub_srv;
157*042d53a7SEvalZero gen_onoff_pub_cli.msg = bt_mesh_pub_msg_gen_onoff_pub_cli;
158*042d53a7SEvalZero gen_onoff_pub_srv_s_0.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_0;
159*042d53a7SEvalZero gen_onoff_pub_cli_s_0.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_0;
160*042d53a7SEvalZero gen_onoff_pub_srv_s_1.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_1;
161*042d53a7SEvalZero gen_onoff_pub_cli_s_1.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_1;
162*042d53a7SEvalZero gen_onoff_pub_srv_s_2.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_2;
163*042d53a7SEvalZero gen_onoff_pub_cli_s_2.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_2;
164*042d53a7SEvalZero }
165*042d53a7SEvalZero
166*042d53a7SEvalZero /*
167*042d53a7SEvalZero * Models in an element must have unique op codes.
168*042d53a7SEvalZero *
169*042d53a7SEvalZero * The mesh stack dispatches a message to the first model in an element
170*042d53a7SEvalZero * that is also bound to an app key and supports the op code in the
171*042d53a7SEvalZero * received message.
172*042d53a7SEvalZero *
173*042d53a7SEvalZero */
174*042d53a7SEvalZero
175*042d53a7SEvalZero /*
176*042d53a7SEvalZero * OnOff Model Server Op Dispatch Table
177*042d53a7SEvalZero *
178*042d53a7SEvalZero */
179*042d53a7SEvalZero
180*042d53a7SEvalZero static const struct bt_mesh_model_op gen_onoff_srv_op[] = {
181*042d53a7SEvalZero { BT_MESH_MODEL_OP_GEN_ONOFF_GET, 0, gen_onoff_get },
182*042d53a7SEvalZero { BT_MESH_MODEL_OP_GEN_ONOFF_SET, 2, gen_onoff_set },
183*042d53a7SEvalZero { BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set_unack },
184*042d53a7SEvalZero BT_MESH_MODEL_OP_END,
185*042d53a7SEvalZero };
186*042d53a7SEvalZero
187*042d53a7SEvalZero /*
188*042d53a7SEvalZero * OnOff Model Client Op Dispatch Table
189*042d53a7SEvalZero */
190*042d53a7SEvalZero
191*042d53a7SEvalZero static const struct bt_mesh_model_op gen_onoff_cli_op[] = {
192*042d53a7SEvalZero { BT_MESH_MODEL_OP_GEN_ONOFF_STATUS, 1, gen_onoff_status },
193*042d53a7SEvalZero BT_MESH_MODEL_OP_END,
194*042d53a7SEvalZero };
195*042d53a7SEvalZero
196*042d53a7SEvalZero struct onoff_state {
197*042d53a7SEvalZero u8_t current;
198*042d53a7SEvalZero u8_t previous;
199*042d53a7SEvalZero u8_t led_gpio_pin;
200*042d53a7SEvalZero };
201*042d53a7SEvalZero
202*042d53a7SEvalZero /*
203*042d53a7SEvalZero * Declare and Initialize Element Contexts
204*042d53a7SEvalZero * Change to select different GPIO output pins
205*042d53a7SEvalZero */
206*042d53a7SEvalZero
207*042d53a7SEvalZero static struct onoff_state onoff_state_arr[] = {
208*042d53a7SEvalZero { .led_gpio_pin = LED_1 },
209*042d53a7SEvalZero { .led_gpio_pin = LED_2 },
210*042d53a7SEvalZero { .led_gpio_pin = LED_3 },
211*042d53a7SEvalZero { .led_gpio_pin = LED_4 },
212*042d53a7SEvalZero };
213*042d53a7SEvalZero
214*042d53a7SEvalZero /*
215*042d53a7SEvalZero *
216*042d53a7SEvalZero * Element Model Declarations
217*042d53a7SEvalZero *
218*042d53a7SEvalZero * Element 0 Root Models
219*042d53a7SEvalZero */
220*042d53a7SEvalZero
221*042d53a7SEvalZero static struct bt_mesh_model root_models[] = {
222*042d53a7SEvalZero BT_MESH_MODEL_CFG_SRV(&cfg_srv),
223*042d53a7SEvalZero BT_MESH_MODEL_CFG_CLI(&cfg_cli),
224*042d53a7SEvalZero BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
225*042d53a7SEvalZero BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
226*042d53a7SEvalZero &gen_onoff_pub_srv, &onoff_state_arr[0]),
227*042d53a7SEvalZero BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
228*042d53a7SEvalZero &gen_onoff_pub_cli, &onoff_state_arr[0]),
229*042d53a7SEvalZero };
230*042d53a7SEvalZero
231*042d53a7SEvalZero /*
232*042d53a7SEvalZero * Element 1 Models
233*042d53a7SEvalZero */
234*042d53a7SEvalZero
235*042d53a7SEvalZero static struct bt_mesh_model secondary_0_models[] = {
236*042d53a7SEvalZero BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
237*042d53a7SEvalZero &gen_onoff_pub_srv_s_0, &onoff_state_arr[1]),
238*042d53a7SEvalZero BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
239*042d53a7SEvalZero &gen_onoff_pub_cli_s_0, &onoff_state_arr[1]),
240*042d53a7SEvalZero };
241*042d53a7SEvalZero
242*042d53a7SEvalZero /*
243*042d53a7SEvalZero * Element 2 Models
244*042d53a7SEvalZero */
245*042d53a7SEvalZero
246*042d53a7SEvalZero static struct bt_mesh_model secondary_1_models[] = {
247*042d53a7SEvalZero BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
248*042d53a7SEvalZero &gen_onoff_pub_srv_s_1, &onoff_state_arr[2]),
249*042d53a7SEvalZero BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
250*042d53a7SEvalZero &gen_onoff_pub_cli_s_1, &onoff_state_arr[2]),
251*042d53a7SEvalZero };
252*042d53a7SEvalZero
253*042d53a7SEvalZero /*
254*042d53a7SEvalZero * Element 3 Models
255*042d53a7SEvalZero */
256*042d53a7SEvalZero
257*042d53a7SEvalZero static struct bt_mesh_model secondary_2_models[] = {
258*042d53a7SEvalZero BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
259*042d53a7SEvalZero &gen_onoff_pub_srv_s_2, &onoff_state_arr[3]),
260*042d53a7SEvalZero BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
261*042d53a7SEvalZero &gen_onoff_pub_cli_s_2, &onoff_state_arr[3]),
262*042d53a7SEvalZero };
263*042d53a7SEvalZero
264*042d53a7SEvalZero /*
265*042d53a7SEvalZero * Button to Client Model Assignments
266*042d53a7SEvalZero */
267*042d53a7SEvalZero
268*042d53a7SEvalZero struct bt_mesh_model *mod_cli_sw[] = {
269*042d53a7SEvalZero &root_models[4],
270*042d53a7SEvalZero &secondary_0_models[1],
271*042d53a7SEvalZero &secondary_1_models[1],
272*042d53a7SEvalZero &secondary_2_models[1],
273*042d53a7SEvalZero };
274*042d53a7SEvalZero
275*042d53a7SEvalZero /*
276*042d53a7SEvalZero * LED to Server Model Assigmnents
277*042d53a7SEvalZero */
278*042d53a7SEvalZero
279*042d53a7SEvalZero struct bt_mesh_model *mod_srv_sw[] = {
280*042d53a7SEvalZero &root_models[3],
281*042d53a7SEvalZero &secondary_0_models[0],
282*042d53a7SEvalZero &secondary_1_models[0],
283*042d53a7SEvalZero &secondary_2_models[0],
284*042d53a7SEvalZero };
285*042d53a7SEvalZero
286*042d53a7SEvalZero /*
287*042d53a7SEvalZero * Root and Secondary Element Declarations
288*042d53a7SEvalZero */
289*042d53a7SEvalZero
290*042d53a7SEvalZero static struct bt_mesh_elem elements[] = {
291*042d53a7SEvalZero BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
292*042d53a7SEvalZero BT_MESH_ELEM(0, secondary_0_models, BT_MESH_MODEL_NONE),
293*042d53a7SEvalZero BT_MESH_ELEM(0, secondary_1_models, BT_MESH_MODEL_NONE),
294*042d53a7SEvalZero BT_MESH_ELEM(0, secondary_2_models, BT_MESH_MODEL_NONE),
295*042d53a7SEvalZero };
296*042d53a7SEvalZero
297*042d53a7SEvalZero static const struct bt_mesh_comp comp = {
298*042d53a7SEvalZero .cid = CID_RUNTIME,
299*042d53a7SEvalZero .elem = elements,
300*042d53a7SEvalZero .elem_count = ARRAY_SIZE(elements),
301*042d53a7SEvalZero };
302*042d53a7SEvalZero
303*042d53a7SEvalZero struct sw {
304*042d53a7SEvalZero u8_t sw_num;
305*042d53a7SEvalZero u8_t onoff_state;
306*042d53a7SEvalZero struct ble_npl_callout button_work;
307*042d53a7SEvalZero struct k_delayed_work button_timer;
308*042d53a7SEvalZero };
309*042d53a7SEvalZero
310*042d53a7SEvalZero
311*042d53a7SEvalZero static u8_t button_press_cnt;
312*042d53a7SEvalZero static struct sw sw;
313*042d53a7SEvalZero
314*042d53a7SEvalZero static u8_t trans_id;
315*042d53a7SEvalZero static u32_t time, last_time;
316*042d53a7SEvalZero static u16_t primary_addr;
317*042d53a7SEvalZero static u16_t primary_net_idx;
318*042d53a7SEvalZero
319*042d53a7SEvalZero /*
320*042d53a7SEvalZero * Generic OnOff Model Server Message Handlers
321*042d53a7SEvalZero *
322*042d53a7SEvalZero * Mesh Model Specification 3.1.1
323*042d53a7SEvalZero *
324*042d53a7SEvalZero */
325*042d53a7SEvalZero
gen_onoff_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)326*042d53a7SEvalZero static void gen_onoff_get(struct bt_mesh_model *model,
327*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
328*042d53a7SEvalZero struct os_mbuf *buf)
329*042d53a7SEvalZero {
330*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
331*042d53a7SEvalZero struct onoff_state *state = model->user_data;
332*042d53a7SEvalZero
333*042d53a7SEvalZero BT_INFO("addr 0x%04x onoff 0x%02x",
334*042d53a7SEvalZero bt_mesh_model_elem(model)->addr, state->current);
335*042d53a7SEvalZero bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
336*042d53a7SEvalZero net_buf_simple_add_u8(msg, state->current);
337*042d53a7SEvalZero
338*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
339*042d53a7SEvalZero BT_ERR("Unable to send On Off Status response");
340*042d53a7SEvalZero }
341*042d53a7SEvalZero
342*042d53a7SEvalZero os_mbuf_free_chain(msg);
343*042d53a7SEvalZero }
344*042d53a7SEvalZero
gen_onoff_set_unack(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)345*042d53a7SEvalZero static void gen_onoff_set_unack(struct bt_mesh_model *model,
346*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
347*042d53a7SEvalZero struct os_mbuf *buf)
348*042d53a7SEvalZero {
349*042d53a7SEvalZero struct os_mbuf *msg = model->pub->msg;
350*042d53a7SEvalZero struct onoff_state *state = model->user_data;
351*042d53a7SEvalZero int err;
352*042d53a7SEvalZero
353*042d53a7SEvalZero state->current = net_buf_simple_pull_u8(buf);
354*042d53a7SEvalZero BT_INFO("addr 0x%02x state 0x%02x",
355*042d53a7SEvalZero bt_mesh_model_elem(model)->addr, state->current);
356*042d53a7SEvalZero
357*042d53a7SEvalZero /* Pin set low turns on LED's on the nrf52840-pca10056 board */
358*042d53a7SEvalZero hal_gpio_write(state->led_gpio_pin,
359*042d53a7SEvalZero state->current ? 0 : 1);
360*042d53a7SEvalZero
361*042d53a7SEvalZero /*
362*042d53a7SEvalZero * If a server has a publish address, it is required to
363*042d53a7SEvalZero * publish status on a state change
364*042d53a7SEvalZero *
365*042d53a7SEvalZero * See Mesh Profile Specification 3.7.6.1.2
366*042d53a7SEvalZero *
367*042d53a7SEvalZero * Only publish if there is an assigned address
368*042d53a7SEvalZero */
369*042d53a7SEvalZero
370*042d53a7SEvalZero if (state->previous != state->current &&
371*042d53a7SEvalZero model->pub->addr != BT_MESH_ADDR_UNASSIGNED) {
372*042d53a7SEvalZero BT_INFO("publish last 0x%02x cur 0x%02x",
373*042d53a7SEvalZero state->previous,
374*042d53a7SEvalZero state->current);
375*042d53a7SEvalZero state->previous = state->current;
376*042d53a7SEvalZero bt_mesh_model_msg_init(msg,
377*042d53a7SEvalZero BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
378*042d53a7SEvalZero net_buf_simple_add_u8(msg, state->current);
379*042d53a7SEvalZero err = bt_mesh_model_publish(model);
380*042d53a7SEvalZero if (err) {
381*042d53a7SEvalZero BT_ERR("bt_mesh_model_publish err %d", err);
382*042d53a7SEvalZero }
383*042d53a7SEvalZero }
384*042d53a7SEvalZero }
385*042d53a7SEvalZero
gen_onoff_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)386*042d53a7SEvalZero static void gen_onoff_set(struct bt_mesh_model *model,
387*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
388*042d53a7SEvalZero struct os_mbuf *buf)
389*042d53a7SEvalZero {
390*042d53a7SEvalZero BT_INFO("");
391*042d53a7SEvalZero
392*042d53a7SEvalZero gen_onoff_set_unack(model, ctx, buf);
393*042d53a7SEvalZero gen_onoff_get(model, ctx, buf);
394*042d53a7SEvalZero }
395*042d53a7SEvalZero
gen_onoff_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)396*042d53a7SEvalZero static void gen_onoff_status(struct bt_mesh_model *model,
397*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
398*042d53a7SEvalZero struct os_mbuf *buf)
399*042d53a7SEvalZero {
400*042d53a7SEvalZero u8_t state;
401*042d53a7SEvalZero
402*042d53a7SEvalZero state = net_buf_simple_pull_u8(buf);
403*042d53a7SEvalZero
404*042d53a7SEvalZero BT_INFO("Node 0x%04x OnOff status from 0x%04x with state 0x%02x",
405*042d53a7SEvalZero bt_mesh_model_elem(model)->addr, ctx->addr, state);
406*042d53a7SEvalZero }
407*042d53a7SEvalZero
output_number(bt_mesh_output_action_t action,u32_t number)408*042d53a7SEvalZero static int output_number(bt_mesh_output_action_t action, u32_t number)
409*042d53a7SEvalZero {
410*042d53a7SEvalZero BT_INFO("OOB Number %u", number);
411*042d53a7SEvalZero return 0;
412*042d53a7SEvalZero }
413*042d53a7SEvalZero
output_string(const char * str)414*042d53a7SEvalZero static int output_string(const char *str)
415*042d53a7SEvalZero {
416*042d53a7SEvalZero BT_INFO("OOB String %s", str);
417*042d53a7SEvalZero return 0;
418*042d53a7SEvalZero }
419*042d53a7SEvalZero
prov_complete(u16_t net_idx,u16_t addr)420*042d53a7SEvalZero static void prov_complete(u16_t net_idx, u16_t addr)
421*042d53a7SEvalZero {
422*042d53a7SEvalZero BT_INFO("provisioning complete for net_idx 0x%04x addr 0x%04x",
423*042d53a7SEvalZero net_idx, addr);
424*042d53a7SEvalZero primary_addr = addr;
425*042d53a7SEvalZero primary_net_idx = net_idx;
426*042d53a7SEvalZero }
427*042d53a7SEvalZero
prov_reset(void)428*042d53a7SEvalZero static void prov_reset(void)
429*042d53a7SEvalZero {
430*042d53a7SEvalZero bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
431*042d53a7SEvalZero }
432*042d53a7SEvalZero
433*042d53a7SEvalZero static u8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID);
434*042d53a7SEvalZero
435*042d53a7SEvalZero #define BUTTON_DEBOUNCE_DELAY_MS 250
436*042d53a7SEvalZero
437*042d53a7SEvalZero /*
438*042d53a7SEvalZero * Map GPIO pins to button number
439*042d53a7SEvalZero * Change to select different GPIO input pins
440*042d53a7SEvalZero */
441*042d53a7SEvalZero
pin_to_sw(int pin_pos)442*042d53a7SEvalZero static uint8_t pin_to_sw(int pin_pos)
443*042d53a7SEvalZero {
444*042d53a7SEvalZero switch (pin_pos) {
445*042d53a7SEvalZero case BUTTON_1: return 0;
446*042d53a7SEvalZero case BUTTON_2: return 1;
447*042d53a7SEvalZero case BUTTON_3: return 2;
448*042d53a7SEvalZero case BUTTON_4: return 3;
449*042d53a7SEvalZero default:break;
450*042d53a7SEvalZero }
451*042d53a7SEvalZero
452*042d53a7SEvalZero BT_ERR("No match for GPIO pin 0x%08x", pin_pos);
453*042d53a7SEvalZero return 0;
454*042d53a7SEvalZero }
455*042d53a7SEvalZero
button_pressed(struct os_event * ev)456*042d53a7SEvalZero static void button_pressed(struct os_event *ev)
457*042d53a7SEvalZero {
458*042d53a7SEvalZero int pin_pos = (int ) ev->ev_arg;
459*042d53a7SEvalZero /*
460*042d53a7SEvalZero * One button press within a 1 second interval sends an on message
461*042d53a7SEvalZero * More than one button press sends an off message
462*042d53a7SEvalZero */
463*042d53a7SEvalZero
464*042d53a7SEvalZero time = k_uptime_get_32();
465*042d53a7SEvalZero
466*042d53a7SEvalZero /* debounce the switch */
467*042d53a7SEvalZero if (time < last_time + BUTTON_DEBOUNCE_DELAY_MS) {
468*042d53a7SEvalZero last_time = time;
469*042d53a7SEvalZero return;
470*042d53a7SEvalZero }
471*042d53a7SEvalZero
472*042d53a7SEvalZero if (button_press_cnt == 0) {
473*042d53a7SEvalZero k_delayed_work_submit(&sw.button_timer, K_SECONDS(1));
474*042d53a7SEvalZero }
475*042d53a7SEvalZero
476*042d53a7SEvalZero BT_INFO("button_press_cnt 0x%02x", button_press_cnt);
477*042d53a7SEvalZero button_press_cnt++;
478*042d53a7SEvalZero
479*042d53a7SEvalZero /* The variable pin_pos is the pin position in the GPIO register,
480*042d53a7SEvalZero * not the pin number. It's assumed that only one bit is set.
481*042d53a7SEvalZero */
482*042d53a7SEvalZero
483*042d53a7SEvalZero sw.sw_num = pin_to_sw(pin_pos);
484*042d53a7SEvalZero last_time = time;
485*042d53a7SEvalZero }
486*042d53a7SEvalZero
487*042d53a7SEvalZero /*
488*042d53a7SEvalZero * Button Count Timer Worker
489*042d53a7SEvalZero */
490*042d53a7SEvalZero
button_cnt_timer(struct ble_npl_event * work)491*042d53a7SEvalZero static void button_cnt_timer(struct ble_npl_event *work)
492*042d53a7SEvalZero {
493*042d53a7SEvalZero struct sw *button_sw = work->ev.ev_arg;
494*042d53a7SEvalZero
495*042d53a7SEvalZero button_sw->onoff_state = button_press_cnt == 1 ? 1 : 0;
496*042d53a7SEvalZero BT_INFO("button_press_cnt 0x%02x onoff_state 0x%02x",
497*042d53a7SEvalZero button_press_cnt, button_sw->onoff_state);
498*042d53a7SEvalZero button_press_cnt = 0;
499*042d53a7SEvalZero k_work_submit(&sw.button_work);
500*042d53a7SEvalZero }
501*042d53a7SEvalZero
502*042d53a7SEvalZero /*
503*042d53a7SEvalZero * Button Pressed Worker Task
504*042d53a7SEvalZero */
505*042d53a7SEvalZero
button_pressed_worker(struct ble_npl_event * work)506*042d53a7SEvalZero static void button_pressed_worker(struct ble_npl_event *work)
507*042d53a7SEvalZero {
508*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(1);
509*042d53a7SEvalZero struct bt_mesh_model *mod_cli, *mod_srv;
510*042d53a7SEvalZero struct bt_mesh_model_pub *pub_cli, *pub_srv;
511*042d53a7SEvalZero struct sw *sw = work->ev.ev_arg;
512*042d53a7SEvalZero u8_t sw_idx = sw->sw_num;
513*042d53a7SEvalZero int err;
514*042d53a7SEvalZero
515*042d53a7SEvalZero mod_cli = mod_cli_sw[sw_idx];
516*042d53a7SEvalZero pub_cli = mod_cli->pub;
517*042d53a7SEvalZero
518*042d53a7SEvalZero mod_srv = mod_srv_sw[sw_idx];
519*042d53a7SEvalZero pub_srv = mod_srv->pub;
520*042d53a7SEvalZero (void)pub_srv;
521*042d53a7SEvalZero
522*042d53a7SEvalZero /* If unprovisioned, just call the set function.
523*042d53a7SEvalZero * The intent is to have switch-like behavior
524*042d53a7SEvalZero * prior to provisioning. Once provisioned,
525*042d53a7SEvalZero * the button and its corresponding led are no longer
526*042d53a7SEvalZero * associated and act independently. So, if a button is to
527*042d53a7SEvalZero * control its associated led after provisioning, the button
528*042d53a7SEvalZero * must be configured to either publish to the led's unicast
529*042d53a7SEvalZero * address or a group to which the led is subscribed.
530*042d53a7SEvalZero */
531*042d53a7SEvalZero
532*042d53a7SEvalZero if (primary_addr == BT_MESH_ADDR_UNASSIGNED) {
533*042d53a7SEvalZero struct bt_mesh_msg_ctx ctx = {
534*042d53a7SEvalZero .addr = sw_idx + primary_addr,
535*042d53a7SEvalZero };
536*042d53a7SEvalZero
537*042d53a7SEvalZero /* This is a dummy message sufficient
538*042d53a7SEvalZero * for the led server
539*042d53a7SEvalZero */
540*042d53a7SEvalZero
541*042d53a7SEvalZero net_buf_simple_add_u8(msg, sw->onoff_state);
542*042d53a7SEvalZero gen_onoff_set_unack(mod_srv, &ctx, msg);
543*042d53a7SEvalZero goto done;
544*042d53a7SEvalZero }
545*042d53a7SEvalZero
546*042d53a7SEvalZero if (pub_cli->addr == BT_MESH_ADDR_UNASSIGNED) {
547*042d53a7SEvalZero goto done;
548*042d53a7SEvalZero }
549*042d53a7SEvalZero
550*042d53a7SEvalZero BT_INFO("publish to 0x%04x onoff 0x%04x sw_idx 0x%04x",
551*042d53a7SEvalZero pub_cli->addr, sw->onoff_state, sw_idx);
552*042d53a7SEvalZero bt_mesh_model_msg_init(pub_cli->msg,
553*042d53a7SEvalZero BT_MESH_MODEL_OP_GEN_ONOFF_SET);
554*042d53a7SEvalZero net_buf_simple_add_u8(pub_cli->msg, sw->onoff_state);
555*042d53a7SEvalZero net_buf_simple_add_u8(pub_cli->msg, trans_id++);
556*042d53a7SEvalZero err = bt_mesh_model_publish(mod_cli);
557*042d53a7SEvalZero if (err) {
558*042d53a7SEvalZero BT_ERR("bt_mesh_model_publish err %d", err);
559*042d53a7SEvalZero }
560*042d53a7SEvalZero
561*042d53a7SEvalZero done:
562*042d53a7SEvalZero os_mbuf_free_chain(msg);
563*042d53a7SEvalZero }
564*042d53a7SEvalZero
565*042d53a7SEvalZero /* Disable OOB security for SILabs Android app */
566*042d53a7SEvalZero
567*042d53a7SEvalZero static const struct bt_mesh_prov prov = {
568*042d53a7SEvalZero .uuid = dev_uuid,
569*042d53a7SEvalZero #if 1
570*042d53a7SEvalZero .output_size = 6,
571*042d53a7SEvalZero .output_actions = (BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING),
572*042d53a7SEvalZero .output_number = output_number,
573*042d53a7SEvalZero .output_string = output_string,
574*042d53a7SEvalZero #else
575*042d53a7SEvalZero .output_size = 0,
576*042d53a7SEvalZero .output_actions = 0,
577*042d53a7SEvalZero .output_number = 0,
578*042d53a7SEvalZero #endif
579*042d53a7SEvalZero .complete = prov_complete,
580*042d53a7SEvalZero .reset = prov_reset,
581*042d53a7SEvalZero };
582*042d53a7SEvalZero
init_led(u8_t dev)583*042d53a7SEvalZero void init_led(u8_t dev)
584*042d53a7SEvalZero {
585*042d53a7SEvalZero hal_gpio_init_out(onoff_state_arr[dev].led_gpio_pin, 1);
586*042d53a7SEvalZero }
587*042d53a7SEvalZero
588*042d53a7SEvalZero static struct os_event button_event;
589*042d53a7SEvalZero
590*042d53a7SEvalZero static void
gpio_irq_handler(void * arg)591*042d53a7SEvalZero gpio_irq_handler(void *arg)
592*042d53a7SEvalZero {
593*042d53a7SEvalZero button_event.ev_arg = arg;
594*042d53a7SEvalZero os_eventq_put(os_eventq_dflt_get(), &button_event);
595*042d53a7SEvalZero }
596*042d53a7SEvalZero
init_button(int button)597*042d53a7SEvalZero void init_button(int button)
598*042d53a7SEvalZero {
599*042d53a7SEvalZero button_event.ev_cb = button_pressed;
600*042d53a7SEvalZero
601*042d53a7SEvalZero hal_gpio_irq_init(button, gpio_irq_handler, (void *)button,
602*042d53a7SEvalZero HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
603*042d53a7SEvalZero hal_gpio_irq_enable(button);
604*042d53a7SEvalZero }
605*042d53a7SEvalZero
606*042d53a7SEvalZero static void
blemesh_on_reset(int reason)607*042d53a7SEvalZero blemesh_on_reset(int reason)
608*042d53a7SEvalZero {
609*042d53a7SEvalZero BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
610*042d53a7SEvalZero }
611*042d53a7SEvalZero
612*042d53a7SEvalZero static void
blemesh_on_sync(void)613*042d53a7SEvalZero blemesh_on_sync(void)
614*042d53a7SEvalZero {
615*042d53a7SEvalZero int err;
616*042d53a7SEvalZero ble_addr_t addr;
617*042d53a7SEvalZero
618*042d53a7SEvalZero console_printf("Bluetooth initialized\n");
619*042d53a7SEvalZero
620*042d53a7SEvalZero /* Use NRPA */
621*042d53a7SEvalZero err = ble_hs_id_gen_rnd(1, &addr);
622*042d53a7SEvalZero assert(err == 0);
623*042d53a7SEvalZero err = ble_hs_id_set_rnd(addr.val);
624*042d53a7SEvalZero assert(err == 0);
625*042d53a7SEvalZero
626*042d53a7SEvalZero err = bt_mesh_init(addr.type, &prov, &comp);
627*042d53a7SEvalZero if (err) {
628*042d53a7SEvalZero console_printf("Initializing mesh failed (err %d)\n", err);
629*042d53a7SEvalZero return;
630*042d53a7SEvalZero }
631*042d53a7SEvalZero
632*042d53a7SEvalZero if (IS_ENABLED(CONFIG_SETTINGS)) {
633*042d53a7SEvalZero settings_load();
634*042d53a7SEvalZero }
635*042d53a7SEvalZero
636*042d53a7SEvalZero if (bt_mesh_is_provisioned()) {
637*042d53a7SEvalZero console_printf("Mesh network restored from flash\n");
638*042d53a7SEvalZero }
639*042d53a7SEvalZero
640*042d53a7SEvalZero bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV);
641*042d53a7SEvalZero
642*042d53a7SEvalZero console_printf("Mesh initialized\n");
643*042d53a7SEvalZero }
644*042d53a7SEvalZero
main(void)645*042d53a7SEvalZero int main(void)
646*042d53a7SEvalZero {
647*042d53a7SEvalZero #ifdef ARCH_sim
648*042d53a7SEvalZero mcu_sim_parse_args(argc, argv);
649*042d53a7SEvalZero #endif
650*042d53a7SEvalZero
651*042d53a7SEvalZero /* Initialize OS */
652*042d53a7SEvalZero sysinit();
653*042d53a7SEvalZero
654*042d53a7SEvalZero BT_INFO("Initializing...");
655*042d53a7SEvalZero
656*042d53a7SEvalZero /* Initialize the button debouncer */
657*042d53a7SEvalZero last_time = k_uptime_get_32();
658*042d53a7SEvalZero
659*042d53a7SEvalZero /* Initialize button worker task*/
660*042d53a7SEvalZero k_work_init(&sw.button_work, button_pressed_worker);
661*042d53a7SEvalZero k_work_add_arg(&sw.button_work, &sw);
662*042d53a7SEvalZero
663*042d53a7SEvalZero /* Initialize button count timer */
664*042d53a7SEvalZero k_delayed_work_init(&sw.button_timer, button_cnt_timer);
665*042d53a7SEvalZero k_delayed_work_add_arg(&sw.button_timer, &sw);
666*042d53a7SEvalZero
667*042d53a7SEvalZero /* Initialize LED's */
668*042d53a7SEvalZero init_led(0);
669*042d53a7SEvalZero init_led(1);
670*042d53a7SEvalZero init_led(2);
671*042d53a7SEvalZero init_led(3);
672*042d53a7SEvalZero
673*042d53a7SEvalZero init_button(BUTTON_1);
674*042d53a7SEvalZero init_button(BUTTON_2);
675*042d53a7SEvalZero init_button(BUTTON_3);
676*042d53a7SEvalZero init_button(BUTTON_4);
677*042d53a7SEvalZero
678*042d53a7SEvalZero init_pub();
679*042d53a7SEvalZero
680*042d53a7SEvalZero /* Initialize the NimBLE host configuration. */
681*042d53a7SEvalZero ble_hs_cfg.reset_cb = blemesh_on_reset;
682*042d53a7SEvalZero ble_hs_cfg.sync_cb = blemesh_on_sync;
683*042d53a7SEvalZero ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
684*042d53a7SEvalZero
685*042d53a7SEvalZero while (1) {
686*042d53a7SEvalZero os_eventq_run(os_eventq_dflt_get());
687*042d53a7SEvalZero }
688*042d53a7SEvalZero
689*042d53a7SEvalZero return 0;
690*042d53a7SEvalZero }
691