/**************************************************************************** * * Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED. * * This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT * be copied by any method or incorporated into another program without * the express written consent of Aerospace C.Power. This Information or any portion * thereof remains the property of Aerospace C.Power. The Information contained herein * is believed to be accurate and Aerospace C.Power assumes no responsibility or * liability for its use in any way and conveys no license or title under * any patent or copyright and makes no representation or warranty that this * Information is free from patent or copyright infringement. * * ****************************************************************************/ #include "os_types.h" #include "os_utils_api.h" #include "os_mem_api.h" #include "iot_config.h" #include "iot_errno_api.h" #include "iot_io_api.h" #include "iot_config_api.h" #include "iot_utils_api.h" #include "iot_board_api.h" #include "iot_task_api.h" #include "iot_crc_api.h" #include "iot_uart_h.h" #include "iot_bt_ext_msg.h" #include "iot_bt_ext.h" #include "iot_bt_ext_upgrade.h" #include "iot_bt_ext_dev_mgmt.h" #if IOT_BT_EXT_ENABLE /* for debug mode. default 0 */ #define IOT_BT_EXT_DEBUG 0 /* task priority */ #define IOT_BT_EXT_TASK_PRIO 7 /* task stack size */ #define IOT_BT_EXT_TASK_STACK_SIZE 512 /* task message count */ #define IOT_BT_EXT_TASK_MSG_COUNT 64 /* alarm timer period */ #define IOT_BT_EXT_ALARM_PERIOD_MS 1000 #define iot_bt_ext_ctxt_get() (g_bt_ext_ctxt) static iot_bt_ext_ctxt_t *g_bt_ext_ctxt = NULL; #if IOT_BT_EXT_DEBUG #define iot_bt_ext_dbg(fmt, ...) iot_printf(fmt, ##__VA_ARGS__) #else #define iot_bt_ext_dbg(fmt, ...) #endif /* sub system config table */ static const iot_bt_ext_sub_cfg_t gc_bt_ext_sub_cfg_tbl[] = { /* bt upgrade port config */ { /* sub port id */ IOT_BT_EXT_PORT_UPGRADE, /* sub port open function */ iot_bt_ext_upgrade_init, /* sub port close function */ iot_bt_ext_upgrade_deinit, /* sub port rx report callback function */ iot_bt_ext_upgrade_rx, /* sub port alarm task callback function, implement by post messages */ iot_bt_ext_upgrade_timeover_cb, }, /* bt device management port config */ { /* sub port id */ IOT_BT_EXT_PORT_DEV_MGMT, /* sub port open function */ iot_bt_ext_dm_open, /* sub port close function */ iot_bt_ext_dm_close, /* sub port rx report callback function */ iot_bt_ext_dm_rx, /* sub port alarm task callback function, implement by post messages */ iot_bt_ext_dm_alarm_cb, }, }; static void iot_bt_ext_data_print(uint8_t is_tx, uint16_t len, uint8_t *buf) { uint16_t i; iot_printf("bt:is_tx=%d,len=%d. ", is_tx, len); len = min(len, 32); for (i = 0; i < len; i++) { iot_printf("0x%02x ", *(buf + i)); } iot_printf("\n"); } void iot_bt_ext_clean_msg(uint16_t msg_type, uint16_t msg_id) { iot_bt_ext_ctxt_t *bt_ctxt = iot_bt_ext_ctxt_get(); if (bt_ctxt) { iot_task_clean_msg(bt_ctxt->task_hdl, msg_type, msg_id); } } /* post message to task */ uint32_t iot_bt_ext_post_msg(uint16_t msg_type, uint16_t msg_id, void *data) { iot_task_msg_t *msg; iot_bt_ext_msg_type_t *task_msg; iot_bt_ext_ctxt_t *bt_ctxt = iot_bt_ext_ctxt_get(); msg = iot_task_alloc_msg_with_reserved(bt_ctxt->task_hdl, 0); if (NULL == msg) { //IOT_ASSERT(0); return ERR_NOMEM; } task_msg = (iot_bt_ext_msg_type_t *)msg; task_msg->msg.type = msg_type; task_msg->msg.id = msg_id; task_msg->data = data; iot_task_queue_msg(bt_ctxt->task_hdl, &task_msg->msg, 0); return ERR_OK; } static iot_bt_ext_rpt_func_t iot_bt_ext_rpt_hdl_get(uint8_t port) { uint8_t i, offset; iot_bt_ext_ctxt_t *bt_ctxt = iot_bt_ext_ctxt_get(); /* sub port */ if (port < IOT_BT_EXT_PORT_USER_BASE) { for (i = 0; i < bt_ctxt->sub_info.sub_num; i++) { if (bt_ctxt->sub_info.cfg[i].port_id == port) { return bt_ctxt->sub_info.cfg[i].rx_rpt_func; } } } else { /* user port */ for (i = IOT_BT_EXT_PORT_USER_BASE; i < IOT_BT_EXT_PORT_USER_END; i++) { offset = i - IOT_BT_EXT_PORT_USER_BASE; if (bt_ctxt && (bt_ctxt->user_info[offset].port_id == port)) { return bt_ctxt->user_info[offset].rx_rpt_func; } } } return NULL; } static void iot_bt_ext_rpt_handle(uint8_t port, iot_pkt_t *pkt) { iot_bt_ext_ctxt_t *bt_ctxt = iot_bt_ext_ctxt_get(); if (!bt_ctxt) { if (pkt) { iot_pkt_free(pkt); pkt = NULL; } return; } iot_bt_ext_dbg("bt:%s. port=%d\n", __FUNCTION__, port); iot_bt_ext_rpt_func_t func = iot_bt_ext_rpt_hdl_get(port); if (func) { func(pkt); } else { iot_printf("bt:port[%d] rpt not support\n", port); iot_pkt_free(pkt); } } static void iot_bt_ext_proto_parse(iot_pkt_t *pkt) { uint16_t crc_cal, len; uint32_t err_no = 0; uint8_t *buf; iot_bt_ext_proto_start_t *proto_start; iot_bt_ext_proto_hdr_t *proto_hdr; iot_bt_ext_proto_end_t *proto_end; if (!pkt) { return; } buf = (uint8_t *)iot_pkt_data(pkt); len = (uint16_t)iot_pkt_data_len(pkt); iot_bt_ext_data_print(0, len, buf); do { /* check total len */ if (len < IOT_BT_EXT_PROTO_PACKET_MIN_LEN) { err_no = (uint32_t)__LINE__; break; } /* check start field */ proto_start = (iot_bt_ext_proto_start_t *)buf; iot_bt_ext_dbg("bt:proto-start.0x%x-0x%x\n", proto_start->start[0], proto_start->start[1]); if ((IOT_BT_EXT_PROTO_START_CODE != proto_start->start[0]) || (IOT_BT_EXT_PROTO_START_CODE != proto_start->start[1])) { err_no = (uint32_t)__LINE__; break; } /* check header field */ proto_hdr = (iot_bt_ext_proto_hdr_t *)(proto_start + 1); iot_bt_ext_dbg("bt:proto-hdr.version:%d,port:%d," "crc=0x%x,len:%d\n", proto_hdr->version, proto_hdr->port, proto_hdr->crc, proto_hdr->length); /* check version */ //TODO: /* check port valid */ if (proto_hdr->port >= IOT_BT_EXT_PORT_USER_END) { err_no = (uint32_t)__LINE__; break; } /* check payload len */ if (proto_hdr->length > (len - IOT_BT_EXT_PROTO_PACKET_MIN_LEN)) { err_no = (uint32_t)__LINE__; break; } /* check payload crc */ crc_cal = iot_getcrc16((uint8_t *)(proto_hdr + 1), proto_hdr->length, IOT_CRC16_TYPE_BT); iot_bt_ext_dbg("bt:proto-src_crc=0x%x, cal_crc=0x%x\n", proto_hdr->crc, crc_cal); if (proto_hdr->crc != crc_cal) { //err_no = (uint32_t)__LINE__; //break; } /* check tail */ proto_end = (iot_bt_ext_proto_end_t *)((uint8_t *)(proto_hdr + 1) + proto_hdr->length); iot_bt_ext_dbg("bt:proto-end.0x%x-0x%x\n", proto_end->end[0], proto_end->end[1]); if ((IOT_BT_EXT_PROTO_END_CODE != proto_end->end[0]) || (IOT_BT_EXT_PROTO_END_CODE != proto_end->end[1])) { err_no = (uint32_t)__LINE__; break; } /* set pkt data ptr for payload start */ iot_pkt_pull(pkt, sizeof(*proto_start) + sizeof(*proto_hdr)); /* set pkt tail ptr for payload end */ iot_pkt_shrink(pkt, sizeof(*proto_end)); iot_bt_ext_dbg("bt:proto_rpt_sub pkt_len=%d\n", iot_pkt_data_len(pkt)); /* report pkt */ iot_bt_ext_rpt_handle(proto_hdr->port, pkt); } while(0); if (err_no) { iot_printf("bt:proto_parse.err=%d.\n", err_no); iot_pkt_free(pkt); } } /* protocol uart tx */ static void iot_bt_ext_send_handle(uint8_t port, iot_pkt_t *pkt) { uint16_t crc, len; uint32_t err_no = 0; iot_bt_ext_proto_start_t *proto_start; iot_bt_ext_proto_hdr_t *proto_hdr; iot_bt_ext_proto_end_t *proto_end; iot_bt_ext_ctxt_t *bt_ctxt = iot_bt_ext_ctxt_get(); do { if ((NULL == bt_ctxt) || (NULL == pkt)) { err_no = __LINE__; break; } /* get input data len and crc */ len = (uint16_t)iot_pkt_data_len(pkt); crc = iot_getcrc16(iot_pkt_data(pkt), len, IOT_CRC16_TYPE_BT); /* set pkt data ptr */ proto_start = (iot_bt_ext_proto_start_t *)iot_pkt_push(pkt, sizeof(iot_bt_ext_proto_start_t) + sizeof(iot_bt_ext_proto_hdr_t)); if (NULL == proto_start) { err_no = __LINE__; break; } /* set tail ptr */ if (NULL == iot_pkt_put(pkt, sizeof(iot_bt_ext_proto_end_t))) { err_no = __LINE__; break; } /* fill start code */ os_mem_set(proto_start, IOT_BT_EXT_PROTO_START_CODE, sizeof(*proto_start)); /* fill proto header */ proto_hdr = (iot_bt_ext_proto_hdr_t *)(proto_start + 1); proto_hdr->version = IOT_BT_EXT_PROTO_VERSION; proto_hdr->port = port; proto_hdr->length = len; proto_hdr->crc = crc; /* fill tail */ proto_end = (iot_bt_ext_proto_end_t *)((uint8_t *)(proto_hdr + 1) + len); os_mem_set(proto_end, IOT_BT_EXT_PROTO_END_CODE, sizeof(*proto_end)); /* print output data */ iot_bt_ext_data_print(1, (uint16_t)iot_pkt_data_len(pkt), (uint8_t *)iot_pkt_data(pkt)); /* send data */ iot_uart_send(bt_ctxt->peri_info.peri_hdl, pkt, NULL); } while(0); if (err_no) { iot_bt_ext_dbg("bt:%s, err = %d\n", __FUNCTION__, err_no); if (pkt) { iot_pkt_free(pkt); } } } static void iot_bt_ext_msg_handle(iot_task_h task_h, iot_task_msg_t *msg) { iot_bt_ext_msg_type_t *msg_entry = (iot_bt_ext_msg_type_t *)msg; switch (msg_entry->msg.type) { case IOT_BT_EXT_MSG_TYPE_DATA_RX: iot_bt_ext_proto_parse((iot_pkt_t *)msg_entry->data); break; case IOT_BT_EXT_MSG_TYPE_DATA_TX: iot_bt_ext_send_handle((uint8_t)msg_entry->msg.id, (iot_pkt_t *)msg_entry->data); break; case IOT_BT_EXT_MSG_TYPE_UPGRADE: iot_bt_ext_upgrade_msg_handle((uint8_t)msg_entry->msg.id, msg_entry->data); break; case IOT_BT_EXT_MSG_TYPE_DEV_MGMT: iot_bt_ext_dm_msg_handle(msg_entry->msg.id, msg_entry->data); break; default: break; } iot_task_free_msg(task_h, &(msg_entry->msg)); } static void iot_bt_ext_msg_cancel(iot_task_h task_h, iot_task_msg_t *msg) { iot_bt_ext_msg_type_t *msg_entry = (iot_bt_ext_msg_type_t *)msg; switch (msg_entry->msg.type) { case IOT_BT_EXT_MSG_TYPE_DATA_RX: case IOT_BT_EXT_MSG_TYPE_DATA_TX: if (msg_entry->data) { iot_pkt_free((iot_pkt_t *)msg_entry->data); } break; case IOT_BT_EXT_MSG_TYPE_UPGRADE: case IOT_BT_EXT_MSG_TYPE_DEV_MGMT: break; default: break; } iot_task_free_msg(task_h, &(msg_entry->msg)); } static iot_task_h iot_bt_ext_task_init(void) { iot_task_config_t task_cfg = {0}; /* task config */ task_cfg.stack_size = IOT_BT_EXT_TASK_STACK_SIZE; task_cfg.task_prio = IOT_BT_EXT_TASK_PRIO; task_cfg.msg_size = sizeof(iot_bt_ext_msg_type_t); task_cfg.msg_cnt = IOT_BT_EXT_TASK_MSG_COUNT; task_cfg.queue_cnt = 1; task_cfg.queue_cfg[0].quota = 0; task_cfg.task_event_func = NULL; task_cfg.msg_exe_func = iot_bt_ext_msg_handle; task_cfg.msg_cancel_func = iot_bt_ext_msg_cancel; return iot_task_create(IOT_DRIVER_MID, &task_cfg); } static void iot_bt_ext_peri_recv(uint8_t* buffer, uint32_t buffer_len, bool_t is_full_frame, uint32_t invalid_data_len) { iot_pkt_t *pkt; (void)invalid_data_len; (void)is_full_frame; iot_bt_ext_dbg("bt:%s-rx len %d\n", __FUNCTION__, buffer_len); pkt = iot_pkt_alloc(buffer_len, IOT_DRIVER_MID); if (pkt) { os_mem_cpy(iot_pkt_put(pkt, buffer_len), buffer, buffer_len); iot_bt_ext_post_msg(IOT_BT_EXT_MSG_TYPE_DATA_RX, 0, pkt); } } static iot_uart_h iot_bt_ext_uart_init(iot_bt_ext_uart_cfg_t *cfg) { uint8_t uart_type; iot_uart_h uart_hdl = NULL; iot_frame_fmt fmt = { 0 }; fmt.preamble_code[0] = IOT_BT_EXT_PROTO_START_CODE; fmt.preamble_code[1] = IOT_BT_EXT_PROTO_START_CODE; fmt.preamble_codelen = IOT_BT_EXT_PROTO_START_LEN; fmt.datalen_offset = sizeof(iot_bt_ext_proto_hdr_t) - IOT_BT_EXT_PROTO_PL_LEN_FIELD_LEN; fmt.datalen_size = IOT_BT_EXT_PROTO_PL_LEN_FIELD_LEN; fmt.datalen_fix = 0; fmt.backcode[0] = IOT_BT_EXT_PROTO_END_CODE; fmt.backcode[1] = IOT_BT_EXT_PROTO_END_CODE; fmt.backcode_offset = 0; fmt.backcode_len = IOT_BT_EXT_PROTO_END_LEN; fmt.frame_timeout = 20; fmt.timeout_mode = TIMEOUT_PERDATA; //TODO: will fix uart port #if (HW_PLATFORM >= HW_PLATFORM_FPGA) uart_type = UART_EXT_BT_PORT; #else uart_type = UART_IR_PORT; //TODO: #endif if (iot_board_get_uart(uart_type) >= IOT_UART_PORT_SUPP_MAX) { return uart_hdl; } uart_hdl = iot_uart_open(iot_board_get_uart(uart_type), iot_bt_ext_peri_recv, IOT_EXT_BT_PERI_BUF_LEN, &fmt); if (uart_hdl && cfg) { if (!iot_uart_set_config(uart_hdl, cfg->baud, (uint8_t)cfg->parity, (uint8_t)cfg->data, (uint8_t)cfg->stop)) { uart_hdl = (iot_uart_h)NULL; } } return uart_hdl; } static void iot_bt_ext_alarm_inform(timer_id_t timer_id, void *arg) { uint8_t i; iot_bt_ext_alarm_func_t alarm_func; iot_bt_ext_ctxt_t *bt_ctxt; (void)timer_id; bt_ctxt = (iot_bt_ext_ctxt_t *)arg; if (!bt_ctxt) { return; } for (i = 0; i < bt_ctxt->sub_info.sub_num; i++) { alarm_func = bt_ctxt->sub_info.cfg[i].alarm_func; if (alarm_func) { alarm_func((uint32_t)bt_ctxt->alarm_period); } } } static uint32_t iot_bt_ext_alarm_init(iot_bt_ext_ctxt_t *bt_ctxt) { if (!bt_ctxt) { return ERR_INVAL; } bt_ctxt->alarm_timer = os_create_timer(IOT_DRIVER_MID, true, (os_timer_func_t)iot_bt_ext_alarm_inform, bt_ctxt); if (!bt_ctxt->alarm_timer) { return ERR_FAIL; } bt_ctxt->alarm_period = IOT_BT_EXT_ALARM_PERIOD_MS; return ERR_OK; } static void iot_bt_ext_alarm_start(iot_bt_ext_ctxt_t *bt_ctxt) { if (bt_ctxt && bt_ctxt->alarm_timer) { if (0 == bt_ctxt->alarm_period) { bt_ctxt->alarm_period = IOT_BT_EXT_ALARM_PERIOD_MS; } os_start_timer(bt_ctxt->alarm_timer, bt_ctxt->alarm_period); } } static uint32_t iot_bt_ext_sub_open(iot_bt_ext_ctxt_t *bt_ctxt) { uint8_t i; iot_bt_ext_sub_open_func_t func; if (!bt_ctxt) { return ERR_INVAL; } bt_ctxt->sub_info.sub_num = sizeof(gc_bt_ext_sub_cfg_tbl) / sizeof(gc_bt_ext_sub_cfg_tbl[0]); bt_ctxt->sub_info.cfg = (iot_bt_ext_sub_cfg_t *)gc_bt_ext_sub_cfg_tbl; for (i = 0; i < bt_ctxt->sub_info.sub_num; i++) { func = bt_ctxt->sub_info.cfg[i].open_func; if (func) { if (ERR_OK != func()) { break; } } } if (i < bt_ctxt->sub_info.sub_num) { return ERR_FAIL; } return ERR_OK; } static void iot_bt_ext_sub_close(iot_bt_ext_ctxt_t *bt_ctxt) { uint8_t i; iot_bt_ext_sub_close_func_t func; if (bt_ctxt) { return; } for (i = 0; i < bt_ctxt->sub_info.sub_num; i++) { func = bt_ctxt->sub_info.cfg[i].close_func; if (func) { func(); } } bt_ctxt->sub_info.sub_num = 0; bt_ctxt->sub_info.cfg = NULL; } iot_pkt_t *iot_bt_ext_send_pkt_get(uint32_t len) { iot_pkt_t *pkt; if (NULL == iot_bt_ext_ctxt_get()) { return NULL; } IOT_PKT_GET(pkt, IOT_BT_EXT_PROTO_PACKET_MIN_LEN + len, sizeof(iot_bt_ext_proto_start_t) + sizeof(iot_bt_ext_proto_hdr_t), IOT_DRIVER_MID); return pkt; } uint32_t iot_bt_ext_rpt_register(uint8_t port, iot_bt_ext_rpt_func_t cb) { uint8_t offset; iot_bt_ext_ctxt_t *bt_ctxt = iot_bt_ext_ctxt_get(); /* check port valid */ if ((port < IOT_BT_EXT_PORT_USER_BASE) || (port >= IOT_BT_EXT_PORT_USER_END)) { return ERR_INVAL; } if (bt_ctxt) { offset = port - IOT_BT_EXT_PORT_USER_BASE; bt_ctxt->user_info[offset].port_id = port; bt_ctxt->user_info[offset].rx_rpt_func = cb; iot_bt_ext_dbg("bt:%s. port=%d, func=0x%x\n", __FUNCTION__, port, (uint32_t)cb); return ERR_OK; } return ERR_NOT_READY; } void iot_bt_ext_send(uint8_t port, iot_pkt_t *pkt) { if (NULL == iot_bt_ext_ctxt_get()) { return; } iot_bt_ext_post_msg(IOT_BT_EXT_MSG_TYPE_DATA_TX, port, pkt); } uint32_t iot_bt_ext_open(void) { uint32_t reason = 0; if (g_bt_ext_ctxt) { iot_printf("bt:exist\n"); return ERR_EXIST; } do { /* check port id valid */ BUILD_BUG_ON((uint32_t)IOT_BT_EXT_PORT_SUB_NUM <= (uint32_t)IOT_BT_EXT_PORT_USER_BASE); /* alloc ctxt */ if (NULL == (g_bt_ext_ctxt = os_mem_malloc(IOT_DRIVER_MID, sizeof(*g_bt_ext_ctxt)))) { reason = (uint32_t)__LINE__; break; } os_mem_set(g_bt_ext_ctxt, 0, sizeof(*g_bt_ext_ctxt)); /* init task ctxt */ g_bt_ext_ctxt->task_hdl = iot_bt_ext_task_init(); if (NULL == g_bt_ext_ctxt->task_hdl) { reason = (uint32_t)__LINE__; break; } /* init uart ctxt */ g_bt_ext_ctxt->peri_info.uart_cfg.parity = IOT_UART_PARITY_EVEN; g_bt_ext_ctxt->peri_info.uart_cfg.data = 8; g_bt_ext_ctxt->peri_info.uart_cfg.stop = 1; g_bt_ext_ctxt->peri_info.uart_cfg.baud = 115200; g_bt_ext_ctxt->peri_info.peri_hdl = iot_bt_ext_uart_init(&g_bt_ext_ctxt->peri_info.uart_cfg); if (NULL == g_bt_ext_ctxt->peri_info.peri_hdl) { reason = (uint32_t)__LINE__; break; } /* open sub module */ if (ERR_OK != iot_bt_ext_sub_open(g_bt_ext_ctxt)) { reason = (uint32_t)__LINE__; break; } if (ERR_OK != iot_bt_ext_alarm_init(g_bt_ext_ctxt)) { reason = (uint32_t)__LINE__; break; } } while(0); iot_printf("bt:open-%d\n", reason); if (reason) { iot_bt_ext_close(); return ERR_FAIL; } else { iot_bt_ext_reset(IOT_BT_EXT_DM_BT_HW_RST); /* start alarm timer */ iot_bt_ext_alarm_start(g_bt_ext_ctxt); return ERR_OK; } } uint32_t iot_bt_ext_close(void) { iot_bt_ext_ctxt_t *bt_ctxt = iot_bt_ext_ctxt_get(); if (NULL == bt_ctxt) { return ERR_NOT_EXIST; } iot_bt_ext_sub_close(bt_ctxt); /* release resources */ if (bt_ctxt->alarm_timer) { os_delete_timer(bt_ctxt->alarm_timer); bt_ctxt->alarm_timer = (timer_id_t)0; } if (bt_ctxt->peri_info.peri_hdl) { iot_uart_close(bt_ctxt->peri_info.peri_hdl); bt_ctxt->peri_info.peri_hdl = NULL; } if (bt_ctxt->task_hdl) { iot_task_delete(bt_ctxt->task_hdl); bt_ctxt->task_hdl = NULL; } os_mem_free(bt_ctxt); g_bt_ext_ctxt = NULL; iot_printf("bt:closed\n"); return ERR_OK; } #else /* IOT_BT_EXT_ENABLE */ iot_pkt_t *iot_bt_ext_send_pkt_get(uint32_t len) { (void)len; return NULL; } void iot_bt_ext_send(uint8_t port, iot_pkt_t *pkt) { (void)port; if (pkt) { iot_pkt_free(pkt); } return; } uint32_t iot_bt_ext_rpt_register(uint8_t port, iot_bt_ext_rpt_func_t cb) { (void)port; (void)cb; return ERR_NOSUPP; } uint32_t iot_bt_ext_open(void) { return ERR_NOSUPP; } uint32_t iot_bt_ext_close(void) { return ERR_OK; } #endif /* IOT_BT_EXT_ENABLE */