1 /*
2 * Copyright (C) 2018-2020 Alibaba Group Holding Limited
3 */
4
5 #include <api/mesh.h>
6 #include "sig_models/sig_model.h"
7
8 #define BT_DBG_ENABLED 1 //IS_ENABLED(CONFIG_BT_MESH_DEBUG_MODEL)
9 #include "common/log.h"
10
11 struct bt_mesh_model_pub g_gen_onoff_pub = {
12 #ifndef CONFIG_BT_MESH_NOPUB
13 .msg = NET_BUF_SIMPLE(2 + 3 + 4),
14 #endif
15 };
16
_gen_onoff_prepear_buf(struct bt_mesh_model * p_model,struct net_buf_simple * p_msg,bool is_ack)17 static void _gen_onoff_prepear_buf(struct bt_mesh_model *p_model, struct net_buf_simple *p_msg, bool is_ack)
18 {
19 sig_model_state_t *p_state = &((sig_model_element_state_t *)p_model->user_data)->state;
20 u8_t remain_time_byte = 0;
21
22 BT_DBG("onoff cur(%d) tar(%d)", p_state->onoff[TYPE_PRESENT], p_state->onoff[TYPE_TARGET]);
23 #ifdef CONFIG_MESH_MODEL_TRANS
24 remain_time_byte = sig_model_transition_get_remain_time_byte(p_state, is_ack);
25
26 BT_DBG("remain(0x%02x)", remain_time_byte);
27 #endif
28
29 //prepear buff
30 bt_mesh_model_msg_init(p_msg, OP_GENERIC_ONOFF_STATUS);
31
32 if (is_ack && remain_time_byte == 0)
33 {
34 net_buf_simple_add_u8(p_msg, p_state->onoff[TYPE_TARGET]);
35 }
36 else
37 {
38 net_buf_simple_add_u8(p_msg, p_state->onoff[TYPE_PRESENT]);
39 #ifdef CONFIG_MESH_MODEL_TRANS
40 if (remain_time_byte)
41 {
42 net_buf_simple_add_u8(p_msg, p_state->onoff[TYPE_TARGET]);
43 net_buf_simple_add_u8(p_msg, remain_time_byte);
44 }
45 #endif
46 }
47 }
48
_gen_onoff_status(struct bt_mesh_model * p_model,struct bt_mesh_msg_ctx * p_ctx,bool is_ack)49 static void _gen_onoff_status(struct bt_mesh_model *p_model,
50 struct bt_mesh_msg_ctx *p_ctx, bool is_ack)
51 {
52 struct net_buf_simple *p_msg = NET_BUF_SIMPLE(2 + 3 + 4);
53
54 BT_DBG("addr(0x%04x)", bt_mesh_model_elem(p_model)->addr);
55
56 _gen_onoff_prepear_buf(p_model, p_msg, is_ack);
57 p_ctx->send_ttl = GENIE_TRANSPORT_DEFAULT_TTL;
58 if (bt_mesh_model_send(p_model, p_ctx, p_msg, NULL, NULL))
59 {
60 BT_ERR("Unable to send OnOff Status");
61 }
62 BT_DBG("Success!!!");
63 }
64
65 struct net_buf_simple *p_ack_buff;
66
_gen_onoff_analyze(struct bt_mesh_model * p_model,u16_t src_addr,struct net_buf_simple * p_buf)67 static E_MESH_ERROR_TYPE _gen_onoff_analyze(struct bt_mesh_model *p_model,
68 u16_t src_addr, struct net_buf_simple *p_buf)
69 {
70 u8_t onoff = 0;
71 u8_t tid = 0;
72 #ifdef CONFIG_MESH_MODEL_TRANS
73 u8_t trans = 0;
74 u8_t delay = 0;
75 #endif
76 sig_model_element_state_t *p_elem = NULL;
77
78 if (!p_model || !p_buf)
79 {
80 return MESH_ANALYZE_ARGS_ERROR;
81 }
82
83 p_elem = p_model->user_data;
84
85 if (p_buf->len != 2 && p_buf->len != 4)
86 {
87 BT_ERR("MESH_ANALYZE_SIZE_ERROR buf->len(%d)", p_buf->len);
88 return MESH_ANALYZE_SIZE_ERROR;
89 }
90
91 //get message info
92 onoff = net_buf_simple_pull_u8(p_buf);
93 tid = net_buf_simple_pull_u8(p_buf);
94 #ifdef CONFIG_MESH_MODEL_TRANS
95 if (p_buf->len)
96 {
97 trans = net_buf_simple_pull_u8(p_buf);
98 delay = net_buf_simple_pull_u8(p_buf);
99 }
100 else
101 {
102 trans = 0;
103 delay = 0;
104 }
105 #endif
106
107 if (onoff >> 1)
108 {
109 BT_ERR("MESH_ANALYZE_ARGS_ERROR onoff(0x%02x)", onoff);
110 return MESH_ANALYZE_ARGS_ERROR;
111 }
112
113 #ifdef CONFIG_MESH_MODEL_TRANS
114 if ((trans & 0x3F) == 0x3F)
115 {
116 BT_ERR("MESH_SET_TRANSTION_ERROR");
117 return MESH_SET_TRANSTION_ERROR;
118 }
119 #endif
120
121 if (genie_transport_check_tid(src_addr, tid, p_elem->element_id) != MESH_SUCCESS)
122 {
123 BT_ERR("MESH_TID_REPEAT src_addr(0x%04x) tid(0x%02x)", src_addr, tid);
124 return MESH_TID_REPEAT;
125 }
126 genie_transport_src_addr_set(src_addr);
127
128 p_elem->state.onoff[TYPE_TARGET] = onoff;
129 BT_DBG("onoff cur(%d) tar(%d)", p_elem->state.onoff[TYPE_PRESENT], p_elem->state.onoff[TYPE_TARGET]);
130 #ifdef CONFIG_MESH_MODEL_TRANS
131 p_elem->state.trans = trans;
132 p_elem->state.delay = delay;
133 if (p_elem->state.trans)
134 {
135 p_elem->state.trans_start_time = k_uptime_get() + p_elem->state.delay * 5;
136 p_elem->state.trans_end_time = p_elem->state.trans_start_time + sig_model_transition_get_transition_time(p_elem->state.trans);
137 }
138 BT_DBG("trans(0x%02x) delay(0x%02x)", p_elem->state.trans, p_elem->state.delay);
139 #endif
140
141 if (p_elem->state.onoff[TYPE_PRESENT] != p_elem->state.onoff[TYPE_TARGET])
142 {
143 sig_model_event_set_indicate(SIG_MODEL_INDICATE_GEN_ONOFF);
144 sig_model_generic_onoff_bind_ops(p_elem);
145 }
146
147 return MESH_SUCCESS;
148 }
149
gen_onoff_publication(struct bt_mesh_model * p_model)150 void gen_onoff_publication(struct bt_mesh_model *p_model)
151 {
152 }
153
_gen_onoff_get(struct bt_mesh_model * p_model,struct bt_mesh_msg_ctx * p_ctx,struct net_buf_simple * p_buf)154 static void _gen_onoff_get(struct bt_mesh_model *p_model,
155 struct bt_mesh_msg_ctx *p_ctx,
156 struct net_buf_simple *p_buf)
157 {
158 sig_model_msg msg;
159 sig_model_element_state_t *p_elem_state = NULL;
160
161 if (!p_model || !p_model->user_data)
162 {
163 GENIE_LOG_ERR("param err");
164 return;
165 }
166
167 memset(&msg, 0, sizeof(sig_model_msg));
168 msg.opcode = OP_GENERIC_ONOFF_GET;
169 if (p_buf != NULL)
170 {
171 msg.len = p_buf->len;
172 msg.data = (u8_t *)p_buf->data;
173 }
174 genie_transport_src_addr_set(p_ctx->addr);
175
176 p_elem_state = (sig_model_element_state_t *)p_model->user_data;
177 msg.element_id = p_elem_state->element_id;
178
179 sig_model_event(SIG_MODEL_EVT_GENERIC_MESG, (void *)&msg);
180
181 #ifndef CONFIG_GENIE_MESH_NO_AUTO_REPLY
182 _gen_onoff_status(p_model, p_ctx, 0);
183 #endif
184 }
185
_gen_onoff_set(struct bt_mesh_model * p_model,struct bt_mesh_msg_ctx * p_ctx,struct net_buf_simple * p_buf)186 static void _gen_onoff_set(struct bt_mesh_model *p_model,
187 struct bt_mesh_msg_ctx *p_ctx,
188 struct net_buf_simple *p_buf)
189 {
190 sig_model_msg msg;
191 sig_model_element_state_t *p_elem_state = NULL;
192
193 memset(&msg, 0, sizeof(sig_model_msg));
194
195 msg.opcode = OP_GENERIC_ONOFF_SET;
196 if (p_buf != NULL)
197 {
198 msg.len = p_buf->len;
199 msg.data = (u8_t *)p_buf->data;
200 }
201
202 E_MESH_ERROR_TYPE ret = _gen_onoff_analyze(p_model, p_ctx->addr, p_buf);
203 if (ret == MESH_SUCCESS)
204 {
205 p_elem_state = (sig_model_element_state_t *)p_model->user_data;
206 msg.element_id = p_elem_state->element_id;
207 sig_model_event(SIG_MODEL_EVT_GENERIC_MESG, (void *)&msg);
208 }
209
210 #ifndef CONFIG_GENIE_MESH_NO_AUTO_REPLY
211 if (ret == MESH_SUCCESS || ret == MESH_TID_REPEAT)
212 {
213 _gen_onoff_status(p_model, p_ctx, 1);
214 if (ret == MESH_SUCCESS)
215 {
216 sig_model_event(SIG_MODEL_EVT_ANALYZE_MSG, (sig_model_element_state_t *)p_model->user_data);
217 }
218 }
219 #endif
220 }
221
_gen_onoff_set_unack(struct bt_mesh_model * p_model,struct bt_mesh_msg_ctx * p_ctx,struct net_buf_simple * p_buf)222 static void _gen_onoff_set_unack(struct bt_mesh_model *p_model,
223 struct bt_mesh_msg_ctx *p_ctx,
224 struct net_buf_simple *p_buf)
225 {
226 sig_model_msg msg;
227 sig_model_element_state_t *p_elem_state = NULL;
228
229 memset(&msg, 0, sizeof(sig_model_msg));
230 msg.opcode = OP_GENERIC_ONOFF_SET_UNACK;
231 if (p_buf != NULL)
232 {
233 msg.len = p_buf->len;
234 msg.data = (u8_t *)p_buf->data;
235 }
236
237 E_MESH_ERROR_TYPE ret = _gen_onoff_analyze(p_model, p_ctx->addr, p_buf);
238 if (ret == MESH_SUCCESS)
239 {
240 p_elem_state = (sig_model_element_state_t *)p_model->user_data;
241 msg.element_id = p_elem_state->element_id;
242 sig_model_event(SIG_MODEL_EVT_GENERIC_MESG, (void *)&msg);
243 #ifndef CONFIG_GENIE_MESH_NO_AUTO_REPLY
244 sig_model_event(SIG_MODEL_EVT_ANALYZE_MSG, (sig_model_element_state_t *)p_model->user_data);
245 #endif
246 }
247 }
248
249 const struct bt_mesh_model_op g_gen_onoff_op[] = {
250 {OP_GENERIC_ONOFF_GET, 0, _gen_onoff_get},
251 {OP_GENERIC_ONOFF_SET, 2, _gen_onoff_set},
252 {OP_GENERIC_ONOFF_SET_UNACK, 2, _gen_onoff_set_unack},
253 BT_MESH_MODEL_OP_END,
254 };
255
256 #ifdef CONFIG_MESH_MODEL_CTL_SRV
sig_model_onoff_update_by_color_temperature(sig_model_element_state_t * p_elem)257 void sig_model_onoff_update_by_color_temperature(sig_model_element_state_t *p_elem)
258 {
259 sig_model_state_t *p_state = &p_elem->state;
260
261 if (p_state->onoff[TYPE_TARGET] == 0)
262 {
263 //turn on
264 p_state->onoff[TYPE_TARGET] = 1;
265
266 sig_model_generic_onoff_bind_ops(p_elem);
267 }
268 }
269 #endif
270
271 #ifdef CONFIG_MESH_MODEL_LIGHTNESS_SRV
sig_model_onoff_update_by_lightness(sig_model_element_state_t * p_elem,E_VALUE_TYPE type)272 void sig_model_onoff_update_by_lightness(sig_model_element_state_t *p_elem, E_VALUE_TYPE type)
273 {
274 sig_model_state_t *p_state = &p_elem->state;
275
276 if (type == TYPE_TARGET)
277 {
278 if (p_state->lightness[TYPE_PRESENT] == 0 && p_state->lightness[TYPE_TARGET] != 0)
279 {
280 //turn on
281 p_state->onoff[TYPE_TARGET] = 1;
282 }
283 else if (p_state->lightness[TYPE_PRESENT] != 0 && p_state->lightness[TYPE_TARGET] == 0)
284 {
285 //turn off
286 p_state->onoff[TYPE_TARGET] = 0;
287 }
288 }
289 else if (type == TYPE_PRESENT)
290 {
291 if (p_state->lightness[TYPE_PRESENT] == 0 && p_state->lightness[TYPE_TARGET] == 0)
292 {
293 //turn off
294 p_state->onoff[TYPE_PRESENT] = 0;
295 }
296 }
297 }
298 #endif
299