/* * Copyright (c) 2019 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief OTA bluetooth backend interface */ #include #include #include #include #include #include #include #include #include #define PROT_OTA_FACTORY_OFFLINE (1) struct cli_prot_head { u8_t svc_id; u8_t cmd; u8_t param_type; u16_t param_len; } __attribute__((packed)); struct cli_tlv_head { u8_t type; u16_t len; u8_t value[0]; } __attribute__((packed)); struct cli_tlv_data { u8_t type; u16_t len; u16_t max_len; u8_t *value_ptr; }; typedef int (*cli_prot_cmd_handler_t)(struct cli_prot_context *ctx, u16_t param_len); struct cli_prot_cmd { u8_t cmd; cli_prot_cmd_handler_t handler; }; #if 1 int ota_cli_send_cmd(struct cli_prot_context *ctx, u8_t cmd,u8_t *buf, int size); int cli_tlv_unpack_head(struct cli_prot_context *ctx, struct cli_tlv_data *tlv); int cli_prot_get_rx_data(struct cli_prot_context *ctx, u8_t *buf, int size); int cli_prot_skip_rx_data(struct cli_prot_context *ctx, int size); int cli_drop_all_rx_data(struct cli_prot_context *ctx, int wait_ms); u8_t *cli_tlv_pack_data(u8_t *buf, u8_t type, u16_t len, u32_t number); int cli_tlv_unpack_data(struct cli_prot_context *ctx, u8_t type, int *len, u8_t *value_ptr, int max_len); #define TLV_PACK_U8(buf, type, value) cli_tlv_pack_data(buf, type, sizeof(u8_t), value) #define TLV_PACK_U16(buf, type, value) cli_tlv_pack_data(buf, type, sizeof(u16_t), value) #define TLV_PACK_U32(buf, type, value) cli_tlv_pack_data(buf, type, sizeof(u32_t), value) #define TLV_UNPACK_U8(ctx, type, value_ptr) \ cli_tlv_unpack_data(ctx, type, NULL, (u8_t *)value_ptr, sizeof(u8_t)) #define TLV_UNPACK_U16(ctx, type, value_ptr) \ cli_tlv_unpack_data(ctx, type, NULL, (u8_t *)value_ptr, sizeof(u16_t)) #define TLV_UNPACK_U32(ctx, type, value_ptr) \ cli_tlv_unpack_data(ctx, type, NULL, (u8_t *)value_ptr, sizeof(u32_t)) #endif #define print_hex1(str, buf, size) do {printk("%s\n", str); print_buffer(buf, 1, size, 16, 0);} while(0) /* support check data checksum in each ota unit */ /* for sppble_stream callback */ static struct ota_trans_bt *g_trans_bt; int cli_prot_get_rx_data(struct cli_prot_context *ctx, uint8_t *buf, int size) { int read_size; while (size > 0) { read_size = stream_read(ctx->sppble_stream, buf, size); if (read_size <= 0) { SYS_LOG_ERR("need read %d bytes, but only got %d bytes", size, read_size); return -EIO; } size -= read_size; buf += read_size; } return 0; } int cli_prot_skip_rx_data(struct cli_prot_context *ctx, int size) { int err; uint8_t c; while (size > 0) { err = cli_prot_get_rx_data(ctx, &c, sizeof(uint8_t)); if (err) { SYS_LOG_ERR("failed to get data"); return err; } size--; } return 0; } int cli_drop_all_rx_data(struct cli_prot_context *ctx, int wait_ms) { int err, data_len; int ms = wait_ms; while (wait_ms > 0) { data_len = stream_tell(ctx->sppble_stream); if (data_len > 0) { SYS_LOG_INF("drop data len 0x%x", data_len); err = cli_prot_skip_rx_data(ctx, data_len); if (err) return err; wait_ms = ms; } os_sleep(20); wait_ms -= 20; } return 0; } uint8_t *cli_tlv_pack(uint8_t *buf, const struct cli_tlv_data *tlv) { uint16_t len; len = tlv->len; *buf++ = tlv->type; *buf++ = len & 0xff; *buf++ = len >> 8; if (tlv->value_ptr) { memcpy(buf, tlv->value_ptr, len); buf += len; } return buf; } uint8_t *cli_tlv_pack_data(uint8_t *buf, uint8_t type, uint16_t len, uint32_t number) { struct cli_tlv_data tlv; tlv.type = type; tlv.len = len; tlv.value_ptr = (uint8_t *)&number; return cli_tlv_pack(buf, &tlv); } int cli_tlv_unpack_head(struct cli_prot_context *ctx, struct cli_tlv_data *tlv) { int err, total_len; /* read type */ err = cli_prot_get_rx_data(ctx, &tlv->type, sizeof(tlv->type)); if (err) { SYS_LOG_ERR("failed to read tlv type"); return err; } /* read length */ err = cli_prot_get_rx_data(ctx, (uint8_t *)&tlv->len, sizeof(tlv->len)); if (err) { SYS_LOG_ERR("failed to read tlv type"); return err; } total_len = sizeof(tlv->type) + sizeof(tlv->len); return total_len; } int cli_tlv_unpack(struct cli_prot_context *ctx, struct cli_tlv_data *tlv) { uint16_t data_len; int err, total_len; total_len = cli_tlv_unpack_head(ctx, tlv); if (tlv->len <= 0) return total_len; data_len = tlv->len; if (data_len > tlv->max_len) { data_len = tlv->max_len; } /* read value */ if (tlv->value_ptr) { err = cli_prot_get_rx_data(ctx, tlv->value_ptr, data_len); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } total_len += data_len; } return total_len; } int cli_tlv_unpack_data(struct cli_prot_context *ctx, uint8_t type, int *len, uint8_t *value_ptr, int max_len) { struct cli_tlv_data tlv; int rlen; tlv.value_ptr = value_ptr; tlv.max_len = max_len; rlen = cli_tlv_unpack(ctx, &tlv); if (rlen < 0) { SYS_LOG_ERR("cli_tlv_unpack failed, err 0x%x", rlen); return rlen; } if (tlv.type != type) { SYS_LOG_ERR("unmatched type, need 0x%x but got 0x%x", type, tlv.type); return -EIO; } if (len) *len = tlv.len; return rlen; } int cli_prot_send_data(struct cli_prot_context *ctx, uint8_t *buf, int size) { int err; err = stream_write(ctx->sppble_stream, buf, size); if (err < 0) { SYS_LOG_ERR("failed to send data, size %d, err %d", size, err); return -EIO; } return 0; } int ota_cli_send_cmd(struct cli_prot_context *ctx, uint8_t cmd, uint8_t *buf, int size) { struct cli_prot_head *head; int err; head = (struct cli_prot_head *)buf; head->svc_id = SERVICE_ID_OTA; head->cmd = cmd; head->param_type = TLV_TYPE_MAIN; head->param_len = size - sizeof(struct cli_prot_head); SYS_LOG_INF("send cmd: %d", cmd); //print_buffer(buf, 1, size, 16, buf); err = cli_prot_send_data(ctx, buf, size); if (err) { SYS_LOG_ERR("failed to send cmd %d, err %d", cmd, err); return err; } return 0; } int ota_ioctl_request_upgrade_ack(struct cli_prot_context *ctx, u16_t param_size) { int err, head_len; struct cli_tlv_data tlv; u8_t host_features, device_features; struct ota_trans *trans = &g_trans_bt->trans; SYS_LOG_INF("upgrade request: param_size %d", param_size); ctx->host_features = 0; device_features = 0; while (param_size > 0) { head_len = cli_tlv_unpack_head(ctx, &tlv); if (head_len <= 0) return -EIO; switch (tlv.type) { case TLV_TYPE_OTA_SUPPORT_FEATURES: err = cli_prot_get_rx_data(ctx, &host_features, 1); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } ctx->host_features = host_features; SYS_LOG_INF("host support features: 0x%x", host_features); break; default: /* skip other parameters by now */ err = cli_prot_skip_rx_data(ctx, tlv.len); if (err) return -EIO; break; } param_size -= head_len + tlv.len; } ctx->state = PROT_STATE_IDLE; if (trans->cb) { trans->cb(trans,OTA_TRANS_REQUEST_UPGRADE_ACK,NULL); } return 0; } int ota_ioctl_connect_negotiation_ack(struct cli_prot_context *ctx, u16_t param_len) { u16_t app_wait_timeout, device_restart_timeout, ota_unit_size, interval; int head_len; int err; struct cli_tlv_data tlv; struct ota_trans *trans = &g_trans_bt->trans; SYS_LOG_INF("param_len %d\n", param_len); while (param_len > 0) { head_len = cli_tlv_unpack_head(ctx, &tlv); if (head_len <= 0) return -EIO; switch (tlv.type) { case TLV_TYPE_OTA_WAIT_TIMEOUT: err = cli_prot_get_rx_data(ctx, (u8_t *)&app_wait_timeout, 2); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } ctx->app_wait_timeout = app_wait_timeout; // SYS_LOG_INF("host wait_timeout: 0x%x", app_wait_timeout); break; case TLV_TYPE_OTA_RESTART_TIMEOUT: err = cli_prot_get_rx_data(ctx, (u8_t *)&device_restart_timeout, 2); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } ctx->device_restart_timeout = device_restart_timeout; // SYS_LOG_INF("device_restart_timeout: 0x%x", device_restart_timeout); break; case TLV_TYPE_OTA_UINT_SIZE: err = cli_prot_get_rx_data(ctx, (u8_t *)&ota_unit_size, 2); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } ctx->ota_unit_size = ota_unit_size; SYS_LOG_INF("ota_unit_size: 0x%x", ota_unit_size); break; case TLV_TYPE_OTA_INTERVAL: err = cli_prot_get_rx_data(ctx, (u8_t *)&interval, 2); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } ctx->ota_interval = interval; // SYS_LOG_INF("interval: 0x%x", interval); break; default: /* skip other parameters by now */ err = cli_prot_skip_rx_data(ctx, tlv.len); if (err) return -EIO; break; } param_len -= head_len + tlv.len; } ctx->state = PROT_STATE_IDLE; if (trans->cb) { trans->cb(trans,OTA_TRANS_CONNECT_NEGOTIATION_ACK,NULL); } return err; } int ota_ioctl_require_image_data(struct cli_prot_context *ctx, u16_t param_size) { u32_t ota_file_offset, ota_file_len; u8_t ota_apply_bitmap; int head_len; int err; struct cli_tlv_data tlv; struct ota_trans *trans = &g_trans_bt->trans; struct ota_trans_image_info image; // SYS_LOG_INF("param_len %d\n", param_size); while (param_size > 0) { head_len = cli_tlv_unpack_head(ctx, &tlv); if (head_len <= 0) return -EIO; switch (tlv.type) { case TLV_TYPE_OTA_FILE_OFFSET: err = cli_prot_get_rx_data(ctx, (u8_t *)&ota_file_offset, 4); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } // SYS_LOG_INF("ota_file_offset: 0x%x", ota_file_offset); break; case TLV_TYPE_OTA_FILE_LEN: err = cli_prot_get_rx_data(ctx, (u8_t *)&ota_file_len, 4); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } // SYS_LOG_INF("ota_file_len: 0x%x", ota_file_len); break; case TLV_TYPE_OTA_APPLY_BITMAP: err = cli_prot_get_rx_data(ctx, (u8_t *)&ota_apply_bitmap, 1); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } // SYS_LOG_INF("ota_apply_bitmap: 0x%x", ota_apply_bitmap); break; default: /* skip other parameters by now */ err = cli_prot_skip_rx_data(ctx, tlv.len); if (err) return -EIO; break; } param_size -= head_len + tlv.len; } ctx->state = PROT_STATE_IDLE; if (trans->cb) { SYS_LOG_INF("ota_file_offset 0x%x ota_file_len 0x%x\n", ota_file_offset,ota_file_len); image.image_offset = ota_file_offset; image.read_len = ota_file_len; trans->cb(trans,OTA_TRANS_REQUEST_IMAGE_DATA,&image); } return 0; } int ota_ioctl_validate_image_report(struct cli_prot_context *ctx,u16_t param_size) { int err, send_len; u8_t *send_buf; int head_len; u8_t valid_report; struct cli_tlv_data tlv; struct ota_trans *trans = &g_trans_bt->trans; SYS_LOG_INF("%x",(uint32)ctx); while (param_size > 0) { head_len = cli_tlv_unpack_head(ctx, &tlv); if (head_len <= 0) return -EIO; switch (tlv.type) { case TLV_TYPE_OTA_VALID_REPORT: err = cli_prot_get_rx_data(ctx, (u8_t *)&valid_report, 1); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } SYS_LOG_INF("valid_report: 0x%x", valid_report); break; default: /* skip other parameters by now */ err = cli_prot_skip_rx_data(ctx, tlv.len); if (err) return -EIO; break; } param_size -= head_len + tlv.len; } send_buf = ctx->send_buf + sizeof(struct cli_prot_head); send_len = send_buf - ctx->send_buf; err = ota_cli_send_cmd(ctx, OTA_CMD_D2H_VALIDATE_IMAGE, ctx->send_buf, send_len); if (err) { SYS_LOG_ERR("failed to send cmd %d, error %d", OTA_CMD_D2H_VALIDATE_IMAGE, err); return err; } ctx->state = PROT_STATE_IDLE; if (trans->cb) { trans->cb(trans,OTA_TRANS_VALIDATE_REPORT,&valid_report); } return 0; } int ota_ioctl_remote_report_satus(struct cli_prot_context *ctx,u16_t param_size) { int err; u32_t status_code ; int head_len; struct cli_tlv_data tlv; struct ota_trans *trans = &g_trans_bt->trans; SYS_LOG_INF("%x",(uint32)ctx); while (param_size > 0) { head_len = cli_tlv_unpack_head(ctx, &tlv); if (head_len <= 0) return -EIO; switch (tlv.type) { case TLV_TYPE_OTA_STATUS_CODE: err = cli_prot_get_rx_data(ctx, (u8_t *)&status_code, 4); if (err) { SYS_LOG_ERR("failed to read tlv value"); return err; } SYS_LOG_INF("status_code: 0x%x", status_code); break; default: /* skip other parameters by now */ err = cli_prot_skip_rx_data(ctx, tlv.len); if (err) return -EIO; break; } param_size -= head_len + tlv.len; } ctx->state = PROT_STATE_IDLE; if (trans->cb) { trans->cb(trans,OTA_TRANS_UPGRADE_STATUS_NOTIFY,&status_code); } return 0; } struct cli_prot_cmd ota_cli_cmds[] = { {OTA_CMD_H2D_REQUEST_UPGRADE, ota_ioctl_request_upgrade_ack,}, {OTA_CMD_H2D_CONNECT_NEGOTIATION, ota_ioctl_connect_negotiation_ack,}, {OTA_CMD_D2H_REQUIRE_IMAGE_DATA, ota_ioctl_require_image_data,}, {OTA_CMD_D2H_VALIDATE_IMAGE, ota_ioctl_validate_image_report,}, {OTA_CMD_D2H_REPORT_STATUS,ota_ioctl_remote_report_satus,} }; int ota_trans_process_command(struct cli_prot_context *ctx, u32_t *processed_cmd) { struct cli_prot_head head; cli_prot_cmd_handler_t cmd_handler; int i, err; if (ctx->state != PROT_STATE_IDLE) { SYS_LOG_ERR("current state is not idle"); return -EIO; } err = cli_prot_get_rx_data(ctx, (u8_t *)&head, sizeof(struct cli_prot_head)); if (err) { SYS_LOG_ERR("cannot read head bytes"); return -EIO; } SYS_LOG_INF("cli head: svc_id 0x%x, cmd_id 0x%x, param type 0x%x, len 0x%x", head.svc_id, head.cmd, head.param_type, head.param_len); ctx->state = PROT_STATE_DATA; if (head.svc_id != SERVICE_ID_OTA) { SYS_LOG_ERR("invalid svc_id: %d", head.svc_id); return -EIO; } if (head.param_type != TLV_TYPE_MAIN) { SYS_LOG_ERR("invalid param type: %d", head.svc_id); return -EIO; } for (i = 0; i < ARRAY_SIZE(ota_cli_cmds); i++) { if (ota_cli_cmds[i].cmd == head.cmd) { cmd_handler = ota_cli_cmds[i].handler; err = cmd_handler(ctx, head.param_len); if (processed_cmd){ *processed_cmd = head.cmd; } if (err) { SYS_LOG_ERR("cmd_handler %p, err: %d", cmd_handler, err); return err; } } } if (i > ARRAY_SIZE(ota_cli_cmds)) { SYS_LOG_ERR("invalid cmd: %d", head.cmd); return -1; } ctx->state = PROT_STATE_IDLE; return err; } int ota_ioctl_request_upgrade(struct cli_prot_context *ctx,struct ota_trans_image_head_info * head_info) { int err, send_len; u8_t *send_buf; u32_t version = head_info->version; u32_t head_crc = head_info->head_crc; u8_t temp = 0; u32_t feature = 1; u32_t ota_type = PROT_OTA_FACTORY_OFFLINE; SYS_LOG_INF("%x %x %x",(uint32)ctx,version,head_crc); ctx->host_features = 1; send_buf = ctx->send_buf + sizeof(struct cli_prot_head); send_buf = TLV_PACK_U32(send_buf,0x01,version); send_buf = TLV_PACK_U32(send_buf,0x03,head_crc); send_buf = TLV_PACK_U8(send_buf, 0x04, temp); send_buf = TLV_PACK_U8(send_buf, 0x09, feature); send_buf = TLV_PACK_U32(send_buf, 0x0A, ota_type); send_len = send_buf - ctx->send_buf; err = ota_cli_send_cmd(ctx, OTA_CMD_H2D_REQUEST_UPGRADE, ctx->send_buf, send_len); if (err) { SYS_LOG_ERR("failed to send cmd %d, error %d", OTA_CMD_H2D_REQUEST_UPGRADE, err); return err; } ctx->state = PROT_STATE_IDLE; return 0; } int ota_ioctl_connect_negotiation(struct cli_prot_context *ctx) { int err, send_len; SYS_LOG_INF("%x",(uint32)ctx); send_len = sizeof(struct cli_prot_head); err = ota_cli_send_cmd(ctx, OTA_CMD_H2D_CONNECT_NEGOTIATION, ctx->send_buf, send_len); if (err) { SYS_LOG_ERR("failed to send cmd %d, error %d", OTA_CMD_H2D_CONNECT_NEGOTIATION, err); return err; } ctx->state = PROT_STATE_IDLE; return 0; } int ota_ioctl_negotiation_result(struct cli_prot_context *ctx) { int err, send_len; u8_t *send_buf; u8_t negotiation_result = 1; struct ota_trans *trans = &g_trans_bt->trans; SYS_LOG_INF("%x",(uint32)ctx); send_buf = ctx->send_buf + sizeof(struct cli_prot_head); send_buf = TLV_PACK_U8(send_buf, 0x01, negotiation_result); send_len = send_buf - ctx->send_buf; err = ota_cli_send_cmd(ctx, OTA_CMD_H2D_NEGOTIATION_RESULT, ctx->send_buf, send_len); if (err) { SYS_LOG_ERR("failed to send cmd %d, error %d", OTA_CMD_H2D_NEGOTIATION_RESULT, err); return err; } ctx->state = PROT_STATE_IDLE; ctx->negotiation_done = 1; if (trans->cb) { trans->cb(trans,OTA_TRANS_NEGOTIATION_RESULT_ACK,NULL); } return 0; } int ota_ioctl_send_image_data(struct cli_prot_context *ctx,struct ota_trans_upgrade_image * image_info) { int err, send_len; u8_t *send_buf; int image_size = image_info->size; u8_t *image_buffer = image_info->buffer; u16_t unit_size = ctx->ota_unit_size; u8_t * crc_pos; u32_t crc; SYS_LOG_INF("%x %d %x",(uint32)ctx,ctx->ota_unit_size,image_size); if (0 == image_info->ctn) { ctx->last_psn = 0; } while(image_size) { send_buf = ctx->send_buf + sizeof(struct cli_prot_head); *(send_buf++) = ctx->last_psn; crc_pos = send_buf; send_buf += sizeof(u32_t); if(image_size > unit_size) { memcpy(send_buf,image_buffer,unit_size); crc = utils_crc32(0,send_buf, unit_size); image_size -= unit_size; image_buffer += unit_size; send_buf += unit_size; } else { memcpy(send_buf,image_buffer,image_size); crc = utils_crc32(0,send_buf, image_size); send_buf += image_size; image_size = 0; } *(crc_pos++) = (u8_t)(crc & 0xff); *(crc_pos++) = (u8_t)((crc >> 8) & 0xff); *(crc_pos++) = (u8_t)((crc >> 16) & 0xff); *(crc_pos++) = (u8_t)((crc >> 24) & 0xff); send_len = send_buf - ctx->send_buf; SYS_LOG_INF("%d:",send_len); // print_hex1("image",ctx->send_buf,32); err = ota_cli_send_cmd(ctx, OTA_CMD_H2D_SEND_IMAGE_DATA_WITH_CRC, ctx->send_buf, send_len); if (err) { SYS_LOG_ERR("failed to send cmd %d, error %d", OTA_CMD_H2D_CONNECT_NEGOTIATION, err); return err; } ctx->state = PROT_STATE_IDLE; ctx->last_psn += 1; //os_sleep(1); } return 0; } int ota_trans_bt_open(struct ota_trans *trans) { struct ota_trans_bt *trans_bt = CONTAINER_OF(trans, struct ota_trans_bt, trans); struct cli_prot_context *cli_ctx = &trans_bt->cli_ctx; int err; if (cli_ctx->sppble_stream) { err = stream_open(cli_ctx->sppble_stream, MODE_IN_OUT); if (err) { SYS_LOG_ERR("stream_open Failed"); return err; } else { cli_ctx->sppble_stream_opened = 1; } } SYS_LOG_INF("open sppble_stream %p", cli_ctx->sppble_stream); return 0; } int ota_trans_bt_close(struct ota_trans *trans) { struct ota_trans_bt *trans_bt = CONTAINER_OF(trans, struct ota_trans_bt, trans); struct cli_prot_context *cli_ctx = &trans_bt->cli_ctx; int err; SYS_LOG_INF("close: type %d", trans->type); if (cli_ctx->sppble_stream_opened) { err = stream_close(cli_ctx->sppble_stream); if (err) { SYS_LOG_ERR("stream_close Failed"); } else { cli_ctx->sppble_stream_opened = 0; } /* clear internal status */ cli_ctx->negotiation_done = 0; } return 0; } void ota_trans_bt_exit(struct ota_trans *trans) { struct ota_trans_bt *trans_bt = CONTAINER_OF(trans, struct ota_trans_bt, trans); struct cli_prot_context *cli_ctx = &trans_bt->cli_ctx; /* avoid connect again after exit */ g_trans_bt = NULL; if (cli_ctx->sppble_stream) { stream_destroy(cli_ctx->sppble_stream); } if (trans_bt->cli_ctx.send_buf) mem_free(trans_bt->cli_ctx.send_buf); mem_free(trans_bt); } int ota_trans_bt_ioctl(struct ota_trans *trans, int cmd, void* param) { struct ota_trans_bt *trans_bt = CONTAINER_OF(trans, struct ota_trans_bt, trans); struct cli_prot_context *cli_ctx = &trans_bt->cli_ctx; int err = 0; SYS_LOG_INF("cmd %d", cmd); switch(cmd) { case OTA_TRANS_IOCTL_REQUEST_UPGRADE: err = ota_ioctl_request_upgrade(cli_ctx,(struct ota_trans_image_head_info *)param); break; case OTA_TRANS_IOCTL_CONNECT_NEGOTIATION: err = ota_ioctl_connect_negotiation(cli_ctx); break; case OTA_TRANS_IOCTL_NEGOTIATION_RESULT: err = ota_ioctl_negotiation_result(cli_ctx); break; case OTA_TRANS_IOCTL_SEND_IMAGE: err = ota_ioctl_send_image_data(cli_ctx,(struct ota_trans_upgrade_image *)param); break; case OTA_TRANS_IOCTL_UNITSIZE_GET: return cli_ctx->ota_unit_size; default : break; } if (err) { SYS_LOG_INF("send cmd 0x%x error", cmd); return -EIO; } return 0; } int ota_trans_bt_read(struct ota_trans *trans, int offset, void *buf, int size) { return 0; } static void ota_sppble_connect_cb(int connected) { struct ota_trans *trans; SYS_LOG_INF("connect: %d", connected); /* avoid connect again after exit */ if (g_trans_bt) { trans = &g_trans_bt->trans; if (trans->cb) { SYS_LOG_INF("call cb %p", trans->cb); if(connected) { trans->cb(trans, OTA_TRANS_CONNECTED,NULL); } else { trans->cb(trans, OTA_TRANS_DISCONNECT,NULL); } } } } #if 0 static void ota_sppble_sdap_cb(uint16 status) { struct ota_trans *trans; uint16 sdp_status = status; SYS_LOG_INF("sdp status: %d", status); if (g_trans_bt) { trans = &g_trans_bt->trans; if (trans->cb) { trans->cb(trans, OTA_TRANS_SDAP_RESULT,&sdp_status); } } } #endif static void ota_sppble_rxdata_cb(void) { struct ota_trans *trans; trans = &g_trans_bt->trans; struct ota_trans_bt *trans_bt = CONTAINER_OF(trans, struct ota_trans_bt, trans); struct cli_prot_context *cli_ctx = &trans_bt->cli_ctx; // SYS_LOG_INF(""); /* avoid connect again after exit */ if (g_trans_bt) { ota_trans_process_command(cli_ctx,NULL); } } static struct ota_trans_api ota_trans_api_bt = { /* .init = ota_backend_bt_init, */ .exit = ota_trans_bt_exit, .open = ota_trans_bt_open, .close = ota_trans_bt_close, .read = ota_trans_bt_read, .ioctl = ota_trans_bt_ioctl, }; struct ota_trans *ota_trans_bt_init(ota_trans_notify_cb_t cb, struct ota_trans_bt_init_param *param) { struct ota_trans_bt *trans_bt; struct sppble_stream_init_param init_param; struct cli_prot_context *cli_ctx; SYS_LOG_INF("init"); trans_bt = mem_malloc(sizeof(struct ota_trans_bt)); if (!trans_bt) { SYS_LOG_ERR("malloc failed"); return NULL; } memset(trans_bt, 0x0, sizeof(struct ota_trans_bt)); cli_ctx = &trans_bt->cli_ctx; memset(&init_param, 0, sizeof(struct sppble_stream_init_param)); init_param.spp_uuid = (uint8_t *)param->spp_uuid; init_param.connect_cb = ota_sppble_connect_cb; //init_param.read_timeout = param->read_timeout; /* K_FOREVER, K_NO_WAIT, K_MSEC(ms) */ //init_param.write_timeout = param->write_timeout; //init_param.read_buf_size = OTA_SPPBLE_BUFF_SIZE; init_param.rxdata_cb = ota_sppble_rxdata_cb; //init_param.sdap_cb = ota_sppble_sdap_cb; init_param.read_timeout = OS_FOREVER; init_param.write_timeout = OS_FOREVER; /* Just call stream_create once, for register spp/ble service * not need call stream_destroy */ cli_ctx->sppble_stream = sppble_stream_create(&init_param); if (!cli_ctx->sppble_stream) { SYS_LOG_ERR("stream_create failed"); } cli_ctx->send_buf = mem_malloc(OTA_SVC_TRANS_SEND_BUFFER_SIZE); cli_ctx->send_buf_size = OTA_SVC_TRANS_SEND_BUFFER_SIZE; cli_ctx->ota_unit_size = OTA_UNIT_SIZE; cli_ctx->state = PROT_STATE_IDLE; cli_ctx->negotiation_done = 0; g_trans_bt = trans_bt; ota_trans_init(&trans_bt->trans, OTA_TRANS_TYPE_BLUETOOTH, &ota_trans_api_bt, cb); return &trans_bt->trans; }