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