Files
kunlun/cli/host_interface/plc/iot_cli_cco_upgrade.c
2024-09-28 14:24:04 +08:00

1958 lines
63 KiB
C

/****************************************************************************
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_oem_api.h"
#include "iot_img_hdr.h"
#include "iot_ntoh_api.h"
#include "iot_system.h"
#include "iot_cli_plc_tx_rx.h"
#include "iot_cli_plc_module.h"
#include "iot_cli_upgrade_api.h"
#include "iot_cli_host_upgrade_internal.h"
#include "iot_cli_upgrade_status_type_def.h"
#include "iot_cli_sg.h"
#include "iot_bitmap_api.h"
#include "plc_utils.h"
#include "iot_mtd.h"
extern iot_plc_upgrade_info_t *upgrade_info;
extern iot_plc_host_config_t *host_config;
extern iot_cli_host_info_t *host_info;
#if PLC_SUPPORT_CCO_ROLE
iot_cli_upgrade_app_handler sg_upgrade_handler = NULL;
#if IOT_CLI_UPGRADE_ENABLE
/* remote upgrade dst list check */
static uint8_t cli_upgrade_dst_list_check(
iot_plc_upgrade_dst_list_t *data)
{
if (!data) {
return UPGRADE_DST_LIST_INVALID_DATA;
}
if (upgrade_info->dst_list_idx != data->dst_list_idx) {
iot_printf("plc_upgrade:recv dst list, expect %d, recv %x",
upgrade_info->dst_list_idx, data->dst_list_idx);
return UPGRADE_DST_LIST_IDX_ERROR;
}
return UPGRADE_DST_LIST_SUCCESS;
}
static void cli_upgrade_set_dst_status_ack(
iot_plc_upgrade_dst_status_query *query)
{
if (!query) {
return;
}
query->dst_total_num = upgrade_info->dest_info.dst_total_num;
query->dst_num = UPGRADE_REMOTE_DST_STATUS_ONCE_MAX_NUM;
query->upgrade_state = upgrade_info->upgrade_state;
}
/* cco handle destination status query from plc manager */
static void cli_upgrade_dst_status_query_internal(uint8_t *src_mac)
{
iot_plc_upgrade_dst_status_query_ul query_ack;
cli_upgrade_set_dst_status_ack(&(query_ack.query));
iot_cli_send_to_host(CLI_MSGID_UPGRADE_DST_STATUS_QUERY_ACK,
(uint8_t *)&query_ack, sizeof(query_ack), src_mac);
}
static void cli_upgrade_set_dst_status_list(uint16_t start_idx,
uint8_t count, iot_plc_upgrade_dst_status_list *status_list)
{
uint16_t end_idx = 0;
uint16_t total_dst_num;
iot_plc_upgrade_dest_desc_t **org_dest_desc;
iot_plc_upgrade_dest_desc_t *dest_desc;
if (!status_list) {
return;
}
if (upgrade_info->upgrade_type == IOT_PLC_UPGRADE_STA_LIST) {
total_dst_num = upgrade_info->dst_list_idx;
org_dest_desc = &upgrade_info->dest_info.upgrading_list[0];
} else {
total_dst_num = upgrade_info->dest_info.dst_total_num;
org_dest_desc = upgrade_info->dest_info.entry_ptr;
}
if ((!count) || (start_idx >= total_dst_num)) {
status_list->dst_num = 0;
status_list->end = 1;
return;
}
if (count > UPGRADE_REMOTE_DST_STATUS_ONCE_MAX_NUM) {
count = UPGRADE_REMOTE_DST_STATUS_ONCE_MAX_NUM;
}
end_idx = start_idx + count - 1;
status_list->dst_status_list_idx = start_idx;
status_list->end = 0;
if (end_idx > (total_dst_num - 1)) {
end_idx = total_dst_num - 1;
status_list->end = 1;
}
if (upgrade_info->dest_info.entry_ptr) {
status_list->dst_num = (uint8_t)(end_idx - start_idx + 1);
os_mem_set(status_list->dst_status_list, 0,
UPGRADE_REMOTE_DST_STATUS_ONCE_MAX_NUM *
sizeof(iot_plc_upgrade_dst_status_t));
org_dest_desc += start_idx;
for (uint8_t i = 0; i < status_list->dst_num; i++, org_dest_desc++) {
dest_desc = *org_dest_desc;
if (dest_desc) {
status_list->dst_status_list[i].status =
dest_desc->status;
status_list->dst_status_list[i].percentage =
dest_desc->percentage;
status_list->dst_status_list[i].error_code =
dest_desc->error_code;
iot_mac_addr_cpy(status_list->dst_status_list[i].dst,
dest_desc->entry.addr);
}
}
} else {
status_list->dst_num = 0;
status_list->end = 1;
}
}
/* coo handle destination status list query from plc manager*/
void cli_upgrade_dst_status_list_internal(uint16_t start_index,
uint8_t dst_num, uint8_t *src_mac)
{
iot_plc_upgrade_dst_status_list_ul *list_ul;
iot_pkt_t *buf_pkt;
uint16_t rsp_len;
uint8_t i;
uint8_t temp_percent;
/* allocate buffer for response */
rsp_len = sizeof(iot_plc_upgrade_dst_status_list_ul);
buf_pkt = iot_pkt_alloc(rsp_len, IOT_CLI_MID);
if (!buf_pkt) {
iot_printf("%s pkt malloc fail\n", __FUNCTION__);
return;
}
list_ul = (iot_plc_upgrade_dst_status_list_ul*)iot_pkt_data(buf_pkt);
cli_upgrade_set_dst_status_list(start_index, dst_num,
&(list_ul->status_list));
if (upgrade_info->upgrade_state == IOT_PLC_UPGRADE_TRANSFERRED) {
for (i = 0; i < list_ul->status_list.dst_num; i++) {
temp_percent = list_ul->status_list.dst_status_list->percentage;
list_ul->status_list.dst_status_list->percentage =
UPGRADE_BDCT_PROGRESS_IN_BCAST_PHASE +
(temp_percent * (100 - UPGRADE_BDCT_PROGRESS_IN_BCAST_PHASE));
}
}
iot_pkt_put(buf_pkt, rsp_len);
iot_printf("upgrade status rpt sta cnt %d \n",
list_ul->status_list.dst_num);
iot_cli_send_to_host(CLI_MSGID_UPGRADE_DST_STATUS_LIST_ACK,
(uint8_t *)list_ul, rsp_len, src_mac);
iot_pkt_free(buf_pkt);
}
/* cco handle destination list from plc manager */
void cli_upgrade_dst_list(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)bufferlen;
(void)src_mac;
iot_plc_upgrade_dst_list_ul_t ack;
iot_plc_upgrade_dst_list_dl_t *data;
iot_plc_upgrade_dst_list_t *info;
data = (iot_plc_upgrade_dst_list_dl_t *)buffer;
info = (iot_plc_upgrade_dst_list_t *)&(data->info);
ack.dst_list_idx = data->info.dst_list_idx;
ack.error_code = cli_upgrade_dst_list_check(info);
if (UPGRADE_DST_LIST_SUCCESS != ack.error_code) {
goto err_exit;
}
iot_cli_upgrade_set_dst_list(info, 0);
ack.error_code = UPGRADE_DST_LIST_SUCCESS;
err_exit:
iot_cli_send_to_host(CLI_MSGID_UPGRADE_DST_LIST_ACK, (uint8_t *)&ack,
sizeof(ack), src_mac);
}
/* cco send upgrade progress to PLC Manager */
void cli_remote_upgrade_send_upgrade_progress(uint8_t progress_value,
uint8_t *mac)
{
iot_plc_upgrade_progress_ul_t progress;
if (!mac) {
return;
}
#if PLC_SUPPORT_UPGRADE_DEBUG
iot_printf("plc_upgrade:cco send upgrade progress"
" to plc manager, sta mac:\n");
cli_upgrade_print_mac_info(mac);
#endif
progress.progress = progress_value;
progress.upgrade_id = upgrade_info->upgrade_id;
progress.upgrade_type = IOT_PLC_UPGRADE_ALL;
os_mem_cpy(progress.dst, mac, IOT_MAC_ADDR_LEN);
iot_cli_send_to_host(CLI_MSGID_UPGRADE_PROGRESS,
(uint8_t*)&progress, sizeof(progress), upgrade_info->upgrade_src_mac);
}
static uint32_t cli_upgrade_get_dest_index(uint16_t *index)
{
uint16_t i = 0;
for (i = 0; i < IOT_PLC_UPGRADE_STATUS_ITEM_MAX_CNT; i++) {
if (!upgrade_info->dest_info.entry_ptr[i]) {
*index = i;
return ERR_OK;
}
}
return ERR_FAIL;
}
/* cco add dest info into hash table */
iot_plc_upgrade_dest_desc_t *cli_upgrade_add_dest_info(uint8_t *mac)
{
iot_plc_upgrade_dest_desc_t *dest = NULL;
uint16_t idx;
dest = (iot_plc_upgrade_dest_desc_t *)iot_addr_hash_table_find(
upgrade_info->dest_info.table, mac);
if (dest) {
return dest;
}
if (!mac || (IOT_PLC_UPGRADE_STATUS_ITEM_MAX_CNT <=
upgrade_info->dest_info.dst_total_num)) {
return dest;
}
if (ERR_OK != cli_upgrade_get_dest_index(&idx)) {
return dest;
}
dest = (iot_plc_upgrade_dest_desc_t *)iot_addr_hash_table_alloc(
upgrade_info->dest_info.table);
if (dest) {
dest->status = IOT_PLC_UPGRADE_INIT;
dest->percentage = 0;
dest->reported_percentage = 0;
dest->start_retry_times = 0;
dest->upgrade_type = CLI_UPGRADE_TYPE_UNKNOWN;
if (IOT_PLC_UPGRADE_INIT != upgrade_info->upgrade_state) {
dest->error_code = UPGRADE_DATA_STA_IN_PROGRESS;
} else {
dest->error_code = 0;
}
iot_mac_addr_cpy(dest->entry.addr, mac);
upgrade_info->dest_info.entry_ptr[idx] = dest;
iot_addr_hash_table_add(upgrade_info->dest_info.table,
&dest->entry);
upgrade_info->dest_info.dst_total_num++;
} else {
iot_printf("add dest failed, alloc failed\n");
}
return dest;
}
uint16_t cli_upgrade_add_upgrade_list_dest_info(
uint8_t *node_mac, uint16_t node_cnt, uint8_t is_renew)
{
uint16_t i;
iot_plc_upgrade_dest_desc_t *desc;
uint16_t cnt = 0;
if (is_renew) {
for (i = 0; i < IOT_PLC_UPGRADE_PHASE_THREE_MAX_SAT_CNT; i++) {
upgrade_info->dest_info.upgrading_list[i] = NULL;
}
upgrade_info->dst_list_idx = 0;
}
for (i = 0; i < node_cnt; i++) {
desc = cli_upgrade_add_dest_info(node_mac + (i * IOT_MAC_ADDR_LEN));
if (desc) {
upgrade_info->dest_info.upgrading_list[upgrade_info->dst_list_idx] =
desc;
upgrade_info->dst_list_idx++;
cnt++;
}
}
return cnt;
}
/* cco destroy buffer for remote upgrade */
void cli_remote_upgrade_destroy_buffer()
{
if (upgrade_info->file_data) {
os_mem_free(upgrade_info->file_data);
upgrade_info->file_data = NULL;
upgrade_info->pib_data = NULL;
upgrade_info->fw_data = NULL;
upgrade_info->cus_data = NULL;
}
}
/* cco init dest info */
void cli_remote_upgrade_init_dest_info()
{
if (upgrade_info->dest_info.table) {
cli_remote_upgrade_destroy_dest_info();
}
upgrade_info->dest_info.dst_total_num = 0;
upgrade_info->dest_info.dst_transferred_num = 0;
upgrade_info->dest_info.dest_idx = 0;
upgrade_info->dest_info.upgrading_list_idx = 0;
upgrade_info->dest_info.query_node_timeout = 0;
upgrade_info->dest_info.entry_ptr = (iot_plc_upgrade_dest_desc_t **)
os_mem_malloc(IOT_CLI_MID, IOT_PLC_UPGRADE_STATUS_ITEM_MAX_CNT *
sizeof(iot_plc_upgrade_dest_desc_t *));
IOT_ASSERT(upgrade_info->dest_info.entry_ptr);
upgrade_info->dest_info.table = iot_addr_hash_table_create(
IOT_CLI_MID, IOT_PLC_UPGRADE_STATUS_ITEM_MAX_CNT,
sizeof(iot_plc_upgrade_dest_desc_t),
IOT_PLC_UPGRADE_STATUS_TABLE_SIZE);
IOT_ASSERT(upgrade_info->dest_info.table);
}
/* reset cli upgrade dest info when begin cli upgrade */
void cli_remote_upgrade_dest_info_reset()
{
uint16_t i;
iot_plc_upgrade_dest_desc_t *entry_ptr;
/* init node upgrade info */
for (i = 0; i < IOT_PLC_UPGRADE_STATUS_ITEM_MAX_CNT; i++) {
entry_ptr = upgrade_info->dest_info.entry_ptr[i];
if (!entry_ptr) {
continue;
}
entry_ptr->status = IOT_PLC_UPGRADE_INIT;
entry_ptr->error_code = 0;
entry_ptr->percentage = 0;
entry_ptr->reported_percentage = 0;
entry_ptr->start_retry_times = 0;
entry_ptr->updated = 0;
entry_ptr->error_code = UPGRADE_DATA_STA_IN_PROGRESS;
entry_ptr->upgrade_type = CLI_UPGRADE_TYPE_UNKNOWN;
}
/* init cli upgrade info */
upgrade_info->dest_info.dst_transferred_num = 0;
upgrade_info->dest_info.dest_idx = 0;
upgrade_info->dest_info.upgrading_list_idx = 0;
upgrade_info->dest_info.query_node_timeout = 0;
}
/* cco destroy dest info */
void cli_remote_upgrade_destroy_dest_info()
{
for (uint16_t i = 0; i < upgrade_info->dest_info.dst_total_num; i++) {
if (upgrade_info->dest_info.entry_ptr[i]) {
iot_addr_hash_table_free(upgrade_info->dest_info.table,
(iot_addr_hash_entry_t *)
upgrade_info->dest_info.entry_ptr[i]);
}
}
if (upgrade_info->dest_info.entry_ptr) {
os_mem_free(upgrade_info->dest_info.entry_ptr);
upgrade_info->dest_info.entry_ptr = NULL;
}
if (upgrade_info->dest_info.table) {
iot_addr_hash_table_delete(upgrade_info->dest_info.table);
upgrade_info->dest_info.table = NULL;
}
}
/* cco send stop report upgrade result command to target pco/sta */
void cli_remote_upgrade_send_stop_rpt_notify(uint8_t *dest_mac)
{
iot_plc_sg_upgrade_stop_rpt_dl_t stop_rpt_dl = { 0 };
stop_rpt_dl.flag = 1;
iot_printf("%s set sta: %x:%x:%x:%x:%x:%x stop report\n", __FUNCTION__,
dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4],
dest_mac[5]);
iot_cli_module_send_data_with_retry(IOT_PLC_MSG_TYPE_UNICAST,
IOT_PLC_UPGRADE_RETRY_COUNT, CLI_MODULEID_HOSTINTERFACE,
CLI_MSGID_SET_STOP_UPGRADE_RPT, NULL, dest_mac, (uint8_t *)&stop_rpt_dl,
sizeof(stop_rpt_dl));
}
/* cco stop remote upgrade */
void cli_remote_upgrade_coo_stop()
{
//stop all logic
//todo: add stop one sta logic
upgrade_info->dest_info.dest_idx = upgrade_info->dest_info.dst_total_num;
cli_upgrade_reset_timer(0, 0);
if (upgrade_info->full_bitmap) {
os_mem_free(upgrade_info->full_bitmap);
upgrade_info->full_bitmap = NULL;
}
iot_printf("plc_upgrade:cco stop timer\n");
}
/* query next broadcast block idx */
static bool_t cli_remote_upgrade_next_block_idx(bool_t first)
{
bool_t next = true;
if (first) {
upgrade_info->block_idx = 0;
if (upgrade_info->pib_size) {
upgrade_info->current_file_type = UPGRADE_DATA_TYPE_PIB;
} else if (upgrade_info->fw_size) {
upgrade_info->current_file_type = UPGRADE_DATA_TYPE_FW;
} else if (upgrade_info->cus_size) {
upgrade_info->current_file_type = UPGRADE_DATA_TYPE_CUS;
} else {
next = false;
}
} else {
upgrade_info->block_idx++;
if ((UPGRADE_DATA_TYPE_PIB == upgrade_info->current_file_type) &&
(upgrade_info->pib_blocks == upgrade_info->block_idx)) {
upgrade_info->block_idx = 0;
if (upgrade_info->fw_size) {
upgrade_info->current_file_type = UPGRADE_DATA_TYPE_FW;
} else if (upgrade_info->cus_size) {
upgrade_info->current_file_type = UPGRADE_DATA_TYPE_CUS;
} else {
next = false;
}
} else if ((UPGRADE_DATA_TYPE_FW == upgrade_info->current_file_type) &&
(upgrade_info->fw_blocks == upgrade_info->block_idx)) {
if (upgrade_info->cus_size) {
upgrade_info->block_idx = 0;
upgrade_info->current_file_type = UPGRADE_DATA_TYPE_CUS;
} else {
next = false;
}
} else if ((UPGRADE_DATA_TYPE_CUS == upgrade_info->current_file_type) &&
(upgrade_info->cus_blocks == upgrade_info->block_idx)) {
next = false;
}
}
return next;
}
uint8_t cli_remote_upgrade_calculate_bcast_max_times()
{
uint8_t max_times =
(uint8_t)upgrade_info->phase_one_broadcast_times;
if (!max_times) {
max_times = IOT_PLC_UPGRADE_BCAST_TIMES_LEV1;
if (upgrade_info->dest_info.dst_total_num >
IOT_PLC_UPGRADE_BCAST_STA_THRESHOLD2) {
max_times = IOT_PLC_UPGRADE_BCAST_TIMES_LEV3;
} else if (upgrade_info->dest_info.dst_total_num >
IOT_PLC_UPGRADE_BCAST_STA_THRESHOLD) {
max_times = IOT_PLC_UPGRADE_BCAST_TIMES_LEV2;
}
}
if (max_times > IOT_PLC_UPGRADE_BCAST_TIMES_LEV4) {
max_times = IOT_PLC_UPGRADE_BCAST_TIMES_LEV4;
}
iot_printf("calculate bcast max times %d\n", max_times);
return max_times;
}
/* cco report broadcast progress to plc mgr */
static void cli_remote_upgrade_report_broadcast_progress()
{
uint8_t dest[IOT_MAC_ADDR_LEN] = { 0 };
uint16_t blocks = upgrade_info->block_idx + 1;
uint16_t total_blocks =
upgrade_info->pib_blocks + upgrade_info->fw_blocks;
if (UPGRADE_DATA_TYPE_FW == upgrade_info->current_file_type) {
blocks += upgrade_info->pib_blocks;
}
if ((blocks % IOT_PLC_UPGRADE_PROGRESS_BLOCKS_INTERVAL) == 0) {
uint8_t progress = (uint8_t)((blocks + total_blocks *
upgrade_info->broadcast_times) *
UPGRADE_BDCT_PROGRESS_IN_BCAST_PHASE / (total_blocks *
cli_remote_upgrade_calculate_bcast_max_times()));
cli_remote_upgrade_send_upgrade_progress(progress, dest);
}
}
static uint32_t cli_remote_upgrade_calculate_broadcast_time()
{
uint32_t base_interval_tm;
#if HW_PLATFORM == HW_PLATFORM_SIMU
base_interval_tm = IOT_PLC_UPGRADE_CCO_BCAST_TIME;
#else
if (upgrade_info->dest_info.dst_total_num <=
IOT_PLC_UPGRADE_CCO_MIN_BCAST_NODE_CNT) {
base_interval_tm = IOT_PLC_UPGRADE_CCO_MIN_BCAST_TIME;
} else {
base_interval_tm = IOT_PLC_UPGRADE_CCO_SHORT_BCAST_TIME;
}
#endif
base_interval_tm = (uint32_t)(base_interval_tm +
upgrade_info->dest_info.dst_total_num *
IOT_PLC_UPGRADE_STA_CNT_ADJ_VALUE + IOT_PLC_UPGRADE_PCO_ADJ_TIME *
upgrade_info->level_one_pco_count);
return base_interval_tm;
}
void cli_remote_upgrade_bcast_tx_done()
{
uint32_t interval = 0;
if (upgrade_info->bcast_wait_flag) {
upgrade_info->bcast_wait_flag = 0;
interval = cli_remote_upgrade_calculate_broadcast_time();
cli_upgrade_reset_timer(1, interval);
}
}
/* cco send broadcast data */
void cli_remote_upgrade_cco_broadcast_data(bool_t first)
{
uint8_t ctrl_type = UPGRADE_REMOTE_ALL_PHASE1_DATA;
if (upgrade_info->upgrade_type == IOT_PLC_UPGRADE_STA_LIST) {
ctrl_type = UPGRADE_REMOTE_STA_LIST_DATA;
}
if (cli_remote_upgrade_next_block_idx(first)) {
uint8_t dest[IOT_MAC_ADDR_LEN] = { 0 };
uint16_t idx[1];
idx[0] = upgrade_info->block_idx;
cli_remote_upgrade_send_data(IOT_PLC_MSG_TYPE_BCAST,
upgrade_info->broadcast_retry_times, dest,
upgrade_info->upgrade_id, upgrade_info->current_file_type,
ctrl_type, upgrade_info->remote_block_size, idx, 1,
UPGRADE_DATA_FORWARD_INVALID,
cli_remote_upgrade_bcast_tx_done_callback);
if (first) {
if (!os_is_timer_active(upgrade_info->upgrade_timer)) {
uint32_t broadcast_interval =
cli_remote_upgrade_calculate_broadcast_time();
iot_printf("plc_upgrade: start broadcast data"
" interval %d, retry times %d\n",
broadcast_interval, upgrade_info->broadcast_retry_times);
os_start_timer(upgrade_info->upgrade_timer,
broadcast_interval);
}
} else {
cli_remote_upgrade_report_broadcast_progress();
}
} else {
upgrade_info->broadcast_times++;
iot_printf("plc_upgrade:cco bcast time %d phase1\n",
upgrade_info->broadcast_times);
if (upgrade_info->broadcast_times <
cli_remote_upgrade_calculate_bcast_max_times()) {
cli_remote_upgrade_cco_broadcast_data(true);
} else {
cli_upgrade_reset_timer(0, 0);
iot_printf("plc_upgrade:coo stop broadcast\n");
os_delay(5000);
iot_printf("plc_upgrade:phase 2\n");
upgrade_info->upgrade_state = IOT_PLC_UPGRADE_TRANSFERRED;
iot_plc_query_neighbor_dev(host_config->app_handle,
IOT_PLC_API_REQ_ID_DEFAULT, 0, 1,
IOT_PLC_QUERY_TOPO_START_AS_TEI);
}
}
}
static void cli_remote_upgrade_prepare()
{
upgrade_info->upgrade_state = IOT_PLC_UPGRADE_STARTING;
upgrade_info->fw_blocks = (uint16_t)iot_ceil(upgrade_info->fw_size,
upgrade_info->remote_block_size);
upgrade_info->pib_blocks = (uint16_t)iot_ceil(upgrade_info->pib_size,
upgrade_info->remote_block_size);
upgrade_info->cus_blocks = (uint16_t)iot_ceil(upgrade_info->cus_size,
upgrade_info->remote_block_size);
iot_printf("cco prepare for upgrade pib blocks %d fw blocks %d"
"cus blocks %d\n", upgrade_info->pib_blocks, upgrade_info->fw_blocks,
upgrade_info->cus_blocks);
//create new upgrade id
upgrade_info->upgrade_id++;
}
/* cco send upgrade broadcast start to sta list */
uint32_t cli_remote_upgrade_broadcast_start_sta_list(bool_t first)
{
uint32_t result = ERR_OK;
if (first) {
upgrade_info->dest_info.upgrading_list_idx = 0;
cli_upgrade_reset_timer(1, upgrade_info->time_window);
iot_printf("upgrade start time window: %lu\n",
upgrade_info->time_window);
}
result = cli_remote_upgrade_multi_node_start_notify(IOT_PLC_MSG_TYPE_BCAST,
UPGRADE_START_UPGRADE_PHASE1);
if ((!first) && result == ERR_OK) {
upgrade_info->broadcast_times++;
iot_printf("plc_upgrade:cco bcast start cmd time %d phase1\n",
upgrade_info->broadcast_times);
if ((cli_remote_upgrade_find_init_dest_from_idx(0) != NULL) &&
(upgrade_info->broadcast_times <
IOT_PLC_UPGRADE_BROADCAST_TIMES_CNT)) {
cli_remote_upgrade_broadcast_start_sta_list(true);
} else {
iot_printf("plc_upgrade:coo stop broadcast start upgrade cmd\n");
cli_upgrade_reset_timer(0, 0);
upgrade_info->upgrade_state = IOT_PLC_UPGRADE_STARTED;
/*
* list node upgrade, begin broadcast upgrade data
* init broadcast upgrade file count
*/
upgrade_info->broadcast_times = 0;
iot_printf("plc_upgrade:coo begin broadcast upgrade data\n");
cli_remote_upgrade_cco_broadcast_data(true);
}
}
return result;
}
/* cco start sta list to start upgrade */
void cli_remote_upgrade_sta_list_start()
{
cli_remote_upgrade_prepare();
cli_remote_upgrade_initialize_latest_block();
//init broadcast start upgrade count
upgrade_info->broadcast_times = 0;
upgrade_info->action_times = 0;
upgrade_info->last_timer_time = 0;
upgrade_info->time_window =
cli_remote_upgrade_calculate_time_window(upgrade_info->dst_list_idx);
iot_printf("plc_upgrade:coo start upgrade timer for broadcast data, "
"timewindow: %lu\n",
upgrade_info->time_window);
cli_remote_upgrade_broadcast_start_sta_list(true);
}
/* cco start remote upgrade */
void cli_remote_upgrade_all_sta_start()
{
cli_remote_upgrade_prepare();
//start broadcast
upgrade_info->broadcast_times = 0;
upgrade_info->upgrade_state = IOT_PLC_UPGRADE_STARTED;
cli_remote_upgrade_cco_broadcast_data(true);
}
/* add status to list for report timer */
void cli_remote_upgrade_add_report_status(
iot_plc_upgrade_dest_desc_t *status)
{
if (status) {
if ((!status->updated) &&
(IOT_PLC_UPGRADE_LATEST_STATUS_MAX_CNT >
upgrade_info->dest_info.dest_idx))
{
status->updated = true;
iot_printf("add status upgrade, %d, %d ",\
"mac: %02X:%02X:%02X:%02X:%02X:%02X\n",
status->percentage, status->error_code,
status->entry.addr[0], status->entry.addr[1],
status->entry.addr[2], status->entry.addr[3],
status->entry.addr[4], status->entry.addr[5]);
upgrade_info->dest_info.latest_status_list[
upgrade_info->dest_info.dest_idx] = status;
upgrade_info->dest_info.dest_idx++;
}
}
}
/* coo handle remote upgrade start ack from sta */
void cli_remote_upgrade_start_ack(
uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)src_mac;
iot_plc_upgrade_dest_desc_t * dest = NULL;
iot_plc_upgrade_start_ul_t *ack;
ack = (iot_plc_upgrade_start_ul_t*)buffer;
if (!ack){
IOT_ASSERT(ack);
return;
}
IOT_ASSERT(bufferlen >= sizeof(*ack));
cli_upgrade_print_mac_info(ack->dst);
dest = (iot_plc_upgrade_dest_desc_t *)
iot_addr_hash_table_find(upgrade_info->dest_info.table, ack->dst);
if (dest) {
if (UPGRADE_START_OK == ack->result) {
dest->status = IOT_PLC_UPGRADE_STARTED;
} else {
if ((dest->status != IOT_PLC_UPGRADE_TRANSFERRED) &&
(dest->status != IOT_PLC_UPGRADE_FAILED) &&
(dest->status != IOT_PLC_UPGRADE_START_FAIL)) {
iot_printf("upgrade result, mac: %02X:%02X:%02X:%02X:%02X:%02X,"
" result %d\n",
dest->entry.addr[0], dest->entry.addr[1],
dest->entry.addr[2], dest->entry.addr[3],
dest->entry.addr[4], dest->entry.addr[5],
UPGRADE_START_END_SINCE_COMPLETED == ack->result);
}
dest->status = IOT_PLC_UPGRADE_START_FAIL;
dest->error_code = UPGRADE_DATA_OTHER_ERROR;
if (UPGRADE_START_END_SINCE_COMPLETED == ack->result) {
if (dest->status != IOT_PLC_UPGRADE_TRANSFERRED) {
upgrade_info->dest_info.dst_transferred_num++;
}
dest->status = IOT_PLC_UPGRADE_TRANSFERRED;
dest->error_code = UPGRADE_DATA_SUCCESS;
}
cli_remote_upgrade_add_report_status(dest);
}
}
}
/* cco check sta recv done */
static uint8_t cli_remote_upgrade_check_sta_recv_done(uint8_t *bm, uint16_t cnt)
{
uint8_t result = 1;
uint16_t byte_count = 0;
uint8_t over_bit = 0;
byte_count = (cnt + 7) >> 3;
over_bit = (uint8_t)((byte_count << 3) - cnt);
/* last byte redundant bit set 1 */
bm[byte_count - 1] |= 0xff << (8 - over_bit);
if (iot_bitmap_cbz(bm, byte_count) == 0) {
result = 1;
} else {
result = 0;
}
return result;
}
/* cco handle sta info ack from sta */
void cli_remote_upgrade_node_info_rsp(uint8_t *buffer, uint32_t bufferlen,
uint8_t *src_mac)
{
(void)src_mac;
uint8_t err_code = 0;
uint16_t sta_written_block = 0;
uint16_t bm_size = 0;
iot_plc_upgrade_query_sta_info_ul_t *ack =
(iot_plc_upgrade_query_sta_info_ul_t *)buffer;
iot_plc_upgrade_dest_desc_t *dest;
if (bufferlen < sizeof(*ack)) {
err_code = 1;
goto err;
}
iot_printf("plc_upgrade:response node-%02X:%02X:%02X:%02X:%02X:%02X, "
"state:%d\n", ack->dst[0], ack->dst[1], ack->dst[2], ack->dst[3],
ack->dst[4], ack->dst[5], ack->state);
dest = (iot_plc_upgrade_dest_desc_t *)iot_addr_hash_table_find(
upgrade_info->dest_info.table, ack->dst);
if (dest == NULL) {
err_code = 2;
goto err;
}
if (iot_mac_addr_cmp(ack->dst, upgrade_info->sta_mac) == 0) {
if (ack->state == IOT_PLC_UPGRADE_TRANSFERRED) {
dest->status = IOT_PLC_UPGRADE_TRANSFERRED;
dest->error_code = UPGRADE_DATA_SUCCESS;
dest->percentage = 100;
}
err_code = 3;
goto err;
}
if(upgrade_info->resend_data_state == CLI_SEND_DATA) {
err_code = 4;
goto err;
}
upgrade_info->node_response_flag = 1;
if (ack->state == IOT_PLC_UPGRADE_INIT) {
/* the current node not started to upgrade, query the next node */
upgrade_info->resend_data_state = CLI_QUERY_NODE;
os_mem_set(upgrade_info->sta_mac, 0, IOT_MAC_ADDR_LEN);
cli_remote_upgrade_send_start_notify(IOT_PLC_MSG_TYPE_UNICAST,
dest->entry.addr, dest->entry.addr, UPGRADE_START_UPGRADE_PHASE1);
goto err;
}
bm_size = (ack->cnt + 7) >> 3;
sta_written_block = (uint16_t)iot_bitmap_cbs(ack->bm, bm_size);
dest->percentage = (uint8_t)(sta_written_block * 100 /
(upgrade_info->pib_blocks + upgrade_info->fw_blocks));
if (cli_remote_upgrade_check_sta_recv_done(ack->bm, ack->cnt) ||
ack->state == IOT_PLC_UPGRADE_TRANSFERRED) {
dest->status = IOT_PLC_UPGRADE_TRANSFERRED;
dest->error_code = UPGRADE_DATA_SUCCESS;
dest->percentage = 100;
upgrade_info->resend_data_state = CLI_QUERY_NODE;
os_mem_set(upgrade_info->sta_mac, 0, IOT_MAC_ADDR_LEN);
iot_printf("%02x:%02x:%02x:%02x:%02x:%02x: upgrade complete\n",
dest->entry.addr[0], dest->entry.addr[1], dest->entry.addr[2],
dest->entry.addr[3], dest->entry.addr[4], dest->entry.addr[5]);
} else {
os_mem_cpy(upgrade_info->full_bitmap, ack->bm, bm_size);
upgrade_info->resend_data_state = CLI_SEND_DATA;
dest->upgrade_type = CLI_UPGRADE_TYPE_V1;
}
err:
iot_printf("plc_upgrade: %s , resend state:%d err:%d \n", __FUNCTION__,
upgrade_info->resend_data_state, err_code);
}
/* cco send upgrade result to plc manager */
void cli_remote_upgrade_result(
uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)src_mac;
iot_plc_upgrade_dest_desc_t * dest = NULL;
iot_plc_upgrade_result_ul_t *result;
result = (iot_plc_upgrade_result_ul_t *)buffer;
if ((!result) || (bufferlen < sizeof(*result))) {
iot_printf("%s param error", __FUNCTION__);
return;
}
if (!upgrade_info->dest_info.table) {
return;
}
dest = (iot_plc_upgrade_dest_desc_t *)iot_addr_hash_table_find(
upgrade_info->dest_info.table, result->dst);
if (dest) {
if ((dest->status != IOT_PLC_UPGRADE_TRANSFERRED) &&
(dest->status != IOT_PLC_UPGRADE_FAILED)) {
upgrade_info->sta_upgrade_active = 1;
iot_printf("upgrade result, mac: %02X:%02X:%02X:%02X:%02X:%02X,"
" result %d\n",
dest->entry.addr[0], dest->entry.addr[1],
dest->entry.addr[2], dest->entry.addr[3],
dest->entry.addr[4], dest->entry.addr[5],
result->error_code);
}
if (UPGRADE_DATA_SUCCESS == result->error_code) {
if (dest->status != IOT_PLC_UPGRADE_TRANSFERRED) {
upgrade_info->dest_info.dst_transferred_num++;
}
cli_remote_upgrade_send_stop_rpt_notify(result->dst);
dest->status = IOT_PLC_UPGRADE_TRANSFERRED;
dest->error_code = result->error_code;
if (upgrade_info->control_upgrade_flag) {
/* the current node upgrade complete, resend next node */
if (iot_mac_addr_cmp(upgrade_info->sta_mac, result->dst)) {
os_mem_set(upgrade_info->sta_mac, 0, IOT_METER_ADDR_LEN);
upgrade_info->node_response_flag = 1;
upgrade_info->resend_data_state = CLI_QUERY_NODE;
}
}
} else {
dest->status = IOT_PLC_UPGRADE_FAILED;
dest->error_code = result->error_code;
}
cli_remote_upgrade_add_report_status(dest);
}
}
/* cco send upgrade progress to plc manager */
void cli_remote_upgrade_progress(
uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)src_mac;
iot_plc_upgrade_dest_desc_t * dest = NULL;
iot_plc_upgrade_progress_ul_t *progress;
progress = (iot_plc_upgrade_progress_ul_t *)buffer;
if ((!progress) || (bufferlen < sizeof(*progress))) {
iot_printf("%s param error", __FUNCTION__);
return;
}
if (!upgrade_info->dest_info.table) {
return;
}
upgrade_info->sta_upgrade_active = 1;
dest = (iot_plc_upgrade_dest_desc_t *)iot_addr_hash_table_find(
upgrade_info->dest_info.table, progress->dst);
if (dest) {
dest->percentage = progress->progress;
dest->error_code = UPGRADE_DATA_STA_IN_PROGRESS;
cli_remote_upgrade_add_report_status(dest);
}
}
/* initialize upgrading list */
void cli_remote_upgrade_initialize_upgrading_list()
{
uint16_t index = 0;
upgrade_info->dest_info.upgrading_list_idx = 0;
for (uint16_t i = 0; i < upgrade_info->dest_info.dst_total_num; i++) {
iot_plc_upgrade_dest_desc_t *desc =
upgrade_info->dest_info.entry_ptr[i];
// add uncompleted sta into
if (desc && (IOT_PLC_UPGRADE_TRANSFERRED != desc->status &&
(index < IOT_PLC_UPGRADE_PHASE_THREE_MAX_SAT_CNT))) {
upgrade_info->dest_info.upgrading_list[index] = desc;
index++;
}
}
upgrade_info->dst_list_idx = index;
iot_printf("plc_upgrade:cco initialize upgrading"
" list for phase3 %lu\n", index);
}
static uint8_t cli_remote_upgrade_conform_node_mode(
iot_plc_upgrade_dest_desc_t *dest, uint8_t mode)
{
uint8_t result = 0;
if (mode == CLI_FIND_START_NODE) {
if ((dest->upgrade_type == CLI_UPGRADE_TYPE_UNKNOWN) ||
(dest->upgrade_type == CLI_UPGRADE_TYPE_V0)) {
result = 1;
}
} else {
if ((dest->upgrade_type == CLI_UPGRADE_TYPE_UNKNOWN) ||
(dest->upgrade_type == CLI_UPGRADE_TYPE_V1)) {
result = 1;
}
}
return result;
}
static iot_plc_upgrade_dest_desc_t *
cli_remote_upgrade_find_uncompleted_dest_from_idx(uint16_t start_idx,
uint8_t mode)
{
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_TRANSFERRED !=
upgrade_info->dest_info.upgrading_list[start_idx]->status) {
if (cli_remote_upgrade_conform_node_mode(
upgrade_info->dest_info.upgrading_list[start_idx], mode)) {
dest = upgrade_info->dest_info.upgrading_list[start_idx];
upgrade_info->dest_info.upgrading_list_idx = start_idx + 1;
break;
}
}
start_idx++;
}
return dest;
}
static iot_plc_upgrade_dest_desc_t *cli_remote_upgrade_find_uncompleted_dest(
uint8_t mode)
{
iot_plc_upgrade_dest_desc_t *dest = NULL;
dest = cli_remote_upgrade_find_uncompleted_dest_from_idx(
upgrade_info->dest_info.upgrading_list_idx, mode);
if (!dest) {
dest = cli_remote_upgrade_find_uncompleted_dest_from_idx(0, mode);
}
return dest;
}
/* get resend phase time window */
uint16_t cli_remote_upgrade_get_resend_time_window(uint16_t node_cnt)
{
uint16_t result = IOT_PLC_UPGRADE_CCO_SHORT_BCAST_TIME;
if (node_cnt > 500) {
result += ((node_cnt - 200) + (node_cnt - 500) * 2);
} else if (node_cnt > 300) {
result += ((node_cnt - 100) + (node_cnt - 300) * 2);
} else if (node_cnt > 50) {
result += (node_cnt - 50) * 2;
}
return result;
}
static uint8_t cli_remote_upgrade_find_resend_dest()
{
uint8_t query_cnt = 0;
iot_plc_upgrade_dest_desc_t *dest = NULL;
dest = cli_remote_upgrade_find_uncompleted_dest(CLI_FIND_QUERY_NODE);
if (dest) {
iot_mac_addr_cpy(upgrade_info->sta_mac, dest->entry.addr);
query_cnt++;
iot_printf("plc_upgrade: find a resend node -"
"%02X:%02X:%02X:%02X:%02X:%02X\n", dest->entry.addr[0],
dest->entry.addr[1], dest->entry.addr[2], dest->entry.addr[3],
dest->entry.addr[4], dest->entry.addr[5]);
}
return query_cnt;
}
static void cli_remote_upgrade_query_node_bitmap(uint16_t start, uint16_t cnt)
{
iot_plc_upgrade_query_sta_info_dl_t query_dl = {0};
if (iot_mac_addr_valid(upgrade_info->sta_mac) == 0) {
iot_printf("plc_upgrade: %s dest mac invalid\n", __FUNCTION__);
return;
}
query_dl.upgrade_id = upgrade_info->upgrade_id;
query_dl.start_idx = start;
query_dl.cnt = cnt;
iot_mac_addr_cpy(query_dl.dst, upgrade_info->sta_mac);
iot_cli_module_send_data_with_retry(IOT_PLC_MSG_TYPE_UNICAST,
IOT_PLC_UPGRADE_PHASE_THREE_RETRY_TIMES,
CLI_MODULEID_HOSTINTERFACE,
CLI_MSGID_UPGRADE_NODE_INFO_QUERY, host_config->mac_addr,
upgrade_info->sta_mac, (uint8_t*)&query_dl, sizeof(query_dl));
iot_printf("plc_upgrade: cco send query node info cmd\n");
}
static uint16_t cli_remote_upgrade_find_miss_block(uint8_t *file_type)
{
uint16_t block_index = 0;
uint16_t bm_size = 0;
uint16_t fw_blocks = upgrade_info->fw_blocks;
uint16_t pib_blocks = upgrade_info->pib_blocks;
bm_size = (pib_blocks + fw_blocks + 7) >> 3;
block_index =
(uint16_t)iot_bitmap_ffz_and_s(upgrade_info->full_bitmap, bm_size);
if (block_index > 0) {
if (block_index <= pib_blocks) {
*file_type = UPGRADE_DATA_TYPE_PIB;
block_index -= 1;
} else if (block_index <= (fw_blocks + pib_blocks)) {
*file_type = UPGRADE_DATA_TYPE_FW;
block_index -= pib_blocks + 1;
}
} else {
if (upgrade_info->full_bitmap[0] & 0x01) {
/* if block index is 0,but bitmap bit0 is 1, return invalid index */
block_index = IOT_PLC_UPGRADE_INVALID_BLOCK_INDEX;
}
}
return block_index;
}
static uint8_t cli_remote_upgrade_send_miss_block()
{
uint8_t file_type = UPGRADE_DATA_TYPE_PIB;
uint16_t idx[1];
uint16_t block_idx;
uint8_t i = 0;
if (iot_mac_addr_valid(upgrade_info->sta_mac) == 0) {
iot_printf("plc_upgrade: %s dest mac invalid\n", __FUNCTION__);
return 0;
}
for (i = 0; i < IOT_PLC_UPGRADE_SEND_BLOCK_CNT; ++i) {
block_idx = cli_remote_upgrade_find_miss_block(&file_type);
if (block_idx == IOT_PLC_UPGRADE_INVALID_BLOCK_INDEX) {
return 0;
}
idx[0] = block_idx;
cli_remote_upgrade_send_data(IOT_PLC_MSG_TYPE_UNICAST,
IOT_PLC_UPGRADE_MAX_START_RETRY_TIMES, upgrade_info->sta_mac,
upgrade_info->upgrade_id, file_type, UPGRADE_REMOTE_STA_LIST_DATA,
upgrade_info->remote_block_size, idx, 1,
UPGRADE_DATA_FORWARD_LOCAL_BCAST, NULL);
}
return 1;
}
uint8_t cli_remote_upgrade_resend_phase()
{
uint8_t node_cnt = 1;
if (upgrade_info->node_response_flag) {
if (upgrade_info->resend_data_state == CLI_QUERY_NODE) {
if (iot_mac_addr_valid(upgrade_info->sta_mac) == 0) {
node_cnt = cli_remote_upgrade_find_resend_dest();
upgrade_info->query_node_retry_cnt = 0;
}
cli_remote_upgrade_query_node_bitmap(1, IOT_PLC_UPGRADE_QUERY_BM_ALL);
upgrade_info->dest_info.query_node_timeout_cnt = 0;
upgrade_info->node_response_flag = 0;
upgrade_info->query_node_retry_cnt++;
os_mem_set(upgrade_info->full_bitmap, 0,
IOT_PLC_UPGRADE_STA_BM_SIZE_MAX);
} else if (upgrade_info->resend_data_state == CLI_SEND_DATA) {
if (cli_remote_upgrade_send_miss_block() == 0) {
upgrade_info->resend_data_state = CLI_QUERY_NODE;
os_mem_set(upgrade_info->full_bitmap, 0,
IOT_PLC_UPGRADE_STA_BM_SIZE_MAX);
if (upgrade_info->query_node_retry_cnt >
IOT_PLC_UPGRADE_QUERY_RETRY_MAX) {
os_mem_set(upgrade_info->sta_mac, 0, IOT_MAC_ADDR_LEN);
}
}
}
} else {
upgrade_info->dest_info.query_node_timeout_cnt++;
if (upgrade_info->dest_info.query_node_timeout_cnt >=
upgrade_info->dest_info.query_node_timeout) {
upgrade_info->node_response_flag = 1;
upgrade_info->resend_data_state = CLI_QUERY_NODE;
os_mem_set(upgrade_info->sta_mac, 0, IOT_MAC_ADDR_LEN);
}
}
return node_cnt;
}
void cli_remote_upgrade_complete()
{
iot_printf("plc_upgrade: cli remote upgrade complete\n");
upgrade_info->upgrade_state = IOT_PLC_UPGRADE_STOPED;
}
/* start phase three */
uint8_t cli_remote_upgrade_start_phase_three()
{
iot_plc_upgrade_dest_desc_t *dest = NULL;
iot_plc_upgrade_dest_desc_t *prev = NULL;
uint8_t phase_three_cnt = IOT_PLC_UPGRADE_PHASE_THREE_START_CNT;
uint8_t dec_mac[IOT_MAC_ADDR_LEN] = { 0 };
uint8_t total_send_cnt = 0;
iot_printf("plc_upgrade: cco start phase3\n");
for (uint8_t i = 0; i < phase_three_cnt; i++) {
//find next start sta
dest = cli_remote_upgrade_find_uncompleted_dest(CLI_FIND_START_NODE);
if (!dest) {
break;
}
if (prev && (prev == dest)) {
break;
} else {
prev = dest;
}
if (IOT_PLC_UPGRADE_STA_LIST == upgrade_info->upgrade_type) {
iot_mac_addr_cpy(dec_mac, dest->entry.addr);
}
cli_remote_upgrade_send_start_notify(IOT_PLC_MSG_TYPE_UNICAST,
dest->entry.addr, dec_mac, UPGRADE_START_UPGRADE_PHASE3);
total_send_cnt++;
}
return total_send_cnt;
}
/* cco receive stop ack from sta */
void cli_upgrade_stop_ack(
uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)src_mac;
iot_plc_upgrade_stop_ul_t *stop_ul;
stop_ul = (iot_plc_upgrade_stop_ul_t *)buffer;
if ((!stop_ul) || (bufferlen < sizeof(*stop_ul))) {
iot_printf("%s param error", __FUNCTION__);
return;
}
cli_upgrade_send_stop_ack(stop_ul->dst, stop_ul->error_code);
if (upgrade_info->dest_info.table) {
iot_plc_upgrade_dest_desc_t * dest = (iot_plc_upgrade_dest_desc_t *)
iot_addr_hash_table_find(
upgrade_info->dest_info.table, stop_ul->dst);
if (dest) {
dest->status = IOT_PLC_UPGRADE_STOPED;
}
}
}
/* cco receive reset ack from sta */
void cli_upgrade_reset_ack(
uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)src_mac;
iot_plc_upgrade_reset_ul_t *reset_ul;
reset_ul = (iot_plc_upgrade_reset_ul_t *)buffer;
if ((!reset_ul) || (bufferlen < sizeof(*reset_ul))) {
iot_printf("%s param error", __FUNCTION__);
return;
}
cli_upgrade_send_reset_ack(reset_ul->dst, reset_ul->error_code);
}
/* cco handle sta join */
void iot_cli_cco_handle_sta_join(uint8_t *mac)
{
iot_plc_upgrade_dest_desc_t *dest = NULL;
iot_printf("plc_upgrade: sta join\n");
cli_upgrade_print_mac_info(mac);
dest = (iot_plc_upgrade_dest_desc_t *)iot_addr_hash_table_find(
upgrade_info->dest_info.table, mac);
if (!dest) {
cli_upgrade_add_dest_info(mac);
// add node to phase3
if (IOT_PLC_UPGRADE_ALL == upgrade_info->upgrade_type) {
if (upgrade_info->dst_list_idx) {
cli_upgrade_add_upgrade_list_dest_info(mac, 1, 0);
}
}
}
}
/* cco handle sta leave */
void iot_cli_cco_handle_sta_leave(iot_plc_sta_info_t *sta)
{
iot_plc_upgrade_dest_desc_t *dest = NULL;
iot_printf("plc_upgrade: sta leave\n");
cli_upgrade_print_mac_info(sta->mac_addr);
if (!upgrade_info->dest_info.dst_total_num) {
return;
}
dest = (iot_plc_upgrade_dest_desc_t *)
iot_addr_hash_table_find(upgrade_info->dest_info.table, sta->mac_addr);
if (dest) {
dest->error_code = UPGRADE_DATA_STA_LEAVE;
}
}
void iot_cli_upgrade_app_register_handler(iot_cli_upgrade_app_handler handler)
{
sg_upgrade_handler = handler;
}
void cli_upgrade_cache_file_init(uint8_t *file_hdr)
{
upgrade_info->cus_size = iot_get_file_cus_len(file_hdr);
upgrade_info->cus_data = NULL;
upgrade_info->pib_size = 0;
upgrade_info->pib_data = NULL;
upgrade_info->fw_size = (iot_get_file_len(file_hdr) +
iot_get_file_header_len(file_hdr)) - upgrade_info->cus_size;
upgrade_info->fw_data = NULL;
cli_upgrade_write_data_to_flash_cache_init(upgrade_info->upgrade_id++,
upgrade_info->fw_size, upgrade_info->cus_size, upgrade_info->block_size);
}
uint32_t iot_cli_upgrade_prepare(iot_cli_upgrade_completed_handler handler,
uint32_t file_size, uint8_t **data, uint8_t *file_hdr, uint16_t block_size,
uint8_t upgrade_type)
{
uint32_t ret = ERR_OK;
uint32_t file_len = iot_get_file_len(file_hdr);
/* if the file header is invalid, the file size is used */
if (file_len == 0) {
file_len = file_size;
} else {
file_len += iot_get_file_header_len(file_hdr);
}
if ((block_size != 100) && (block_size != 200) &&
(block_size != 300) && (block_size != 400)) {
iot_printf("%s block size %d is invalid\n", block_size);
ret = ERR_FAIL;
goto out;
}
if (file_size) {
cli_remote_upgrade_dest_info_reset();
} else {
ret = ERR_FAIL;
goto out;
}
if (handler) {
upgrade_info->completed_handler = handler;
}
upgrade_info->block_size = block_size;
#if IOT_CLI_UPGRADE_CACHE_TYPE
(void)file_hdr;
(void)upgrade_type;
if (file_len > IOT_CLI_UPGRADE_MAX_FILE_SIZE) {
ret = ERR_FAIL;
goto out;
}
#else
uint8_t part_num;
uint32_t part_size = 0;
if (upgrade_type == IOT_PLC_UPGRADE_LOCAL) {
ret = ERR_FAIL;
goto out;
}
dev_get_upgrade_fw_part_num(&part_num);
part_size = dev_get_part_size(part_num);
if (file_len > part_size) {
ret = ERR_FAIL;
goto out;
}
cli_upgrade_cache_file_init(file_hdr);
upgrade_info->fw_start = iot_get_file_fw_start(file_hdr);
upgrade_info->pib_start = iot_get_file_pib_start(file_hdr);
upgrade_info->cus_start = iot_get_file_cus_start(file_hdr);
upgrade_info->fw_size = iot_get_file_fw_len(file_hdr);
upgrade_info->pib_size = iot_get_file_pib_len(file_hdr);
upgrade_info->cus_size = iot_get_file_cus_len(file_hdr);
#endif
*data = upgrade_info->file_data;
out:
return ret;
}
void iot_cli_translate_file()
{
upgrade_info->fw_size = iot_get_file_fw_len(upgrade_info->file_data);
upgrade_info->pib_size = iot_get_file_pib_len(upgrade_info->file_data);
upgrade_info->cus_size = iot_get_file_cus_len(upgrade_info->file_data);
upgrade_info->pib_data = upgrade_info->file_data +
iot_get_file_pib_start(upgrade_info->file_data);
upgrade_info->fw_data = upgrade_info->file_data +
iot_get_file_fw_start(upgrade_info->file_data);
upgrade_info->cus_data = upgrade_info->file_data +
iot_get_file_cus_start(upgrade_info->file_data);
}
uint32_t iot_cli_upgrade_calc_file_crc(uint32_t file_size, uint32_t start_pos)
{
uint32_t crc_tmp = 0xFFFFFFFF;
uint32_t index = 0;
uint8_t *ptr;
uint32_t block_size = 2000;
uint32_t read_size = block_size;
iot_pkt_t *pkt = iot_pkt_alloc(block_size, IOT_CLI_MID);
IOT_ASSERT(pkt);
ptr = iot_pkt_put(pkt, block_size);
while (index < file_size) {
if ((index + block_size) > file_size) {
read_size = file_size - index;
}
cli_upgrade_read_data_from_flash(UPGRADE_DATA_TYPE_FW,
start_pos + index, ptr, (uint16_t)read_size);
crc_tmp = iot_getcrc32_update(crc_tmp, ptr, read_size);
index += block_size;
}
iot_pkt_free(pkt);
return (crc_tmp ^ 0xFFFFFFFF);
}
uint8_t iot_cli_upgrade_external_start(uint8_t upgrade_type,
uint8_t control_flag)
{
if (upgrade_info->upgrade_state != IOT_PLC_UPGRADE_INIT) {
return UPGRADE_START_CCO_UPGRADING;
}
if ((IOT_PLC_UPGRADE_ALL != upgrade_type) &&
(IOT_PLC_UPGRADE_STA_LIST != upgrade_type)) {
iot_printf("cli upgrade not support upgrade type: %d\n", upgrade_type);
return UPGRADE_START_INVALID_TYPE;
}
iot_printf("cli upgrade start\n");
#if IOT_CLI_UPGRADE_CACHE_TYPE
iot_cli_translate_file();
if (upgrade_info->fw_data && upgrade_info->fw_size) {
upgrade_info->fw_checksum =
iot_getcrc32(upgrade_info->fw_data, upgrade_info->fw_size);
}
if (upgrade_info->pib_data && upgrade_info->pib_size) {
upgrade_info->pib_checksum =
iot_getcrc32(upgrade_info->pib_data, upgrade_info->pib_size);
}
if (upgrade_info->cus_data && upgrade_info->cus_size) {
upgrade_info->cus_checksum =
iot_getcrc32(upgrade_info->cus_data, upgrade_info->cus_size);
}
#else
//delay for share task write upgrade file.
os_delay(100);
if (upgrade_info->fw_size) {
upgrade_info->fw_checksum = iot_cli_upgrade_calc_file_crc(
upgrade_info->fw_size, upgrade_info->fw_start);
}
if (upgrade_info->pib_size) {
upgrade_info->pib_checksum = iot_cli_upgrade_calc_file_crc(
upgrade_info->pib_size, upgrade_info->pib_start);
}
if (upgrade_info->cus_size) {
upgrade_info->cus_checksum = iot_cli_upgrade_calc_file_crc(
upgrade_info->cus_size, upgrade_info->cus_start);
}
#endif
cli_remote_upgrade_sta_initialize(upgrade_type,
UPGRADE_DEFAULT_BLOCK_SIZE, UPGRADE_DEFAULT_BLOCK_SIZE,
upgrade_info->fw_size, upgrade_info->pib_size, upgrade_info->cus_size,
upgrade_info->fw_checksum, upgrade_info->pib_checksum,
upgrade_info->cus_checksum, IOT_PLC_UPGRADE_DEFAULT_TIMER,
IOT_PLC_UPGRADE_DEFAULT_REMOTE_BLOCK_CNT);
upgrade_info->control_upgrade_flag = !!control_flag;
upgrade_info->level_one_pco_count = IOT_PLC_UPGRADE_PCO_DEFAULT_ADJ_COUNT;
upgrade_info->broadcast_retry_times =
IOT_PLC_UPGRADE_CCO_BCAST_MIN_RETRY_CNT;
//start sg upgrade
cli_remote_upgrade_prepare();
if (IOT_PLC_UPGRADE_STA_LIST == upgrade_type) {
cli_remote_upgrade_sta_list_start();
} else {
/* init upgrade list */
cli_upgrade_add_upgrade_list_dest_info(NULL, 0, 1);
upgrade_info->upgrade_state = IOT_PLC_UPGRADE_STARTED;
cli_remote_upgrade_cco_broadcast_data(true);
}
return UPGRADE_START_OK;
}
/* sg cli upgrade start */
uint8_t iot_cli_upgrade_start(uint8_t upgrade_type, uint8_t control_flag)
{
return iot_cli_upgrade_external_start(upgrade_type, control_flag);
}
/* sg cli upgrade stop */
void iot_cli_upgrade_stop()
{
iot_printf("cli upgrade stop\n");
upgrade_info->completed_handler = NULL;
if ((IOT_PLC_UPGRADE_STARTING == upgrade_info->upgrade_state) ||
(IOT_PLC_UPGRADE_STARTED == upgrade_info->upgrade_state) ||
(IOT_PLC_UPGRADE_TRANSFERRED == upgrade_info->upgrade_state)) {
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);
}
}
/* write pib or fw data to flash !! */
void iot_cli_upgrade_write_file_to_flash(uint8_t file_type,
uint16_t interval)
{
uint32_t written_size = 0;
uint16_t block_index = 0;
uint32_t src_block_size = upgrade_info->pib_size;
uint8_t *src_data = upgrade_info->pib_data;
uint16_t block_size = upgrade_info->block_size;
if (UPGRADE_DATA_TYPE_PIB != file_type) {
src_block_size = upgrade_info->fw_size;
src_data = upgrade_info->fw_data;
}
while (written_size < src_block_size) {
if ((written_size + block_size) >
src_block_size) {
block_size = (uint16_t)(src_block_size - written_size);
}
cli_upgrade_write_data_to_flash(file_type, 1,
&block_index, &block_size,
src_data + written_size);
written_size += block_size;
block_index++;
os_delay(interval);
}
}
/* cco handle destination list from app */
uint8_t iot_cli_upgrade_set_dst_list(iot_plc_upgrade_dst_list_t *data,
uint8_t is_renew)
{
uint8_t error_code;
uint16_t tmp_dst_list_idx = upgrade_info->dst_list_idx;
if (is_renew) {
upgrade_info->dst_list_idx = 0;
}
error_code = cli_upgrade_dst_list_check(data);
upgrade_info->dst_list_idx = tmp_dst_list_idx;
if (UPGRADE_DST_LIST_SUCCESS != error_code) {
goto err_exit;
}
cli_upgrade_add_upgrade_list_dest_info(data->dst_list, data->dst_num,
is_renew);
upgrade_info->dest_info.upgrading_list_idx = 0;
error_code = UPGRADE_DST_LIST_SUCCESS;
err_exit:
return error_code;
}
void iot_cli_upgrade_qr_dst_status_list(uint16_t start_idx,
uint8_t count, iot_plc_upgrade_dst_status_list *status_list)
{
uint8_t progress = 0;
iot_plc_upgrade_dst_status_list tmp_status_list;
uint8_t i = 0;
uint8_t weight_value = UPGRADE_BDCT_PROGRESS_WEIGHT_FOR_LIST;
if ((upgrade_info->upgrade_type == IOT_PLC_UPGRADE_ALL) &&
(upgrade_info->dest_info.dst_total_num >
UPGRADE_PROGRESS_THRESHOLD_VALUE_STA_CNT)) {
weight_value = UPGRADE_BDCT_PROGRESS_WEIGHT_FOR_ALL;
}
cli_upgrade_set_dst_status_list(start_idx, count, &tmp_status_list);
switch (upgrade_info->upgrade_state) {
case IOT_PLC_UPGRADE_STARTING:
case IOT_PLC_UPGRADE_STARTED:
if ((upgrade_info->current_file_type == UPGRADE_DATA_TYPE_PIB) &&
upgrade_info->pib_blocks) {
progress = (uint8_t)((weight_value *
upgrade_info->block_idx) /
(upgrade_info->pib_blocks + upgrade_info->fw_blocks));
} else {
progress = (uint8_t)((weight_value *
(upgrade_info->block_idx + upgrade_info->pib_blocks)) /
(upgrade_info->pib_blocks + upgrade_info->fw_blocks));
}
status_list->end = 1;
if (count > UPGRADE_REMOTE_DST_STATUS_ONCE_MAX_NUM) {
count = UPGRADE_REMOTE_DST_STATUS_ONCE_MAX_NUM;
status_list->end = 0;
}
status_list->dst_num = tmp_status_list.dst_num;
status_list->dst_status_list_idx = tmp_status_list.dst_status_list_idx;
for (i = 0; i < status_list->dst_num; i++) {
os_mem_cpy(status_list->dst_status_list[i].dst,
tmp_status_list.dst_status_list[i].dst, IOT_MAC_ADDR_LEN);
status_list->dst_status_list[i].error_code =
UPGRADE_DATA_STA_IN_PROGRESS;
status_list->dst_status_list[i].percentage = progress;
}
break;
case IOT_PLC_UPGRADE_TRANSFERRED:
{
status_list->dst_num = tmp_status_list.dst_num;
status_list->dst_status_list_idx = tmp_status_list.dst_status_list_idx;
status_list->end = tmp_status_list.end;
for (i = 0; i < tmp_status_list.dst_num; i++) {
os_mem_cpy(status_list->dst_status_list[i].dst,
tmp_status_list.dst_status_list[i].dst,
IOT_MAC_ADDR_LEN);
status_list->dst_status_list[i].error_code =
tmp_status_list.dst_status_list[i].error_code;
if ((IOT_PLC_UPGRADE_INIT ==
tmp_status_list.dst_status_list[i].status) ||
(IOT_PLC_UPGRADE_STARTED ==
tmp_status_list.dst_status_list[i].status) ||
(IOT_PLC_UPGRADE_LISTEN ==
tmp_status_list.dst_status_list[i].status)) {
status_list->dst_status_list[i].error_code =
UPGRADE_DATA_STA_IN_PROGRESS;
}
if (UPGRADE_DATA_SUCCESS ==
status_list->dst_status_list[i].error_code) {
status_list->dst_status_list[i].percentage = 100;
} else {
status_list->dst_status_list[i].percentage =
(weight_value +
(tmp_status_list.dst_status_list[i].percentage *
(100 - weight_value)));
}
}
break;
}
case IOT_PLC_UPGRADE_STOPED:
case IOT_PLC_UPGRADE_RESET:
case IOT_PLC_UPGRADE_INIT:
default:
break;
}
}
void iot_cli_upgrade_qr_dst_status(iot_plc_upgrade_dst_status_query *query)
{
cli_upgrade_set_dst_status_ack(query);
}
#if (!IOT_SMART_GRID_ENABLE)
uint16_t iot_cli_upgrade_set_renew_nodelist(uint8_t *dstlist, uint16_t cnt)
{
uint16_t tmp_cnt = 0;
if (cnt > IOT_PLC_UPGRADE_PHASE_THREE_MAX_SAT_CNT) {
cnt = IOT_PLC_UPGRADE_PHASE_THREE_MAX_SAT_CNT;
}
tmp_cnt = cli_upgrade_add_upgrade_list_dest_info(dstlist, cnt, 1);
upgrade_info->dest_info.upgrading_list_idx = 0;
if (tmp_cnt) {
cli_remote_upgrade_start_phase3();
}
return tmp_cnt;
}
#endif /* end !IOT_SMART_GRID_ENABLE */
#else /* IOT_CLI_UPGRADE_ENABLE */
/* cco handle sta join */
void iot_cli_cco_handle_sta_join(uint8_t *mac)
{
iot_printf("plc_upgrade: sta join: %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
/* cco handle sta leave */
void iot_cli_cco_handle_sta_leave(iot_plc_sta_info_t *sta)
{
iot_printf("plc_upgrade: sta leave: %02x:%02x:%02x:%02x:%02x:%02x\n",
sta->mac_addr[0], sta->mac_addr[1], sta->mac_addr[2],
sta->mac_addr[3], sta->mac_addr[4], sta->mac_addr[5]);
}
/* sg cli upgrade stop */
void iot_cli_upgrade_stop()
{
}
uint32_t iot_cli_upgrade_prepare(iot_cli_upgrade_completed_handler handler,
uint32_t file_size, uint8_t **data, uint8_t *file_hdr, uint16_t block_size,
uint8_t upgrade_type)
{
(void)handler;
uint32_t ret = ERR_OK;
uint32_t file_len = iot_get_file_len(file_hdr);
/* if the file header is invalid, the file size is used */
if (file_len == 0) {
file_len = file_size;
}
if ((block_size != 100) && (block_size != 200) &&
(block_size != 300) && (block_size != 400)) {
iot_printf("%s block size %d is invalid\n", block_size);
ret = ERR_FAIL;
goto out;
}
upgrade_info->block_size = block_size;
#if IOT_CLI_UPGRADE_CACHE_TYPE
(void)file_hdr;
(void)upgrade_type;
if (file_len > IOT_CLI_UPGRADE_MAX_FILE_SIZE) {
ret = ERR_FAIL;
goto out;
}
#else
uint8_t part_num;
uint32_t part_size = 0;
if (upgrade_type == IOT_PLC_UPGRADE_LOCAL) {
ret = ERR_FAIL;
goto out;
}
dev_get_upgrade_fw_part_num(&part_num);
part_size = dev_get_part_size(part_num);
if (file_len > part_size) {
ret = ERR_FAIL;
goto out;
}
cli_upgrade_cache_file_init(file_hdr);
#endif
*data = upgrade_info->file_data;
out:
return ret;
}
static void cli_upgrade_dst_status_query_internal(uint8_t *src_mac)
{
(void)src_mac;
}
void cli_upgrade_dst_status_list_internal(uint16_t start_index,
uint8_t dst_num, uint8_t *src_mac)
{
(void)start_index;
(void)dst_num;
(void)src_mac;
}
/* sg cli upgrade start */
uint8_t iot_cli_upgrade_start(uint8_t upgrade_type, uint8_t control_flag)
{
(void)upgrade_type;
(void)control_flag;
return 0;
}
void iot_cli_upgrade_app_register_handler(iot_cli_upgrade_app_handler handler)
{
sg_upgrade_handler = handler;
}
void cli_remote_upgrade_bcast_tx_done()
{
}
#endif /* IOT_CLI_UPGRADE_ENABLE */
void cli_upgrade_dst_status_query(uint8_t *buffer, uint32_t bufferlen,
uint8_t *src_mac)
{
(void)buffer;
(void)bufferlen;
if (host_config->cli_upgrade_enabled) {
cli_upgrade_dst_status_query_internal(src_mac);
} else {
cli_upgrade_dst_status_sg_query(add_addr_to_mapping_table(src_mac));
}
}
void cli_upgrade_dst_status_list(
uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
iot_plc_upgrade_dst_status_list_dl *list_dl;
list_dl = (iot_plc_upgrade_dst_status_list_dl *)buffer;
if ((!list_dl) || (bufferlen < sizeof(*list_dl))) {
iot_printf("%s param error", __FUNCTION__);
return;
}
if (host_config->cli_upgrade_enabled) {
cli_upgrade_dst_status_list_internal(list_dl->dst_status_list_idx,
list_dl->dst_num, src_mac);
} else {
cli_upgrade_dst_status_sg_list(list_dl->dst_status_list_idx,
list_dl->dst_num, add_addr_to_mapping_table(src_mac));
}
}
/* sg upgrade data ack */
void cli_sg_upgrade_data_ack(uint8_t result_code, uint16_t seg_index)
{
iot_plc_sg_upgrade_data_ack_ul_t ack_ul;
ack_ul.error_code = result_code;
ack_ul.seg_index = seg_index;
iot_printf("sg upgrade data ack, seg_index %lu result code %lu\n",
seg_index, result_code);
iot_cli_send_to_host(CLI_MSGID_SG_UPGRADE_DATA_ACK,
(uint8_t*)&ack_ul, sizeof(ack_ul), NULL);
}
/* sg upgrade stop */
void cli_sg_upgrade_stop()
{
iot_printf("cli set sg upgrade stop\n");
if (sg_upgrade_handler) {
sg_upgrade_handler(UPGRADE_CLI_UPGRADE_STOP_CMD, NULL, 0);
}
}
/* sg upgrade data */
void cli_sg_upgrade_data(
uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
iot_plc_sg_upgrade_data_dl_t *data =
(iot_plc_sg_upgrade_data_dl_t *)buffer;
(void)src_mac;
uint8_t result_code = UPGRADE_DATA_SUCCESS;
BUILD_BUG_ON(sizeof(iot_plc_sg_upgrade_data_dl_t) ==
sizeof(iot_plc_app_upgrade_data_t));
if ((!data) || (bufferlen < sizeof(*data))) {
iot_printf("%s param error", __FUNCTION__);
return;
}
if ((data->seg_index == 0) && host_config->cli_upgrade_enabled) {
host_config->cli_upgrade_enabled = 0;
}
iot_printf("sg upgrade data, seg_index %lu,"
" total seg cnt %lu, data len %lu\n",
data->seg_index, data->total_seg_count, data->data_len);
if (sg_upgrade_handler) {
if (ERR_OK != sg_upgrade_handler(UPGRADE_CLI_UPGRADE_DATA, buffer,
bufferlen)) {
result_code = UPGRADE_DATA_OTHER_ERROR;
}
}
if ((data->total_seg_count - 1) == data->seg_index) {
iot_printf("sg upgrade data recv done\n");
}
cli_sg_upgrade_data_ack(result_code, data->seg_index);
}
uint32_t iot_cli_upgrade_read(uint32_t offset, uint8_t *buf,
uint16_t buf_len)
{
uint8_t result = UPGRADE_DATA_SUCCESS;
#if IOT_CLI_UPGRADE_CACHE_TYPE
result = cli_upgrade_read_data_from_buffer(UPGRADE_DATA_TYPE_PKG, offset,
buf, buf_len);
#else
result = cli_upgrade_read_data_from_flash(UPGRADE_DATA_TYPE_FW, offset,
buf, buf_len);
#endif
return result;
}
uint32_t iot_cli_upgrade_write(uint32_t offset, uint8_t *buf,
uint16_t buf_len)
{
uint8_t result = UPGRADE_DATA_SUCCESS;
uint16_t block_idx = (uint16_t)(offset / upgrade_info->block_size);
if (offset % upgrade_info->block_size != 0) {
result = UPGRADE_DATA_INVALID_DATA;
iot_printf(" %s invalid offset.\n");
goto out;
}
#if IOT_CLI_UPGRADE_CACHE_TYPE
result = cli_upgrade_write_data_to_buffer(UPGRADE_DATA_TYPE_PKG, 1,
&block_idx, &buf_len, buf);
#else
result = cli_upgrade_write_data_to_flash(UPGRADE_DATA_TYPE_FW, 1,
&block_idx, &buf_len, buf);
#endif
out:
return result;
}
uint32_t iot_cli_upgrade_get_file_limit(uint8_t local_upgrade,
uint8_t *file_hdr)
{
uint32_t size = 0;
uint8_t part_num;
if (local_upgrade) {
if (file_hdr == NULL) {
return 0;
}
if (iot_get_file_fw_len(file_hdr)) {
dev_get_upgrade_fw_part_num(&part_num);
size += dev_get_part_size(part_num);
}
if (iot_get_file_pib_len(file_hdr)) {
dev_get_upgrade_pib_part_num(&part_num);
size += dev_get_part_size(part_num);
}
if (iot_get_file_cus_len(file_hdr)) {
dev_get_upgrade_cus_part_num(&part_num);
size += dev_get_part_size(part_num);
}
} else {
if (IOT_CLI_UPGRADE_MAX_FILE_SIZE) {
size = IOT_CLI_UPGRADE_MAX_FILE_SIZE;
} else {
dev_get_upgrade_fw_part_num(&part_num);
size = dev_get_part_size(part_num);
}
}
return size;
}
#endif /* PLC_SUPPORT_CCO_ROLE */