/**************************************************************************** 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 "iot_cli_plc_module.h" #include "iot_cli_host_upgrade_internal.h" #include "iot_version_api.h" #include "iot_oem.h" #include "iot_cli_plc_tx_rx.h" #include "plc_utils.h" iot_plc_upgrade_info_t *upgrade_info = NULL; extern iot_plc_host_config_t *host_config; extern iot_cli_host_info_t *host_info; extern iot_cli_t cli; extern uint32_t cli_module_type; #if IOT_CLI_UPGRADE_ENABLE /* print block info */ void cli_upgrade_print_block_info(iot_plc_upgrade_data_dl_t *data) { if (!data) { return; } iot_printf("file type:%d, req_block_cnt:%d\n", data->file_type, data->block_cnt); for (uint16_t i = 0; i < data->block_cnt; i++) { iot_printf("plc_upgrade:block_index:%d, block size:%d\n", data->block_idx_array[i], data->block_size_array[i]); } } /* calculate total size of data */ static uint32_t cli_upgrade_data_size(uint16_t block_cnt, uint16_t *block_size_array) { uint32_t size = 0; if (NULL != block_size_array) { for (uint32_t i = 0; i < block_cnt; i++) { size += block_size_array[i]; } } return size; } /* calculate crc per 4 bytes data */ static uint32_t cli_upgrade_data_crc_calculate(uint8_t *crc_data) { if (!crc_data) { return 0; } return *(crc_data)+((uint32_t)*(crc_data + 1) << 8) + ((uint32_t)*(crc_data + 2) << 16) + ((uint32_t)*(crc_data + 3) << 24); } /* upgrade type check */ uint8_t cli_upgrade_type_check(iot_plc_upgrade_start_dl_t *data) { if (!data) { return UPGRADE_START_OTHER_ERROR; } if ((IOT_PLC_UPGRADE_LOCAL != data->upgrade_type) && (IOT_PLC_UPGRADE_ALL != data->upgrade_type) && (IOT_PLC_UPGRADE_STA_LIST != data->upgrade_type)) { return UPGRADE_START_INVALID_TYPE; } #if PLC_SUPPORT_CCO_ROLE if ((IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) && (IOT_PLC_UPGRADE_ALL == data->upgrade_type) && !data->dst_total_num) { return UPGRADE_START_INVALID_DATA; } #endif return UPGRADE_START_OK; } /* upgrade data check */ uint8_t cli_upgrade_data_check(uint16_t block_cnt, uint16_t *block_idx_array, uint16_t *block_size_array, uint8_t *data, uint8_t file_type) { if ((!data) || (!block_idx_array)) { return UPGRADE_DATA_INVALID_DATA; } /* 0 means stop */ if (0 == block_cnt) { return UPGRADE_DATA_STA_STOP; } /* upgrade type check */ if ((IOT_PLC_UPGRADE_LOCAL == upgrade_info->upgrade_type) || (((IOT_PLC_UPGRADE_ALL == upgrade_info->upgrade_type) || (IOT_PLC_UPGRADE_STA_LIST == upgrade_info->upgrade_type)) && (IOT_PLC_DEV_ROLE_CCO == host_config->dev_role))) { uint32_t data_size = cli_upgrade_data_size(block_cnt, block_size_array); uint32_t crcCode = iot_getcrc32(data, data_size); uint32_t crcCodePLC = cli_upgrade_data_crc_calculate( data + data_size); if (crcCode != crcCodePLC) { /* crc check only for local upgrade */ /*iot_printf("plc_upgrade:crc check, crcCode:%x, crcCodePLC:%x\n", crcCode, crcCodePLC);*/ return UPGRADE_DATA_CRC_ERROR; } } /* file type check */ if ((UPGRADE_DATA_TYPE_FW != file_type) && (UPGRADE_DATA_TYPE_PIB != file_type) && (UPGRADE_DATA_TYPE_CUS != file_type)) { iot_printf("plc_upgrade: invalid file type\n"); return UPGRADE_DATA_INVALID_FILE_TYPE; } if ((IOT_PLC_UPGRADE_STARTED == upgrade_info->upgrade_state) || (IOT_PLC_UPGRADE_STARTING == upgrade_info->upgrade_state)) { /* block idx check */ for (uint32_t i = 0; i < block_cnt; i++) { if ((upgrade_info->block_idx + i) != block_idx_array[i]) { iot_printf("plc_ugrade:expect block_index = 0n%d," "block_index = 0n%d\n", upgrade_info->block_idx + i, block_idx_array[i]); return UPGRADE_DATA_BLOCK_IDX_ERROR; } } } return UPGRADE_DATA_SUCCESS; } /* initialize latest block info */ void cli_remote_upgrade_initialize_latest_block() { for (uint8_t idx = 0; idx < IOT_PLC_UPGRADE_LATEST_BLOCK_CNT; idx++) { upgrade_info->latest_block_info.latest_block_request[idx].block_idx = 0; upgrade_info->latest_block_info.latest_block_request[idx].file_type = UPGRADE_DATA_TYPE_INVALID; upgrade_info->latest_block_info.latest_block_request[idx].request_times = 0; } } /* query latest block info */ static void cli_remote_upgrade_update_latest_block(uint8_t file_type, uint16_t block_idx) { uint16_t request_times = 0xFFFF; uint8_t candiate_index = 0; for (uint8_t idx = 0; idx < IOT_PLC_UPGRADE_LATEST_BLOCK_CNT; idx++) { iot_plc_upgrade_block_info_t *block_info = &upgrade_info->latest_block_info.latest_block_request[idx]; if (UPGRADE_DATA_TYPE_INVALID == block_info->file_type) { candiate_index = idx; break; } else { if (block_info->request_times < request_times) { request_times = block_info->request_times; candiate_index = idx; } } } upgrade_info->latest_block_info. latest_block_request[candiate_index].file_type = file_type; upgrade_info->latest_block_info. latest_block_request[candiate_index].block_idx = block_idx; } /* find latest block info with file type and block idx */ static bool_t cli_remote_upgrade_update_find_latest_block(uint8_t file_type, uint16_t block_idx) { for (uint8_t idx = 0; idx < IOT_PLC_UPGRADE_LATEST_BLOCK_CNT; idx++) { iot_plc_upgrade_block_info_t *block_info = &upgrade_info->latest_block_info.latest_block_request[idx]; if ((block_info->block_idx == block_idx) && (block_info->file_type == file_type)) { block_info->request_times++; return true; } } return false; } /* pco strart upgrade */ void cli_remote_upgrade_pco_start() { iot_plc_query_neighbor_dev(host_config->app_handle, IOT_PLC_API_REQ_ID_DEFAULT, 0, 1, IOT_PLC_QUERY_TOPO_START_AS_TEI); } /* clean gw upgrade info, in case gw upgrade get error info */ static void cli_clean_gw_upgrade_info() { uint32_t part = 0; uint32_t other_part = 0; if (iot_upgrade_get_part(&part)) { /* cannot upgrade because failed to read partition info */ iot_printf("failed to get current boot part.\n"); return; } other_part = iot_upgrade_get_another_part(part); /* clean crc info */ iot_upgrade_save_fw_crc(other_part, 0); } /* crc check callback for flash write operation */ static void cli_upgrade_file_part_crc_check(uint8_t check_result) { uint8_t error_code = UPGRADE_DATA_SUCCESS; iot_printf("plc_upgrade: crc_check, role %x state:%x\n", host_config->dev_role, upgrade_info->upgrade_state); if ((IOT_PLC_UPGRADE_LOCAL == upgrade_info->upgrade_type) && (COMMUNICATOR_BT == cli.commu.type)) { iot_upgrade_commit(upgrade_info->src.id); upgrade_info->upgrade_state = IOT_PLC_UPGRADE_TRANSFERRED; } cli_upgrade_reset_timer(0, 0); if (upgrade_info->src.crc_check_buf) { iot_pkt_free(upgrade_info->src.crc_check_buf); upgrade_info->src.crc_check_buf = NULL; } if ((IOT_PLC_UPGRADE_STARTING == upgrade_info->upgrade_state) || (IOT_PLC_UPGRADE_STARTED == upgrade_info->upgrade_state) || (IOT_PLC_UPGRADE_LISTEN == upgrade_info->upgrade_state)) { if (check_result) { /* set LED to show upgrading state */ iot_plc_led_request(IOT_PLC_LED_UPGRADE_ON); cli_clean_gw_upgrade_info(); upgrade_info->upgrade_state = IOT_PLC_UPGRADE_TRANSFERRED; iot_printf("plc_upgrade: crc passed, commit\n"); iot_upgrade_commit(upgrade_info->src.id); if (IOT_PLC_DEV_ROLE_PCO == host_config->dev_role) { //pco to start 1hop remote upgrade iot_printf("plc_upgrade: start sub nodes, role %x\n", host_config->dev_role); cli_remote_upgrade_pco_start(); } } else { upgrade_info->upgrade_state = IOT_PLC_UPGRADE_FAILED; iot_printf("plc_upgrade: crc failed\n"); iot_upgrade_cancel_commit(upgrade_info->src.id); error_code = UPGRADE_DATA_CRC_ERROR; //todo:handle crc error } cli_upgrade_sta_send_upgrade_result(IOT_PLC_MSG_TYPE_UNICAST, host_config->mac_addr, host_config->cco_mac, error_code); } } /* sta upgrade info initialize */ void cli_remote_upgrade_sta_initialize( uint8_t upgrade_type, uint16_t block_size, uint16_t remote_block_size, uint32_t fw_size, uint32_t pib_size, uint32_t cus_size, uint32_t fw_checksum, uint32_t pib_checksum, uint32_t cus_checksum, uint16_t time_window, uint16_t remote_block_cnt) { //stop last timer cli_upgrade_reset_timer(0, 0); upgrade_info->upgrade_type = upgrade_type; upgrade_info->block_size = block_size; upgrade_info->remote_block_size = remote_block_size; upgrade_info->block_idx = 0; upgrade_info->fw_recv_done = 0; upgrade_info->pib_recv_done = 0; upgrade_info->cus_recv_done = 0; upgrade_info->fw_size = fw_size; if (upgrade_info->fw_size == 0) { upgrade_info->fw_recv_done = 1; upgrade_info->fw_blocks = 0; upgrade_info->fw_checksum = 0; } else { upgrade_info->fw_blocks = (uint16_t)iot_ceil(upgrade_info->fw_size, upgrade_info->block_size); upgrade_info->fw_checksum = fw_checksum; } upgrade_info->pib_size = pib_size; if (upgrade_info->pib_size == 0) { upgrade_info->pib_recv_done = 1; upgrade_info->pib_blocks = 0; upgrade_info->pib_checksum = 0; } else { upgrade_info->pib_blocks = (uint16_t)iot_ceil(upgrade_info->pib_size, upgrade_info->block_size); upgrade_info->pib_checksum = pib_checksum; } upgrade_info->cus_size = cus_size; if (upgrade_info->cus_size == 0) { upgrade_info->cus_recv_done = 1; upgrade_info->cus_blocks = 0; upgrade_info->cus_checksum = 0; } else { upgrade_info->cus_blocks = (uint16_t)iot_ceil(upgrade_info->cus_size, upgrade_info->block_size); upgrade_info->cus_checksum = cus_checksum; } iot_printf("fw_size:%d,fw_recv_done:%d,fw_blocks:%d," "fw_checksum %x\n", upgrade_info->fw_size, upgrade_info->fw_recv_done, upgrade_info->fw_blocks, upgrade_info->fw_checksum); iot_printf("pib_size:%d,pib_recv_done:%d,pib_blocks:%d," "pib_checksum %x\n", upgrade_info->pib_size, upgrade_info->pib_recv_done, upgrade_info->pib_blocks, upgrade_info->pib_checksum); iot_printf("cus_size:%d,cus_recv_done:%d,cus_blocks:%d," "cus_checksum %x\n", upgrade_info->cus_size, upgrade_info->cus_recv_done, upgrade_info->cus_blocks, upgrade_info->cus_checksum); iot_printf("time_window %d, remote_block_cnt %d\n", time_window, remote_block_cnt); upgrade_info->time_window = time_window; upgrade_info->remote_block_cnt = remote_block_cnt; upgrade_info->reported_percentage = 0; if (UPGRADE_DATA_BLOCK_MAX_SIZE < upgrade_info->remote_block_size) { upgrade_info->remote_block_size = UPGRADE_DATA_BLOCK_MAX_SIZE; } if (IOT_PLC_UPGRADE_LISTEN != upgrade_info->upgrade_state) { upgrade_info->upgrade_state = IOT_PLC_UPGRADE_INIT; //upgrade_info->remote_written_blocks = 0; } } /* initialize upgrade info */ void cli_upgrade_info_initialize(iot_plc_upgrade_start_dl_t *data) { iot_plc_upgrade_cust_start_dl_t cus_info; if (!data) { return; } if (data->cus_upgrade_flag) { os_mem_cpy((uint8_t *)&cus_info, (data->dst + data->dst_num * IOT_MAC_ADDR_LEN), sizeof(iot_plc_upgrade_cust_start_dl_t)); } else { os_mem_set((uint8_t *)&cus_info, 0, sizeof(cus_info)); } cli_remote_upgrade_sta_initialize(data->upgrade_type, data->block_size, data->remote_block_size, data->fw_size, data->pib_size, cus_info.cus_size, data->fw_checksum, data->pib_checksum, cus_info.cus_checksum, data->time_window, data->remote_block_cnt); /** *for local upgrade, always start from block #0 *todo: for remote upgrade support resuming from break point */ upgrade_info->fw_version = data->fw_version; upgrade_info->pib_version = data->pib_version; upgrade_info->cus_version = cus_info.cus_version; upgrade_info->control_upgrade_flag = !!data->control_flag; if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) { upgrade_info->upgrade_id = data->upgrade_id; } #if PLC_SUPPORT_CCO_ROLE else { upgrade_info->broadcast_retry_times = data->broadcast_retry_times; if (upgrade_info->broadcast_retry_times < IOT_PLC_UPGRADE_CCO_BCAST_MIN_RETRY_CNT) { upgrade_info->broadcast_retry_times = IOT_PLC_UPGRADE_CCO_BCAST_MIN_RETRY_CNT; } upgrade_info->level_one_pco_count = data->level_one_pco_count; cli_remote_upgrade_dest_info_reset(); cli_upgrade_add_upgrade_list_dest_info(data->dst, data->dst_num, 1); } #endif } /* initialize falsh info */ uint32_t cli_upgrade_flash_info_initialize(uint16_t block_size, uint32_t fw_size, uint16_t pib_size, uint16_t cus_size, uint32_t upgrade_id, uint32_t fw_checksum, uint32_t pib_checksum, uint32_t cus_checksum, uint32_t fw_version) { upgrade_info->src.block_size = block_size; upgrade_info->src.fw_size = fw_size; upgrade_info->src.pib_size = pib_size; upgrade_info->src.cus_size = cus_size; upgrade_info->src.id = upgrade_id; upgrade_info->src.fw_crc = fw_checksum; upgrade_info->src.pib_crc = pib_checksum; upgrade_info->src.cus_crc = cus_checksum; upgrade_info->src.fw_version = fw_version; if (!upgrade_info->src.crc_check_buf) { upgrade_info->src.crc_check_buf = iot_pkt_alloc( UPGRADE_DEFAULT_BLOCK_SIZE, IOT_DRIVER_MID); } upgrade_info->src.crc_check_cb = cli_upgrade_file_part_crc_check; upgrade_info->src.read_block_cb = NULL; upgrade_info->src.write_block_cb = NULL; return iot_upgrade_start(&upgrade_info->result, &upgrade_info->src); } #if PLC_SUPPORT_CCO_ROLE /* initialize buffer */ void cli_upgrade_buffer_initialize() { IOT_ASSERT(upgrade_info->file_data); IOT_ASSERT(IOT_CLI_UPGRADE_MAX_FILE_SIZE >= (upgrade_info->fw_size + upgrade_info->pib_size + upgrade_info->cus_size)); upgrade_info->pib_data = upgrade_info->file_data; upgrade_info->fw_data = upgrade_info->file_data + upgrade_info->pib_size; upgrade_info->cus_data = upgrade_info->file_data + upgrade_info->pib_size + upgrade_info->fw_size; } static uint32_t cli_upgrade_get_cache_data(uint8_t file_type, uint32_t offset, uint8_t *buf, uint32_t len) { uint32_t ret = ERR_OK; #if IOT_CLI_UPGRADE_CACHE_TYPE if (file_type == UPGRADE_DATA_TYPE_PIB) { os_mem_cpy(buf, upgrade_info->pib_data + offset, len); } else if (file_type == UPGRADE_DATA_TYPE_FW) { os_mem_cpy(buf, upgrade_info->fw_data + offset, len); } else if (file_type == UPGRADE_DATA_TYPE_CUS) { os_mem_cpy(buf, upgrade_info->cus_data + offset, len); } else { IOT_ASSERT(0); } #else uint32_t data_pos = 0; uint8_t read_file_type = UPGRADE_DATA_TYPE_FW; if (file_type == UPGRADE_DATA_TYPE_PIB) { data_pos = upgrade_info->pib_start; } else if (file_type == UPGRADE_DATA_TYPE_FW) { data_pos = upgrade_info->fw_start; } else if (file_type == UPGRADE_DATA_TYPE_CUS) { read_file_type = UPGRADE_DATA_TYPE_CUS; data_pos = upgrade_info->cus_start; } else { IOT_ASSERT(0); } ret = cli_upgrade_read_data_from_flash(read_file_type, data_pos + offset, buf, (uint16_t)len); if (ret != UPGRADE_DATA_SUCCESS) { ret = ERR_FAIL; } #endif return ret; } iot_plc_upgrade_dest_desc_t * cli_remote_upgrade_find_init_dest_from_idx(uint16_t start_idx) { iot_plc_upgrade_dest_desc_t *dest = NULL; while ((start_idx < IOT_PLC_UPGRADE_PHASE_THREE_MAX_SAT_CNT) && upgrade_info->dest_info.upgrading_list[start_idx]) { if (IOT_PLC_UPGRADE_INIT == upgrade_info->dest_info.upgrading_list[start_idx]->status) { dest = upgrade_info->dest_info.upgrading_list[start_idx]; upgrade_info->dest_info.upgrading_list_idx = start_idx + 1; break; } start_idx++; } return dest; } /* cco add multi node start upgrade command */ uint32_t cli_remote_upgrade_multi_node_start_notify(uint8_t send_type, uint8_t phase_flag) { iot_plc_upgrade_start_dl_t *start_dl; iot_pkt_t *pkt = NULL; uint32_t len; iot_plc_upgrade_dest_desc_t *dest; uint8_t *list_mac; uint8_t sta_cnt; uint32_t ret = ERR_OK; iot_plc_upgrade_cust_start_dl_t *cus_start = NULL; len = IOT_MAC_ADDR_LEN * IOT_PLC_UPGRADE_BROADCAST_STA_MAX_CNT; len += sizeof(*start_dl); if (upgrade_info->cus_size) { len += sizeof(iot_plc_upgrade_cust_start_dl_t); } pkt = iot_pkt_alloc(len, IOT_CLI_MID); if (!pkt) { ret = ERR_FAIL; goto out; } list_mac = iot_pkt_data(pkt) + sizeof(*start_dl); for (sta_cnt = 0; sta_cnt < IOT_PLC_UPGRADE_BROADCAST_STA_MAX_CNT; sta_cnt++) { //find next start sta dest = cli_remote_upgrade_find_init_dest_from_idx( upgrade_info->dest_info.upgrading_list_idx); if (!dest) { break; } iot_mac_addr_cpy(list_mac + (sta_cnt * IOT_MAC_ADDR_LEN), dest->entry.addr); } if (upgrade_info->cus_size) { cus_start = (iot_plc_upgrade_cust_start_dl_t *) (list_mac + (sta_cnt * IOT_MAC_ADDR_LEN)); } if (sta_cnt) { len = sizeof(*start_dl) + IOT_MAC_ADDR_LEN * sta_cnt; if (upgrade_info->cus_size) { len += sizeof(iot_plc_upgrade_cust_start_dl_t); } start_dl = (iot_plc_upgrade_start_dl_t *)iot_pkt_data(pkt); start_dl->phase_flag = phase_flag; start_dl->upgrade_id = upgrade_info->upgrade_id; start_dl->fw_checksum = upgrade_info->fw_checksum; start_dl->pib_checksum = upgrade_info->pib_checksum; start_dl->block_size = upgrade_info->remote_block_size; start_dl->fw_size = upgrade_info->fw_size; start_dl->fw_version = upgrade_info->fw_version; start_dl->pib_size = (uint16_t)upgrade_info->pib_size; start_dl->pib_version = upgrade_info->pib_version; start_dl->upgrade_type = upgrade_info->upgrade_type; start_dl->remote_block_cnt = upgrade_info->remote_block_cnt; start_dl->remote_block_size = upgrade_info->remote_block_size; start_dl->time_window = upgrade_info->time_window; start_dl->dst_num = sta_cnt; start_dl->control_flag = upgrade_info->control_upgrade_flag; if (upgrade_info->cus_size) { cus_start->cus_size = (uint16_t)upgrade_info->cus_size; cus_start->cus_checksum = upgrade_info->cus_checksum; cus_start->cus_version = upgrade_info->cus_version; start_dl->cus_upgrade_flag = 1; } else { start_dl->cus_upgrade_flag = 0; } iot_cli_module_send_data_with_retry(send_type, IOT_PLC_UPGRADE_START_RETRY_TIMES, CLI_MODULEID_HOSTINTERFACE, CLI_MSGID_REMOTE_UPGRADE_START, NULL, NULL, (uint8_t*)start_dl, len); } if (sta_cnt >= IOT_PLC_UPGRADE_BROADCAST_STA_MAX_CNT) { ret = ERR_AGAIN; } out: if (pkt) { iot_pkt_free(pkt); } return ret; } /* cco upgrade timer handler */ void iot_cli_upgrade_cco_handle_timer_msg() { uint8_t phase3_node_cnt = 0; uint16_t phase3_interval = 0; host_info->link_load = iot_plc_get_link_load(); switch (upgrade_info->upgrade_state) { case IOT_PLC_UPGRADE_INIT: { break; } case IOT_PLC_UPGRADE_STARTING: { /* list node upgrade, continue broadcast start upgrade */ cli_remote_upgrade_broadcast_start_sta_list(false); break; } case IOT_PLC_UPGRADE_STARTED: { if (host_info->link_load < IOT_PLC_UPGRADE_LINK_LOAD_LIMIT) { if (upgrade_info->bcast_wait_flag == 0) { /* continue broadcast upgrade data */ cli_remote_upgrade_cco_broadcast_data(false); } } break; } case IOT_PLC_UPGRADE_TRANSFERRED: { upgrade_info->action_times++; cli_remote_upgrade_initialize_latest_block(); if (0 == (upgrade_info->action_times % IOT_PLC_UPGRADE_LONG_TIMER_CNT)) { if (upgrade_info->request_times) { upgrade_info->request_times /= IOT_PLC_UPGRADE_LONG_TIMER_CNT; if ((cli_remote_upgrade_calculate_time_window( upgrade_info->request_times) * IOT_PLC_UPGRADE_TIME_WINDOW_ADJ_VALUE2) < upgrade_info->time_window) { iot_printf("plc_upgrade: request times %lu," " new time window %lu, old time window %lu\n", upgrade_info->request_times, cli_remote_upgrade_calculate_time_window( upgrade_info->request_times), upgrade_info->time_window); upgrade_info->time_window = (uint16_t)(upgrade_info->time_window * IOT_PLC_UPGRADE_TIME_WINDOW_ADJ_VALUE1); } upgrade_info->request_times = 0; } if ((!upgrade_info->recv_req_flag) && ((IOT_PLC_UPGRADE_ALL == upgrade_info->upgrade_type) || (IOT_PLC_UPGRADE_STA_LIST == upgrade_info->upgrade_type))) { cli_remote_upgrade_start_sub_nodes(); } /* clean recv req flag */ upgrade_info->recv_req_flag = 0; } // check if need to start phase 3 if ((IOT_PLC_UPGRADE_STA_LIST == upgrade_info->upgrade_type) || (upgrade_info->dest_info.dst_transferred_num > (upgrade_info->dest_info.dst_total_num * IOT_PLC_UPGRADE_PHASE_THREE_THRESHOLD))) { iot_printf("plc_upgrade:upgraded sta num %lu," " total num %lu\n", upgrade_info->dest_info.dst_transferred_num, upgrade_info->dest_info.dst_total_num); // initialize upgrading list for the first time if (IOT_PLC_UPGRADE_ALL == upgrade_info->upgrade_type) { if (upgrade_info->dst_list_idx == 0) { cli_remote_upgrade_initialize_upgrading_list(); } } if (!upgrade_info->calc_time_window_flag) { upgrade_info->calc_time_window_flag = 1; if (upgrade_info->control_upgrade_flag) { phase3_interval = cli_remote_upgrade_get_resend_time_window( upgrade_info->dest_info.dst_total_num); upgrade_info->dest_info.query_node_timeout = IOT_PLC_UPGRADE_QUERY_NODE_INFO_TIMEOUT / phase3_interval; cli_upgrade_reset_timer(1, phase3_interval); break; } } if (upgrade_info->control_upgrade_flag) { phase3_node_cnt = cli_remote_upgrade_resend_phase(); } // start uncompleted sta phase3_node_cnt += cli_remote_upgrade_start_phase_three(); } if (IOT_PLC_UPGRADE_ALL == upgrade_info->upgrade_type) { if ((0 == (upgrade_info->action_times % IOT_PLC_UPGRADE_COMPLETE_CHECK_TIMER_CNT))) { iot_printf("plc_upgrade:cco complete upgrade %lu\n", upgrade_info->sta_upgrade_active); if (upgrade_info->sta_upgrade_active) { upgrade_info->sta_upgrade_active = 0; } else { if (upgrade_info->completed_handler) { upgrade_info->completed_handler(); } } } } else if ((!phase3_node_cnt) && upgrade_info->completed_handler) { upgrade_info->completed_handler(); } break; } case IOT_PLC_UPGRADE_STOPED: { if (upgrade_info->action_times < IOT_PLC_UPGRADE_STOP_RETRY_TIMES) { uint8_t dest[IOT_MAC_ADDR_LEN] = { 0 }; iot_plc_upgrade_stop_dl_t stop_dl; iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_BCAST, CLI_MSGID_UPGRADE_STOP, dest, (uint8_t*)&stop_dl, sizeof(stop_dl)); upgrade_info->action_times++; } else { // cco stop after broadcast stop cli_remote_upgrade_coo_stop(); upgrade_info->upgrade_state = IOT_PLC_UPGRADE_INIT; upgrade_info->action_times = 0; upgrade_info->calc_time_window_flag = 0; upgrade_info->node_response_flag = 1; upgrade_info->resend_data_state = CLI_QUERY_NODE; upgrade_info->query_node_retry_cnt = 0; upgrade_info->control_upgrade_flag = 0; iot_printf("plc_upgrade:cco stop upgrade\n"); } break; } case IOT_PLC_UPGRADE_RESET: { if (upgrade_info->action_times < IOT_PLC_UPGRADE_RESET_RETRY_TIMES) { uint8_t dest[IOT_MAC_ADDR_LEN] = { 0 }; iot_plc_upgrade_reset_dl_t reset_dl; iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_BCAST, CLI_MSGID_UPGRADE_RESET, dest, (uint8_t*)&reset_dl, sizeof(reset_dl)); upgrade_info->action_times++; } else { cli_remote_upgrade_coo_stop(); upgrade_info->upgrade_state = IOT_PLC_UPGRADE_INIT; upgrade_info->action_times = 0; } break; } default: //IOT_ASSERT(0); // invalid state break; } } #else /* sta/pco upgrade timer handler */ void iot_cli_upgrade_sta_handle_timer_msg() { switch (upgrade_info->upgrade_state) { case IOT_PLC_UPGRADE_INIT: case IOT_PLC_UPGRADE_LISTEN: { break; } case IOT_PLC_UPGRADE_STARTING: { //sta send data request upgrade_info->upgrade_state = IOT_PLC_UPGRADE_STARTED; cli_remote_upgrade_sta_send_request_data(false); cli_upgrade_reset_timer(1, upgrade_info->time_window); break; } case IOT_PLC_UPGRADE_STARTED: { upgrade_info->last_timer_time = os_boot_time32(); if (upgrade_info->skip_timer) { upgrade_info->skip_timer = false; return; } //sta send data request cli_remote_upgrade_sta_send_request_data(false); break; } case IOT_PLC_UPGRADE_TRANSFERRED: { if ((IOT_PLC_DEV_ROLE_PCO == host_config->dev_role) && ((IOT_PLC_UPGRADE_ALL == upgrade_info->upgrade_type) || (IOT_PLC_UPGRADE_STA_LIST == upgrade_info->upgrade_type))) { upgrade_info->action_times++; cli_remote_upgrade_initialize_latest_block(); if (0 == (upgrade_info->action_times % IOT_PLC_UPGRADE_LONG_TIMER_CNT)) { if (upgrade_info->request_times) { upgrade_info->request_times /= IOT_PLC_UPGRADE_LONG_TIMER_CNT; if ((cli_remote_upgrade_calculate_time_window( upgrade_info->request_times) * IOT_PLC_UPGRADE_TIME_WINDOW_ADJ_VALUE2) < upgrade_info->time_window) { iot_printf("plc_upgrade: request times %lu," " new time window %lu, old time window %lu\n", upgrade_info->request_times, cli_remote_upgrade_calculate_time_window( upgrade_info->request_times), upgrade_info->time_window); upgrade_info->time_window = (uint16_t)(upgrade_info->time_window * IOT_PLC_UPGRADE_TIME_WINDOW_ADJ_VALUE1); } upgrade_info->request_times = 0; } if (!upgrade_info->recv_req_flag) { cli_remote_upgrade_start_sub_nodes(); } else { /* clean recv req flag */ upgrade_info->recv_req_flag = 0; } } } else { cli_upgrade_sta_send_upgrade_result(IOT_PLC_MSG_TYPE_UNICAST, host_config->mac_addr, host_config->cco_mac, UPGRADE_DATA_SUCCESS); cli_upgrade_reset_timer(0, 0); } break; } case IOT_PLC_UPGRADE_FAILED: case IOT_PLC_UPGRADE_START_FAIL: { cli_upgrade_reset_timer(0, 0); break; } case IOT_PLC_UPGRADE_STOPED: case IOT_PLC_UPGRADE_RESET: default: IOT_ASSERT(0); // invalid state break; } } #endif /* PLC_SUPPORT_CCO_ROLE */ /* upgrade timer handler */ void iot_cli_upgrade_handle_timer_msg() { switch (host_config->dev_role) { case IOT_PLC_DEV_ROLE_CCO: { #if PLC_SUPPORT_CCO_ROLE iot_cli_upgrade_cco_handle_timer_msg(); #endif break; } case IOT_PLC_DEV_ROLE_STA: case IOT_PLC_DEV_ROLE_PCO: { #if !PLC_SUPPORT_CCO_ROLE iot_cli_upgrade_sta_handle_timer_msg(); #endif break; } default: break; } } uint32_t cli_upgrade_write_data_to_flash_cache_init(uint32_t upgrade_id, uint32_t fw_size, uint32_t cus_sise, uint32_t block_size) { iot_upgrade_cancel_commit(0); upgrade_info->src.block_size = block_size; upgrade_info->src.fw_size = fw_size; upgrade_info->src.pib_size = 0; upgrade_info->src.cus_size = cus_sise; upgrade_info->src.id = upgrade_id; upgrade_info->src.fw_crc = 0; upgrade_info->src.pib_crc = 0; upgrade_info->src.fw_version = 0; upgrade_info->src.crc_check_cb = NULL; upgrade_info->src.read_block_cb = NULL; upgrade_info->src.write_block_cb = NULL; return iot_upgrade_start(&upgrade_info->result, &upgrade_info->src); } /* check if block is blank */ uint8_t cli_upgrade_block_blank_check( uint8_t file_type, uint16_t block_index) { iot_upg_block_info_rst rst; iot_upg_block_info_src src; rst.blank = false; src.id = upgrade_info->src.id; src.file_type = file_type; src.block_index = block_index; iot_upgrade_query_block_info(&rst, &src); return rst.blank; } /* write fw data to flash */ uint8_t cli_upgrade_write_data_to_flash(uint8_t file_type, uint16_t block_cnt, uint16_t *block_idx_array, uint16_t *block_size_array, uint8_t *data) { iot_trans_cmd_t trans; iot_pkt_t *block_data = NULL; uint32_t begin_index = 0; uint16_t i; for (i = 0; i < block_cnt; i++) { if (cli_upgrade_block_blank_check(file_type, block_idx_array[i])) { trans.id = upgrade_info->src.id; block_data = iot_pkt_alloc(block_size_array[i], IOT_CLI_MID); if (!block_data) { return UPGRADE_DATA_CLI_NO_MEM; } trans.block_num = block_idx_array[i]; trans.data = block_data; trans.data_type = file_type; os_mem_cpy(iot_pkt_data(block_data), data + begin_index, block_size_array[i]); iot_pkt_put(block_data, block_size_array[i]); iot_upgrade_trans(&trans); //upgrade_info->remote_written_blocks++; #if PLC_SUPPORT_UPGRADE_DEBUG iot_printf("write data to flash. %d bytes," "index:%d, blocks:%d\n", trans.block_size, block_idx_array[i], upgrade_info->remote_written_blocks); #endif } begin_index += block_size_array[i]; } return UPGRADE_DATA_SUCCESS; } uint8_t cli_upgrade_read_data_from_flash(uint8_t file_type, uint32_t offset, uint8_t *data, uint16_t data_len) { if ((file_type != UPGRADE_DATA_TYPE_FW) && (file_type != UPGRADE_DATA_TYPE_PIB) && (file_type != UPGRADE_DATA_TYPE_CUS)) { return UPGRADE_DATA_INVALID_DATA; } iot_pkg_upgrade_read(data, data_len, offset, file_type, 1); return UPGRADE_DATA_SUCCESS; } /* check if data receive done */ bool_t cli_upgrade_check_data_recv_done(uint8_t file_type) { if (UPGRADE_DATA_TYPE_FW == file_type) { if (upgrade_info->block_idx >= upgrade_info->fw_blocks) { iot_printf("fw done\n"); upgrade_info->fw_recv_done = 1; upgrade_info->block_idx = 0; } } else if(UPGRADE_DATA_TYPE_PIB == file_type) { if (upgrade_info->block_idx >= upgrade_info->pib_blocks) { iot_printf("pib done\n"); upgrade_info->pib_recv_done = 1; upgrade_info->block_idx = 0; } } else { if (upgrade_info->block_idx >= upgrade_info->cus_blocks) { iot_printf("cus done\n"); upgrade_info->cus_recv_done = 1; upgrade_info->block_idx = 0; } } if (upgrade_info->fw_recv_done && upgrade_info->pib_recv_done && upgrade_info->cus_recv_done) { // reset these value when recv file done. upgrade_info->fw_recv_done = 0; upgrade_info->pib_recv_done = 0; upgrade_info->cus_recv_done = 0; upgrade_info->block_idx = 0; return true; } return false; } /* handle upgrade start command from plc manager */ void cli_upgrade_start(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac) { iot_plc_upgrade_start_ul_t ack; iot_plc_upgrade_start_dl_t *data; data = (iot_plc_upgrade_start_dl_t *)buffer; iot_plc_upgrade_cust_start_dl_t cus_info; #if PLC_SUPPORT_CCO_ROLE os_mem_set(upgrade_info->upgrade_src_mac, 0, IOT_MAC_ADDR_LEN); if (src_mac) { iot_mac_addr_cpy(upgrade_info->upgrade_src_mac, src_mac); } #endif /* ckb p2p upgrade sta */ add_addr_to_mapping_table(src_mac); iot_printf("plc_upgrade:cco recv upgrade start, role:%d\n", host_config->dev_role); if ((!data) || (bufferlen < (sizeof(*data)))) { iot_printf("%s param error\n", __FUNCTION__); return; } if (data->cus_upgrade_flag) { if (bufferlen < (sizeof(*data) + data->dst_num * IOT_MAC_ADDR_LEN + sizeof(cus_info))) { iot_printf("%s data len error\n", __FUNCTION__); return; } os_mem_cpy((uint8_t *)&cus_info, (data->dst + data->dst_num * IOT_MAC_ADDR_LEN), sizeof(iot_plc_upgrade_cust_start_dl_t)); } else { if (bufferlen < (sizeof(*data) + data->dst_num * IOT_MAC_ADDR_LEN)) { iot_printf("%s data len error\n", __FUNCTION__); return; } os_mem_set((uint8_t *)&cus_info, 0, sizeof(cus_info)); } if (upgrade_info->upgrade_state != IOT_PLC_UPGRADE_INIT) { ack.result = UPGRADE_START_CCO_UPGRADING; goto err_exit; } ack.result = cli_upgrade_type_check(data); if (UPGRADE_START_OK != ack.result) { goto err_exit; } #if PLC_SUPPORT_CCO_ROLE /* set plc manager upgrade flag */ host_config->cli_upgrade_enabled = 1; #endif cli_upgrade_info_initialize(data); if (IOT_PLC_UPGRADE_LOCAL == upgrade_info->upgrade_type) { cli_upgrade_flash_info_initialize(data->block_size, data->fw_size, data->pib_size, cus_info.cus_size, data->upgrade_id, data->fw_checksum, data->pib_checksum, cus_info.cus_checksum, data->fw_version); } #if PLC_SUPPORT_CCO_ROLE else { if ((upgrade_info->full_bitmap == NULL) && upgrade_info->control_upgrade_flag) { upgrade_info->full_bitmap = os_mem_malloc(IOT_CLI_MID, IOT_PLC_UPGRADE_STA_BM_SIZE_MAX); if (upgrade_info->full_bitmap == NULL) { ack.result = UPGRADE_START_OTHER_ERROR; goto err_exit; } } upgrade_info->phase_one_broadcast_times = data->phase_one_broadcast_times; iot_printf("p1_bcast_times %d\n", upgrade_info->phase_one_broadcast_times); #if IOT_CLI_UPGRADE_CACHE_TYPE cli_upgrade_buffer_initialize(); #else uint32_t fw_size = 0; upgrade_info->pib_start = 0; upgrade_info->cus_start = 0; upgrade_info->fw_start = ((data->pib_size + (data->block_size - 1)) / data->block_size) * data->block_size; if (upgrade_info->fw_size) { fw_size = upgrade_info->fw_size + upgrade_info->fw_start; } else { fw_size = upgrade_info->pib_size; } if (cli_upgrade_write_data_to_flash_cache_init(data->upgrade_id, fw_size, upgrade_info->cus_size, data->block_size) != ERR_OK) { ack.result = UPGRADE_START_OTHER_ERROR; goto err_exit; } #endif } #endif ack.result = UPGRADE_START_OK; iot_mac_addr_cpy(ack.dst, host_config->mac_addr); upgrade_info->upgrade_state = IOT_PLC_UPGRADE_STARTING; err_exit: iot_printf("plc_upgrade:upgrade start, ack.result: %d\n", ack.result); iot_cli_send_to_host(CLI_MSGID_UPGRADE_START_ACK, (uint8_t *)&ack, sizeof(ack), src_mac); } /* handle upgrade data command */ void cli_upgrade_data(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac) { uint16_t index = 0; bool_t recv_done = false; iot_plc_upgrade_data_ack_ul_t ack; iot_plc_upgrade_data_dl_t *data = NULL; data = (iot_plc_upgrade_data_dl_t *)buffer; (void)index; if ((!data) || (bufferlen < sizeof(*data))) { iot_printf("%s param error", __FUNCTION__); return; } /* ckb p2p upgrade sta */ add_addr_to_mapping_table(src_mac); iot_printf("plc_upgrade:recv upgrade data\n"); cli_upgrade_print_block_info(data); ack.file_type = data->file_type; ack.upgrade_id = data->upgrade_id; ack.block_idx = data->block_idx_array[0]; ack.error_code = cli_upgrade_data_check(data->block_cnt, data->block_idx_array, data->block_size_array, data->data, data->file_type); if (UPGRADE_DATA_SUCCESS != ack.error_code) { if (UPGRADE_DATA_BLOCK_IDX_ERROR != ack.error_code) { goto err_exit; } if ((COMMUNICATOR_BT != cli.commu.type) || (IOT_PLC_UPGRADE_LOCAL != upgrade_info->upgrade_type)) { ack.block_idx = upgrade_info->block_idx; if (upgrade_info->pib_recv_done) { ack.file_type = UPGRADE_DATA_TYPE_FW; } else { ack.file_type = UPGRADE_DATA_TYPE_PIB; } goto err_exit; } } /* write data to flash directly only if it's local upgrade */ if (IOT_PLC_UPGRADE_LOCAL == upgrade_info->upgrade_type) { if (upgrade_info->upgrade_state == IOT_PLC_UPGRADE_TRANSFERRED) { ack.error_code = UPGRADE_DATA_DUPLICATE; goto err_exit; } if (upgrade_info->upgrade_state == IOT_PLC_UPGRADE_INIT) { ack.error_code = UPGRADE_DATA_STA_STOP; goto err_exit; } ack.error_code = cli_upgrade_write_data_to_flash(data->file_type, data->block_cnt, data->block_idx_array, data->block_size_array, data->data); if (UPGRADE_DATA_SUCCESS != ack.error_code) { goto err_exit; } } #if PLC_SUPPORT_CCO_ROLE else { #if IOT_CLI_UPGRADE_CACHE_TYPE cli_upgrade_write_data_to_buffer(data->file_type, data->block_cnt, data->block_idx_array, data->block_size_array, data->data); #else uint8_t file_type = UPGRADE_DATA_TYPE_FW; if (data->file_type == UPGRADE_DATA_TYPE_CUS) { file_type = UPGRADE_DATA_TYPE_CUS; } if (data->file_type == UPGRADE_DATA_TYPE_FW) { index = (uint16_t)((upgrade_info->pib_size + (upgrade_info->block_size - 1)) / upgrade_info->block_size); } for (uint8_t i = 0; i < data->block_cnt; i++) { data->block_idx_array[i] += index; } cli_upgrade_write_data_to_flash(file_type, data->block_cnt, data->block_idx_array, data->block_size_array, data->data); #endif } #endif upgrade_info->block_idx += data->block_cnt; if ((COMMUNICATOR_BT != cli.commu.type) || (IOT_PLC_UPGRADE_LOCAL != upgrade_info->upgrade_type)) { recv_done = cli_upgrade_check_data_recv_done(data->file_type); } if (recv_done) { if (IOT_PLC_UPGRADE_LOCAL == upgrade_info->upgrade_type) { iot_upgrade_commit(upgrade_info->src.id); upgrade_info->upgrade_state = IOT_PLC_UPGRADE_TRANSFERRED; } #if PLC_SUPPORT_CCO_ROLE else if (IOT_PLC_UPGRADE_STA_LIST == upgrade_info->upgrade_type) { upgrade_info->completed_handler = cli_remote_upgrade_complete; cli_remote_upgrade_sta_list_start(); } else if (IOT_PLC_UPGRADE_ALL == upgrade_info->upgrade_type) { cli_remote_upgrade_all_sta_start(); } #endif } ack.error_code = UPGRADE_DATA_SUCCESS; err_exit: iot_printf("plc_upgrade:send ack. error_code = %d\n", ack.error_code); iot_cli_send_to_host(CLI_MSGID_UPGRADE_DATA_ACK, (uint8_t *)&ack, sizeof(ack), src_mac); } /* cco/pco send start command to target STA */ void cli_remote_upgrade_send_start_notify(uint8_t send_type, uint8_t *sta_mac, uint8_t *dest_mac, uint8_t phase_flag) { iot_plc_upgrade_start_dl_t *start_dl; iot_pkt_t *pkt; uint32_t len; iot_plc_upgrade_cust_start_dl_t *cus_start = NULL; if ((!sta_mac) || (!dest_mac)) { return; } len = sizeof(*start_dl) + IOT_MAC_ADDR_LEN; if (upgrade_info->cus_size) { len += sizeof(iot_plc_upgrade_cust_start_dl_t); } pkt = iot_pkt_alloc(len, IOT_CLI_MID); if (!pkt) { return; } start_dl = (iot_plc_upgrade_start_dl_t *)iot_pkt_data(pkt); if (upgrade_info->cus_size) { cus_start = (iot_plc_upgrade_cust_start_dl_t *) (start_dl + sizeof(*start_dl) + IOT_MAC_ADDR_LEN); } start_dl->phase_flag = phase_flag; start_dl->upgrade_id = upgrade_info->upgrade_id; start_dl->fw_checksum = upgrade_info->fw_checksum; start_dl->pib_checksum = upgrade_info->pib_checksum; start_dl->block_size = upgrade_info->remote_block_size; start_dl->fw_size = upgrade_info->fw_size; start_dl->fw_version = upgrade_info->fw_version; start_dl->pib_size = (uint16_t)upgrade_info->pib_size; start_dl->pib_version = upgrade_info->pib_version; start_dl->upgrade_type = upgrade_info->upgrade_type; start_dl->remote_block_cnt = upgrade_info->remote_block_cnt; start_dl->remote_block_size = upgrade_info->remote_block_size; start_dl->time_window = upgrade_info->time_window; start_dl->dst_num = 1; start_dl->control_flag = upgrade_info->control_upgrade_flag; iot_mac_addr_cpy(start_dl->dst, dest_mac); if (upgrade_info->cus_size) { cus_start->cus_size = (uint16_t)upgrade_info->cus_size; cus_start->cus_checksum = upgrade_info->cus_checksum; cus_start->cus_version = upgrade_info->cus_version; start_dl->cus_upgrade_flag = 1; } else { start_dl->cus_upgrade_flag = 0; } iot_cli_module_send_data_with_retry(send_type, IOT_PLC_UPGRADE_START_RETRY_TIMES, CLI_MODULEID_HOSTINTERFACE, CLI_MSGID_REMOTE_UPGRADE_START, host_config->mac_addr, sta_mac, (uint8_t*)start_dl, len); iot_pkt_free(pkt); } /* start sub nodes to upgrade */ void cli_remote_upgrade_start_sub_nodes() { uint8_t dest[IOT_MAC_ADDR_LEN] = { 0xFF }; iot_printf("plc_upgrade: start sub nodes\n"); cli_upgrade_print_mac_info(host_config->mac_addr); cli_remote_upgrade_send_start_notify( IOT_PLC_MSG_TYPE_BCAST_1HOP, dest, dest, UPGRADE_START_UPGRADE_PHASE2); } uint32_t cli_upgrade_is_unicast_to_broadcast( iot_plc_upgrade_remote_data_dl *data) { if (iot_mac_addr_cmp(host_config->mac_addr, data->dst) && data->fwd_type) { return ERR_OK; } return ERR_FAIL; } /* create date packet for remote upgrade */ static iot_pkt_t *cli_remote_create_remote_data_packet(uint8_t send_type, uint8_t retry_cnt, uint8_t *dst, uint16_t block_size, uint32_t upgrade_id, uint8_t control_byte, uint8_t file_type, uint16_t block_idx, uint8_t fwd_type) { iot_pkt_t *data_pkt = NULL; uint32_t data_len = block_size + sizeof(iot_plc_upgrade_remote_data_dl); data_pkt = iot_cli_create_pkt_plc(send_type, retry_cnt, CLI_MODULEID_HOSTINTERFACE, CLI_MSGID_REMOTE_UPGRADE_DATA, NULL, dst, dst, data_len); if (data_pkt) { iot_plc_upgrade_remote_data_dl *data = NULL; data = (iot_plc_upgrade_remote_data_dl *) iot_pkt_block_ptr(data_pkt, IOT_PKT_BLOCK_TAIL); data->fwd_type = fwd_type; data->upgrade_id = upgrade_id; data->block_cnt = 1; data->block_idx_array[0] = block_idx; data->block_size_array[0] = block_size; data->fw_size = upgrade_info->fw_size; data->pib_size = (uint16_t)upgrade_info->pib_size; data->cus_size = (uint16_t)upgrade_info->cus_size; data->block_size = upgrade_info->remote_block_size; data->fw_checksum = upgrade_info->fw_checksum; data->pib_checksum = upgrade_info->pib_checksum; data->cus_checksum = upgrade_info->cus_checksum; data->contol_byte = control_byte; data->time_window = upgrade_info->time_window; data->remote_block_cnt = upgrade_info->remote_block_cnt; data->file_type = file_type; iot_mac_addr_cpy(data->dst, dst); } return data_pkt; } /* send data for remote upgrade */ void cli_remote_upgrade_send_data(uint8_t send_type, uint8_t retry_cnt, uint8_t *dst, uint32_t upgrade_id, uint8_t file_type, uint8_t control_byte, uint16_t block_size, uint16_t* block_idx_array, uint16_t block_cnt, uint8_t fwd_type, iot_pkt_free_func_t bcast_tx_done_func) { uint32_t file_size = 0; uint32_t blocks = 0; if (block_cnt) { if (file_type == UPGRADE_DATA_TYPE_PIB) { file_size = upgrade_info->pib_size; blocks = upgrade_info->pib_blocks; } else if (file_type == UPGRADE_DATA_TYPE_FW) { file_size = upgrade_info->fw_size; blocks = upgrade_info->fw_blocks; } else if (file_type == UPGRADE_DATA_TYPE_CUS) { file_size = upgrade_info->cus_size; blocks = upgrade_info->cus_blocks; } for (int i = 0; i < block_cnt; i++) { iot_pkt_t *packet = cli_remote_create_remote_data_packet( send_type, retry_cnt, dst, block_size, upgrade_id, control_byte, file_type, block_idx_array[i], fwd_type); if (packet) { iot_plc_upgrade_remote_data_dl * data = (iot_plc_upgrade_remote_data_dl *) iot_pkt_block_ptr(packet, IOT_PKT_BLOCK_TAIL); iot_pkt_put(packet, sizeof(*data)); if (block_idx_array[i] <= (blocks - 1)) { if (block_idx_array[i] == (blocks - 1)) { data->block_size_array[0] = (uint16_t)(file_size - (blocks - 1) * block_size); } if (data->block_size_array[0] > block_size) { IOT_ASSERT(0); } if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) { (void)bcast_tx_done_func; iot_pkg_upgrade_read( data->data, data->block_size_array[0], block_idx_array[i] * block_size, file_type, 1); iot_pkt_put(packet, block_size); iot_plc_send_msdu(host_config->app_handle, packet); } #if PLC_SUPPORT_CCO_ROLE else { cli_upgrade_get_cache_data(file_type, block_idx_array[i] * block_size, data->data, data->block_size_array[0]); if (bcast_tx_done_func && (send_type == IOT_PLC_MSG_TYPE_BCAST)) { if (iot_pkt_set_free_callback(packet, bcast_tx_done_func, NULL) == ERR_OK) { upgrade_info->bcast_wait_flag = 1; } } iot_pkt_put(packet, block_size); iot_plc_send_msdu(host_config->app_handle, packet); } #endif cli_remote_upgrade_update_latest_block( file_type, block_idx_array[i]); iot_printf("plc_upgrade:cco send remote data file_type %d" " block_index %d, block size %d\n", file_type, block_idx_array[i], block_size); } } } } } /* cco handle remote upgrade data request */ void cli_remote_upgrade_data_request( uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac) { (void)src_mac; #if PLC_SUPPORT_CCO_ROLE iot_plc_upgrade_dest_desc_t * dest = NULL; #endif iot_plc_upgrade_remote_data_req_ul_t *req; uint8_t send_type = IOT_PLC_MSG_TYPE_BCAST_1HOP; uint8_t retry_cnt = IOT_PLC_LOCAL_RETRY_CNT; uint8_t control_byte = UPGRADE_REMOTE_ALL_PHASE2_DATA; req = (iot_plc_upgrade_remote_data_req_ul_t *)buffer; if ((!req) || (bufferlen < sizeof(*req))) { iot_printf("%s param error", __FUNCTION__); return; } iot_printf("cco recv request," " %02X:%02X:%02X:%02X:%02X:%02X\n", req->dst[0], req->dst[1], req->dst[2], req->dst[3], req->dst[4], req->dst[5]); if ((IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) && (IOT_PLC_DEV_ROLE_PCO != host_config->dev_role)) { iot_printf("reject request, role %x\n", host_config->dev_role); return; } if ((IOT_PLC_UPGRADE_TRANSFERRED != upgrade_info->upgrade_state) || (IOT_PLC_UPGRADE_LOCAL == upgrade_info->upgrade_type)) { //if (IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) { // return; //} else if ((IOT_PLC_DEV_ROLE_PCO == host_config->dev_role) && // cli_upgrade_block_blank_check( // req->file_type, req->block_idx_array[0])) { // return; //} else { // iot_printf("pco not yet upgraded but has this block\n"); //} return; } upgrade_info->request_times++; upgrade_info->recv_req_flag = 1; #if PLC_SUPPORT_CCO_ROLE if ((IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) && upgrade_info->dest_info.table) { cli_upgrade_print_mac_info(req->dst); upgrade_info->sta_upgrade_active = 1; dest = (iot_plc_upgrade_dest_desc_t *)iot_addr_hash_table_find( upgrade_info->dest_info.table, req->dst); if (dest && (dest->status != IOT_PLC_UPGRADE_TRANSFERRED)) { if (req->progress) { dest->percentage = req->progress; } dest->upgrade_type = CLI_UPGRADE_TYPE_V0; dest->error_code = UPGRADE_DATA_STA_IN_PROGRESS; if (dest->percentage > (dest->reported_percentage + IOT_PLC_UPGRADE_PROGRESS_REPORT_INTERVAL)) { dest->reported_percentage = dest->percentage; cli_remote_upgrade_add_report_status(dest); } dest->status = IOT_PLC_UPGRADE_STARTED; } } #endif if (!req->phase3) { if (cli_remote_upgrade_update_find_latest_block( req->file_type, req->block_idx_array[0])) { return; } if (upgrade_info->last_timer_time) { if ((IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) && (os_boot_time32() < (upgrade_info->last_timer_time + IOT_PLC_UPGRADE_PCO_REJECT_REQ_TIME))) { return; } #if PLC_SUPPORT_CCO_ROLE else if ((IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) && (os_boot_time32() < (upgrade_info->last_timer_time + IOT_PLC_UPGRADE_CCO_REJECT_REQ_TIME))) { return; } #endif } upgrade_info->last_timer_time = os_boot_time32(); } if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) { if (req->progress) { cli_upgrade_sta_send_progress(req->dst, host_config->cco_mac, req->progress); } } iot_printf("plc_upgrade: cco accept request, " "file_type %d, progress %d, block cnt %d, block idx %d\n", req->file_type, req->progress, req->req_block_cnt, req->block_idx_array[0]); if ((IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) && (req->phase3)) { send_type = IOT_PLC_MSG_TYPE_UNICAST; retry_cnt = IOT_PLC_UPGRADE_PHASE_THREE_RETRY_TIMES; control_byte = UPGRADE_REMOTE_ALL_PHASE3_DATA; } if (IOT_PLC_UPGRADE_STA_LIST == upgrade_info->upgrade_type) { control_byte = UPGRADE_REMOTE_STA_LIST_DATA; } cli_remote_upgrade_send_data(send_type, retry_cnt, req->dst, upgrade_info->upgrade_id, req->file_type, control_byte, upgrade_info->remote_block_size, req->block_idx_array, req->req_block_cnt, UPGRADE_DATA_FORWARD_LOCAL_BCAST, NULL); } /* timer for one/all sta upgrade */ static void iot_cli_upgrade_timer(timer_id_t timer_id, void *arg) { (void)timer_id; (void)arg; iot_task_msg_t *msg = iot_cli_create_cli_msg(IOT_CLI_UPGRADE_TIMER, NULL); if (msg) { iot_task_queue_msg( cli.cli_task_h, msg, IOT_CLI_QUEUE_TIMER); } } /* pco/cco calculate time window by sub node cnt */ uint16_t cli_remote_upgrade_calculate_time_window(uint16_t sub_node_cnt) { uint16_t time_window = 0; if (sub_node_cnt > 350) { time_window = 20000; } else if (sub_node_cnt > 30) { time_window = 2400 + 50 * sub_node_cnt; } else { time_window = 800 + 100 * sub_node_cnt; } return 2 * time_window; } void cli_upgrade_reset_timer(uint8_t start, uint32_t time_window) { os_stop_timer(upgrade_info->upgrade_timer); iot_task_clean_msg(cli.cli_task_h, IOT_CLI_MSG_TYPE, IOT_CLI_UPGRADE_TIMER); if (start) { os_start_timer(upgrade_info->upgrade_timer, time_window); } } /* handle stop command */ void cli_upgrade_stop(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac) { (void)src_mac; iot_plc_upgrade_stop_dl_t *stop_dl = (iot_plc_upgrade_stop_dl_t *)buffer; if ((!stop_dl) || (bufferlen < sizeof(*stop_dl))) { return; } #if PLC_SUPPORT_CCO_ROLE if (!host_config->cli_upgrade_enabled) { cli_sg_upgrade_stop(); cli_upgrade_send_stop_ack(host_config->mac_addr, UPGRADE_ACTION_SUCCESS); return; } host_config->cli_upgrade_enabled = 0; #endif if (IOT_PLC_UPGRADE_LOCAL == upgrade_info->upgrade_type) { cli_upgrade_print_mac_info(host_config->mac_addr); upgrade_info->upgrade_state = IOT_PLC_UPGRADE_INIT; //send stop ack t plc mgr cli_upgrade_send_stop_ack(host_config->mac_addr, UPGRADE_ACTION_SUCCESS); } else if ((IOT_PLC_UPGRADE_ALL == upgrade_info->upgrade_type) || (IOT_PLC_UPGRADE_STA_LIST == upgrade_info->upgrade_type)) { if (IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) { cli_upgrade_print_mac_info(stop_dl->dst); // cco stop upgrade_info->upgrade_state = IOT_PLC_UPGRADE_STOPED; upgrade_info->action_times = 0; cli_upgrade_reset_timer(1, IOT_PLC_UPGRADE_CCO_MIN_BCAST_TIME); cli_upgrade_send_stop_ack(host_config->mac_addr, UPGRADE_ACTION_WAIT); } else { // sta stop requesting data if ((IOT_PLC_UPGRADE_STARTED == upgrade_info->upgrade_state) || (IOT_PLC_UPGRADE_STARTING == upgrade_info->upgrade_state) || (IOT_PLC_UPGRADE_LISTEN == upgrade_info->upgrade_state)) { cli_remote_upgrade_sta_stop(); cli_upgrade_send_stop_ack(host_config->mac_addr, UPGRADE_ACTION_SUCCESS); } } } } /* start remote upgrade phase2 */ void cli_remote_upgrade_start_phase2(uint16_t sub_node_cnt) { cli_remote_upgrade_initialize_latest_block(); upgrade_info->action_times = 0; upgrade_info->last_timer_time = 0; upgrade_info->request_times = 0; upgrade_info->time_window = cli_remote_upgrade_calculate_time_window(sub_node_cnt); cli_remote_upgrade_start_sub_nodes(); cli_upgrade_reset_timer(1, 2 * IOT_PLC_UPGRADE_DEFAULT_TIMER); } /* start remote upgrade phase3 */ void cli_remote_upgrade_start_phase3() { upgrade_info->upgrade_state = IOT_PLC_UPGRADE_TRANSFERRED; upgrade_info->action_times = 0; upgrade_info->last_timer_time = 0; upgrade_info->request_times = 0; cli_upgrade_reset_timer(1, IOT_PLC_UPGRADE_DEFAULT_TIMER / 6); } /* init the upgrade module of CLI host */ void iot_cli_upgrade_init() { void* ptr = os_mem_malloc(IOT_CLI_MID, sizeof(iot_plc_upgrade_info_t)); upgrade_info = (iot_plc_upgrade_info_t*)ptr; if (!upgrade_info){ IOT_ASSERT(upgrade_info); return; } upgrade_info->upgrade_timer = os_create_timer(IOT_CLI_MID, 1, iot_cli_upgrade_timer, NULL); iot_printf("plc_upgrade: timer:%x\n", upgrade_info->upgrade_timer); upgrade_info->upgrade_state = IOT_PLC_UPGRADE_INIT; upgrade_info->upgrade_type = IOT_PLC_UPGRADE_ALL; upgrade_info->upgrade_id = 0; upgrade_info->time_window = IOT_PLC_UPGRADE_DEFAULT_TIMER; upgrade_info->src.crc_check_buf = NULL; #if PLC_SUPPORT_CCO_ROLE if (MODULE_TYPE_CCO == cli_module_type) { iot_printf("plc_upgrade:cco init upgrade info\n"); upgrade_info->file_size = IOT_CLI_UPGRADE_MAX_FILE_SIZE; if (upgrade_info->file_size) { upgrade_info->file_data = os_mem_malloc(IOT_CLI_MID, upgrade_info->file_size); IOT_ASSERT(upgrade_info->file_data); } upgrade_info->pib_data = NULL; upgrade_info->fw_data = NULL; upgrade_info->dest_info.entry_ptr = NULL; upgrade_info->dest_info.table = NULL; upgrade_info->sta_upgrade_active = 0; upgrade_info->completed_handler = NULL; upgrade_info->sg_upgrade_handler = NULL; upgrade_info->calc_time_window_flag = 0; upgrade_info->node_response_flag = 1; upgrade_info->resend_data_state = CLI_QUERY_NODE; upgrade_info->query_node_retry_cnt = 0; cli_remote_upgrade_init_dest_info(); } #endif } /* deinit the upgrade module of CLI host */ void iot_cli_upgrade_deinit() { if (upgrade_info) { #if PLC_SUPPORT_CCO_ROLE cli_remote_upgrade_destroy_buffer(); cli_remote_upgrade_destroy_dest_info(); #endif if (upgrade_info->src.crc_check_buf) { iot_pkt_free(upgrade_info->src.crc_check_buf); upgrade_info->src.crc_check_buf = NULL; } if (upgrade_info->upgrade_timer) { os_delete_timer(upgrade_info->upgrade_timer); iot_task_clean_msg(cli.cli_task_h, IOT_CLI_MSG_TYPE, IOT_CLI_UPGRADE_TIMER); upgrade_info->upgrade_timer = 0; } os_mem_free(upgrade_info); upgrade_info = NULL; } } void cli_remote_upgrade_bcast_tx_done_callback(void *param, uint8_t state) { (void)param; (void)state; iot_task_msg_t *msg = iot_cli_create_cli_msg(IOT_CLI_BCAST_TX_DONE, NULL); if (msg) { iot_task_queue_msg(cli.cli_task_h, msg, IOT_CLI_QUEUE_HOST); } else { IOT_ASSERT(0); } } #else /* IOT_CLI_UPGRADE_ENABLE */ /* handle stop command */ void cli_upgrade_stop(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac) { (void)src_mac; iot_plc_upgrade_stop_dl_t *stop_dl = (iot_plc_upgrade_stop_dl_t *)buffer; if ((!stop_dl) || (bufferlen < sizeof(*stop_dl))) { return; } #if PLC_SUPPORT_CCO_ROLE if (!host_config->cli_upgrade_enabled) { cli_sg_upgrade_stop(); cli_upgrade_send_stop_ack(host_config->mac_addr, UPGRADE_ACTION_SUCCESS); return; } host_config->cli_upgrade_enabled = 0; #endif } /* init the upgrade module of CLI host */ void iot_cli_upgrade_init() { iot_printf("disable cli upgrade\n"); #if PLC_SUPPORT_CCO_ROLE void* ptr = os_mem_malloc(IOT_CLI_MID, sizeof(iot_plc_upgrade_info_t)); upgrade_info = (iot_plc_upgrade_info_t*)ptr; if (!upgrade_info){ IOT_ASSERT(upgrade_info); return; } upgrade_info->file_size = IOT_CLI_UPGRADE_MAX_FILE_SIZE; upgrade_info->file_data = os_mem_malloc(IOT_CLI_MID, upgrade_info->file_size); IOT_ASSERT(upgrade_info->file_data); #endif } /* deinit the upgrade module of CLI host */ void iot_cli_upgrade_deinit() { #if PLC_SUPPORT_CCO_ROLE if (!upgrade_info) { return; } if (upgrade_info->file_data) { os_mem_free(upgrade_info->file_data); } os_mem_free(upgrade_info); upgrade_info = NULL; #endif } /* start remote upgrade phase2 */ void cli_remote_upgrade_start_phase2(uint16_t sub_node_cnt) { (void)sub_node_cnt; } void iot_cli_upgrade_handle_timer_msg() { } #endif /* IOT_CLI_UPGRADE_ENABLE */ /* print mac info */ void cli_upgrade_print_mac_info(uint8_t *mac) { if (!mac) { return; } iot_printf("mac: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } /* send stop ack to PLC Manager */ void cli_upgrade_send_stop_ack(uint8_t * mac, uint16_t error_code) { iot_plc_upgrade_stop_ul_t stop_ul; if (!mac) { return; } cli_upgrade_print_mac_info(mac); stop_ul.upgrade_id = upgrade_info->upgrade_id; stop_ul.error_code = error_code; os_mem_cpy(stop_ul.dst, mac, IOT_MAC_ADDR_LEN); iot_cli_send_to_host(CLI_MSGID_UPGRADE_STOP_ACK, (uint8_t*)&stop_ul, sizeof(stop_ul), NULL); } #if PLC_SUPPORT_CCO_ROLE /* read fw data from buffer */ uint8_t cli_upgrade_read_data_from_buffer(uint8_t file_type, uint32_t offset, uint8_t *data, uint16_t data_len) { uint8_t *data_part = NULL; if (!data) { return UPGRADE_DATA_INVALID_DATA; } #if IOT_CLI_UPGRADE_ENABLE if (file_type == UPGRADE_DATA_TYPE_FW) { data_part = upgrade_info->fw_data; } else if (file_type == UPGRADE_DATA_TYPE_PIB) { data_part = upgrade_info->pib_data; } else if (file_type == UPGRADE_DATA_TYPE_CUS) { data_part = upgrade_info->cus_data; } else if (file_type == UPGRADE_DATA_TYPE_PKG) { data_part = upgrade_info->file_data; } else { IOT_ASSERT(0); } #else if (file_type == UPGRADE_DATA_TYPE_PKG) { data_part = upgrade_info->file_data; } else { IOT_ASSERT(0); } #endif /* IOT_CLI_UPGRADE_ENABLE */ os_mem_cpy(data, data_part + offset, data_len); return UPGRADE_DATA_SUCCESS; } /* write fw data to buffer */ uint8_t cli_upgrade_write_data_to_buffer(uint8_t file_type, uint16_t block_cnt, uint16_t *block_idx_array, uint16_t *block_size_array, uint8_t *data) { uint32_t begin_index = 0; uint8_t *data_part = NULL; if (!data) { return UPGRADE_DATA_INVALID_DATA; } for (uint32_t i = 0; i < block_cnt; i++) { if (block_size_array[i]) { iot_printf("plc_upgrade:cco write %d block %d bytes type %d\n", block_idx_array[i], block_size_array[i], file_type); #if IOT_CLI_UPGRADE_ENABLE if (file_type == UPGRADE_DATA_TYPE_FW) { data_part = upgrade_info->fw_data; } else if (file_type == UPGRADE_DATA_TYPE_PIB) { data_part = upgrade_info->pib_data; } else if (file_type == UPGRADE_DATA_TYPE_CUS) { data_part = upgrade_info->cus_data; } else if (file_type == UPGRADE_DATA_TYPE_PKG) { data_part = upgrade_info->file_data; } else { IOT_ASSERT(0); } #else if (file_type == UPGRADE_DATA_TYPE_PKG) { data_part = upgrade_info->file_data; } else { IOT_ASSERT(0); } #endif /* IOT_CLI_UPGRADE_ENABLE */ iot_printf("cpy dst idx %d, size %d\n", block_idx_array[i] * upgrade_info->block_size, block_size_array[i]); os_mem_cpy(data_part + block_idx_array[i] * upgrade_info->block_size, data + begin_index, block_size_array[i]); begin_index += block_size_array[i]; } } return UPGRADE_DATA_SUCCESS; } #endif /* PLC_SUPPORT_CCO_ROLE */ /* send reset ack to PLC Manager */ void cli_upgrade_send_reset_ack(uint8_t * mac, uint16_t error_code) { iot_plc_upgrade_reset_ul_t reset_ul; if (!mac) { return; } cli_upgrade_print_mac_info(mac); reset_ul.upgrade_id = upgrade_info->upgrade_id; reset_ul.error_code = error_code; os_mem_cpy(reset_ul.dst, mac, IOT_MAC_ADDR_LEN); iot_cli_send_to_host(CLI_MSGID_UPGRADE_RESET_ACK, (uint8_t*)&reset_ul, sizeof(reset_ul), NULL); } /* handle reset command */ void cli_upgrade_reset(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac) { iot_plc_upgrade_reset_ul_t reset_ul; (void)src_mac; iot_plc_upgrade_reset_dl_t *data = NULL; data = (iot_plc_upgrade_reset_dl_t *)buffer; if ((!data) || (bufferlen < sizeof(*data))) { iot_printf("%s param error", __FUNCTION__); return; } if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) { os_mem_cpy(reset_ul.dst, host_config->mac_addr, IOT_MAC_ADDR_LEN); iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_UNICAST, CLI_MSGID_UPGRADE_RESET_ACK, host_config->cco_mac, (uint8_t*)&reset_ul, sizeof(reset_ul)); #if IOT_CLI_UPGRADE_ENABLE upgrade_info->upgrade_state = IOT_PLC_UPGRADE_INIT; #endif //reset sta iot_upgrade_reset(); } #if PLC_SUPPORT_CCO_ROLE else { //reset one if (data->type) { if (iot_mac_addr_cmp(data->dst, host_config->mac_addr)) { //reset cco iot_upgrade_reset(); } else { iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_UNICAST, CLI_MSGID_UPGRADE_RESET, data->dst, buffer, bufferlen); } } else { #if !IOT_CLI_UPGRADE_ENABLE cli_upgrade_send_reset_ack(host_config->mac_addr, UPGRADE_ACTION_OTHER_ERROR); #else cli_upgrade_send_reset_ack(host_config->mac_addr, UPGRADE_ACTION_WAIT); // cco reset all upgrade_info->upgrade_state = IOT_PLC_UPGRADE_RESET; upgrade_info->action_times = 0; if (!os_is_timer_active(upgrade_info->upgrade_timer)) { os_start_timer(upgrade_info->upgrade_timer, upgrade_info->time_window); } #endif } } #endif }