xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/mesh/src/model_cli.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /*
2*042d53a7SEvalZero  * Copyright (c) 2017 Intel Corporation
3*042d53a7SEvalZero  *
4*042d53a7SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*042d53a7SEvalZero  */
6*042d53a7SEvalZero 
7*042d53a7SEvalZero #include <mesh/mesh.h>
8*042d53a7SEvalZero 
9*042d53a7SEvalZero #define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_MODEL))
10*042d53a7SEvalZero #include "mesh/model_cli.h"
11*042d53a7SEvalZero #include "mesh_priv.h"
12*042d53a7SEvalZero 
13*042d53a7SEvalZero static s32_t msg_timeout = K_SECONDS(5);
14*042d53a7SEvalZero 
15*042d53a7SEvalZero struct bt_mesh_gen_model_cli gen_onoff_cli;
16*042d53a7SEvalZero struct bt_mesh_gen_model_cli gen_level_cli;
17*042d53a7SEvalZero 
18*042d53a7SEvalZero static u8_t transaction_id = 0;
19*042d53a7SEvalZero 
20*042d53a7SEvalZero struct gen_onoff_param {
21*042d53a7SEvalZero     u8_t *state;
22*042d53a7SEvalZero };
23*042d53a7SEvalZero 
24*042d53a7SEvalZero struct gen_level_param {
25*042d53a7SEvalZero     s16_t *level;
26*042d53a7SEvalZero };
27*042d53a7SEvalZero 
gen_onoff_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)28*042d53a7SEvalZero static void gen_onoff_status(struct bt_mesh_model *model,
29*042d53a7SEvalZero 			     struct bt_mesh_msg_ctx *ctx,
30*042d53a7SEvalZero 			     struct os_mbuf *buf)
31*042d53a7SEvalZero {
32*042d53a7SEvalZero 	struct bt_mesh_gen_model_cli *cli = model->user_data;
33*042d53a7SEvalZero 	struct gen_onoff_param *param;
34*042d53a7SEvalZero 	u8_t state;
35*042d53a7SEvalZero 
36*042d53a7SEvalZero 
37*042d53a7SEvalZero 	BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
38*042d53a7SEvalZero 	       ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
39*042d53a7SEvalZero 	       bt_hex(buf->om_data, buf->om_len));
40*042d53a7SEvalZero 
41*042d53a7SEvalZero 	if (cli->op_pending != OP_GEN_ONOFF_STATUS) {
42*042d53a7SEvalZero 		BT_WARN("Unexpected Generic OnOff Status message");
43*042d53a7SEvalZero 		return;
44*042d53a7SEvalZero 	}
45*042d53a7SEvalZero 
46*042d53a7SEvalZero 	param = cli->op_param;
47*042d53a7SEvalZero 
48*042d53a7SEvalZero 	state = net_buf_simple_pull_u8(buf);
49*042d53a7SEvalZero 	if (param->state) {
50*042d53a7SEvalZero 		*param->state = state;
51*042d53a7SEvalZero 	}
52*042d53a7SEvalZero 
53*042d53a7SEvalZero 	BT_DBG("state: %d", state);
54*042d53a7SEvalZero 
55*042d53a7SEvalZero 	transaction_id++;
56*042d53a7SEvalZero 
57*042d53a7SEvalZero 	k_sem_give(&cli->op_sync);
58*042d53a7SEvalZero }
59*042d53a7SEvalZero 
gen_level_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)60*042d53a7SEvalZero static void gen_level_status(struct bt_mesh_model *model,
61*042d53a7SEvalZero 			     struct bt_mesh_msg_ctx *ctx,
62*042d53a7SEvalZero 			     struct os_mbuf *buf)
63*042d53a7SEvalZero {
64*042d53a7SEvalZero 	struct bt_mesh_gen_model_cli *cli = model->user_data;
65*042d53a7SEvalZero 	struct gen_level_param *param;
66*042d53a7SEvalZero 	s16_t level;
67*042d53a7SEvalZero 
68*042d53a7SEvalZero 
69*042d53a7SEvalZero 	BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
70*042d53a7SEvalZero 	       ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
71*042d53a7SEvalZero 	       bt_hex(buf->om_data, buf->om_len));
72*042d53a7SEvalZero 
73*042d53a7SEvalZero 	if (cli->op_pending != OP_GEN_LEVEL_STATUS) {
74*042d53a7SEvalZero 		BT_WARN("Unexpected Generic LEVEL Status message");
75*042d53a7SEvalZero 		return;
76*042d53a7SEvalZero 	}
77*042d53a7SEvalZero 
78*042d53a7SEvalZero 	param = cli->op_param;
79*042d53a7SEvalZero 
80*042d53a7SEvalZero 	level = net_buf_simple_pull_le16(buf);
81*042d53a7SEvalZero 	if (param->level) {
82*042d53a7SEvalZero 		*param->level = level;
83*042d53a7SEvalZero 	}
84*042d53a7SEvalZero 
85*042d53a7SEvalZero 	BT_DBG("level: %d", level);
86*042d53a7SEvalZero 
87*042d53a7SEvalZero 	transaction_id++;
88*042d53a7SEvalZero 
89*042d53a7SEvalZero 	k_sem_give(&cli->op_sync);
90*042d53a7SEvalZero }
91*042d53a7SEvalZero 
92*042d53a7SEvalZero const struct bt_mesh_model_op gen_onoff_cli_op[] = {
93*042d53a7SEvalZero 	{ OP_GEN_ONOFF_STATUS, 1, gen_onoff_status },
94*042d53a7SEvalZero 	BT_MESH_MODEL_OP_END,
95*042d53a7SEvalZero };
96*042d53a7SEvalZero 
97*042d53a7SEvalZero const struct bt_mesh_model_op gen_level_cli_op[] = {
98*042d53a7SEvalZero 	{ OP_GEN_LEVEL_STATUS, 2, gen_level_status },
99*042d53a7SEvalZero 	BT_MESH_MODEL_OP_END,
100*042d53a7SEvalZero };
101*042d53a7SEvalZero 
cli_wait(struct bt_mesh_gen_model_cli * cli,void * param,u32_t op)102*042d53a7SEvalZero static int cli_wait(struct bt_mesh_gen_model_cli *cli, void *param, u32_t op)
103*042d53a7SEvalZero {
104*042d53a7SEvalZero 	int err;
105*042d53a7SEvalZero 
106*042d53a7SEvalZero 	BT_DBG("");
107*042d53a7SEvalZero 
108*042d53a7SEvalZero 	cli->op_param = param;
109*042d53a7SEvalZero 	cli->op_pending = op;
110*042d53a7SEvalZero 
111*042d53a7SEvalZero 	err = k_sem_take(&cli->op_sync, msg_timeout);
112*042d53a7SEvalZero 
113*042d53a7SEvalZero 	cli->op_pending = 0;
114*042d53a7SEvalZero 	cli->op_param = NULL;
115*042d53a7SEvalZero 
116*042d53a7SEvalZero 	return err;
117*042d53a7SEvalZero }
118*042d53a7SEvalZero 
bt_mesh_gen_onoff_get(u16_t net_idx,u16_t addr,u16_t app_idx,u8_t * state)119*042d53a7SEvalZero int bt_mesh_gen_onoff_get(u16_t net_idx, u16_t addr, u16_t app_idx,
120*042d53a7SEvalZero 			  u8_t *state)
121*042d53a7SEvalZero {
122*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
123*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
124*042d53a7SEvalZero 		.net_idx = net_idx,
125*042d53a7SEvalZero 		.app_idx = app_idx,
126*042d53a7SEvalZero 		.addr = addr,
127*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
128*042d53a7SEvalZero 	};
129*042d53a7SEvalZero 	struct gen_onoff_param param = {
130*042d53a7SEvalZero 		.state = state,
131*042d53a7SEvalZero 	};
132*042d53a7SEvalZero 	int err;
133*042d53a7SEvalZero 
134*042d53a7SEvalZero 	bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_GET);
135*042d53a7SEvalZero 
136*042d53a7SEvalZero 	err = bt_mesh_model_send(gen_onoff_cli.model, &ctx, msg, NULL, NULL);
137*042d53a7SEvalZero 	if (err) {
138*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
139*042d53a7SEvalZero 		goto done;
140*042d53a7SEvalZero 	}
141*042d53a7SEvalZero 
142*042d53a7SEvalZero 	err = cli_wait(&gen_onoff_cli, &param, OP_GEN_ONOFF_STATUS);
143*042d53a7SEvalZero done:
144*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
145*042d53a7SEvalZero 	return err;
146*042d53a7SEvalZero }
147*042d53a7SEvalZero 
bt_mesh_gen_onoff_set(u16_t net_idx,u16_t addr,u16_t app_idx,u8_t val,u8_t * state)148*042d53a7SEvalZero int bt_mesh_gen_onoff_set(u16_t net_idx, u16_t addr, u16_t app_idx,
149*042d53a7SEvalZero 			  u8_t val, u8_t *state)
150*042d53a7SEvalZero {
151*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
152*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
153*042d53a7SEvalZero 		.net_idx = net_idx,
154*042d53a7SEvalZero 		.app_idx = app_idx,
155*042d53a7SEvalZero 		.addr = addr,
156*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
157*042d53a7SEvalZero 	};
158*042d53a7SEvalZero 	struct gen_onoff_param param = {
159*042d53a7SEvalZero 		.state = state,
160*042d53a7SEvalZero 	};
161*042d53a7SEvalZero 	int err;
162*042d53a7SEvalZero 
163*042d53a7SEvalZero 	if (state) {
164*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_SET);
165*042d53a7SEvalZero 	} else {
166*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_SET_UNACK);
167*042d53a7SEvalZero 	}
168*042d53a7SEvalZero 
169*042d53a7SEvalZero 	net_buf_simple_add_u8(msg, val);
170*042d53a7SEvalZero 	net_buf_simple_add_u8(msg, transaction_id);
171*042d53a7SEvalZero 
172*042d53a7SEvalZero 	err = bt_mesh_model_send(gen_onoff_cli.model, &ctx, msg, NULL, NULL);
173*042d53a7SEvalZero 	if (err) {
174*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
175*042d53a7SEvalZero 		goto done;
176*042d53a7SEvalZero 	}
177*042d53a7SEvalZero 
178*042d53a7SEvalZero 	if (!state) {
179*042d53a7SEvalZero 		goto done;
180*042d53a7SEvalZero 	}
181*042d53a7SEvalZero 
182*042d53a7SEvalZero 	err = cli_wait(&gen_onoff_cli, &param, OP_GEN_ONOFF_STATUS);
183*042d53a7SEvalZero done:
184*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
185*042d53a7SEvalZero 	return err;
186*042d53a7SEvalZero }
187*042d53a7SEvalZero 
bt_mesh_gen_level_get(u16_t net_idx,u16_t addr,u16_t app_idx,s16_t * level)188*042d53a7SEvalZero int bt_mesh_gen_level_get(u16_t net_idx, u16_t addr, u16_t app_idx,
189*042d53a7SEvalZero 			  s16_t *level)
190*042d53a7SEvalZero {
191*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
192*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
193*042d53a7SEvalZero 		.net_idx = net_idx,
194*042d53a7SEvalZero 		.app_idx = app_idx,
195*042d53a7SEvalZero 		.addr = addr,
196*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
197*042d53a7SEvalZero 	};
198*042d53a7SEvalZero 	struct gen_level_param param = {
199*042d53a7SEvalZero 		.level = level,
200*042d53a7SEvalZero 	};
201*042d53a7SEvalZero 	int err;
202*042d53a7SEvalZero 
203*042d53a7SEvalZero 	bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_GET);
204*042d53a7SEvalZero 
205*042d53a7SEvalZero 	err = bt_mesh_model_send(gen_level_cli.model, &ctx, msg, NULL, NULL);
206*042d53a7SEvalZero 	if (err) {
207*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
208*042d53a7SEvalZero 		goto done;
209*042d53a7SEvalZero 	}
210*042d53a7SEvalZero 
211*042d53a7SEvalZero 	err = cli_wait(&gen_level_cli, &param, OP_GEN_LEVEL_STATUS);
212*042d53a7SEvalZero done:
213*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
214*042d53a7SEvalZero 	return err;
215*042d53a7SEvalZero }
216*042d53a7SEvalZero 
bt_mesh_gen_level_set(u16_t net_idx,u16_t addr,u16_t app_idx,s16_t val,s16_t * state)217*042d53a7SEvalZero int bt_mesh_gen_level_set(u16_t net_idx, u16_t addr, u16_t app_idx,
218*042d53a7SEvalZero 			  s16_t val, s16_t *state)
219*042d53a7SEvalZero {
220*042d53a7SEvalZero 	struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 3 + 4);
221*042d53a7SEvalZero 	struct bt_mesh_msg_ctx ctx = {
222*042d53a7SEvalZero 		.net_idx = net_idx,
223*042d53a7SEvalZero 		.app_idx = app_idx,
224*042d53a7SEvalZero 		.addr = addr,
225*042d53a7SEvalZero 		.send_ttl = BT_MESH_TTL_DEFAULT,
226*042d53a7SEvalZero 	};
227*042d53a7SEvalZero 	struct gen_level_param param = {
228*042d53a7SEvalZero 		.level = state,
229*042d53a7SEvalZero 	};
230*042d53a7SEvalZero 	int err;
231*042d53a7SEvalZero 
232*042d53a7SEvalZero 	if (state) {
233*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_SET);
234*042d53a7SEvalZero 	} else {
235*042d53a7SEvalZero 		bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_SET_UNACK);
236*042d53a7SEvalZero 	}
237*042d53a7SEvalZero 
238*042d53a7SEvalZero 	net_buf_simple_add_le16(msg, val);
239*042d53a7SEvalZero 	net_buf_simple_add_u8(msg, transaction_id);
240*042d53a7SEvalZero 
241*042d53a7SEvalZero 	err = bt_mesh_model_send(gen_level_cli.model, &ctx, msg, NULL, NULL);
242*042d53a7SEvalZero 	if (err) {
243*042d53a7SEvalZero 		BT_ERR("model_send() failed (err %d)", err);
244*042d53a7SEvalZero 		goto done;
245*042d53a7SEvalZero 	}
246*042d53a7SEvalZero 
247*042d53a7SEvalZero 	if (!state) {
248*042d53a7SEvalZero 		goto done;
249*042d53a7SEvalZero 	}
250*042d53a7SEvalZero 
251*042d53a7SEvalZero 	err = cli_wait(&gen_level_cli, &param, OP_GEN_LEVEL_STATUS);
252*042d53a7SEvalZero done:
253*042d53a7SEvalZero 	os_mbuf_free_chain(msg);
254*042d53a7SEvalZero 	return err;
255*042d53a7SEvalZero }
256*042d53a7SEvalZero 
bt_mesh_gen_model_cli_init(struct bt_mesh_model * model,bool primary)257*042d53a7SEvalZero int bt_mesh_gen_model_cli_init(struct bt_mesh_model *model, bool primary)
258*042d53a7SEvalZero {
259*042d53a7SEvalZero 	struct bt_mesh_gen_model_cli *cli = model->user_data;
260*042d53a7SEvalZero 
261*042d53a7SEvalZero 	BT_DBG("primary %u", primary);
262*042d53a7SEvalZero 
263*042d53a7SEvalZero 	if (!cli) {
264*042d53a7SEvalZero 		BT_ERR("No Generic Model Client context provided");
265*042d53a7SEvalZero 		return -EINVAL;
266*042d53a7SEvalZero 	}
267*042d53a7SEvalZero 
268*042d53a7SEvalZero 	cli->model = model;
269*042d53a7SEvalZero 
270*042d53a7SEvalZero 	k_sem_init(&cli->op_sync, 0, 1);
271*042d53a7SEvalZero 
272*042d53a7SEvalZero 	return 0;
273*042d53a7SEvalZero }
274*042d53a7SEvalZero 
275