• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }