1 /*
2 * Copyright (C) 2018-2020 Alibaba Group Holding Limited
3 */
4
5 #include <port/mesh_hal_ble.h>
6
7 //#include "multi_adv.h"
8
9 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_OTA)
10 #include "common/log.h"
11 #include "bt_mesh_custom_log.h"
12
13 #include "genie_service.h"
14 #include "ali_dfu_port.h"
15
16 #define DEBUG_AIS_DETAIL_DATA 1
17
18 static genie_ais_ctx_t genie_ais_ctx;
19 extern genie_ota_ctx_t genie_ota_ctx;
20
21 static struct bt_gatt_attr _ais_srv_attrs[];
22
_ais_decrypt(uint8_t * payload,uint8_t len)23 static int _ais_decrypt(uint8_t *payload, uint8_t len)
24 {
25 uint8_t dec[16];
26
27 if (genie_crypto_decrypt(payload, dec) != 0)
28 {
29 printf("ais decrypt:%s fail\r\n", bt_hex(payload, len));
30 return -1;
31 }
32
33 memcpy(payload, dec, 16);
34
35 return 0;
36 }
37
_ais_indicate_rsp(struct bt_conn * conn,const struct bt_gatt_attr * attr,u8_t err,void * p_params)38 static void _ais_indicate_rsp(struct bt_conn *conn, const struct bt_gatt_attr *attr, u8_t err, void *p_params)
39 {
40 struct bt_gatt_indicate_params *p_indicate = (struct bt_gatt_indicate_params *)p_params;
41
42 printf("ais rsp err(%d) p_ind(%p)\r\n", err, p_indicate);
43 if (p_indicate)
44 {
45 aos_free(p_indicate);
46 p_indicate = NULL;
47 }
48 }
49
_ais_server_indicate(uint8_t msg_id,uint8_t cmd,uint8_t * p_msg,uint16_t len)50 static void _ais_server_indicate(uint8_t msg_id, uint8_t cmd, uint8_t *p_msg, uint16_t len)
51 {
52 int ret = 0;
53 ais_pdu_t msg;
54 struct bt_gatt_indicate_params *p_indicate = NULL;
55
56 p_indicate = aos_malloc(sizeof(struct bt_gatt_indicate_params));
57
58 if (!p_indicate)
59 {
60 BT_ERR("no mem");
61 return;
62 }
63
64 memset(&msg, 0, sizeof(msg));
65 if (genie_ais_ctx.state == AIS_STATE_IDLE)
66 {
67 msg.header.enc = 1;
68 }
69 else
70 {
71 msg.header.enc = 0;
72 }
73 msg.header.msg_id = msg_id;
74 msg.header.cmd = cmd;
75 msg.header.payload_len = len;
76 if (p_msg)
77 {
78 memcpy(msg.payload, p_msg, len);
79 }
80
81 BT_DBG("len %d: %s", len + 4, bt_hex(&msg, len + 4));
82
83 //indicate._req
84 p_indicate->attr = &_ais_srv_attrs[6];
85 p_indicate->func = _ais_indicate_rsp;
86 p_indicate->data = &msg;
87 p_indicate->len = len + 4;
88
89 if (genie_ais_ctx.p_conn)
90 {
91 #ifdef DEBUG_AIS_DETAIL_DATA
92 printf("ais ind msgid:%d cmd:%02x p_ind:%p len:%d data:%s\r\n", msg_id, cmd, p_indicate, len, bt_hex(&msg, len + 4));
93 #else
94 printf("ais ind msgid:%d cmd:%02x p_ind:%p len:%d\r\n", msg_id, cmd, p_indicate, len);
95 #endif
96
97 ret = bt_gatt_indicate(genie_ais_ctx.p_conn, p_indicate);
98 if (ret < 0)
99 {
100 printf("ais bt_gatt_indicate err:%d\r\n", ret);
101 aos_free(p_indicate);
102 }
103 }
104 else
105 {
106 printf("ais not connect\r\n");
107 aos_free(p_indicate);
108 }
109 }
110
genie_ais_notify(uint8_t msg_id,uint8_t cmd,uint8_t * p_msg,uint16_t len)111 void genie_ais_notify(uint8_t msg_id, uint8_t cmd, uint8_t *p_msg, uint16_t len)
112 {
113 ais_pdu_t msg;
114
115 memset(&msg, 0, sizeof(msg));
116 if (genie_ais_ctx.state >= AIS_STATE_IDLE && genie_ais_ctx.state <= AIS_STATE_REBOOT)
117 {
118 msg.header.enc = 1;
119 }
120 else
121 {
122 msg.header.enc = 0;
123 }
124
125 msg.header.cmd = cmd;
126 msg.header.msg_id = msg_id;
127 msg.header.payload_len = len;
128 if (p_msg)
129 {
130 memcpy(msg.payload, p_msg, len);
131 }
132
133 BT_DBG("len %d: %s", len + 4, bt_hex(&msg, len + 4));
134
135 if (genie_ais_ctx.p_conn)
136 {
137 #ifdef DEBUG_AIS_DETAIL_DATA
138 printf("ais notify msgid:%d cmd:%02x len:%d data:%s\r\n", msg_id, cmd, len, bt_hex(&msg, len + 4));
139 #else
140 printf("ais notify msgid:%d cmd:%02x len:%d\r\n", msg_id, cmd, len);
141 #endif
142
143 bt_gatt_notify(genie_ais_ctx.p_conn, &_ais_srv_attrs[11], &msg, len + 4);
144 }
145 }
146
handle_ais_disconnect(void)147 static void handle_ais_disconnect(void)
148 {
149 if (genie_ais_ctx.p_conn)
150 {
151 BT_DBG("ais handle disconn:%p\r\n", genie_ais_ctx.p_conn);
152 bt_conn_disconnect(genie_ais_ctx.p_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
153 genie_ais_ctx.p_conn = NULL;
154 }
155 }
156
genie_ais_disconnect(uint8_t reason)157 void genie_ais_disconnect(uint8_t reason)
158 {
159 BT_DBG("ais disconn 0x%x, state %d\r\n", reason, genie_ais_ctx.state);
160 if (genie_ais_ctx.state != AIS_STATE_REBOOT)
161 {
162 k_timer_stop(&genie_ais_ctx.state_update_timer);
163 handle_ais_disconnect();
164
165 genie_ais_ctx.state = AIS_STATE_DISCON;
166 /* Flash is dirty, need erase */
167 if (genie_ota_ctx.flash_clean == 1 &&
168 genie_ota_ctx.ota_ready == 0)
169 {
170 erase_dfu_flash();
171 genie_ota_ctx.flash_clean = 0;
172 }
173 /* restart adv */
174 genie_event(GENIE_EVT_SDK_AIS_DISCON, NULL);
175 }
176 else
177 {
178 if (genie_ota_ctx.ota_flag != OTA_FLAG_SILENT || genie_sal_ota_is_allow_reboot())
179 {
180 //clear image change
181 BT_WARN("OTA Reboot!");
182 genie_storage_delete_reliable(GFI_OTA_IMAGE_ID);
183 dfu_reboot();
184 }
185 }
186 }
187
genie_ais_state_update(void)188 static void genie_ais_state_update(void)
189 {
190 if (genie_ais_ctx.state != AIS_STATE_OTA)
191 {
192 BT_DBG("ais update state:%d", genie_ais_ctx.state);
193 }
194
195 if (genie_ais_ctx.p_conn == NULL)
196 {
197 BT_WARN("proxy is disconnected");
198 return;
199 }
200
201 switch (genie_ais_ctx.state)
202 {
203 case AIS_STATE_DISCON:
204 k_timer_stop(&genie_ais_ctx.state_update_timer);
205 handle_ais_disconnect();
206 break;
207 case AIS_STATE_CONNECT:
208 case AIS_STATE_IDLE:
209 //no disconnect after one minute
210 //k_timer_start(&genie_ais_ctx.state_update_timer, AIS_OTA_DISCONN_TIMEOUT);
211 break;
212 case AIS_STATE_AUTH:
213 k_timer_start(&genie_ais_ctx.state_update_timer, AIS_OTA_AUTH_TIMEOUT);
214 break;
215 case AIS_STATE_OTA:
216 k_timer_start(&genie_ais_ctx.state_update_timer, AIS_OTA_REPORT_TIMEOUT);
217 break;
218 case AIS_STATE_REBOOT:
219 k_timer_start(&genie_ais_ctx.state_update_timer, AIS_OTA_REBOOT_TIMEOUT);
220 k_timer_start(&genie_ais_ctx.disconnect_timer, AIS_DISCONNECT_TIMEOUT);
221 break;
222 default:
223 break;
224 }
225 }
226
state_update_timer_cb(void * p_timer,void * args)227 static void state_update_timer_cb(void *p_timer, void *args)
228 {
229 BT_DBG(" %d", genie_ais_ctx.state);
230 switch (genie_ais_ctx.state)
231 {
232 case AIS_STATE_CONNECT:
233 case AIS_STATE_IDLE:
234 {
235 genie_ais_ctx.state = AIS_STATE_DISCON;
236 }
237 break;
238 case AIS_STATE_AUTH:
239 {
240 genie_ais_reset();
241 genie_ais_ctx.state = AIS_STATE_CONNECT;
242 }
243 break;
244 case AIS_STATE_OTA:
245 {
246 if (genie_ota_ctx.err_count++ >= OTA_RECV_MAX_ERR_COUNT)
247 {
248 BT_ERR("OTA failed");
249 genie_ais_ctx.state = AIS_STATE_IDLE;
250 genie_ota_ctx.rx_len = 0;
251 _ais_server_indicate(0, AIS_RESP_ERR, NULL, 0);
252 }
253 else
254 {
255 genie_ota_status_report();
256 }
257 }
258 break;
259 case AIS_STATE_REBOOT:
260 {
261 printf("ais ota update done,do reboot ...\r\n");
262 dfu_reboot();
263 }
264 break;
265 default:
266 break;
267 }
268 genie_ais_state_update();
269 }
270
genie_ais_connect(struct bt_conn * p_conn)271 void genie_ais_connect(struct bt_conn *p_conn)
272 {
273 BT_DBG("ais connect state:%d conn:%p", genie_ais_ctx.state, p_conn);
274 if (genie_ais_ctx.state != AIS_STATE_REBOOT)
275 {
276 BT_DBG("status %d", genie_ais_ctx.state);
277 genie_ais_ctx.p_conn = p_conn;
278 genie_ais_ctx.state = AIS_STATE_CONNECT;
279 genie_ais_state_update();
280 genie_event(GENIE_EVT_SDK_AIS_CONNECT, NULL);
281 }
282 }
283
_ais_dis_timer_cb(void * p_timer,void * args)284 static void _ais_dis_timer_cb(void *p_timer, void *args)
285 {
286 printf("ais timeout disconnect\r\n");
287 handle_ais_disconnect();
288 }
289
_ais_scrt_random(uint8_t msg_id,ais_scrt_random_t * p_scrt_random)290 static bool _ais_scrt_random(uint8_t msg_id, ais_scrt_random_t *p_scrt_random)
291 {
292 uint8_t cipher[16];
293
294 genie_ais_ctx.state = AIS_STATE_AUTH;
295 genie_ais_get_cipher(p_scrt_random->random, cipher);
296 _ais_server_indicate(msg_id, AIS_SCRT_CIPHER, cipher, 16);
297
298 return true;
299 }
300
_ais_scrt_result(uint8_t msg_id,ais_scrt_result_t * p_scrt_result)301 static bool _ais_scrt_result(uint8_t msg_id, ais_scrt_result_t *p_scrt_result)
302 {
303 uint8_t ack = 0;
304
305 if (p_scrt_result->result == 1)
306 {
307 genie_ais_reset();
308 genie_ais_ctx.state = AIS_STATE_CONNECT;
309 }
310 else
311 {
312 genie_ais_ctx.state = AIS_STATE_IDLE;
313 }
314
315 _ais_server_indicate(msg_id, AIS_SCRT_ACK, &ack, 1);
316
317 return true;
318 }
319
_ais_link_ack(uint8_t msg_id,ais_scrt_result_t * p_scrt_result)320 static bool _ais_link_ack(uint8_t msg_id, ais_scrt_result_t *p_scrt_result)
321 {
322 uint8_t plaine_data[GENIE_CRYPTO_UNIT_SIZE];
323 uint8_t encrypt_data[GENIE_CRYPTO_UNIT_SIZE];
324
325 if (p_scrt_result->result == 0)
326 {
327 genie_ais_reset();
328 genie_ais_ctx.state = AIS_STATE_CONNECT;
329 }
330 memset(plaine_data, 0x0F, sizeof(plaine_data));
331 plaine_data[0] = 1;
332
333 genie_crypto_encrypt(plaine_data, encrypt_data);
334 _ais_server_indicate(msg_id, AIS_LINK_ACK, encrypt_data, GENIE_CRYPTO_UNIT_SIZE);
335
336 return true;
337 }
338
_ais_msg_check_header(ais_header_t * p_msg_header)339 static bool _ais_msg_check_header(ais_header_t *p_msg_header)
340 {
341 //check seq & total, in ota case, the seq & total must be 0
342 if (p_msg_header->total_frame != 0 || p_msg_header->seq != 0 || p_msg_header->ver != 0 || p_msg_header->seq > p_msg_header->total_frame)
343 {
344 BT_ERR("fail %s", bt_hex(p_msg_header, sizeof(ais_header_t)));
345 return false;
346 }
347 return true;
348 }
349
_ais_server_msg_handle(struct bt_conn * p_conn,ais_pdu_t * p_msg,uint16_t len)350 static void _ais_server_msg_handle(struct bt_conn *p_conn, ais_pdu_t *p_msg, uint16_t len)
351 {
352 bool timer_refresh = false;
353
354 if (p_msg->header.cmd != AIS_OTA_DATA && !_ais_msg_check_header((ais_header_t *)p_msg))
355 {
356 printf("ais invalid msg, ignore");
357 }
358
359 if (p_msg->header.cmd != AIS_OTA_DATA)
360 {
361 #ifdef DEBUG_AIS_DETAIL_DATA
362 printf("ais cmd:0x%02x state:%d len:%d data:%s\r\n", p_msg->header.cmd, genie_ais_ctx.state, len, bt_hex(p_msg, len));
363 #else
364 printf("ais cmd:0x%02x state:%d len:%d\r\n", p_msg->header.cmd, genie_ais_ctx.state, len);
365 #endif
366 }
367
368 switch (p_msg->header.cmd)
369 {
370 case AIS_SCRT_RANDOM:
371 {
372 //len = 4+16
373 if (len == 20) //At any state we can negotiation the cipher again
374 {
375 timer_refresh = _ais_scrt_random(p_msg->header.msg_id,
376 (ais_scrt_random_t *)p_msg->payload);
377 }
378 }
379 break;
380
381 case AIS_SCRT_RESULT:
382 {
383 //len = 4+1
384 if (len == 5) //Allow duplicating of this message
385 {
386 k_timer_stop(&genie_ais_ctx.state_update_timer);
387 timer_refresh = _ais_scrt_result(p_msg->header.msg_id, (ais_scrt_result_t *)p_msg->payload);
388 }
389 }
390 break;
391
392 case AIS_LINK_STATUS:
393 {
394 //len = 4+16
395 if (len == 20) //Allow duplicating of this message
396 {
397 if (0 == _ais_decrypt(p_msg->payload, 16))
398 {
399 timer_refresh = _ais_link_ack(p_msg->header.msg_id, (ais_scrt_result_t *)p_msg->payload);
400 }
401 }
402 }
403 break;
404
405 case AIS_OTA_VER_REQ:
406 {
407 if (len == 20) //This is encrypted data
408 {
409 if (0 == _ais_decrypt(p_msg->payload, 16))
410 {
411 timer_refresh = genie_ota_handle_version_request(p_msg->header.msg_id, (ais_ota_ver_req_t *)p_msg->payload, 1);
412 }
413 }
414 else if (len == 5)
415 {
416 timer_refresh = genie_ota_handle_version_request(p_msg->header.msg_id, (ais_ota_ver_req_t *)p_msg->payload, 0);
417 }
418 }
419 break;
420
421 case AIS_OTA_FIRMWARE_REQ:
422 {
423 //len = 4+16
424 if (len == 20) //Encrypted data
425 {
426 if (0 == _ais_decrypt(p_msg->payload, 16))
427 {
428 timer_refresh = genie_ota_handle_update_request(p_msg->header.msg_id, (ais_ota_upd_req_t *)p_msg->payload, 1);
429 }
430 }
431 else if (len == 16) //Plain data
432 {
433 timer_refresh = genie_ota_handle_update_request(p_msg->header.msg_id, (ais_ota_upd_req_t *)p_msg->payload, 0);
434 }
435 }
436 break;
437
438 case AIS_OTA_DATA:
439 {
440 if ((len == sizeof(ais_header_t) + p_msg->header.payload_len) && p_msg->header.ver == 0)
441 {
442 timer_refresh = genie_ota_parse_pdu(p_msg);
443 }
444 }
445 break;
446
447 case AIS_OTA_CHECK_REQ:
448 {
449 if (len == 20 && genie_ais_ctx.state == AIS_STATE_OTA)
450 {
451 if (0 == _ais_decrypt(p_msg->payload, 16))
452 {
453 timer_refresh = genie_ota_check_firmware(p_msg->header.msg_id, (ais_ota_check_req_t *)p_msg->payload);
454 }
455 }
456 }
457 break;
458
459 default:
460 {
461 /* recv some unsupport cmd, just return */
462 BT_WARN("ais unsupport cmd %x\r\n", p_msg->header.cmd);
463 }
464 return;
465 }
466
467 if (timer_refresh)
468 {
469 genie_ais_state_update();
470 }
471 else
472 {
473 if (genie_ais_ctx.state != AIS_STATE_OTA)
474 {
475 printf("ais err state:%d cmd:0x%02x len:%d\r\n", genie_ais_ctx.state, p_msg->header.cmd, len);
476 _ais_server_indicate(p_msg->header.msg_id, AIS_RESP_ERR, NULL, 0);
477 }
478 }
479 }
480
_ais_server_read(struct bt_conn * p_conn,const struct bt_gatt_attr * p_attr,void * buf,u16_t len,u16_t offset)481 static ssize_t _ais_server_read(struct bt_conn *p_conn, const struct bt_gatt_attr *p_attr,
482 void *buf, u16_t len, u16_t offset)
483 {
484 u16_t *value = p_attr->user_data;
485
486 BT_DBG("len %d: %s", len, bt_hex(buf, len));
487
488 return bt_gatt_attr_read(p_conn, p_attr, buf, len, offset, value, sizeof(*value));
489 }
490
_ais_service_write(struct bt_conn * p_conn,const struct bt_gatt_attr * p_attr,const void * p_buf,u16_t len,u16_t offset,u8_t flags)491 static ssize_t _ais_service_write(struct bt_conn *p_conn, const struct bt_gatt_attr *p_attr,
492 const void *p_buf, u16_t len, u16_t offset, u8_t flags)
493 {
494 //BT_DBG("len %d: %s", len, bt_hex(p_buf, len));
495
496 if (len != 0)
497 {
498 _ais_server_msg_handle(p_conn, (ais_pdu_t *)p_buf, len);
499 }
500
501 return len;
502 }
503
_ais_service_write_nr(struct bt_conn * p_conn,const struct bt_gatt_attr * p_attr,const void * p_buf,u16_t len,u16_t offset,u8_t flags)504 static ssize_t _ais_service_write_nr(struct bt_conn *p_conn, const struct bt_gatt_attr *p_attr,
505 const void *p_buf, u16_t len, u16_t offset, u8_t flags)
506 {
507 //BT_DBG("len %d: %s", len, bt_hex(p_buf, len));
508 return _ais_service_write(p_conn, p_attr, p_buf, len, offset, flags);
509 }
510
_ais_service_ccc_cfg_changed(const struct bt_gatt_attr * p_attr,uint16_t value)511 static void _ais_service_ccc_cfg_changed(const struct bt_gatt_attr *p_attr, uint16_t value)
512 {
513 }
514
515 /* AIS OTA Service Declaration */
516 static struct bt_gatt_attr _ais_srv_attrs[] = {
517 BT_GATT_PRIMARY_SERVICE(AIS_SERVICE_UUID),
518
519 BT_GATT_CHARACTERISTIC(AIS_READ_UUID, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, _ais_server_read, NULL, NULL),
520
521 BT_GATT_CHARACTERISTIC(AIS_WRITE_UUID, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, BT_GATT_PERM_WRITE,
522 NULL, _ais_service_write, NULL),
523
524 BT_GATT_CHARACTERISTIC(AIS_INDICATE_UUID, BT_GATT_CHRC_READ | BT_GATT_CHRC_INDICATE,
525 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, _ais_server_read, NULL, NULL),
526
527 BT_GATT_CCC(_ais_service_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
528
529 BT_GATT_CHARACTERISTIC(AIS_WRITE_WO_RESP_UUID, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
530 BT_GATT_PERM_WRITE, NULL, _ais_service_write_nr, NULL),
531
532 BT_GATT_CHARACTERISTIC(AIS_NOTIFY_UUID, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
533 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, _ais_server_read, NULL, NULL),
534
535 BT_GATT_CCC(_ais_service_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
536 };
537
538 static struct bt_gatt_service _ais_srv = BT_GATT_SERVICE(_ais_srv_attrs);
539
540 #ifdef CONFIG_BT_MESH_MULTIADV
541 static u8_t g_ais_adv_data[14] = {
542 0xa8, 0x01, //taobao
543 0x85, //vid & sub
544 0x15, //FMSK
545 0x15, 0x11, 0x22, 0x33, //PID
546 0xAA, 0xBB, 0xCC, 0x11, 0x22, 0x33 //MAC
547 };
548
549 struct bt_data g_ais_adv[] = {
550 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
551 BT_DATA_BYTES(BT_DATA_UUID16_SOME, 0xB3, 0xFE),
552 BT_DATA(BT_DATA_MANUFACTURER_DATA, g_ais_adv_data, 14),
553 };
554
555 static const struct bt_data g_ais_sd[] = {
556 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
557 BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, (sizeof(CONFIG_BT_DEVICE_NAME) - 1)),
558 };
559
560 struct bt_le_adv_param fast_adv_param = {
561 .options = (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME),
562 .interval_min = BT_GAP_ADV_FAST_INT_MIN_2,
563 .interval_max = BT_GAP_ADV_FAST_INT_MAX_2,
564 .own_addr = NULL,
565 };
566 #endif
567
genie_ais_state_set(uint8_t state)568 int genie_ais_state_set(uint8_t state)
569 {
570 genie_ais_ctx.state = state;
571
572 return 0;
573 }
574
genie_ais_state_get(void)575 uint8_t genie_ais_state_get(void)
576 {
577 return genie_ais_ctx.state;
578 }
579
580 #ifdef CONFIG_BT_MESH_MULTIADV
581 int g_multiadv_instant_id;
multi_adv_init(void)582 static int multi_adv_init(void)
583 {
584 int err = -1;
585
586 genie_crypto_adv_create(g_ais_adv_data, 0);
587
588 err = bt_le_multi_adv_start(&fast_adv_param, g_ais_adv, ARRAY_SIZE(g_ais_adv), g_ais_sd, ARRAY_SIZE(g_ais_sd), &g_multiadv_instant_id);
589 if (err)
590 {
591 BT_ERR("Multi Advertising failed to start (err %d)\n", err);
592 }
593
594 return err;
595 }
596 #endif
597
genie_ais_init(void)598 int genie_ais_init(void)
599 {
600 #ifdef CONFIG_BT_MESH_MULTIADV
601 multi_adv_init();
602 #endif
603
604 bt_gatt_service_register(&_ais_srv);
605
606 k_timer_init(&genie_ais_ctx.state_update_timer, state_update_timer_cb, NULL);
607 k_timer_init(&genie_ais_ctx.disconnect_timer, _ais_dis_timer_cb, NULL);
608
609 printf("ais init\r\n");
610
611 return 0;
612 }
613
genie_ais_pre_init(void)614 int genie_ais_pre_init(void)
615 {
616 printf("ais pre init\r\n");
617
618 memset(&genie_ais_ctx, 0, sizeof(genie_ais_ctx));
619
620 return 0;
621 }
622