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