xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/mesh/src/health_cli.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /*  Bluetooth Mesh */
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 #include <string.h>
10*042d53a7SEvalZero #include <errno.h>
11*042d53a7SEvalZero #include <stdbool.h>
12*042d53a7SEvalZero 
13*042d53a7SEvalZero #include "syscfg/syscfg.h"
14*042d53a7SEvalZero #define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_MODEL))
15*042d53a7SEvalZero #include "host/ble_hs_log.h"
16*042d53a7SEvalZero 
17*042d53a7SEvalZero #include "mesh/mesh.h"
18*042d53a7SEvalZero #include "mesh_priv.h"
19*042d53a7SEvalZero #include "adv.h"
20*042d53a7SEvalZero #include "net.h"
21*042d53a7SEvalZero #include "transport.h"
22*042d53a7SEvalZero #include "foundation.h"
23*042d53a7SEvalZero #include "mesh/health_cli.h"
24*042d53a7SEvalZero 
25*042d53a7SEvalZero static s32_t msg_timeout = K_SECONDS(5);
26*042d53a7SEvalZero 
27*042d53a7SEvalZero static struct bt_mesh_health_cli *health_cli;
28*042d53a7SEvalZero 
29*042d53a7SEvalZero struct health_fault_param {
30*042d53a7SEvalZero 	u16_t   cid;
31*042d53a7SEvalZero 	u8_t   *expect_test_id;
32*042d53a7SEvalZero 	u8_t   *test_id;
33*042d53a7SEvalZero 	u8_t   *faults;
34*042d53a7SEvalZero 	size_t *fault_count;
35*042d53a7SEvalZero };
36*042d53a7SEvalZero 
health_fault_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)37*042d53a7SEvalZero static void health_fault_status(struct bt_mesh_model *model,
38*042d53a7SEvalZero 				struct bt_mesh_msg_ctx *ctx,
39*042d53a7SEvalZero 				struct os_mbuf *buf)
40*042d53a7SEvalZero {
41*042d53a7SEvalZero 	struct health_fault_param *param;
42*042d53a7SEvalZero 	u8_t test_id;
43*042d53a7SEvalZero 	u16_t cid;
44*042d53a7SEvalZero 
45*042d53a7SEvalZero 	BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
46*042d53a7SEvalZero 	       ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
47*042d53a7SEvalZero 	       bt_hex(buf->om_data, buf->om_len));
48*042d53a7SEvalZero 
49*042d53a7SEvalZero 	if (health_cli->op_pending != OP_HEALTH_FAULT_STATUS) {
50*042d53a7SEvalZero 		BT_WARN("Unexpected Health Fault Status message");
51*042d53a7SEvalZero 		return;
52*042d53a7SEvalZero 	}
53*042d53a7SEvalZero 
54*042d53a7SEvalZero 	param = health_cli->op_param;
55*042d53a7SEvalZero 
56*042d53a7SEvalZero 	test_id = net_buf_simple_pull_u8(buf);
57*042d53a7SEvalZero 	if (param->expect_test_id && test_id != *param->expect_test_id) {
58*042d53a7SEvalZero 		BT_WARN("Health fault with unexpected Test ID");
59*042d53a7SEvalZero 		return;
60*042d53a7SEvalZero 	}
61*042d53a7SEvalZero 
62*042d53a7SEvalZero 	cid = net_buf_simple_pull_le16(buf);
63*042d53a7SEvalZero 	if (cid != param->cid) {
64*042d53a7SEvalZero 		BT_WARN("Health fault with unexpected Company ID");
65*042d53a7SEvalZero 		return;
66*042d53a7SEvalZero 	}
67*042d53a7SEvalZero 
68*042d53a7SEvalZero 	if (param->test_id) {
69*042d53a7SEvalZero 		*param->test_id = test_id;
70*042d53a7SEvalZero 	}
71*042d53a7SEvalZero 
72*042d53a7SEvalZero 	if (buf->om_len > *param->fault_count) {
73*042d53a7SEvalZero 		BT_WARN("Got more faults than there's space for");
74*042d53a7SEvalZero 	} else {
75*042d53a7SEvalZero 		*param->fault_count = buf->om_len;
76*042d53a7SEvalZero 	}
77*042d53a7SEvalZero 
78*042d53a7SEvalZero 	memcpy(param->faults, buf->om_data, *param->fault_count);
79*042d53a7SEvalZero 
80*042d53a7SEvalZero 	k_sem_give(&health_cli->op_sync);
81*042d53a7SEvalZero }
82*042d53a7SEvalZero 
health_current_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)83*042d53a7SEvalZero static void health_current_status(struct bt_mesh_model *model,
84*042d53a7SEvalZero 				  struct bt_mesh_msg_ctx *ctx,
85*042d53a7SEvalZero 				  struct os_mbuf *buf)
86*042d53a7SEvalZero {
87*042d53a7SEvalZero 	struct bt_mesh_health_cli *cli = model->user_data;
88*042d53a7SEvalZero 	u8_t test_id;
89*042d53a7SEvalZero 	u16_t cid;
90*042d53a7SEvalZero 
91*042d53a7SEvalZero 	BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
92*042d53a7SEvalZero 	       ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
93*042d53a7SEvalZero 	       bt_hex(buf->om_data, buf->om_len));
94*042d53a7SEvalZero 
95*042d53a7SEvalZero 	test_id = net_buf_simple_pull_u8(buf);
96*042d53a7SEvalZero 	cid = net_buf_simple_pull_le16(buf);
97*042d53a7SEvalZero 
98*042d53a7SEvalZero 	BT_DBG("Test ID 0x%02x Company ID 0x%04x Fault Count %u",
99*042d53a7SEvalZero 	       test_id, cid, buf->om_len);
100*042d53a7SEvalZero 
101*042d53a7SEvalZero 	if (!cli->current_status) {
102*042d53a7SEvalZero 		BT_WARN("No Current Status callback available");
103*042d53a7SEvalZero 		return;
104*042d53a7SEvalZero 	}
105*042d53a7SEvalZero 
106*042d53a7SEvalZero 	cli->current_status(cli, ctx->addr, test_id, cid, buf->om_data, buf->om_len);
107*042d53a7SEvalZero }
108*042d53a7SEvalZero 
109*042d53a7SEvalZero struct health_period_param {
110*042d53a7SEvalZero 	u8_t *divisor;
111*042d53a7SEvalZero };
112*042d53a7SEvalZero 
health_period_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)113*042d53a7SEvalZero static void health_period_status(struct bt_mesh_model *model,
114*042d53a7SEvalZero 				 struct bt_mesh_msg_ctx *ctx,
115*042d53a7SEvalZero 				 struct os_mbuf *buf)
116*042d53a7SEvalZero {
117*042d53a7SEvalZero 	struct health_period_param *param;
118*042d53a7SEvalZero 
119*042d53a7SEvalZero 	BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
120*042d53a7SEvalZero 	       ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
121*042d53a7SEvalZero 	       bt_hex(buf->om_data, buf->om_len));
122*042d53a7SEvalZero 
123*042d53a7SEvalZero 	if (health_cli->op_pending != OP_HEALTH_PERIOD_STATUS) {
124*042d53a7SEvalZero 		BT_WARN("Unexpected Health Period Status message");
125*042d53a7SEvalZero 		return;
126*042d53a7SEvalZero 	}
127*042d53a7SEvalZero 
128*042d53a7SEvalZero 	param = health_cli->op_param;
129*042d53a7SEvalZero 
130*042d53a7SEvalZero 	*param->divisor = net_buf_simple_pull_u8(buf);
131*042d53a7SEvalZero 
132*042d53a7SEvalZero 	k_sem_give(&health_cli->op_sync);
133*042d53a7SEvalZero }
134*042d53a7SEvalZero 
135*042d53a7SEvalZero struct health_attention_param {
136*042d53a7SEvalZero 	u8_t *attention;
137*042d53a7SEvalZero };
138*042d53a7SEvalZero 
health_attention_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)139*042d53a7SEvalZero static void health_attention_status(struct bt_mesh_model *model,
140*042d53a7SEvalZero 				    struct bt_mesh_msg_ctx *ctx,
141*042d53a7SEvalZero 				    struct os_mbuf *buf)
142*042d53a7SEvalZero {
143*042d53a7SEvalZero 	struct health_attention_param *param;
144*042d53a7SEvalZero 
145*042d53a7SEvalZero 	BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
146*042d53a7SEvalZero 	       ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
147*042d53a7SEvalZero 	       bt_hex(buf->om_data, buf->om_len));
148*042d53a7SEvalZero 
149*042d53a7SEvalZero 	if (health_cli->op_pending != OP_ATTENTION_STATUS) {
150*042d53a7SEvalZero 		BT_WARN("Unexpected Health Attention Status message");
151*042d53a7SEvalZero 		return;
152*042d53a7SEvalZero 	}
153*042d53a7SEvalZero 
154*042d53a7SEvalZero 	param = health_cli->op_param;
155*042d53a7SEvalZero 
156*042d53a7SEvalZero 	if (param->attention) {
157*042d53a7SEvalZero 		*param->attention = net_buf_simple_pull_u8(buf);
158*042d53a7SEvalZero 	}
159*042d53a7SEvalZero 
160*042d53a7SEvalZero 	k_sem_give(&health_cli->op_sync);
161*042d53a7SEvalZero }
162*042d53a7SEvalZero 
163*042d53a7SEvalZero const struct bt_mesh_model_op bt_mesh_health_cli_op[] = {
164*042d53a7SEvalZero 	{ OP_HEALTH_FAULT_STATUS,    3,   health_fault_status },
165*042d53a7SEvalZero 	{ OP_HEALTH_CURRENT_STATUS,  3,   health_current_status },
166*042d53a7SEvalZero 	{ OP_HEALTH_PERIOD_STATUS,   1,   health_period_status },
167*042d53a7SEvalZero 	{ OP_ATTENTION_STATUS,       1,   health_attention_status },
168*042d53a7SEvalZero 	BT_MESH_MODEL_OP_END,
169*042d53a7SEvalZero };
170*042d53a7SEvalZero 
cli_prepare(void * param,u32_t op)171*042d53a7SEvalZero static int cli_prepare(void *param, u32_t op)
172*042d53a7SEvalZero {
173*042d53a7SEvalZero 	if (!health_cli) {
174*042d53a7SEvalZero 		BT_ERR("No available Health Client context!");
175*042d53a7SEvalZero 		return -EINVAL;
176*042d53a7SEvalZero 	}
177*042d53a7SEvalZero 
178*042d53a7SEvalZero 	if (health_cli->op_pending) {
179*042d53a7SEvalZero 		BT_WARN("Another synchronous operation pending");
180*042d53a7SEvalZero 		return -EBUSY;
181*042d53a7SEvalZero 	}
182*042d53a7SEvalZero 
183*042d53a7SEvalZero 	health_cli->op_param = param;
184*042d53a7SEvalZero 	health_cli->op_pending = op;
185*042d53a7SEvalZero 
186*042d53a7SEvalZero 	return 0;
187*042d53a7SEvalZero }
188*042d53a7SEvalZero 
cli_reset(void)189*042d53a7SEvalZero static void cli_reset(void)
190*042d53a7SEvalZero {
191*042d53a7SEvalZero 	health_cli->op_pending = 0;
192*042d53a7SEvalZero 	health_cli->op_param = NULL;
193*042d53a7SEvalZero }
194*042d53a7SEvalZero 
cli_wait(void)195*042d53a7SEvalZero static int cli_wait(void)
196*042d53a7SEvalZero {
197*042d53a7SEvalZero 	int err;
198*042d53a7SEvalZero 
199*042d53a7SEvalZero 	err = k_sem_take(&health_cli->op_sync, msg_timeout);
200*042d53a7SEvalZero 
201*042d53a7SEvalZero 	cli_reset();
202*042d53a7SEvalZero 
203*042d53a7SEvalZero 	return err;
204*042d53a7SEvalZero }
205*042d53a7SEvalZero 
bt_mesh_health_attention_get(u16_t net_idx,u16_t addr,u16_t app_idx,u8_t * attention)206*042d53a7SEvalZero int bt_mesh_health_attention_get(u16_t net_idx, u16_t addr, u16_t app_idx,
207*042d53a7SEvalZero 				 u8_t *attention)
208*042d53a7SEvalZero {
209*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
210*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
211*042d53a7SEvalZero 		.net_idx = net_idx,
212*042d53a7SEvalZero 		.app_idx = app_idx,
213*042d53a7SEvalZero 		.addr = addr,
214*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
215*042d53a7SEvalZero 	};
216*042d53a7SEvalZero 	struct health_attention_param param = {
217*042d53a7SEvalZero 		.attention = attention,
218*042d53a7SEvalZero 	};
219*042d53a7SEvalZero 	int err;
220*042d53a7SEvalZero 
221*042d53a7SEvalZero 	err = cli_prepare(&param, OP_ATTENTION_STATUS);
222*042d53a7SEvalZero 	if (err) {
223*042d53a7SEvalZero 		goto done;
224*042d53a7SEvalZero 	}
225*042d53a7SEvalZero 
226*042d53a7SEvalZero 	bt_mesh_model_msg_init(msg, OP_ATTENTION_GET);
227*042d53a7SEvalZero 
228*042d53a7SEvalZero 	err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
229*042d53a7SEvalZero 	if (err) {
230*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
231*042d53a7SEvalZero 		cli_reset();
232*042d53a7SEvalZero 		goto done;
233*042d53a7SEvalZero 	}
234*042d53a7SEvalZero 
235*042d53a7SEvalZero 	err = cli_wait();
236*042d53a7SEvalZero done:
237*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
238*042d53a7SEvalZero 	return err;
239*042d53a7SEvalZero }
240*042d53a7SEvalZero 
bt_mesh_health_attention_set(u16_t net_idx,u16_t addr,u16_t app_idx,u8_t attention,u8_t * updated_attention)241*042d53a7SEvalZero int bt_mesh_health_attention_set(u16_t net_idx, u16_t addr, u16_t app_idx,
242*042d53a7SEvalZero 				 u8_t attention, u8_t *updated_attention)
243*042d53a7SEvalZero {
244*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
245*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
246*042d53a7SEvalZero 		.net_idx = net_idx,
247*042d53a7SEvalZero 		.app_idx = app_idx,
248*042d53a7SEvalZero 		.addr = addr,
249*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
250*042d53a7SEvalZero 	};
251*042d53a7SEvalZero 	struct health_attention_param param = {
252*042d53a7SEvalZero 		.attention = updated_attention,
253*042d53a7SEvalZero 	};
254*042d53a7SEvalZero 	int err;
255*042d53a7SEvalZero 
256*042d53a7SEvalZero 	err = cli_prepare(&param, OP_ATTENTION_STATUS);
257*042d53a7SEvalZero 	if (err) {
258*042d53a7SEvalZero 		goto done;
259*042d53a7SEvalZero 	}
260*042d53a7SEvalZero 
261*042d53a7SEvalZero 	if (updated_attention) {
262*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_ATTENTION_SET);
263*042d53a7SEvalZero 	} else {
264*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_ATTENTION_SET_UNREL);
265*042d53a7SEvalZero 	}
266*042d53a7SEvalZero 
267*042d53a7SEvalZero 	net_buf_simple_add_u8(msg, attention);
268*042d53a7SEvalZero 
269*042d53a7SEvalZero 	err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
270*042d53a7SEvalZero 	if (err) {
271*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
272*042d53a7SEvalZero 		cli_reset();
273*042d53a7SEvalZero 		goto done;
274*042d53a7SEvalZero 	}
275*042d53a7SEvalZero 
276*042d53a7SEvalZero 	if (!updated_attention) {
277*042d53a7SEvalZero 		cli_reset();
278*042d53a7SEvalZero 		goto done;
279*042d53a7SEvalZero 	}
280*042d53a7SEvalZero 
281*042d53a7SEvalZero 	err = cli_wait();
282*042d53a7SEvalZero done:
283*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
284*042d53a7SEvalZero 	return err;
285*042d53a7SEvalZero }
286*042d53a7SEvalZero 
bt_mesh_health_period_get(u16_t net_idx,u16_t addr,u16_t app_idx,u8_t * divisor)287*042d53a7SEvalZero int bt_mesh_health_period_get(u16_t net_idx, u16_t addr, u16_t app_idx,
288*042d53a7SEvalZero 			      u8_t *divisor)
289*042d53a7SEvalZero {
290*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
291*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
292*042d53a7SEvalZero 		.net_idx = net_idx,
293*042d53a7SEvalZero 		.app_idx = app_idx,
294*042d53a7SEvalZero 		.addr = addr,
295*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
296*042d53a7SEvalZero 	};
297*042d53a7SEvalZero 	struct health_period_param param = {
298*042d53a7SEvalZero 		.divisor = divisor,
299*042d53a7SEvalZero 	};
300*042d53a7SEvalZero 	int err;
301*042d53a7SEvalZero 
302*042d53a7SEvalZero 	err = cli_prepare(&param, OP_HEALTH_PERIOD_STATUS);
303*042d53a7SEvalZero 	if (err) {
304*042d53a7SEvalZero 		goto done;
305*042d53a7SEvalZero 	}
306*042d53a7SEvalZero 
307*042d53a7SEvalZero 	bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_GET);
308*042d53a7SEvalZero 
309*042d53a7SEvalZero 	err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
310*042d53a7SEvalZero 	if (err) {
311*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
312*042d53a7SEvalZero 		cli_reset();
313*042d53a7SEvalZero 		goto done;
314*042d53a7SEvalZero 	}
315*042d53a7SEvalZero 
316*042d53a7SEvalZero 	err = cli_wait();
317*042d53a7SEvalZero done:
318*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
319*042d53a7SEvalZero 	return err;
320*042d53a7SEvalZero }
321*042d53a7SEvalZero 
bt_mesh_health_period_set(u16_t net_idx,u16_t addr,u16_t app_idx,u8_t divisor,u8_t * updated_divisor)322*042d53a7SEvalZero int bt_mesh_health_period_set(u16_t net_idx, u16_t addr, u16_t app_idx,
323*042d53a7SEvalZero 			      u8_t divisor, u8_t *updated_divisor)
324*042d53a7SEvalZero {
325*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
326*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
327*042d53a7SEvalZero 		.net_idx = net_idx,
328*042d53a7SEvalZero 		.app_idx = app_idx,
329*042d53a7SEvalZero 		.addr = addr,
330*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
331*042d53a7SEvalZero 	};
332*042d53a7SEvalZero 	struct health_period_param param = {
333*042d53a7SEvalZero 		.divisor = updated_divisor,
334*042d53a7SEvalZero 	};
335*042d53a7SEvalZero 	int err;
336*042d53a7SEvalZero 
337*042d53a7SEvalZero 	err = cli_prepare(&param, OP_HEALTH_PERIOD_STATUS);
338*042d53a7SEvalZero 	if (err) {
339*042d53a7SEvalZero 		goto done;
340*042d53a7SEvalZero 	}
341*042d53a7SEvalZero 
342*042d53a7SEvalZero 	if (updated_divisor) {
343*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_SET);
344*042d53a7SEvalZero 	} else {
345*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_SET_UNREL);
346*042d53a7SEvalZero 	}
347*042d53a7SEvalZero 
348*042d53a7SEvalZero 	net_buf_simple_add_u8(msg, divisor);
349*042d53a7SEvalZero 
350*042d53a7SEvalZero 	err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
351*042d53a7SEvalZero 	if (err) {
352*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
353*042d53a7SEvalZero 		cli_reset();
354*042d53a7SEvalZero 		goto done;
355*042d53a7SEvalZero 	}
356*042d53a7SEvalZero 
357*042d53a7SEvalZero 	if (!updated_divisor) {
358*042d53a7SEvalZero 		cli_reset();
359*042d53a7SEvalZero 		goto done;
360*042d53a7SEvalZero 	}
361*042d53a7SEvalZero 
362*042d53a7SEvalZero 	err = cli_wait();
363*042d53a7SEvalZero done:
364*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
365*042d53a7SEvalZero 	return err;
366*042d53a7SEvalZero }
367*042d53a7SEvalZero 
bt_mesh_health_fault_test(u16_t net_idx,u16_t addr,u16_t app_idx,u16_t cid,u8_t test_id,u8_t * faults,size_t * fault_count)368*042d53a7SEvalZero int bt_mesh_health_fault_test(u16_t net_idx, u16_t addr, u16_t app_idx,
369*042d53a7SEvalZero 			      u16_t cid, u8_t test_id, u8_t *faults,
370*042d53a7SEvalZero 			      size_t *fault_count)
371*042d53a7SEvalZero {
372*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 3 + 4);
373*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
374*042d53a7SEvalZero 		.net_idx = net_idx,
375*042d53a7SEvalZero 		.app_idx = app_idx,
376*042d53a7SEvalZero 		.addr = addr,
377*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
378*042d53a7SEvalZero 	};
379*042d53a7SEvalZero 	struct health_fault_param param = {
380*042d53a7SEvalZero 		.cid = cid,
381*042d53a7SEvalZero 		.expect_test_id = &test_id,
382*042d53a7SEvalZero 		.faults = faults,
383*042d53a7SEvalZero 		.fault_count = fault_count,
384*042d53a7SEvalZero 	};
385*042d53a7SEvalZero 	int err;
386*042d53a7SEvalZero 
387*042d53a7SEvalZero 	err = cli_prepare(&param, OP_HEALTH_FAULT_STATUS);
388*042d53a7SEvalZero 	if (err) {
389*042d53a7SEvalZero 		goto done;
390*042d53a7SEvalZero 	}
391*042d53a7SEvalZero 
392*042d53a7SEvalZero 	if (faults) {
393*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_TEST);
394*042d53a7SEvalZero 	} else {
395*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_TEST_UNREL);
396*042d53a7SEvalZero 	}
397*042d53a7SEvalZero 
398*042d53a7SEvalZero 	net_buf_simple_add_u8(msg, test_id);
399*042d53a7SEvalZero 	net_buf_simple_add_le16(msg, cid);
400*042d53a7SEvalZero 
401*042d53a7SEvalZero 	err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
402*042d53a7SEvalZero 	if (err) {
403*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
404*042d53a7SEvalZero 		cli_reset();
405*042d53a7SEvalZero 		goto done;
406*042d53a7SEvalZero 	}
407*042d53a7SEvalZero 
408*042d53a7SEvalZero 	if (!faults) {
409*042d53a7SEvalZero 		cli_reset();
410*042d53a7SEvalZero 		goto done;
411*042d53a7SEvalZero 	}
412*042d53a7SEvalZero 
413*042d53a7SEvalZero 	err = cli_wait();
414*042d53a7SEvalZero done:
415*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
416*042d53a7SEvalZero 	return err;
417*042d53a7SEvalZero }
418*042d53a7SEvalZero 
bt_mesh_health_fault_clear(u16_t net_idx,u16_t addr,u16_t app_idx,u16_t cid,u8_t * test_id,u8_t * faults,size_t * fault_count)419*042d53a7SEvalZero int bt_mesh_health_fault_clear(u16_t net_idx, u16_t addr, u16_t app_idx,
420*042d53a7SEvalZero 			       u16_t cid, u8_t *test_id, u8_t *faults,
421*042d53a7SEvalZero 			       size_t *fault_count)
422*042d53a7SEvalZero {
423*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
424*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
425*042d53a7SEvalZero 		.net_idx = net_idx,
426*042d53a7SEvalZero 		.app_idx = app_idx,
427*042d53a7SEvalZero 		.addr = addr,
428*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
429*042d53a7SEvalZero 	};
430*042d53a7SEvalZero 	struct health_fault_param param = {
431*042d53a7SEvalZero 		.cid = cid,
432*042d53a7SEvalZero 		.test_id = test_id,
433*042d53a7SEvalZero 		.faults = faults,
434*042d53a7SEvalZero 		.fault_count = fault_count,
435*042d53a7SEvalZero 	};
436*042d53a7SEvalZero 	int err;
437*042d53a7SEvalZero 
438*042d53a7SEvalZero 	err = cli_prepare(&param, OP_HEALTH_FAULT_STATUS);
439*042d53a7SEvalZero 	if (err) {
440*042d53a7SEvalZero 		goto done;
441*042d53a7SEvalZero 	}
442*042d53a7SEvalZero 
443*042d53a7SEvalZero 	if (test_id) {
444*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_CLEAR);
445*042d53a7SEvalZero 	} else {
446*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_CLEAR_UNREL);
447*042d53a7SEvalZero 	}
448*042d53a7SEvalZero 
449*042d53a7SEvalZero 	net_buf_simple_add_le16(msg, cid);
450*042d53a7SEvalZero 
451*042d53a7SEvalZero 	err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
452*042d53a7SEvalZero 	if (err) {
453*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
454*042d53a7SEvalZero 		cli_reset();
455*042d53a7SEvalZero 		goto done;
456*042d53a7SEvalZero 	}
457*042d53a7SEvalZero 
458*042d53a7SEvalZero 	if (!test_id) {
459*042d53a7SEvalZero 		cli_reset();
460*042d53a7SEvalZero 		goto done;
461*042d53a7SEvalZero 	}
462*042d53a7SEvalZero 
463*042d53a7SEvalZero 	err = cli_wait();
464*042d53a7SEvalZero done:
465*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
466*042d53a7SEvalZero 	return err;
467*042d53a7SEvalZero }
468*042d53a7SEvalZero 
bt_mesh_health_fault_get(u16_t net_idx,u16_t addr,u16_t app_idx,u16_t cid,u8_t * test_id,u8_t * faults,size_t * fault_count)469*042d53a7SEvalZero int bt_mesh_health_fault_get(u16_t net_idx, u16_t addr, u16_t app_idx,
470*042d53a7SEvalZero 			     u16_t cid, u8_t *test_id, u8_t *faults,
471*042d53a7SEvalZero 			     size_t *fault_count)
472*042d53a7SEvalZero {
473*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
474*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
475*042d53a7SEvalZero 		.net_idx = net_idx,
476*042d53a7SEvalZero 		.app_idx = app_idx,
477*042d53a7SEvalZero 		.addr = addr,
478*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
479*042d53a7SEvalZero 	};
480*042d53a7SEvalZero 	struct health_fault_param param = {
481*042d53a7SEvalZero 		.cid = cid,
482*042d53a7SEvalZero 		.test_id = test_id,
483*042d53a7SEvalZero 		.faults = faults,
484*042d53a7SEvalZero 		.fault_count = fault_count,
485*042d53a7SEvalZero 	};
486*042d53a7SEvalZero 	int err;
487*042d53a7SEvalZero 
488*042d53a7SEvalZero 	err = cli_prepare(&param, OP_HEALTH_FAULT_STATUS);
489*042d53a7SEvalZero 	if (err) {
490*042d53a7SEvalZero 		goto done;
491*042d53a7SEvalZero 	}
492*042d53a7SEvalZero 
493*042d53a7SEvalZero 	bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_GET);
494*042d53a7SEvalZero 	net_buf_simple_add_le16(msg, cid);
495*042d53a7SEvalZero 
496*042d53a7SEvalZero 	err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
497*042d53a7SEvalZero 	if (err) {
498*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
499*042d53a7SEvalZero 		cli_reset();
500*042d53a7SEvalZero 		goto done;
501*042d53a7SEvalZero 	}
502*042d53a7SEvalZero 
503*042d53a7SEvalZero 	err = cli_wait();
504*042d53a7SEvalZero done:
505*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
506*042d53a7SEvalZero 	return err;
507*042d53a7SEvalZero }
508*042d53a7SEvalZero 
bt_mesh_health_cli_timeout_get(void)509*042d53a7SEvalZero s32_t bt_mesh_health_cli_timeout_get(void)
510*042d53a7SEvalZero {
511*042d53a7SEvalZero 	return msg_timeout;
512*042d53a7SEvalZero }
513*042d53a7SEvalZero 
bt_mesh_health_cli_timeout_set(s32_t timeout)514*042d53a7SEvalZero void bt_mesh_health_cli_timeout_set(s32_t timeout)
515*042d53a7SEvalZero {
516*042d53a7SEvalZero 	msg_timeout = timeout;
517*042d53a7SEvalZero }
518*042d53a7SEvalZero 
bt_mesh_health_cli_set(struct bt_mesh_model * model)519*042d53a7SEvalZero int bt_mesh_health_cli_set(struct bt_mesh_model *model)
520*042d53a7SEvalZero {
521*042d53a7SEvalZero 	if (!model->user_data) {
522*042d53a7SEvalZero 		BT_ERR("No Health Client context for given model");
523*042d53a7SEvalZero 		return -EINVAL;
524*042d53a7SEvalZero 	}
525*042d53a7SEvalZero 
526*042d53a7SEvalZero 	health_cli = model->user_data;
527*042d53a7SEvalZero 
528*042d53a7SEvalZero 	return 0;
529*042d53a7SEvalZero }
530*042d53a7SEvalZero 
bt_mesh_health_cli_init(struct bt_mesh_model * model,bool primary)531*042d53a7SEvalZero int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary)
532*042d53a7SEvalZero {
533*042d53a7SEvalZero 	struct bt_mesh_health_cli *cli = model->user_data;
534*042d53a7SEvalZero 
535*042d53a7SEvalZero 	BT_DBG("primary %u", primary);
536*042d53a7SEvalZero 
537*042d53a7SEvalZero 	if (!cli) {
538*042d53a7SEvalZero 		BT_ERR("No Health Client context provided");
539*042d53a7SEvalZero 		return -EINVAL;
540*042d53a7SEvalZero 	}
541*042d53a7SEvalZero 
542*042d53a7SEvalZero 	cli = model->user_data;
543*042d53a7SEvalZero 	cli->model = model;
544*042d53a7SEvalZero 
545*042d53a7SEvalZero 	k_sem_init(&cli->op_sync, 0, 1);
546*042d53a7SEvalZero 
547*042d53a7SEvalZero 	/* Set the default health client pointer */
548*042d53a7SEvalZero 	if (!health_cli) {
549*042d53a7SEvalZero 		health_cli = cli;
550*042d53a7SEvalZero 	}
551*042d53a7SEvalZero 
552*042d53a7SEvalZero 	return 0;
553*042d53a7SEvalZero }
554