Files
kunlun/app/smart_grid/sta/iot_sg_sta_upgrade.c
2024-09-28 14:24:04 +08:00

1244 lines
43 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.
****************************************************************************/
/* os_shim header files */
#include "os_types_api.h"
#include "os_event_api.h"
#include "os_timer_api.h"
/* iot common header files */
#include "iot_io_api.h"
#include "iot_plc_cco_api.h"
#include "iot_module_api.h"
#include "iot_errno_api.h"
#include "iot_dbglog_api.h"
#include "iot_task_api.h"
#include "iot_plc_msg_api.h"
#include "iot_crc_api.h"
#include "iot_version_api.h"
#include "iot_oem_api.h"
#include "iot_board_api.h"
/* smart grid internal header files */
#include "iot_sg_fr.h"
#include "proto_gw_app.h"
#include "iot_sg.h"
#include "iot_sg_msg.h"
#include "iot_sg_sta_gw.h"
#include "iot_sg_sta_nw.h"
#include "iot_sg_sta_upgrade.h"
#include "iot_upgrade_api.h"
#include "iot_sg_sta_ext_upgrade.h"
#include "os_utils_api.h"
#include "iot_plc_led_api.h"
/* default trail-run timeout value in second */
#define IOT_SG_STA_DEFAULT_TRAIL_RUN_DUR (0)
#if (IOT_SMART_GRID_ENABLE)
/* upgrade timer time out function */
void iot_sg_sta_upgrade_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_UPGRADE;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
/**
* @brief: get a up aligned value
* @param value: the value to get its aligned value
* @param align_base: align base
* @return: the up aligned value.
*/
static uint32_t iot_sg_sta_get_align(uint32_t value, uint32_t align_base) {
uint32_t rest;
uint32_t pad_byte = 0;
if (align_base == 0) {
return value;
}
rest = value % align_base;
if (rest) {
pad_byte = align_base - rest;
}
return value + pad_byte;
}
static void iot_sg_sta_renew_exit_reason_code(uint8_t exit_reason)
{
iot_upgrade_save_upgrade_status(exit_reason);
p_sg_glb->desc.sta->upgrade_info.exit_reason = exit_reason;
}
static void iot_sg_sta_start_upgrade_timer(uint32_t duration)
{
iot_sg_sta_upgrade_info_t *upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_UPGRADE);
os_start_timer(upgrade_info->upgrade_timer, duration);
}
static void iot_sg_sta_stop_upgrade_timer()
{
iot_sg_sta_upgrade_info_t *upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
os_stop_timer(upgrade_info->upgrade_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_UPGRADE);
}
void iot_sg_sta_send_start_ack(uint32_t id, uint8_t msg_type,
uint32_t result)
{
iot_sg_sta_upgrade_info_t *upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
if (upgrade_info->session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_GW) {
iot_sg_sta_gw_send_start_ack(id, msg_type, result);
} else if (upgrade_info->session_type ==
IOT_SG_STA_UPGRADE_SESSION_TYPE_NW) {
iot_sg_sta_nw_send_start_ack(id, msg_type, result);
}
}
void iot_sg_sta_send_query_reply(uint32_t id, uint32_t start_seq,
uint16_t status, uint16_t cnt, iot_pkt_t *bitmap_pkt, uint8_t msg_type,
uint8_t session_type)
{
if (session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_GW) {
iot_sg_sta_gw_send_query_reply(id, start_seq, status, cnt,
bitmap_pkt, msg_type);
} else if (session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_NW) {
(void)cnt;
iot_sg_sta_nw_send_query_reply(id, start_seq, status, bitmap_pkt,
msg_type);
} else {
iot_pkt_free(bitmap_pkt);
}
}
/**
* @brief: calc CRC of the upgrading file. It can only be called when upgrading.
* @retval: the crc of upgrading file.
*/
uint32_t iot_sg_sta_get_crc()
{
uint32_t file_len = 0;
uint32_t file_block_len = 0;
uint32_t crc = 0xFFFFFFFF;
uint32_t offset = 0;
uint32_t len = 0;
uint32_t align_size = 2400;
uint8_t* ptr = NULL;
uint32_t pib_size;
uint32_t fw_size;
uint32_t cus_size;
iot_sg_sta_upgrade_info_t *upgrade_info;
uint32_t block_size = IOT_SG_UPGRADE_MAX_BLOCK_SIZE;
uint32_t pib_read_only = iot_upgrade_get_pib_ro_size();
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
if (upgrade_info->calc_crc) {
return upgrade_info->calc_crc;
}
pib_size = iot_upgrade_get_pib_len();
fw_size = iot_upgrade_get_fw_len();
cus_size = iot_upgrade_get_cus_len();
iot_sg_printf("to calc crc\n");
/* calc header crc */
offset = 0;
if (!upgrade_info->cache) {
goto err_exit;
}
ptr = iot_pkt_data(upgrade_info->cache);
if (align_size >= upgrade_info->block_size) {
crc = iot_getcrc32_update(crc, ptr, upgrade_info->block_size);
len = (align_size - upgrade_info->block_size) / upgrade_info->block_size;
os_mem_set(ptr, iot_pkg_get_pad_value(), upgrade_info->block_size);
while (len) {
/* calc crc for padding */
crc = iot_getcrc32_update(crc, ptr, upgrade_info->block_size);
len--;
}
len = (align_size - upgrade_info->block_size) % upgrade_info->block_size;
crc = iot_getcrc32_update(crc, ptr, len);
} else {
crc = iot_getcrc32_update(crc, ptr, align_size);
}
if (pib_size) {
/* calc pib crc */
offset = 0;
len = pib_read_only / block_size;
/* calc pib read only part */
while (len) {
if (iot_pkg_upgrade_read(ptr, block_size, offset,
UPGRADE_DATA_TYPE_PIB, 0)) {
goto err_exit;
}
crc = iot_getcrc32_update(crc, ptr, block_size);
offset += block_size;
len--;
}
len = pib_read_only % block_size;
if (iot_pkg_upgrade_read(ptr, iot_sg_sta_get_align(len, 4), offset,
UPGRADE_DATA_TYPE_PIB, 0)) {
goto err_exit;
}
crc = iot_getcrc32_update(crc, ptr, len);
offset += len;
/* calc pib read write part */
file_len = pib_size;
len = (file_len - pib_read_only) / block_size;
os_mem_set(ptr, iot_pkg_get_pad_value(), block_size);
while (len) {
crc = iot_getcrc32_update(crc, ptr, block_size);
offset += block_size;
len--;
}
len = (file_len - pib_read_only) % block_size;
crc = iot_getcrc32_update(crc, ptr, len);
offset += len;
if (fw_size) {
/* crc for pib padding content */
file_block_len = iot_sg_sta_get_align(file_len, align_size);
len = (file_block_len - file_len) / block_size;
while (len) {
crc = iot_getcrc32_update(crc, ptr, block_size);
offset += block_size;
len--;
}
len = (file_block_len - file_len) % block_size;
crc = iot_getcrc32_update(crc, ptr, len);
}
}
/* calc fw crc */
if (fw_size) {
offset = 0;
file_len = fw_size;
len = file_len / block_size;
while (len) {
if (iot_pkg_upgrade_read(ptr, block_size, offset, UPGRADE_DATA_TYPE_FW,
0)) {
goto err_exit;
}
crc = iot_getcrc32_update(crc, ptr, block_size);
offset += block_size;
len--;
}
len = file_len % block_size;
if (iot_pkg_upgrade_read(ptr, iot_sg_sta_get_align(len, 4), offset,
UPGRADE_DATA_TYPE_FW, 0)) {
goto err_exit;
}
crc = iot_getcrc32_update(crc, ptr, len);
if (cus_size) {
/* crc for fw padding content */
file_block_len = iot_sg_sta_get_align(file_len, align_size);
len = (file_block_len - file_len) / block_size;
os_mem_set(ptr, iot_pkg_get_pad_value(), block_size);
while (len) {
crc = iot_getcrc32_update(crc, ptr, block_size);
offset += block_size;
len--;
}
len = (file_block_len - file_len) % block_size;
crc = iot_getcrc32_update(crc, ptr, len);
}
}
/* calc cus crc */
if (cus_size) {
offset = 0;
file_len = cus_size;
len = file_len / block_size;
while (len) {
if (iot_pkg_upgrade_read(ptr, block_size, offset,
UPGRADE_DATA_TYPE_CUS, 0)) {
goto err_exit;
}
crc = iot_getcrc32_update(crc, ptr, block_size);
offset += block_size;
len--;
}
len = file_len % block_size;
if (iot_pkg_upgrade_read(ptr, iot_sg_sta_get_align(len, 4), offset,
UPGRADE_DATA_TYPE_CUS, 0)) {
goto err_exit;
}
crc = iot_getcrc32_update(crc, ptr, len);
}
crc ^= 0xFFFFFFFF;
iot_sg_printf("sg_upgrade: calc crc = 0x%08X, recv crc = 0x%08X\n",
crc, upgrade_info->file_crc);
if (crc != upgrade_info->file_crc) {
goto err_exit;
}
return crc;
err_exit:
/* failed to calcluete the CRC. */
iot_sg_printf("sg_upgrade: calc crc = 0x%08X\n", crc);
return upgrade_info->file_crc;
}
static void iot_sg_sta_save_to_flash()
{
uint32_t other_part;
iot_sg_sta_upgrade_info_t *upgrade_info;
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
upgrade_info->calc_crc = iot_sg_sta_get_crc();
other_part = iot_upgrade_get_another_part(upgrade_info->current_part);
iot_sg_printf("sg_upgrade: cur_part = %d, save data to part = %d\n",
upgrade_info->current_part, other_part);
iot_upgrade_save_trail_run_dur(other_part, upgrade_info->trail_run_dur);
iot_upgrade_save_fw_crc(other_part, upgrade_info->file_crc);
iot_upgrade_save_fw_len(other_part, upgrade_info->file_size);
iot_upgrade_save_fw_blksize(other_part, upgrade_info->block_size);
}
static void iot_sg_sta_upgrade_goto_state(uint16_t new_state)
{
iot_sg_sta_upgrade_info_t *p_info = &p_sg_glb->desc.sta->upgrade_info;
uint16_t pre_state = p_info->state;
uint8_t rpt_flag = 0;
uint8_t rpt_result = 0;
if (p_info->state != new_state) {
iot_sg_printf("sg_upgrade: state from %d to %d.\n", p_info->state,
new_state);
p_info->state = new_state;
if (IOT_SG_STA_UPGRADE_ST_IDLE == new_state) {
if (p_info->cache) {
iot_pkt_free(p_info->cache);
p_info->cache = NULL;
}
/* upgrade stop */
rpt_flag = 1;
} else if (IOT_SG_STA_UPGRADE_ST_IDLE == pre_state) {
/* upgrade start */
rpt_flag = 1;
rpt_result = 1;
}
}
if (rpt_flag) {
iot_sg_ext_upgrade_state_rpt_to_cusapp(rpt_result);
}
}
/**
* @brief: init upgrading module
*/
void iot_sg_sta_upgrade_init()
{
uint32_t part;
uint32_t exit_reason;
iot_upg_bp_resume_info_t resume_info = { 0 };
iot_sg_sta_upgrade_info_t *upgrade_info = NULL;
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
if (upgrade_info->state != IOT_SG_STA_UPGRADE_ST_INVALID) {
/* only init when in INVALID state */
iot_sg_printf("sg_upgrade: don't init again.\n");
return;
}
if (iot_upgrade_get_part(&part)) {
/* cannot upgrade because failed to read partition info */
iot_sg_printf("sg_upgrade: failed to get current boot part.\n");
return;
}
exit_reason = iot_upgrade_get_upgrade_status();
if (exit_reason != 0xff) {
upgrade_info->exit_reason = (uint8_t)exit_reason;
}
upgrade_info->current_part = part;
upgrade_info->trail_run_dur = iot_upgrade_get_trail_run_dur(part);
upgrade_info->current_len = iot_upgrade_get_fw_size(part);
if (upgrade_info->current_len == 0) {
upgrade_info->current_len = iot_upgrade_get_backup_len();
iot_upgrade_save_fw_len(part, upgrade_info->current_len);
}
upgrade_info->current_crc = iot_upgrade_get_fw_crc(part);
if (upgrade_info->current_crc == 0) {
upgrade_info->current_crc = iot_upgrade_get_backup_crc();
iot_upgrade_save_fw_crc(part, upgrade_info->current_crc);
}
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_UPGRADE_DBG_ID, 2, 0xff00|part, upgrade_info->current_crc);
upgrade_info->current_bk_size = iot_upgrade_get_fw_blksize(part);
if (upgrade_info->current_bk_size == 0) {
upgrade_info->current_bk_size = IOT_SG_UPGRADE_MAX_BLOCK_SIZE;
}
upgrade_info->block_cnt = (uint16_t)((upgrade_info->current_len +
upgrade_info->current_bk_size - 1) / upgrade_info->current_bk_size);
iot_sg_printf("%s: part = %lu, len = %lu, crc = 0x%08X, trail run dur = "
"%lu, block size = %lu,\n", __FUNCTION__, upgrade_info->current_part,
upgrade_info->current_len, upgrade_info->current_crc,
upgrade_info->trail_run_dur, upgrade_info->current_bk_size);
if (upgrade_info->trail_run_dur) {
iot_sg_sta_upgrade_goto_state(IOT_SG_STA_UPGRADE_ST_TRAIL_RUN);
//clear the trail run time
iot_upgrade_save_trail_run_dur(part, 0);
/* start the timer for upgrading time window */
iot_sg_sta_start_upgrade_timer(upgrade_info->trail_run_dur * 1000);
} else {
if (iot_upgrade_get_bp_resume_info(UPGRADE_GET_METHOD_SG,
&resume_info) == ERR_OK) {
if ((resume_info.state == UPGRADE_BP_STATE_RECV_DONE) &&
(!resume_info.ext_upgrade_flag)) {
upgrade_info->file_crc = resume_info.file_crc;
upgrade_info->file_size = resume_info.file_len;
iot_sg_sta_save_to_flash();
iot_pkg_upgrade_commit(0);
iot_pkg_upgrade_reset();
}
}
iot_sg_sta_upgrade_goto_state(IOT_SG_STA_UPGRADE_ST_IDLE);
}
}
void iot_sg_sta_reset_upgrade_info(iot_sg_sta_upgrade_info_t *upgrade_info)
{
timer_id_t upgrade_timer;
timer_id_t ext_dev_upgrade_timer;
uint32_t current_part;
uint32_t len;
uint32_t crc;
uint32_t block_size;
uint32_t block_cnt;
uint32_t file_size;
uint8_t exit_reason;
block_size = upgrade_info->block_size;
file_size = upgrade_info->file_size;
block_cnt = upgrade_info->block_cnt;
len = upgrade_info->current_len;
crc = upgrade_info->current_crc;
current_part = upgrade_info->current_part;
upgrade_timer = upgrade_info->upgrade_timer;
ext_dev_upgrade_timer = upgrade_info->ext_dev_upgrade_timer;
exit_reason = upgrade_info->exit_reason;
os_mem_set(upgrade_info, 0, sizeof(*upgrade_info));
/* cert test case 3.3.6.4 - keep last upgrade info after upgrade stopped
* for upcoming query from CCO case.
*/
upgrade_info->block_size = block_size;
upgrade_info->file_size = file_size;
upgrade_info->block_cnt = block_cnt;
upgrade_info->upgrade_timer = upgrade_timer;
upgrade_info->ext_dev_upgrade_timer = ext_dev_upgrade_timer;
upgrade_info->current_part = current_part;
upgrade_info->current_len = len;
upgrade_info->current_crc = crc;
upgrade_info->exit_reason = exit_reason;
iot_sg_sta_upgrade_goto_state(IOT_SG_STA_UPGRADE_ST_IDLE);
iot_plc_led_request(IOT_PLC_LED_UPGRADE_OFF);
}
void iot_sg_sta_upgrade_clear(uint32_t upgrade_id, uint32_t cancel_commit)
{
iot_sg_sta_upgrade_info_t *upgrade_info = NULL;
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
iot_sg_printf("sg_upgrade: %s. id = 0x%02X, cancel_commit = %d\n",
__FUNCTION__, upgrade_info->upgrade_id, cancel_commit);
/* clear upgrading status if it's not in INVALID state */
if (upgrade_info->state != IOT_SG_STA_UPGRADE_ST_INVALID &&
upgrade_info->state != IOT_SG_STA_UPGRADE_ST_IDLE) {
if (upgrade_id && upgrade_id != upgrade_info->upgrade_id) {
return;
}
iot_sg_sta_stop_upgrade_timer();
iot_pkg_upgrade_cancel_commit(upgrade_id, cancel_commit);
iot_sg_sta_reset_upgrade_info(upgrade_info);
iot_sg_ext_dev_reset_upgrade_info();
}
}
uint32_t iot_sg_sta_recv_all_block()
{
iot_sg_sta_upgrade_info_t *p_info = &p_sg_glb->desc.sta->upgrade_info;
iot_pkg_upg_sts_rst_t rst = {0};
iot_pkg_upg_sts_src_t src = {0};
uint32_t recv_block_count = 0;
uint32_t byte_count = 0;
src.id = p_info->upgrade_id;
src.block_size = p_info->block_size;
src.block_cnt = p_info->block_cnt;
src.block_index = 0;
if (ERR_OK != iot_pkg_upgrade_query_state(&rst, &src)) {
/* failed to query */
return 0;
}
/* get byte count of the bitmap */
byte_count = rst.block_cnt >> 3;
for (uint32_t i = 0; i < byte_count; ++i) {
if (rst.bitmap[i] != 0xFF) {
break;
}
recv_block_count += 8;
}
if ((byte_count << 3) != p_info->block_cnt) {
/* less than 8 block in the last block */
for (uint32_t i = 0; i < 8; ++i) {
if (rst.bitmap[byte_count-1] & (1 << i)) {
recv_block_count += 1;
}
}
}
iot_sg_printf("upgrade: total block cnt = 0n%d, recv block cnt = %d\n",
p_info->block_cnt, recv_block_count);
if (recv_block_count == p_info->block_cnt) {
iot_sg_sta_renew_exit_reason_code(IOT_SG_STA_UPGRADE_EXIT_NORMAL);
return 1;
}
return 0;
}
/**
* @brief: timer handler for upgrading
*/
void iot_sg_sta_upgrade_timer_handler()
{
iot_sg_sta_upgrade_info_t *p_info = &p_sg_glb->desc.sta->upgrade_info;
iot_sg_printf("sg_upgrade: sta upgrade timer. state = %d\n",
p_info->state);
switch (p_info->state) {
case IOT_SG_STA_UPGRADE_ST_INVALID:
case IOT_SG_STA_UPGRADE_ST_IDLE:
{
/* idle state won't receive any message */
}
break;
case IOT_SG_STA_UPGRADE_ST_RECEIVE:
{
if (iot_sg_sta_recv_all_block() &&
(!p_info->ext_dev_need_upgrade_flag)) {
iot_sg_printf("sg upgrade: trans done. commit.\n");
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_UPGRADE_DBG_ID, 2, 2, 0);
iot_sg_sta_save_to_flash();
iot_pkg_upgrade_commit(p_info->upgrade_id);
iot_pkg_upgrade_reset();
} else {
iot_sg_printf("sg upgrade: trans not done. clear.\n");
iot_sg_sta_upgrade_clear(p_info->upgrade_id, 1);
}
}
break;
case IOT_SG_STA_UPGRADE_ST_RECV_DONE:
{
iot_sg_printf("sg upgrade: upgrade commit, skip: %d ext upgrade:%d\n",
p_info->skip, p_info->ext_dev_need_upgrade_flag);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_UPGRADE_DBG_ID, 2, 3, p_info->skip);
if ((!p_info->skip) && (!p_info->ext_dev_need_upgrade_flag)) {
iot_sg_sta_save_to_flash();
iot_pkg_upgrade_commit(p_info->upgrade_id);
iot_upgrade_reset();
} else {
iot_sg_printf("sg upgrade: skip upgrade, clean upgrade.\n");
iot_sg_sta_upgrade_clear(p_info->upgrade_id, 1);
}
}
break;
case IOT_SG_STA_UPGRADE_ST_EXECUTE:
{
iot_sg_printf("sg upgrade: upgrade execute, skip: %d\n", p_info->skip);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_UPGRADE_DBG_ID, 2, 4, p_info->skip);
if (!p_info->ext_dev_need_upgrade_flag) {
if (!p_info->skip) {
iot_sg_sta_save_to_flash();
iot_pkg_upgrade_commit(p_info->upgrade_id);
iot_upgrade_reset();
} else {
iot_sg_sta_reset_upgrade_info(p_info);
}
} else {
iot_sg_printf("sg upgrade: external upgrade timeout.\n");
iot_sg_sta_upgrade_clear(p_info->upgrade_id, 0);
}
}
break;
case IOT_SG_STA_UPGRADE_ST_TRAIL_RUN:
{
/* trail run is done. */
iot_sg_printf("sg upgrade: trail run timeout. link_ready = %d\n",
p_sg_glb->plc_state.link_ready);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_UPGRADE_TRAIL_RUN_TIMEOUT, 1,
p_sg_glb->plc_state.link_ready);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_UPGRADE_DBG_ID, 2, 1, p_sg_glb->plc_state.link_ready);
if (p_sg_glb->plc_state.link_ready) {
iot_sg_sta_upgrade_goto_state(IOT_SG_STA_UPGRADE_ST_IDLE);
iot_sg_sta_upgrade_clear(p_info->upgrade_id, 0);
} else {
/* STA failed to join network in trail run duration,
* switch back to status before upgrading.
*/
iot_upgrade_switch_part();
iot_upgrade_reset();
}
}
break;
default:
break;
}
}
uint32_t iot_sg_sta_handle_upgrade_data(uint32_t id, uint16_t block_size,
uint32_t seq, uint8_t *data, iot_pkt_t *pkt, uint8_t rsp_flag)
{
uint32_t file_dev_type;
uint32_t file_vendor_id;
uint32_t local_vendor_id;
uint32_t result;
uint32_t reason = 0;
uint32_t offset;
iot_sg_sta_upgrade_info_t *upgrade_info;
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
offset = seq * upgrade_info->block_size;
iot_sg_printf("sg_upgrade: received seq = %d. block size = %d. %d/%d\n",
seq, block_size, offset + block_size,
upgrade_info->file_size);
if (IOT_SG_STA_UPGRADE_ST_RECEIVE != upgrade_info->state) {
/* process upgrading data only in RECV state */
reason = 1;
goto err_exit;
}
if (id != upgrade_info->upgrade_id) {
if (upgrade_info->session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_NW) {
iot_sg_sta_upgrade_on_join(1);
}
reason = 2;
goto err_exit;
}
if (iot_pkg_upgrade_is_set_bit(seq)) {
/* block was processed before */
reason = 3;
goto err_exit;
}
if (seq == 0) {
/* it's the first block */
iot_start_rst_t rst = {0};
file_dev_type = iot_get_file_type(data);
if (IOT_FILE_TYPE_CCO == file_dev_type) {
iot_sg_printf("sg_upgrade: invalid file, it's cco file\n");
reason = 4;
goto err_skip;
} else if (IOT_FILE_TYPE_EXT_DEV == file_dev_type) {
upgrade_info->ext_dev_need_upgrade_flag = 1;
iot_sg_printf("sg_upgrade: upgrade external device\n");
} else if (IOT_FILE_TYPE_STA != file_dev_type) {
iot_sg_printf("sg_upgrade: invalid file type: %04x. skip upgrade\n",
file_dev_type);
reason = 5;
goto err_skip;
}
file_vendor_id = iot_get_vendor_id(data);
local_vendor_id = iot_sg_get_vendor_id();
if (local_vendor_id != file_vendor_id) {
iot_sg_printf("sg_upgrade: vendor_id expect %04X but %04X.\n",
local_vendor_id, file_vendor_id);
reason = 6;
goto err_skip;
}
if (upgrade_info->session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_NW) {
/* nw start cmd dones't have block_size info. */
/* update block_size when receive the 1st block for nw. */
upgrade_info->block_size = block_size;
}
if (ERR_OK == iot_pkg_upgrade_start(&rst, upgrade_info->upgrade_id,
upgrade_info->block_size, upgrade_info->file_size,
upgrade_info->file_crc, upgrade_info->block_cnt,
upgrade_info->ext_dev_need_upgrade_flag, data)) {
if (!upgrade_info->cache) {
upgrade_info->cache = iot_pkt_alloc(
IOT_SG_UPGRADE_MAX_BLOCK_SIZE, IOT_SMART_GRID_MID);
if (!upgrade_info->cache) {
iot_sg_printf("sg_upgrade: iot pkt malloc fail.\n");
reason = 7;
goto err_exit;
}
}
/* save header to cache */
os_mem_cpy(iot_pkt_data(upgrade_info->cache), data, block_size);
iot_pkt_put(upgrade_info->cache, block_size);
upgrade_info->header_recved = 1;
iot_sg_printf("sg_upgrade: start upgrade OK.\n");
} else {
iot_sg_printf("sg_upgrade: start upgrade failed.\n");
reason = 8;
goto err_exit;
}
}
{
/* write data to flash */
iot_trans_cmd_t trans = {0};
iot_pkt_set_data(pkt, data);
iot_pkt_set_tail(pkt, data + block_size);
trans.id = upgrade_info->upgrade_id;
trans.block_num = seq;
trans.crc_flag = 0;
trans.data = pkt;
trans.data_type = UPGRADE_DATA_TYPE_PKG;
result = iot_pkg_upgrade_trans(&trans);
iot_sg_printf("sg_upgrade: trans result = %d. block %d. size = %d\n",
result, trans.block_num, block_size);
}
upgrade_info->rec_blk_cnt++;
if ((upgrade_info->rec_blk_cnt >= upgrade_info->block_cnt) &&
(upgrade_info->session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_645 ||
upgrade_info->session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_DRV)) {
iot_sg_sta_handle_upgrade_execute(id, 0, 0, 0);
}
result = IOT_PLC_UPGRADE_OK;
goto out;
err_skip:
if (0 == upgrade_info->skip) {
upgrade_info->skip = 1;
iot_sg_sta_renew_exit_reason_code(IOT_SG_STA_UPGRADE_EXIT_MISMATCH);
iot_sg_sta_upgrade_goto_state(IOT_SG_STA_UPGRADE_ST_RECV_DONE);
}
err_exit:
result = IOT_PLC_UPGRADE_ERR_UNKNOWN;
iot_pkt_free(pkt);
iot_sg_printf("sg_upgrade: drop data. reason = %d.\n", reason);
out:
if ((upgrade_info->session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_NW) &&
rsp_flag) {
iot_sg_sta_nw_send_upgrade_data_ack(id, result);
}
return result;
}
uint32_t iot_sg_sta_handle_start_upgrade(uint32_t id, uint16_t window,
uint16_t block_size, uint32_t file_size, uint16_t block_cnt,
uint32_t file_crc, uint8_t rsp_flag, uint8_t session_type)
{
iot_sg_sta_upgrade_info_t *upgrade_info;
uint8_t result = IOT_PLC_UPGRADE_OK;
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
iot_sg_printf("sg_upgrade: %s. id = 0x%08X, size = %d, block_size = %d, "
"block_cnt = %d, st = %d, crc = 0x%08X\n", __FUNCTION__, id, file_size,
block_size, block_cnt, upgrade_info->state, file_crc);
if (upgrade_info->state != IOT_SG_STA_UPGRADE_ST_IDLE) {
if (session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_NW) {
if (upgrade_info->upgrade_id == id) {
if ((upgrade_info->block_size != block_size) ||
(upgrade_info->file_size != file_size) ||
(upgrade_info->block_cnt != block_cnt) ||
(upgrade_info->file_crc != file_crc)) {
result = IOT_PLC_UPGRADE_STATE_ERR;
goto out;
}
goto exit_label;
} else {
iot_sg_sta_upgrade_on_join(1);
}
} else if ((upgrade_info->upgrade_id != id) ||
(upgrade_info->block_size != block_size) ||
(upgrade_info->file_size != file_size) ||
(upgrade_info->block_cnt != block_cnt) ||
(upgrade_info->file_crc != file_crc)) {
/* ignore start upgrade command if not id IDLE state. */
result = IOT_PLC_UPGRADE_STATE_ERR;
goto out;
} else {
goto exit_label;
}
}
if (session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_GW &&
0 == iot_sg_sta_gw_is_valid_block_size(block_size)) {
/* block size checking only apply to guowang upgrading. */
result = IOT_PLC_UPGRADE_ERR_BLOCK_SIZE;
goto exit_label;
}
if (p_sg_glb->plc_state.cert_test_detected == 0 &&
upgrade_info->current_crc == file_crc) {
result = IOT_PLC_UPGRADE_ERR_SAME_VERSION;
if (0 == upgrade_info->skip) {
upgrade_info->skip = 1;
upgrade_info->upgrade_id = id;
upgrade_info->session_type = session_type;
iot_sg_sta_renew_exit_reason_code(IOT_SG_STA_UPGRADE_EXIT_SAME_VER);
iot_sg_sta_upgrade_goto_state(IOT_SG_STA_UPGRADE_ST_RECV_DONE);
}
goto exit_label;
}
/* set LED to show upgrading state */
iot_plc_led_request(IOT_PLC_LED_UPGRADE_ON);
iot_sg_sta_upgrade_goto_state(IOT_SG_STA_UPGRADE_ST_RECEIVE);
upgrade_info->file_size = file_size;
upgrade_info->file_crc = file_crc;
upgrade_info->calc_crc = 0;
upgrade_info->upgrade_time_win = window;
upgrade_info->upgrade_id = id;
upgrade_info->block_size = block_size;
upgrade_info->block_cnt = block_cnt;
upgrade_info->rec_blk_cnt = 0;
upgrade_info->skip = 0;
upgrade_info->header_recved = 0;
upgrade_info->session_type = session_type;
iot_sg_ext_dev_reset_upgrade_info();
/* start the timer for upgrading time window */
iot_sg_sta_start_upgrade_timer(upgrade_info->upgrade_time_win * 60 * 1000);
exit_label:
if (rsp_flag) {
iot_sg_sta_send_start_ack(id, IOT_PLC_MSG_TYPE_UNICAST, result);
}
out:
return result;
}
iot_pkt_t *iot_sg_sta_get_recv_bitmap(uint32_t start_seq, uint16_t cnt)
{
iot_pkt_t *bitmap_pkt = NULL;
uint8_t *bm;
iot_sg_sta_upgrade_info_t *upgrade_info;
uint32_t start_sn;
uint32_t start_byte;
uint32_t bm_byte_size;
uint32_t ret_bm_byte_size;
uint32_t pad_bit_cnt;
uint32_t bm_byte_cnt;
uint32_t i;
uint8_t cnt_remainder = 0;
/* query upgrade bitmap */
iot_pkg_upg_sts_rst_t rst = {0};
iot_pkg_upg_sts_src_t src = {0};
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
if (IOT_SG_STA_QUERY_ALL_BLOCK == cnt) {
/* return all blocks */
cnt = (uint16_t)upgrade_info->block_cnt;
start_sn = 0;
start_byte = 0;
bm_byte_size = ((cnt + 7) >> 3);
ret_bm_byte_size = bm_byte_size;
pad_bit_cnt = 0;
bm_byte_cnt = 0;
} else {
/* make start seq align to 8, bm_byte_size align to 1 byte. */
start_byte = start_seq >> 3;
start_sn = start_byte << 3;
bm_byte_size = ((cnt + 7 + (start_seq - start_sn)) >> 3);
ret_bm_byte_size = ((cnt + 7) >> 3);
cnt_remainder = cnt & 0x07;
if (start_seq == start_sn) {
pad_bit_cnt = 0;
} else {
pad_bit_cnt = 8 - (start_seq - start_sn);
}
}
iot_sg_printf("%s cnt is : %lu\n", __FUNCTION__, ret_bm_byte_size);
iot_sg_printf("%s current_len : %lu current_bk_size : %lu\n,",
__FUNCTION__, upgrade_info->current_len, upgrade_info->current_bk_size);
bitmap_pkt = iot_pkt_alloc(bm_byte_size, IOT_SMART_GRID_MID);
if (bitmap_pkt == NULL) {
return NULL;
}
bm = iot_pkt_data(bitmap_pkt);
if (upgrade_info->skip) {
/* if STA shall skip upgrading, STA enter DONE state and
* all bits in bitmap will be set to 1.
*/
os_mem_set(bm, 0xff, ret_bm_byte_size);
iot_pkt_put(bitmap_pkt, ret_bm_byte_size);
return bitmap_pkt;
} else if (0 == upgrade_info->header_recved) {
/* received data is zero, lower upgrade module may not be ready for
* querying bitmap.
*/
os_mem_set(bm, 0x00, ret_bm_byte_size);
iot_pkt_put(bitmap_pkt, ret_bm_byte_size);
return bitmap_pkt;
}
src.id = upgrade_info->upgrade_id;
src.block_size = upgrade_info->block_size;
src.block_index = start_sn;
src.block_cnt = cnt + (start_seq - start_sn);
if (ERR_OK == iot_pkg_upgrade_query_state(&rst, &src)) {
bm_byte_cnt = (uint16_t)(rst.block_cnt >> 3);
if (bm_byte_cnt) {
os_mem_cpy(bm, rst.bitmap, bm_byte_cnt);
if (pad_bit_cnt) {
/* move all bytes (8-pad_bit_cnt) bit forward except the last one */
i = 0;
do {
bm[i] >>= (8 - pad_bit_cnt);
if (i < (bm_byte_cnt - 1)) {
bm[i] |= (bm[i + 1] << (pad_bit_cnt));
}
++i;
} while(i < bm_byte_cnt);
}
if (cnt_remainder) {
bm[ret_bm_byte_size - 1] <<= (8 - cnt_remainder);
bm[ret_bm_byte_size - 1] >>= (8 - cnt_remainder);
}
}
iot_pkt_put(bitmap_pkt, ret_bm_byte_size);
iot_sg_printf("upgrade: bm byte size = %d, start block = %d, len = %d,"
" cnt = %d.\n", bm_byte_cnt, start_seq, ret_bm_byte_size, cnt);
for (i = 0; i < ret_bm_byte_size; ++i) {
if (bm[i] != 0xFF || i + 1 == ret_bm_byte_size) {
iot_sg_printf("upgrade: bm[%d] = %02X\n", i, bm[i]);
}
}
} else {
iot_pkt_free(bitmap_pkt);
bitmap_pkt = NULL;
}
return bitmap_pkt;
}
void iot_sg_sta_handle_upgrade_query_status(uint32_t id, uint32_t start_seq,
uint16_t cnt, uint8_t session_type)
{
iot_sg_sta_upgrade_info_t *upgrade_info;
iot_pkt_t *bitmap_pkt = NULL;
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
iot_sg_printf("sg_upgrade: %s, local_id = %x id = %X start_seq = %d,"
"cnt = %d\n", __FUNCTION__, upgrade_info->upgrade_id, id, start_seq,
cnt);
bitmap_pkt = iot_sg_sta_get_recv_bitmap(start_seq, cnt);
if (bitmap_pkt == NULL) {
return;
}
if (IOT_SG_STA_QUERY_ALL_BLOCK == cnt) {
cnt = (uint16_t)upgrade_info->block_cnt;
}
iot_sg_sta_send_query_reply(upgrade_info->upgrade_id, start_seq,
upgrade_info->state, cnt, bitmap_pkt, IOT_PLC_MSG_TYPE_UNICAST,
session_type);
}
void iot_sg_sta_handle_upgrade_execute(uint32_t id, uint16_t reset_delay,
uint32_t trial_run_dur, uint8_t rsp_flag)
{
uint32_t result = 0;
iot_sg_sta_upgrade_info_t *upgrade_info = NULL;
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
if (upgrade_info->state != IOT_SG_STA_UPGRADE_ST_RECEIVE &&
upgrade_info->state != IOT_SG_STA_UPGRADE_ST_RECV_DONE) {
result = IOT_PLC_UPGRADE_OK;
goto exit_label;
}
if ((!upgrade_info->skip) && (!iot_sg_sta_recv_all_block())) {
result = IOT_PLC_UPGRADE_ERR_UNKNOWN;
goto exit_label;
}
if (id == upgrade_info->upgrade_id) {
if (upgrade_info->ext_dev_need_upgrade_flag) {
iot_sg_sta_ext_upgrade_pre_process();
} else {
upgrade_info->reset_wait_dur = reset_delay;
upgrade_info->trail_run_dur = trial_run_dur;
iot_sg_sta_start_upgrade_timer(upgrade_info->reset_wait_dur * 1000);
}
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_UPGRADE_DBG_ID, 2, 5, upgrade_info->state);
iot_sg_sta_upgrade_goto_state(IOT_SG_STA_UPGRADE_ST_EXECUTE);
}
exit_label:
if ((upgrade_info->session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_NW) &&
rsp_flag) {
iot_sg_sta_nw_send_exe_ack(id, IOT_PLC_MSG_TYPE_UNICAST, result);
}
iot_sg_printf("sg_upgrade: %s, result: %d\n", __FUNCTION__, result);
}
void iot_sg_sta_handle_stop_upgrade(uint32_t id, uint8_t rsp_flag)
{
iot_sg_sta_upgrade_info_t *upgrade_info = NULL;
upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
iot_sg_printf("sg_upgrade: %s. stop_upgrade_id = %08X. state = %d\n",
__FUNCTION__, id, upgrade_info->state);
if ((upgrade_info->state >= IOT_SG_STA_UPGRADE_ST_RECEIVE) &&
(!upgrade_info->skip)) {
iot_sg_sta_renew_exit_reason_code(IOT_SG_STA_UPGRADE_EXIT_STOP_CMD);
}
if (upgrade_info->state == IOT_SG_STA_UPGRADE_ST_TRAIL_RUN) {
/* switch back to previous image */
iot_sg_printf("sg_upgrade: %s. switch back for stop_upgrade\n");
iot_upgrade_switch_part();
iot_upgrade_reset();
} else {
iot_sg_sta_upgrade_clear(id, 1);
}
if ((upgrade_info->session_type == IOT_SG_STA_UPGRADE_SESSION_TYPE_NW) &&
rsp_flag) {
iot_sg_sta_nw_send_stop_ack(id, IOT_PLC_UPGRADE_OK);
}
}
void iot_sg_sta_upgrade_on_join(uint32_t new_nw_joined)
{
iot_sg_sta_upgrade_info_t *p_info = &p_sg_glb->desc.sta->upgrade_info;
if (new_nw_joined) {
/* STA just joined a new network or CCo rebooted,
* stop current upgrading session if necessary.
*/
if ((IOT_SG_STA_UPGRADE_ST_RECEIVE == p_info->state) || p_info->skip) {
if (!p_info->skip) {
iot_sg_sta_renew_exit_reason_code(
IOT_SG_STA_UPGRADE_EXIT_NID_CHANGE);
}
iot_sg_sta_upgrade_clear(p_info->upgrade_id, 1);
}
}
if ((p_info->state > IOT_SG_STA_UPGRADE_ST_IDLE) &&
(p_info->state < IOT_SG_STA_UPGRADE_ST_TRAIL_RUN)) {
iot_plc_led_request(IOT_PLC_LED_UPGRADE_ON);
}
}
void iot_sg_sta_upgrade_on_leave()
{
iot_sg_sta_upgrade_info_t *p_info = &p_sg_glb->desc.sta->upgrade_info;
if (!p_info->skip) {
if (iot_sg_sta_recv_all_block()) {
if (p_info->ext_dev_need_upgrade_flag) {
iot_sg_sta_ext_upgrade_pre_process();
goto exit_label;
} else {
/* if STA received new FW, switch to new FW when leave network. */
if (p_info->trail_run_dur == 0) {
p_info->trail_run_dur = IOT_SG_STA_DEFAULT_TRAIL_RUN_DUR;
}
iot_sg_printf("sg upgrade: reset on sta leave."
"st = %d, trail = %d\n", p_info->state, p_info->trail_run_dur);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_UPGRADE_DBG_ID, 2, 6, p_info->state);
iot_sg_sta_save_to_flash();
iot_pkg_upgrade_commit(p_info->upgrade_id);
iot_pkg_upgrade_reset();
goto exit_label;
}
}
if (p_info->state == IOT_SG_STA_UPGRADE_ST_EXECUTE) {
/* leave network before execute delay timeout.
* reset to use the new firmware image.
*/
iot_sg_printf("sg upgrade: reset on sta leave."
"st = %d, trail = %d\n", p_info->state, p_info->trail_run_dur);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_UPGRADE_DBG_ID, 2, 7, p_info->state);
iot_pkg_upgrade_reset();
goto exit_label;
}
}
if ((p_info->state > IOT_SG_STA_UPGRADE_ST_IDLE) &&
(p_info->state < IOT_SG_STA_UPGRADE_ST_TRAIL_RUN)) {
iot_plc_led_request(IOT_PLC_LED_UPGRADE_OFF);
}
if (p_info->state != IOT_SG_STA_UPGRADE_ST_INVALID &&
p_info->state != IOT_SG_STA_UPGRADE_ST_IDLE) {
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_UPGRADE_DBG_ID, 2, 8, p_info->state);
}
exit_label:
return;
}
uint32_t iot_sg_sta_upgrade_handle_file_segment(uint8_t action,
uint8_t session_type, uint16_t seg_index, uint16_t total_seg_cnt,
uint8_t *seg_data, uint16_t seg_len, uint8_t allow_skip, uint16_t window)
{
uint32_t ret = ERR_OK, file_crc, file_size, result;
iot_sg_sta_upgrade_info_t *upgrade_info = &p_sg_glb->desc.sta->upgrade_info;
iot_pkt_t *src_pkt = NULL;
switch (action) {
case IOT_SG_STA_SEG_UPGRADE_ACTION_STOP:
{
iot_sg_sta_handle_stop_upgrade(0, 0);
break;
}
case IOT_SG_STA_SEG_UPGRADE_ACTION_UPGRADE:
{
if (total_seg_cnt == 0 || seg_len == 0 || !seg_data) {
/* reject invalid data packet. */
ret = ERR_FAIL;
goto out;
}
if (0 == seg_index) {
/* support new session type restart upgrade */
if ((IOT_SG_STA_UPGRADE_SESSION_TYPE_INVALID !=
upgrade_info->session_type) &&
(session_type != upgrade_info->session_type)) {
iot_sg_sta_handle_stop_upgrade(0, 0);
}
if (IOT_FILE_TYPE_INVALID == iot_get_file_type(seg_data)) {
/* reject invalid data packet. */
if (allow_skip) {
upgrade_info->skip = 1;
upgrade_info->session_type = session_type;
} else {
ret = ERR_FAIL;
}
iot_sg_printf("%s invalid upgrade file\n", __FUNCTION__);
goto out;
}
if (iot_get_vendor_id(seg_data) != iot_sg_get_vendor_id()) {
/* reject invalid data packet. */
if (allow_skip) {
upgrade_info->skip = 1;
upgrade_info->session_type = session_type;
} else {
ret = ERR_FAIL;
}
iot_sg_printf("%s invalid vendor id\n", __FUNCTION__);
goto out;
}
file_size = iot_get_file_len(seg_data) +
iot_get_file_header_len(seg_data);
file_crc = iot_get_file_crc(seg_data);
if (IOT_SG_STA_UPGRADE_ST_IDLE == upgrade_info->state) {
/* get a new upgrade id if it's 0. */
upgrade_info->upgrade_id++;
if (upgrade_info->upgrade_id == 0) {
upgrade_info->upgrade_id = 1;
}
}
result = iot_sg_sta_handle_start_upgrade(upgrade_info->upgrade_id,
window, seg_len, file_size, total_seg_cnt, file_crc, 0,
session_type);
if ((IOT_PLC_UPGRADE_OK != result) &&
(IOT_PLC_UPGRADE_ERR_SAME_VERSION != result)) {
ret = ERR_FAIL;
goto out;
}
}
if (session_type != upgrade_info->session_type) {
ret = ERR_FAIL;
goto out;
}
if (upgrade_info->skip) {
if (!allow_skip) {
ret = ERR_FAIL;
}
goto out;
}
src_pkt = iot_pkt_alloc(seg_len, IOT_SMART_GRID_MID);
if (NULL == src_pkt) {
ret = ERR_FAIL;
goto out;
}
os_mem_cpy(iot_pkt_put(src_pkt, seg_len), seg_data, seg_len);
iot_sg_sta_handle_upgrade_data(upgrade_info->upgrade_id,
seg_len, seg_index, iot_pkt_data(src_pkt), src_pkt, 0);
break;
}
default:
ret = ERR_FAIL;
break;
}
out:
return ret;
}
#endif /* IOT_SMART_GRID_ENABLE */