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