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, ¶m, 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, ¶m, 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, ¶m, 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, ¶m, 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