1 /* Bluetooth Mesh */
2
3 /*
4 * Copyright (c) 2017 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <ble_os.h>
10 #include <string.h>
11 #include <bt_errno.h>
12 #include <stdbool.h>
13 #include <ble_types/types.h>
14 #include <misc/byteorder.h>
15 #include <misc/util.h>
16
17 #include <bluetooth/bluetooth.h>
18 #include <api/mesh.h>
19
20 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_MODEL)
21
22
23 #include "common/log.h"
24
25 #include "mesh.h"
26 #include "adv.h"
27 #include "net.h"
28 #include "ble_transport.h"
29 #include "access.h"
30 #include "foundation.h"
31
32 #define HEALTH_TEST_STANDARD 0x00
33
34 /* Health Server context of the primary element */
35 struct bt_mesh_health_srv *health_srv;
36
37 struct bt_mesh_model_pub g_health_pub = {
38 .msg = NET_BUF_SIMPLE(1 + 3 + 0),
39 };
40
41 struct bt_mesh_health_srv g_health_srv;
42
health_get_registered(struct bt_mesh_model * mod,u16_t company_id,struct net_buf_simple * msg)43 static void health_get_registered(struct bt_mesh_model *mod,
44 u16_t company_id,
45 struct net_buf_simple *msg)
46 {
47 struct bt_mesh_health_srv *srv = mod->user_data;
48 u8_t *test_id;
49
50 BT_DBG("Company ID 0x%04x", company_id);
51
52 bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_STATUS);
53
54 test_id = net_buf_simple_add(msg, 1);
55 net_buf_simple_add_le16(msg, company_id);
56
57 if (srv->cb && srv->cb->fault_get_reg) {
58 u8_t fault_count = net_buf_simple_tailroom(msg) - 4;
59 int err;
60
61 err = srv->cb->fault_get_reg(mod, company_id, test_id,
62 net_buf_simple_tail(msg),
63 &fault_count);
64 if (err) {
65 BT_ERR("Failed to get faults (err %d)", err);
66 *test_id = HEALTH_TEST_STANDARD;
67 } else {
68 net_buf_simple_add(msg, fault_count);
69 }
70 } else {
71 BT_WARN("No callback for getting faults");
72 *test_id = HEALTH_TEST_STANDARD;
73 }
74 }
75
health_get_current(struct bt_mesh_model * mod,struct net_buf_simple * msg)76 static size_t health_get_current(struct bt_mesh_model *mod,
77 struct net_buf_simple *msg)
78 {
79 struct bt_mesh_health_srv *srv = mod->user_data;
80 const struct bt_mesh_comp *comp;
81 u8_t *test_id, *company_ptr;
82 u16_t company_id;
83 u8_t fault_count;
84 int err;
85
86 bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS);
87
88 test_id = net_buf_simple_add(msg, 1);
89 company_ptr = net_buf_simple_add(msg, sizeof(company_id));
90 comp = bt_mesh_comp_get();
91
92 if (srv->cb && srv->cb->fault_get_cur) {
93 fault_count = net_buf_simple_tailroom(msg);
94 err = srv->cb->fault_get_cur(mod, test_id, &company_id,
95 net_buf_simple_tail(msg),
96 &fault_count);
97 if (err) {
98 BT_ERR("Failed to get faults (err %d)", err);
99 sys_put_le16(comp->cid, company_ptr);
100 *test_id = HEALTH_TEST_STANDARD;
101 fault_count = 0;
102 } else {
103 sys_put_le16(company_id, company_ptr);
104 net_buf_simple_add(msg, fault_count);
105 }
106 } else {
107 BT_WARN("No callback for getting faults");
108 sys_put_le16(comp->cid, company_ptr);
109 *test_id = HEALTH_TEST_STANDARD;
110 fault_count = 0;
111 }
112
113 return fault_count;
114 }
115
health_fault_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)116 static void health_fault_get(struct bt_mesh_model *model,
117 struct bt_mesh_msg_ctx *ctx,
118 struct net_buf_simple *buf)
119 {
120 NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX);
121 u16_t company_id;
122
123 company_id = net_buf_simple_pull_le16(buf);
124
125 BT_DBG("company_id 0x%04x", company_id);
126
127 health_get_registered(model, company_id, &sdu);
128
129 if (bt_mesh_model_send(model, ctx, &sdu, NULL, NULL)) {
130 BT_ERR("Unable to send Health Current Status response");
131 }
132 }
133
health_fault_clear_unrel(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)134 static void health_fault_clear_unrel(struct bt_mesh_model *model,
135 struct bt_mesh_msg_ctx *ctx,
136 struct net_buf_simple *buf)
137 {
138 struct bt_mesh_health_srv *srv = model->user_data;
139 u16_t company_id;
140
141 company_id = net_buf_simple_pull_le16(buf);
142
143 BT_DBG("company_id 0x%04x", company_id);
144
145 if (srv->cb && srv->cb->fault_clear) {
146 srv->cb->fault_clear(model, company_id);
147 }
148 }
149
health_fault_clear(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)150 static void health_fault_clear(struct bt_mesh_model *model,
151 struct bt_mesh_msg_ctx *ctx,
152 struct net_buf_simple *buf)
153 {
154 NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX);
155 struct bt_mesh_health_srv *srv = model->user_data;
156 u16_t company_id;
157
158 company_id = net_buf_simple_pull_le16(buf);
159
160 BT_DBG("company_id 0x%04x", company_id);
161
162 if (srv->cb && srv->cb->fault_clear) {
163 srv->cb->fault_clear(model, company_id);
164 }
165
166 health_get_registered(model, company_id, &sdu);
167
168 if (bt_mesh_model_send(model, ctx, &sdu, NULL, NULL)) {
169 BT_ERR("Unable to send Health Current Status response");
170 }
171 }
172
health_fault_test_unrel(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)173 static void health_fault_test_unrel(struct bt_mesh_model *model,
174 struct bt_mesh_msg_ctx *ctx,
175 struct net_buf_simple *buf)
176 {
177 struct bt_mesh_health_srv *srv = model->user_data;
178 u16_t company_id;
179 u8_t test_id;
180
181 test_id = net_buf_simple_pull_u8(buf);
182 company_id = net_buf_simple_pull_le16(buf);
183
184 BT_DBG("test 0x%02x company 0x%04x", test_id, company_id);
185
186 if (srv->cb && srv->cb->fault_test) {
187 srv->cb->fault_test(model, test_id, company_id);
188 }
189 }
190
health_fault_test(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)191 static void health_fault_test(struct bt_mesh_model *model,
192 struct bt_mesh_msg_ctx *ctx,
193 struct net_buf_simple *buf)
194 {
195 NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX);
196 struct bt_mesh_health_srv *srv = model->user_data;
197 u16_t company_id;
198 u8_t test_id;
199
200 BT_DBG("");
201
202 test_id = net_buf_simple_pull_u8(buf);
203 company_id = net_buf_simple_pull_le16(buf);
204
205 BT_DBG("test 0x%02x company 0x%04x", test_id, company_id);
206
207 if (srv->cb && srv->cb->fault_test) {
208 int err;
209
210 err = srv->cb->fault_test(model, test_id, company_id);
211 if (err) {
212 BT_WARN("Running fault test failed with err %d", err);
213 return;
214 }
215 }
216
217 health_get_registered(model, company_id, &sdu);
218
219 if (bt_mesh_model_send(model, ctx, &sdu, NULL, NULL)) {
220 BT_ERR("Unable to send Health Current Status response");
221 }
222 }
223
send_attention_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx)224 static void send_attention_status(struct bt_mesh_model *model,
225 struct bt_mesh_msg_ctx *ctx)
226 {
227 /* Needed size: opcode (2 bytes) + msg + MIC */
228 NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4);
229 struct bt_mesh_health_srv *srv = model->user_data;
230 u8_t time;
231
232 time = k_delayed_work_remaining_get(&srv->attn_timer) / 1000;
233 BT_DBG("%u second%s", time, (time == 1) ? "" : "s");
234
235 bt_mesh_model_msg_init(&msg, OP_ATTENTION_STATUS);
236
237 net_buf_simple_add_u8(&msg, time);
238
239 if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
240 BT_ERR("Unable to send Attention Status");
241 }
242 }
243
attention_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)244 static void attention_get(struct bt_mesh_model *model,
245 struct bt_mesh_msg_ctx *ctx,
246 struct net_buf_simple *buf)
247 {
248 BT_DBG("");
249
250 send_attention_status(model, ctx);
251 }
252
attention_set_unrel(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)253 static void attention_set_unrel(struct bt_mesh_model *model,
254 struct bt_mesh_msg_ctx *ctx,
255 struct net_buf_simple *buf)
256 {
257 u8_t time;
258
259 time = net_buf_simple_pull_u8(buf);
260
261 BT_DBG("%u second%s", time, (time == 1) ? "" : "s");
262
263 bt_mesh_attention(model, time);
264 }
265
attention_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)266 static void attention_set(struct bt_mesh_model *model,
267 struct bt_mesh_msg_ctx *ctx,
268 struct net_buf_simple *buf)
269 {
270 BT_DBG("");
271
272 attention_set_unrel(model, ctx, buf);
273
274 send_attention_status(model, ctx);
275 }
276
send_health_period_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx)277 static void send_health_period_status(struct bt_mesh_model *model,
278 struct bt_mesh_msg_ctx *ctx)
279 {
280 /* Needed size: opcode (2 bytes) + msg + MIC */
281 NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4);
282
283 bt_mesh_model_msg_init(&msg, OP_HEALTH_PERIOD_STATUS);
284
285 net_buf_simple_add_u8(&msg, model->pub->period_div);
286
287 if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
288 BT_ERR("Unable to send Health Period Status");
289 }
290 }
291
health_period_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)292 static void health_period_get(struct bt_mesh_model *model,
293 struct bt_mesh_msg_ctx *ctx,
294 struct net_buf_simple *buf)
295 {
296 BT_DBG("");
297
298 send_health_period_status(model, ctx);
299 }
300
health_period_set_unrel(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)301 static void health_period_set_unrel(struct bt_mesh_model *model,
302 struct bt_mesh_msg_ctx *ctx,
303 struct net_buf_simple *buf)
304 {
305 u8_t period;
306
307 period = net_buf_simple_pull_u8(buf);
308 if (period > 15) {
309 BT_WARN("Prohibited period value %u", period);
310 return;
311 }
312
313 BT_DBG("period %u", period);
314 if(0 != period){
315 model->pub->fast_period = 1;
316 }
317 model->pub->period_div = period;
318 }
319
health_period_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)320 static void health_period_set(struct bt_mesh_model *model,
321 struct bt_mesh_msg_ctx *ctx,
322 struct net_buf_simple *buf)
323 {
324 BT_DBG("");
325
326 health_period_set_unrel(model, ctx, buf);
327
328 send_health_period_status(model, ctx);
329 }
330
331 const struct bt_mesh_model_op bt_mesh_health_srv_op[] = {
332 { OP_HEALTH_FAULT_GET, 2, health_fault_get },
333 { OP_HEALTH_FAULT_CLEAR, 2, health_fault_clear },
334 { OP_HEALTH_FAULT_CLEAR_UNREL, 2, health_fault_clear_unrel },
335 { OP_HEALTH_FAULT_TEST, 3, health_fault_test },
336 { OP_HEALTH_FAULT_TEST_UNREL, 3, health_fault_test_unrel },
337 { OP_HEALTH_PERIOD_GET, 0, health_period_get },
338 { OP_HEALTH_PERIOD_SET, 1, health_period_set },
339 { OP_HEALTH_PERIOD_SET_UNREL, 1, health_period_set_unrel },
340 { OP_ATTENTION_GET, 0, attention_get },
341 { OP_ATTENTION_SET, 1, attention_set },
342 { OP_ATTENTION_SET_UNREL, 1, attention_set_unrel },
343 BT_MESH_MODEL_OP_END,
344 };
345
health_pub_update(struct bt_mesh_model * mod)346 static int health_pub_update(struct bt_mesh_model *mod)
347 {
348 struct bt_mesh_model_pub *pub = mod->pub;
349 size_t count;
350
351 BT_DBG("");
352
353 count = health_get_current(mod, pub->msg);
354 if (!count) {
355 pub->period_div = 0;
356 }
357
358 return 0;
359 }
360
bt_mesh_fault_update(struct bt_mesh_elem * elem)361 int bt_mesh_fault_update(struct bt_mesh_elem *elem)
362 {
363 struct bt_mesh_model *mod;
364
365 if (!elem) {
366 return -EINVAL;
367 }
368
369 mod = bt_mesh_model_find(elem, BT_MESH_MODEL_ID_HEALTH_SRV);
370 if (!mod) {
371 return -EINVAL;
372 }
373
374 /* Let periodic publishing, if enabled, take care of sending the
375 * Health Current Status.
376 */
377 if (bt_mesh_model_pub_period_get(mod)) {
378 return 0;
379 }
380
381 health_pub_update(mod);
382
383 return bt_mesh_model_publish(mod);
384 }
385
attention_off(struct k_work * work)386 static void attention_off(struct k_work *work)
387 {
388 struct bt_mesh_health_srv *srv = CONTAINER_OF(work,
389 struct bt_mesh_health_srv,
390 attn_timer.work);
391 BT_DBG("");
392 if (srv->cb && srv->cb->attn_off) {
393 srv->cb->attn_off(srv->model);
394 }
395 }
396
bt_mesh_health_srv_init(struct bt_mesh_model * model,bool primary)397 int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary)
398 {
399 struct bt_mesh_health_srv *srv = model->user_data;
400
401 if (!srv) {
402 if (!primary) {
403 return 0;
404 }
405
406 BT_ERR("No Health Server context provided");
407 return -EINVAL;
408 }
409
410 if (!model->pub) {
411 BT_ERR("Health Server has no publication support");
412 return -EINVAL;
413 }
414
415 model->pub->update = health_pub_update;
416
417 k_delayed_work_init(&srv->attn_timer, attention_off);
418
419 srv->model = model;
420
421 if (primary) {
422 health_srv = srv;
423 }
424
425 return 0;
426 }
427
bt_mesh_attention(struct bt_mesh_model * model,u8_t time)428 void bt_mesh_attention(struct bt_mesh_model *model, u8_t time)
429 {
430 if(0 == time) {
431 BT_DBG("reset attention timer");
432 }
433 struct bt_mesh_health_srv *srv;
434
435 if (!model) {
436 srv = health_srv;
437 if (!srv) {
438 BT_WARN("No Health Server available");
439 return;
440 }
441
442 model = srv->model;
443 } else {
444 srv = model->user_data;
445 }
446
447 if (time) {
448 if (srv->cb && srv->cb->attn_on) {
449 srv->cb->attn_on(model);
450 }
451
452 k_delayed_work_submit(&srv->attn_timer, time * 1000);
453 } else {
454 k_delayed_work_cancel(&srv->attn_timer);
455
456 if (srv->cb && srv->cb->attn_off) {
457 srv->cb->attn_off(model);
458 }
459 }
460 }
461
health_srv_cb_register(struct bt_mesh_health_srv_cb * health_cb)462 int health_srv_cb_register(struct bt_mesh_health_srv_cb *health_cb)
463 {
464 if(!health_cb || !health_srv){
465 return -EINVAL;
466 }
467
468 health_srv->cb = health_cb;
469 return 0;
470 }
471