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