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