1 /*
2 * Copyright (C) 2018-2020 Alibaba Group Holding Limited
3 */
4
5 #include <aos/kernel.h>
6
7 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_DEBUG_GENIE_TRANSPORT)
8 #include "common/log.h"
9 #include "mesh.h"
10 #include "mesh/access.h"
11 #include "net.h"
12 #include "access.h"
13
14 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
15 #include "adv.h"
16 #endif
17
18 #include "genie_service.h"
19
20 static uint16_t last_src_addr = BT_MESH_ADDR_TMALL_GENIE;
21 static genie_transport_tid_queue_t tid_queue[RECV_MSG_TID_QUEUE_SIZE];
22 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
23 static struct k_timer scan_off_timer;
24 #endif
25
26 /**
27 * send_list was used to save the unconfirmed vendor messages
28 * retransmit_timer was used to control when the vendor messages saved in send_list will be resent
29 * */
30 static sys_dlist_t send_list;
31 static struct k_timer retransmit_timer;
32 static aos_mutex_t transport_mutex;
33
34 /** @def genie_transport_msg_node_generate
35 *
36 * @brief duplicate genie_transport_model_param_t and save to genie_transport_node_t
37 *
38 * @param pointer to the vendor model message to be duplicated
39 *
40 * @return pointer to genie_transport_node_t for success, NULL for failure
41 */
genie_transport_msg_node_generate(genie_transport_model_param_t * p_model_msg)42 static genie_transport_node_t *genie_transport_msg_node_generate(genie_transport_model_param_t *p_model_msg)
43 {
44 genie_transport_node_t *p_node = NULL;
45
46 if (p_model_msg->retry > VENDOR_MODEL_MSG_MAX_RETRY_TIMES)
47 {
48 p_model_msg->retry = VENDOR_MODEL_MSG_MAX_RETRY_TIMES;
49 }
50
51 p_node = hal_malloc(sizeof(genie_transport_node_t) + p_model_msg->len);
52 if (!p_node)
53 {
54 BT_ERR("malloc for genie_transport_node_t failed");
55 return NULL;
56 }
57
58 memcpy(&p_node->msg, p_model_msg, sizeof(genie_transport_model_param_t));
59 BT_DBG("p_node->msg:%p, data:%p, %p", &p_node->msg, &p_node->msg.data, &p_node->msg.data + 1);
60 p_node->msg.data = (uint8_t *)(&p_node->msg.data + 1);
61 memcpy(p_node->msg.data, p_model_msg->data, p_model_msg->len);
62 BT_DBG("p_model_msg->data:%p, %s", p_model_msg->data, bt_hex(p_model_msg->data, p_model_msg->len));
63 BT_DBG("p_node->msg.data:%p, %s", p_node->msg.data, bt_hex(p_node->msg.data, p_node->msg.len));
64 p_node->timeout = k_uptime_get() + p_model_msg->retry_period;
65
66 p_node->left_retry = p_model_msg->retry;
67
68 return p_node;
69 }
70
genie_transport_find_by_tid(uint8_t tid)71 static genie_transport_model_param_t *genie_transport_find_by_tid(uint8_t tid)
72 {
73 sys_dnode_t *p_node = NULL;
74 genie_transport_model_param_t *p_msg = NULL;
75 genie_transport_node_t *p_msg_node = NULL;
76
77 SYS_DLIST_FOR_EACH_NODE(&send_list, p_node)
78 {
79 p_msg_node = CONTAINER_OF(p_node, genie_transport_node_t, node);
80 if (p_msg_node == NULL)
81 {
82 continue;
83 }
84
85 p_msg = &p_msg_node->msg;
86
87 if (p_msg->tid == tid)
88 {
89 return p_msg;
90 }
91 }
92
93 return NULL;
94 }
95
96 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
scan_off_timer_cb(void * p_timer,void * args)97 static void scan_off_timer_cb(void *p_timer, void *args)
98 {
99 bt_mesh_scan_disable();
100 }
101
send_start_cb(u16_t duration,int err,void * cb_data)102 static void send_start_cb(u16_t duration, int err, void *cb_data)
103 {
104 bt_mesh_scan_disable();
105 }
106
send_end_cb(int err,void * cb_data)107 static void send_end_cb(int err, void *cb_data)
108 {
109 bt_mesh_scan_enable();
110 k_timer_start(&scan_off_timer, CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND);
111 }
112 #endif
113
114 /** @def genie_transport_model_send
115 *
116 * @brief send the vendor model message
117 *
118 * @param pointer to the message to be sent
119 *
120 * @return 0 for success; negative for failure
121 */
genie_transport_model_send(genie_transport_model_param_t * p_model_msg)122 static int16_t genie_transport_model_send(genie_transport_model_param_t *p_model_msg)
123 {
124 int16_t err = -1;
125 struct bt_mesh_model_pub *p_pub = &genie_model_pub;
126 struct net_buf_simple *p_msg = p_pub->msg;
127 struct bt_mesh_model *p_model = bt_mesh_model_find_vnd(p_model_msg->p_elem, CONFIG_MESH_VENDOR_COMPANY_ID, CONFIG_MESH_VENDOR_MODEL_SRV);
128 struct bt_mesh_msg_ctx ctx;
129
130 if (!p_model)
131 {
132 BT_ERR("cannot find vendor model server %p\n", p_model_msg->p_elem);
133 return err;
134 }
135
136 BT_DBG("p_model:%p, cid:0x%x, id:0x%x, retry:%d", p_model, p_model->vnd.company, p_model->vnd.id, p_model_msg->retry);
137
138 BT_DBG("tid:%02x opcode:%02x", p_model_msg->tid, p_model_msg->opid);
139 BT_DBG("p_model_msg->data:%p, %d, %s", p_model_msg, p_model_msg->len, bt_hex(p_model_msg->data, p_model_msg->len));
140
141 //prepare buffer
142 bt_mesh_model_msg_init(p_msg, BT_MESH_MODEL_OP_3(p_model_msg->opid, CONFIG_MESH_VENDOR_COMPANY_ID));
143 net_buf_simple_add_u8(p_msg, p_model_msg->tid);
144 if (p_model_msg->len)
145 {
146 net_buf_simple_add_mem(p_msg, p_model_msg->data, p_model_msg->len);
147 }
148
149 ctx.app_idx = bt_mesh_model_get_appkey_id(p_model_msg->p_elem, p_model);
150 ctx.net_idx = bt_mesh_model_get_netkey_id(p_model_msg->p_elem);
151 ctx.addr = p_model_msg->dst_addr;
152 ctx.send_ttl = GENIE_TRANSPORT_DEFAULT_TTL;
153 ctx.send_rel = 0;
154
155 if (ctx.addr == BT_MESH_ADDR_UNASSIGNED)
156 {
157 ctx.addr = BT_MESH_ADDR_TMALL_GENIE;
158 }
159
160 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
161 static struct bt_mesh_send_cb model_send_cb = {
162 .start = send_start_cb,
163 .end = send_end_cb,
164 };
165
166 err = bt_mesh_model_send(p_model, &ctx, p_msg, &model_send_cb, NULL);
167 #else
168 err = bt_mesh_model_send(p_model, &ctx, p_msg, NULL, NULL);
169 #endif
170
171 if (err)
172 {
173 BT_ERR("genie transport send fail:%d\n", err);
174 }
175 else
176 {
177 BT_DBG("genie transport send success");
178 }
179
180 return err;
181 }
182
183 /** @def genie_transport_append_mesg
184 *
185 * @brief duplicate genie_transport_model_param_t and append it to vendor model message list to be monitored
186 *
187 * @param pointer to the vendor model message to be duplicated
188 *
189 * @return 0 for success; negative for failure
190 */
genie_transport_append_mesg(genie_transport_model_param_t * p_model_msg)191 static int16_t genie_transport_append_mesg(genie_transport_model_param_t *p_model_msg)
192 {
193 genie_transport_node_t *p_msg_node = NULL;
194
195 BT_DBG("append msg:%p, opid:%x, retry:%d, head:%p, node:%p", p_model_msg, p_model_msg->opid, p_model_msg->retry, &send_list, &p_msg_node->node);
196 if (sys_dlist_node_number(&send_list) >= CONFIG_VENDOR_SEND_MSG_MAX)
197 {
198 GENIE_LOG_WARN("send list full");
199 return -1;
200 }
201
202 aos_mutex_lock(&transport_mutex, AOS_WAIT_FOREVER);
203 p_msg_node = genie_transport_msg_node_generate(p_model_msg);
204 if (!p_msg_node)
205 {
206 return -1;
207 }
208
209 sys_dlist_append(&send_list, &p_msg_node->node);
210 aos_mutex_unlock(&transport_mutex);
211
212 //Check retry timer, if timer is not started yet, start it
213 if (!k_timer_is_started(&retransmit_timer))
214 {
215 k_timer_start(&retransmit_timer, p_model_msg->retry_period);
216 }
217
218 return 0;
219 }
220
genie_transport_check_tid(u16_t src_addr,uint8_t tid,uint8_t elem_id)221 E_MESH_ERROR_TYPE genie_transport_check_tid(u16_t src_addr, uint8_t tid, uint8_t elem_id)
222 {
223 static uint8_t cur_index = 0;
224 uint8_t i = cur_index;
225 uint8_t ri = 0;
226 uint32_t cur_time = k_uptime_get();
227 uint32_t end_time = 0;
228
229 if (src_addr >= TMALL_GENIE_UADDR_START && src_addr <= TMALL_GENIE_UADDR_END)
230 {
231 src_addr = TMALL_GENIE_UADDR_START;
232 }
233
234 while (i < cur_index + RECV_MSG_TID_QUEUE_SIZE)
235 {
236 ri = i % RECV_MSG_TID_QUEUE_SIZE;
237 if ((tid_queue[ri].tid == tid) && (tid_queue[ri].addr == src_addr) && (tid_queue[ri].elemid == elem_id))
238 {
239 end_time = tid_queue[ri].time + GENIE_TRANSPORT_DEDUPLICATE_DURATION;
240 if (cur_time < end_time)
241 {
242 break;
243 }
244 }
245 i++;
246 }
247 if (i < cur_index + RECV_MSG_TID_QUEUE_SIZE)
248 {
249 return MESH_TID_REPEAT;
250 }
251 else
252 {
253 tid_queue[cur_index].tid = tid;
254 tid_queue[cur_index].elemid = elem_id;
255 tid_queue[cur_index].addr = src_addr;
256 tid_queue[cur_index].time = cur_time;
257 cur_index++;
258 cur_index %= RECV_MSG_TID_QUEUE_SIZE;
259
260 return MESH_SUCCESS;
261 }
262 }
263
genie_transport_src_addr_set(uint16_t src_addr)264 void genie_transport_src_addr_set(uint16_t src_addr)
265 {
266 last_src_addr = src_addr;
267 }
268
genie_transport_src_addr_get()269 uint16_t genie_transport_src_addr_get()
270 {
271 return last_src_addr;
272 }
273
274 /** @def transport_msg_node_free
275 *
276 * @brief free the vendor model message node struct's memory
277 *
278 * @param pointer to the vendor model message node to be freed
279 *
280 * @return 0 for success; negative for failure
281 */
transport_msg_node_free(genie_transport_node_t * p_node)282 static int16_t transport_msg_node_free(genie_transport_node_t *p_node)
283 {
284 hal_free(p_node);
285
286 return 0;
287 }
288
transport_remove_by_tid(uint8_t tid)289 static int transport_remove_by_tid(uint8_t tid)
290 {
291 sys_dnode_t *p_node = NULL;
292 sys_dnode_t *p_node_safe = NULL;
293
294 if (sys_dlist_is_empty(&send_list))
295 {
296 return -1;
297 }
298
299 aos_mutex_lock(&transport_mutex, AOS_WAIT_FOREVER);
300 SYS_DLIST_FOR_EACH_NODE_SAFE(&send_list, p_node, p_node_safe)
301 {
302 genie_transport_model_param_t *p_msg = NULL;
303 genie_transport_node_t *p_msg_node = NULL;
304
305 p_msg_node = CONTAINER_OF(p_node, genie_transport_node_t, node);
306 p_msg = &p_msg_node->msg;
307
308 BT_DBG("msg %02x", p_msg->tid);
309 if (p_msg->tid == tid)
310 {
311 sys_dlist_remove(p_node);
312 transport_msg_node_free((genie_transport_node_t *)p_node);
313 return 0;
314 }
315 }
316 aos_mutex_unlock(&transport_mutex);
317
318 return -1;
319 }
320
transport_get_send_timeout(uint16_t payload_len)321 static uint16_t transport_get_send_timeout(uint16_t payload_len)
322 {
323 return GENIE_TRANSPORT_EACH_PDU_TIMEOUT * genie_transport_get_seg_count(payload_len);
324 }
325
genie_transport_send_model(genie_transport_model_param_t * p_model_msg)326 int genie_transport_send_model(genie_transport_model_param_t *p_model_msg)
327 {
328 int r = -1;
329
330 if (!p_model_msg || !p_model_msg->data || p_model_msg->len == 0 || !bt_mesh_is_provisioned())
331 {
332 BT_ERR("send param err");
333 return r;
334 }
335
336 BT_DBG("opcode:0x%x, tid:%d, len:%d", p_model_msg->opid, p_model_msg->tid, p_model_msg->len);
337 BT_DBG("payload:%s", p_model_msg->len ? bt_hex(p_model_msg->data, p_model_msg->len) : "empty");
338
339 switch (p_model_msg->opid)
340 {
341 case VENDOR_OP_ATTR_STATUS:
342 case VENDOR_OP_ATTR_INDICATE:
343 case VENDOR_OP_ATTR_INDICATE_TG:
344 case VENDOR_OP_ATTR_TRANS_MSG:
345 case VENDOR_OP_ATTR_TRANS_INDICATE:
346 {
347 if (p_model_msg->tid == 0)
348 {
349 p_model_msg->tid = genie_transport_gen_tid();
350 }
351
352 /**
353 * no need to duplicate the following messages
354 * 1. retry <= 0 - the message won't want to be resent
355 * 2. tid device tid is [0x80, 0xBF]
356 * 3. opcode is not VENDOR_OP_ATTR_INDICATE/VENDOR_OP_ATTR_INDICATE_TG/VENDOR_OP_ATTR_TRANS_INDICATE
357 * 4. already duplicated or CONFIME/CONFIME_TG
358 * */
359 if ((p_model_msg->tid >= GENIE_TRANSPORT_TID_MIN &&
360 p_model_msg->tid <= GENIE_TRANSPORT_TID_MAX))
361 {
362 if (genie_transport_find_by_tid(p_model_msg->tid) != NULL)
363 {
364 transport_remove_by_tid(p_model_msg->tid); //remove old
365 }
366
367 if ((p_model_msg->opid != VENDOR_OP_ATTR_STATUS) && (p_model_msg->opid != VENDOR_OP_ATTR_TRANS_MSG))
368 {
369 //append for retransmit
370 if (p_model_msg->retry_period > 0)
371 {
372 r = genie_transport_append_mesg(p_model_msg); //append new
373 }
374 }
375
376 GENIE_LOG_INFO("SendTID(%02X)\n", p_model_msg->tid);
377 r = genie_transport_model_send(p_model_msg); //Send at first time
378 }
379 else
380 {
381 BT_WARN("no send");
382 }
383 }
384 break;
385 default:
386 {
387 BT_WARN("unknown opid:0x%x", p_model_msg->opid);
388 }
389 break;
390 }
391
392 return r;
393 }
394
genie_transport_send_payload(genie_transport_payload_param_t * payload_param)395 int genie_transport_send_payload(genie_transport_payload_param_t *payload_param)
396 {
397 genie_transport_model_param_t transport_model_param = {0};
398
399 if (payload_param == NULL || payload_param->p_payload == NULL)
400 {
401 GENIE_LOG_ERR("invalid param");
402 return -1;
403 }
404
405 memset(&transport_model_param, 0, sizeof(genie_transport_model_param_t));
406 transport_model_param.opid = payload_param->opid;
407 transport_model_param.tid = payload_param->tid;
408 transport_model_param.data = payload_param->p_payload;
409 transport_model_param.len = payload_param->payload_len;
410 transport_model_param.p_elem = genie_mesh_get_primary_element();
411 transport_model_param.retry_period = transport_get_send_timeout(payload_param->payload_len);
412 transport_model_param.retry = payload_param->retry_cnt;
413 transport_model_param.result_cb = payload_param->result_cb;
414 transport_model_param.dst_addr = payload_param->dst_addr;
415
416 return genie_transport_send_model(&transport_model_param);
417 }
418
419 /** @def genie_transport_gen_tid
420 *
421 * @brief generate tid used in vendor model message
422 *
423 * @param NULL
424 *
425 * @return tid with range of [0x80, 0xBF]
426 */
genie_transport_gen_tid(void)427 uint8_t genie_transport_gen_tid(void)
428 {
429 static uint8_t tid = GENIE_TRANSPORT_TID_MAX;
430
431 if (tid == GENIE_TRANSPORT_TID_MAX) //When bootup use rand tid
432 {
433 bt_rand(&tid, 1);
434 tid &= 0x3F;
435 }
436 else
437 {
438 tid = (tid + 1) & 0x3F;
439 }
440
441 return (tid | 0x80);
442 }
443
genie_transport_get_seg_count(uint16_t msg_len)444 uint8_t genie_transport_get_seg_count(uint16_t msg_len)
445 {
446 if (msg_len <= 11) //One byte is Lower PDU header
447 {
448 return 1;
449 }
450
451 msg_len -= 8; //SZMIC
452
453 return (msg_len % GENIE_TRANSPORT_EACH_PDU_SIZE) ? (msg_len / GENIE_TRANSPORT_EACH_PDU_SIZE + 2) : (msg_len / GENIE_TRANSPORT_EACH_PDU_SIZE + 1);
454 }
455
genie_transport_tx_in_progress(void)456 bool genie_transport_tx_in_progress(void)
457 {
458 if (!sys_dlist_is_empty(&send_list))
459 {
460 return true;
461 }
462
463 return false;
464 }
465
466 /** @def retransmit_timer_cb
467 *
468 * @brief timeout handler for the retransmit_timer
469 *
470 * @param p_timer - pointer to the timer; args - pointer to send_list
471 *
472 * @return N/A
473 */
retransmit_timer_cb(void * p_timer,void * args)474 static void retransmit_timer_cb(void *p_timer, void *args)
475 {
476 sys_dlist_t *p_head = (sys_dlist_t *)args;
477 sys_dnode_t *p_node = NULL;
478 sys_dnode_t *p_node_safe = NULL;
479 uint32_t nearest = 0;
480 genie_transport_node_t *p_msg_node = NULL;
481 genie_transport_model_param_t *p_msg = NULL;
482
483 BT_DBG("retransmit_timer timeout, p_head:%p", p_head);
484
485 /**
486 * 1. go through p_head
487 * 2. resend the no responsed messages if timeout happens and refresh timeout value
488 * */
489 aos_mutex_lock(&transport_mutex, AOS_WAIT_FOREVER);
490 SYS_DLIST_FOR_EACH_NODE_SAFE(p_head, p_node, p_node_safe)
491 {
492 p_msg_node = CONTAINER_OF(p_node, genie_transport_node_t, node);
493 nearest = p_msg_node->msg.retry_period;
494 p_msg = &p_msg_node->msg;
495 BT_DBG("msg:%p, opid:%d, left:%d\n", p_msg, p_msg->opid, p_msg_node->left_retry);
496
497 if (p_msg_node->timeout <= k_uptime_get())
498 {
499 BT_DBG("timeout - msg:%p, opid:%x, left:%d\n", p_msg, p_msg->opid, p_msg_node->left_retry);
500 if (p_msg_node->left_retry-- == 0)
501 {
502 GENIE_LOG_INFO("TID(%02X) timeout\n", p_msg_node->msg.tid);
503 if (p_msg_node->msg.result_cb)
504 {
505 p_msg_node->msg.result_cb(SEND_RESULT_TIMEOUT);
506 }
507 sys_dlist_remove(p_node);
508 transport_msg_node_free((genie_transport_node_t *)p_node);
509 break;
510 }
511 GENIE_LOG_INFO("ReTID(%02X), LR(%d)\n", p_msg->tid, p_msg_node->left_retry);
512 genie_transport_model_send(p_msg);
513 p_msg_node->timeout = k_uptime_get() + p_msg_node->msg.retry_period;
514 }
515 else
516 {
517 if (nearest > p_msg_node->timeout)
518 {
519 nearest = p_msg_node->timeout;
520 }
521 }
522 }
523 aos_mutex_unlock(&transport_mutex);
524
525 /* start new timer */
526 if (!sys_dlist_is_empty(p_head))
527 {
528 k_timer_start(&retransmit_timer, nearest);
529 BT_DBG("restart retry timer, timeout:%d\n", nearest);
530 }
531 else
532 {
533 k_timer_stop(&retransmit_timer);
534 BT_DBG("list empty, stop timer\n");
535 }
536
537 return;
538 }
539
540 /** @def genie_transport_ack
541 *
542 * @brief check received vendor message's tid
543 *
544 * @param pointer to send_list, tid of the received vendor model message
545 *
546 * @return 0 for success; negative for failure
547 */
genie_transport_ack(uint8_t tid)548 int genie_transport_ack(uint8_t tid)
549 {
550 sys_dnode_t *p_node = NULL;
551 sys_dnode_t *p_node_safe = NULL;
552
553 if (sys_dlist_is_empty(&send_list))
554 {
555 return 0;
556 }
557
558 /**
559 * go through message list and dequeue the vendor model's message and free it if received message
560 * s tid equals this message's tid
561 * */
562 BT_DBG("recv %02x\n", tid);
563 aos_mutex_lock(&transport_mutex, AOS_WAIT_FOREVER);
564 SYS_DLIST_FOR_EACH_NODE_SAFE(&send_list, p_node, p_node_safe)
565 {
566 genie_transport_model_param_t *p_msg = NULL;
567 genie_transport_node_t *p_msg_node = NULL;
568
569 p_msg_node = CONTAINER_OF(p_node, genie_transport_node_t, node);
570 p_msg = &p_msg_node->msg;
571
572 BT_DBG("msg %02x\n", p_msg->tid);
573 if (p_msg->tid == tid)
574 {
575 BT_DBG("dequeue msg:%p, opid:%x, retry:%d\n", p_msg, p_msg->opid, p_msg->retry);
576 if (p_msg->result_cb)
577 {
578 p_msg->result_cb(SEND_RESULT_SUCCESS);
579 }
580
581 sys_dlist_remove(p_node);
582 transport_msg_node_free((genie_transport_node_t *)p_node);
583 break;
584 }
585 }
586 aos_mutex_unlock(&transport_mutex);
587
588 return 0;
589 }
590
genie_transport_init(void)591 void genie_transport_init(void)
592 {
593 sys_dlist_init(&send_list);
594 k_timer_init(&retransmit_timer, retransmit_timer_cb, &send_list);
595 aos_mutex_new(&transport_mutex);
596
597 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
598 k_timer_init(&scan_off_timer, scan_off_timer_cb, NULL);
599 #endif
600 }
601