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