2087 lines
59 KiB
C
2087 lines
59 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 "os_types.h"
|
||
|
||
#if INCLUDE_VIRTUAL_CHANNEL
|
||
#include "iot_errno_api.h"
|
||
#include "iot_uart_api.h"
|
||
#include "iot_spi_dma_api.h"
|
||
#include "iot_task.h"
|
||
#include "iot_pkt_api.h"
|
||
#include "os_lock_api.h"
|
||
#include "os_timer_api.h"
|
||
#include "iot_io.h"
|
||
#include "os_task_api.h"
|
||
#include "iot_utils_api.h"
|
||
#include "iot_board_api.h"
|
||
#include "vc_debug.h"
|
||
#include "vc_commands.h"
|
||
#include "vc_proto.h"
|
||
#include "vc_upgrade.h"
|
||
#include "vc_task.h"
|
||
#include "iot_crc_api.h"
|
||
#include "iot_board.h"
|
||
#include "iot_ntoh_api.h"
|
||
#include "os_utils_api.h"
|
||
#include "iot_mtd.h"
|
||
#include "iot_gpio_api.h"
|
||
|
||
#define STM32_CHECK_UPGRADE 1
|
||
|
||
enum _vc_task_state_flag {
|
||
VC_FLAG_UPGRADE_READY = 0x01,
|
||
VC_FLAG_UPGRADING = 0x02,
|
||
VC_FLAG_UPGRAD_FAILED = 0x04,
|
||
VC_FLAG_UPGRAD_SUCCS = 0x08
|
||
};
|
||
|
||
#define vc_set_upgrading(flag) do { \
|
||
(flag) |= VC_FLAG_UPGRADING;\
|
||
(flag) &= ~(VC_FLAG_UPGRAD_FAILED | VC_FLAG_UPGRAD_SUCCS); \
|
||
} while(0)
|
||
|
||
#define vc_set_upgrade_fail(flag) do { \
|
||
(flag) |= VC_FLAG_UPGRAD_FAILED;\
|
||
(flag) &= ~(VC_FLAG_UPGRAD_SUCCS | VC_FLAG_UPGRADING); \
|
||
} while(0)
|
||
|
||
#define vc_set_upgrade_success(flag) do { \
|
||
(flag) |= VC_FLAG_UPGRAD_SUCCS;\
|
||
(flag) &= ~(VC_FLAG_UPGRAD_FAILED | VC_FLAG_UPGRADING); \
|
||
} while(0)
|
||
|
||
/**
|
||
* @brief p_drv_send_fn - Driver api send data to specific port to stm32.
|
||
* @param handle_h: Handle of driver port.
|
||
* @param p_pkt: Packet of data send to stm32.
|
||
* @return ERR_FAIL -- Operation failed.
|
||
* @return ERR_OK -- Operation Successful.
|
||
*/
|
||
typedef uint32_t (*p_drv_send_fn)(void *handle_h, iot_pkt_t *p_pkt);
|
||
|
||
/**
|
||
* @brief p_drv_init_fn - Driver api initialize the hardware port.
|
||
* @param p_drv: Driver object to initialiaze, see vc_task_drv_obj_t.
|
||
* @return ERR_FAIL -- Operation failed.
|
||
* @return ERR_OK -- Operation Successful.
|
||
*/
|
||
typedef uint32_t (*p_drv_init_fn)(void *p_drv);
|
||
|
||
typedef struct _vc_task_drv_buffer_t_ {
|
||
uint8_t *base;
|
||
uint8_t *end;
|
||
uint8_t *pos;
|
||
} vc_task_drv_buf_t;
|
||
|
||
/**
|
||
* @brief vc_task_t - VC-TASK object structure.
|
||
*/
|
||
typedef struct _vc_task_driver_t_ {
|
||
/* ID of driver. */
|
||
uint32_t id;
|
||
/* Handle of this driver. */
|
||
void *hanle_h;
|
||
/* API to init the hardware port. */
|
||
p_drv_init_fn init_fn;
|
||
/* API to send data to driver. */
|
||
p_drv_send_fn send_fn;
|
||
vc_task_drv_buf_t *p_buf;
|
||
} vc_task_drv_t;
|
||
|
||
/**
|
||
* @brief _vc_task_driver_object_t_ - Driver object structure .
|
||
*/
|
||
typedef struct _vc_task_driver_object_t_ {
|
||
vc_task_drv_t drv[VC_DRVID_MAX];
|
||
} vc_task_drv_obj_t;
|
||
|
||
/**
|
||
* @brief vc_task_chn_t - Channel object structure .
|
||
*/
|
||
typedef struct _vc_task_channel_t_ {
|
||
/*
|
||
* API to upload received data from stm32 to virtual port layer.
|
||
*/
|
||
vc_chn_rcv_func rcv_fn;
|
||
/*
|
||
* API to post data from virtual port layer to stm32.
|
||
*/
|
||
vc_drv_id_e drv_id;
|
||
/*
|
||
* Information of this channel.
|
||
*/
|
||
vc_channel_info_t info;
|
||
} vc_task_channel_t;
|
||
|
||
/**
|
||
* @brief vc_task_chn_t - Channel object structure .
|
||
*/
|
||
typedef struct _vc_task_channel_object_t_ {
|
||
vc_task_channel_t *p_channel[VC_CHNID_MAX]; /* Pointer of channel structure. */
|
||
} vc_task_chn_obj_t;
|
||
|
||
/**
|
||
* @brief _vc_task_upgrade_object_t_ - Upgrade stm32 object structure .
|
||
*/
|
||
typedef struct _vc_task_upgrade_object_t_ {
|
||
/* Callback to upload data received. */
|
||
vc_upg_rcv_func rcv_fn;
|
||
/* State of upgrading. */
|
||
vc_upgrd_state_e state;
|
||
/* Percentage of upgrading. */
|
||
uint32_t percentage;
|
||
/* Driver to tx/rx data. */
|
||
vc_task_drv_t *p_drv;
|
||
} vc_task_upg_obj_t;
|
||
|
||
typedef struct _vc_task_auto_upgrade_t {
|
||
/* flag to control whether enable auto upgrade. */
|
||
uint8_t enable;
|
||
/* stm32 fw state, true: fw is ok, false: fw is not ok. */
|
||
uint8_t fw_state;
|
||
/* stm32 upgrade times. */
|
||
uint8_t upd_cnt;
|
||
/* stm32 fw check timeout times. */
|
||
uint32_t fwchk_timeout_cnt;
|
||
/* stm32 status update timer. */
|
||
uint32_t upd_timer;
|
||
}vc_task_auto_upgrade_t;
|
||
|
||
typedef struct _vc_task_status_object_t {
|
||
uint32_t upgrade_sts;
|
||
vc_dev_status_t error_status;
|
||
vc_ack_get_fw_info_t fw_info;
|
||
vc_task_auto_upgrade_t stm32_auto_upd;
|
||
vc_chn_statistic_t statcs[VC_CHNID_MAX];
|
||
} vc_task_status_obj_t;
|
||
|
||
/**
|
||
* @brief vc_task_t - VC-TASK object structure.
|
||
*/
|
||
typedef struct _vc_task_obj_t_ {
|
||
/* Sequnce of sending frames. */
|
||
uint32_t tx_seq;
|
||
/* Handle of this VC-TASK. */
|
||
iot_task_h p_task_h;
|
||
/* Handle of share timer. */
|
||
timer_id_t share_timer;
|
||
/* function pointer to post aknownage of command to app. */
|
||
vc_module_ack_rcv_func ack_to_app_fn;
|
||
/* Channel object */
|
||
vc_task_chn_obj_t chn_obj;
|
||
/* Driver object. */
|
||
vc_task_drv_obj_t drv_obj;
|
||
/* Upgrading object. */
|
||
vc_task_upg_obj_t upg_obj;
|
||
vc_task_status_obj_t status;
|
||
} vc_task_obj_t;
|
||
|
||
/**
|
||
* @brief vc_msg_t - Message structure of VC-TASK.
|
||
*/
|
||
typedef struct _vc_task_message_t_ {
|
||
iot_task_msg_t msg;
|
||
uint32_t data;
|
||
iot_pkt_t *p_pkt;
|
||
} vc_msg_t;
|
||
|
||
/**
|
||
* @brief VC_UART_RX_BUF_LENGTH - Receive buffer length.
|
||
*/
|
||
#define VC_UART_RX_BUF_LENGTH VC_COMMAND_MAX_FRAME_LENGTH
|
||
|
||
/**
|
||
* @brief VC_TASK_STACK_SIZE - Stack size of VC-TASK.
|
||
*/
|
||
#define VC_TASK_STACK_SIZE 1024
|
||
|
||
/**
|
||
* @brief VC_TASK_PRIORITY - Priority of VC-TASK.
|
||
*/
|
||
#define VC_TASK_PRIORITY 7
|
||
|
||
/**
|
||
* @brief VC_TASK_MSG_CNT - Count of messages for VC-TASK.
|
||
*/
|
||
#define VC_TASK_MSG_CNT 100
|
||
|
||
/**
|
||
* @brief VC_TASK_MSG_SIZE - Size of messages for VC-TASK.
|
||
*/
|
||
#define VC_TASK_MSG_SIZE sizeof(vc_msg_t)
|
||
|
||
/**
|
||
* @brief vc_task_msg_type_e - Type of messages for VC-TASK.
|
||
* VC_MSG_TYPE_TIMER - Timer triggerd message.
|
||
* VC_MSG_TYPE_UPGRD - stm32 upgrading message.
|
||
* VC_MSG_TYPE_CTRL - Control message.
|
||
* VC_MSG_TYPE_FRAME - Data / control frame message between K68 & stm32.
|
||
* VC_MSG_TYPE_DATA - Data packet message between VC-TASK & VP-layer.
|
||
*/
|
||
typedef enum _vc_task_message_type_e_ {
|
||
VC_MSG_TYPE_TIMER = 0x00,
|
||
VC_MSG_TYPE_CONTROL,
|
||
VC_MSG_TYPE_FRAME,
|
||
VC_MSG_TYPE_DATA,
|
||
VC_MSG_TYPE_MAX
|
||
} vc_task_msg_type_e;
|
||
|
||
/**
|
||
* @brief vc_task_msg_timer_id_e - ID of messages for VC_MSG_TYPE_TIMER.
|
||
* VC_MSG_TIMER_ID_COUNTER - Time-base counter timer.
|
||
*/
|
||
typedef enum _vc_task_message_timer_id_e_ {
|
||
VC_MSG_TIMER_ID_SHARE_TIMER = 0x0,
|
||
VC_MSG_TIMER_ID_MAX
|
||
} vc_task_msg_timer_id_e;
|
||
|
||
/**
|
||
* @brief _vc_task_message_control_id_e_ - ID of messages for VC_MSG_TYPE_CONTROL.
|
||
* VC_MSG_CTRL_ID_UPLINK - control packet to Up-layer,like VP / command.
|
||
* VC_MSG_CTRL_ID_DOWNLINK - control packet from Up-layer.
|
||
*/
|
||
typedef enum _vc_task_message_control_id_e_ {
|
||
VC_MSG_CTRL_ID_UPLINK = 0x0,
|
||
VC_MSG_CTRL_ID_DOWNLINK,
|
||
VC_MSG_CTRL_ID_MAX
|
||
} vc_task_msg_ctrl_id_e;
|
||
|
||
/**
|
||
* @brief _vc_task_message_frame_id_e_ - ID of messages for VC_MSG_TYPE_FRAME.
|
||
* VC_MSG_FRM_ID_FROM_UART - Frame from stm32.
|
||
* VC_MSG_FRM_ID_TO_UART - Frame to stm32.
|
||
*/
|
||
typedef enum _vc_task_message_frame_id_e_ {
|
||
VC_MSG_FRM_ID_TO_STM32 = 0x0,
|
||
VC_MSG_FRM_ID_FROM_STM32,
|
||
VC_MSG_FRM_ID_MAX
|
||
} vc_task_msg_frame_id_e;
|
||
|
||
/**
|
||
* @brief _vc_task_message_data_id_e_ - ID of messages for VC_MSG_TYPE_DATA.
|
||
* VC_MSG_DATA_ID_UPLINK - Data packet to Up-layer,like VP / command.
|
||
* VC_MSG_DATA_ID_DOWNLINK - Data packet from Up-layer.
|
||
*/
|
||
typedef enum _vc_task_message_data_id_e_ {
|
||
VC_MSG_DATA_ID_UPLINK = 0x0,
|
||
VC_MSG_DATA_ID_DOWNLINK,
|
||
VC_MSG_DATA_ID_MAX
|
||
} vc_task_msg_data_id_e;
|
||
|
||
/**
|
||
* @brief VC_TASK_UPDATE_TIMER_TIMEOUT - Timer for querying stm32 uograde state, micro-seconds.
|
||
*/
|
||
#define VC_TASK_UPDATE_TIMER_TIMEOUT 500
|
||
|
||
/**
|
||
* @brief VC_TASK_FRAME_TIMEOUT - Timer timeout for a complate frame while receiving, micro-seconds.
|
||
*/
|
||
#define VC_TASK_FRAME_TIMEOUT 5
|
||
|
||
/**
|
||
* @brief STM32_CHECK_FWVER_MAX_TIMES - Times count judge if need upgrade stm32 fw.
|
||
*/
|
||
#define STM32_CHECK_FWVER_MAX_TIMES 3
|
||
|
||
/**
|
||
* @brief STM32_AUTO_UPD_MAX_TIMES - Auto upgrade max times.
|
||
*/
|
||
#define STM32_AUTO_UPD_MAX_TIMES 2
|
||
|
||
/*
|
||
* @brief vc_uart_frame - The uart port frame format.
|
||
*/
|
||
const LOCAL iot_frame_fmt vc_uart_frame = {
|
||
.frame_timeout = VC_TASK_FRAME_TIMEOUT,
|
||
.preamble_code = {(VC_COMMAND_PRECODE >> 8) & 0xFF, (VC_COMMAND_PRECODE) & 0xFF},
|
||
.preamble_codelen = 2,
|
||
.datalen_offset = 4,
|
||
.datalen_size = 2,
|
||
.datalen_fix = 0,
|
||
.backcode = {VC_COMMAND_PRECODE & 0xFF},
|
||
.backcode_len = 1,
|
||
.backcode_offset = 2,
|
||
.timeout_mode = TIMEOUT_REGULAR_TIME,
|
||
.check_frame_func = NULL
|
||
};
|
||
|
||
/**
|
||
* @brief vc_task - The object of vc-task.
|
||
*/
|
||
LOCAL vc_task_obj_t vc_task;
|
||
|
||
/**
|
||
* @brief vc_task_inited - Check if vc-task initailized.
|
||
*/
|
||
#define vc_task_inited() (NULL != vc_task.p_task_h)
|
||
|
||
/**
|
||
* @brief vc_task_check_upgrading - Check if vc-task in upgrading stm32 device.
|
||
*/
|
||
#define vc_task_check_upgrading() \
|
||
((NULL != vc_task.p_task_h) && (vc_task.status.upgrade_sts & VC_FLAG_UPGRADING))
|
||
|
||
/**
|
||
* @brief vc_channel_inited - Check if channel initailized.
|
||
*/
|
||
#define vc_channel_inited(chn) \
|
||
(vc_chn_valid(chn) && (NULL != vc_task.chn_obj.p_channel[chn]))
|
||
|
||
/**
|
||
* @brief vc_port_inited - Check if uart initailized.
|
||
*/
|
||
#define vc_port_inited(drv_id) \
|
||
(vc_drv_id_valid(drv_id) && (NULL != vc_task.drv_obj.drv[drv_id].hanle_h))
|
||
|
||
/**
|
||
* @brief vc_port_inited - Check if uart initailized.
|
||
*/
|
||
#define vc_upgd_ready() \
|
||
((NULL != vc_task.upg_obj.p_drv) && (NULL != vc_task.upg_obj.p_drv->hanle_h) \
|
||
&& (NULL != vc_task.upg_obj.rcv_fn))
|
||
|
||
#ifndef VC_TASK_DEBUG_DUMP
|
||
#define VC_TASK_DEBUG_DUMP 0
|
||
#endif
|
||
|
||
/**
|
||
* @brief vc_task_share_timer_t - Object of share timer.
|
||
*/
|
||
typedef struct _vc_task_share_timer_t {
|
||
/**
|
||
* Timeout time in micro-seconds.
|
||
*/
|
||
uint32_t timeout;
|
||
/**
|
||
* Timeout counter in micro-seconds.
|
||
*/
|
||
uint32_t counter;
|
||
/**
|
||
* Callback function when timeout.
|
||
*/
|
||
vc_module_share_timer_func fn;
|
||
}vc_task_share_timer_t;
|
||
|
||
vc_task_share_timer_t g_share_timer[VC_TASK_SHARE_TIMER_COUNT];
|
||
|
||
#define vc_share_timer_active(tm) \
|
||
(((tm)->timeout >= VC_TASK_SHARE_TIMER_STEP) && (NULL != (tm)->fn))
|
||
|
||
#define vc_set_dbg_data(chn, ena) (((chn) << 8) | (ena))
|
||
#define vc_get_dbg_data(chn, ena, data) do { \
|
||
(chn) = ((data) >> 8) & 0xFF; \
|
||
(ena) = (data) & 0xFF; \
|
||
}while(0)
|
||
|
||
#define vc_statistic_tx_frame_add(chn, num) \
|
||
do { \
|
||
vc_task.status.statcs[chn].k68.sent.frames += num; \
|
||
} while(0)
|
||
|
||
#define vc_statistic_rx_frame_add(chn, num) \
|
||
do { \
|
||
vc_task.status.statcs[chn].k68.recvd.frames += num; \
|
||
} while(0)
|
||
|
||
#define vc_statistic_tx_byte_add(chn, num) \
|
||
do { \
|
||
vc_task.status.statcs[chn].k68.sent.bytes += num; \
|
||
} while(0)
|
||
|
||
#define vc_statistic_rx_byte_add(chn, num) \
|
||
do { \
|
||
vc_task.status.statcs[chn].k68.recvd.bytes += num; \
|
||
} while(0)
|
||
|
||
#if VC_TASK_DEBUG_DUMP
|
||
/**
|
||
* @brief vc_dump_buf - Buffer for debug use.
|
||
*/
|
||
uint8_t *vc_dump_buf = NULL;
|
||
|
||
/**
|
||
* @brief VC_DUMP_BUF_LEN - Length of dump buffer.
|
||
*/
|
||
#define VC_DUMP_BUF_LEN 256
|
||
|
||
/**
|
||
* @brief vc_buffer_dump - Print binary data.
|
||
*/
|
||
void vc_buffer_dump(char *prompt, uint8_t *data, uint32_t len)
|
||
{
|
||
uint32_t offset, idx;
|
||
|
||
/* Prepare memory. */
|
||
if (NULL == vc_dump_buf) {
|
||
if (NULL == (vc_dump_buf =
|
||
os_mem_malloc(VC_TASK_MODULE_ID, VC_DUMP_BUF_LEN + 4))) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
offset = iot_sprintf((char *)vc_dump_buf, "\n[%s len:%d] ", prompt, len);
|
||
|
||
/* Debug buffer hold max bytes of data. */
|
||
len = min((VC_DUMP_BUF_LEN - offset) / 3, len);
|
||
|
||
for (idx = 0; idx < len; idx++) {
|
||
offset += iot_sprintf((char *)vc_dump_buf + offset, "%02X ", data[idx]);
|
||
}
|
||
|
||
vc_dump_buf[offset] = 0;
|
||
|
||
vc_printf("%s\n", vc_dump_buf);
|
||
|
||
return;
|
||
}
|
||
#else /* VC_TASK_DEBUG_DUMP */
|
||
|
||
void vc_buffer_dump(char *prompt, uint8_t *data, uint32_t len)
|
||
{
|
||
(void)prompt;
|
||
(void)data;
|
||
(void)len;
|
||
}
|
||
|
||
#endif /* VC_TASK_DEBUG_DUMP */
|
||
|
||
LOCAL uint32_t vc_module_task_msg_post(uint16_t type, uint16_t id,
|
||
uint32_t data, iot_pkt_t *p_pkt);
|
||
|
||
LOCAL void vc_module_control_stop_upgrade(void);
|
||
|
||
LOCAL void vc_module_control_start_upgrade(void);
|
||
|
||
LOCAL void vc_module_msg_func_control_uplink(iot_pkt_t *p_pkt);
|
||
|
||
LOCAL void vc_module_stm32_query_upgrading_state(void)
|
||
{
|
||
vc_task_upg_obj_t *p_upd = &vc_task.upg_obj;
|
||
|
||
p_upd->state = vc_upgrd_get_state();
|
||
p_upd->percentage = vc_upgrd_get_percentage();
|
||
|
||
vc_printf("[VC]Stm32 upgrade : state %d, percentage %d%%.\n",
|
||
p_upd->state, p_upd->percentage);
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_stm32_get_fw_info(). Get stm32 fw info.
|
||
*/
|
||
void vc_module_stm32_get_fw_info()
|
||
{
|
||
vc_cmd_t cmd;
|
||
|
||
os_mem_set(&cmd, 0, sizeof(cmd));
|
||
cmd.cmd = VC_CMD_GET_STM32_FW_INFO;
|
||
vc_proto_execute_command_from_vc_task(&cmd);
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_stm32_fw_check(). Check stm32 fw version.
|
||
*/
|
||
LOCAL void vc_module_stm32_check_fw_ver()
|
||
{
|
||
vc_ack_get_fw_info_t *p_ack_info = &vc_task.status.fw_info;
|
||
|
||
iot_printf("[VC]Stm32 fw version info, remote:%x, local:%x.\n",
|
||
p_ack_info->remote.version, p_ack_info->local.version);
|
||
|
||
/* Get remote stm32 fw info timeout. */
|
||
if ((0 == p_ack_info->remote.version) &&
|
||
(0 == p_ack_info->remote.crc32) &&
|
||
(0 == p_ack_info->remote.length)) {
|
||
goto out;
|
||
}
|
||
|
||
if (p_ack_info->remote.version != p_ack_info->local.version) {
|
||
vc_task.status.stm32_auto_upd.fwchk_timeout_cnt = STM32_CHECK_FWVER_MAX_TIMES;
|
||
iot_printf("[VC]Stm32 fw version mismatch, start to upgrade!.\n");
|
||
} else {
|
||
vc_task.status.stm32_auto_upd.fw_state = true;
|
||
vc_task.status.stm32_auto_upd.enable = 0;
|
||
iot_printf("[VC]Stm32 fw version match success.\n");
|
||
}
|
||
|
||
out:
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_stm32_check_auto_upgrade(). Check stm32 to judge whether
|
||
* need to upgrade or not..
|
||
*/
|
||
LOCAL void vc_module_stm32_check_auto_upgrade(uint32_t timeout)
|
||
{
|
||
vc_task_auto_upgrade_t *p_auto_upd = &vc_task.status.stm32_auto_upd;
|
||
vc_ack_get_fw_info_t *p_fw_info = (vc_ack_get_fw_info_t *)&vc_task.status.fw_info;
|
||
uint8_t first_run = 0;
|
||
|
||
/* Exit automatic upgrade in the following three cases:
|
||
* 1. local stm32 fw img is invalid.
|
||
* 2. up to max upgrade times.
|
||
* 3. remote stm32 fw info is valid.
|
||
*/
|
||
if (((0 == p_fw_info->local.crc32) &&
|
||
(0 == p_fw_info->local.length) &&
|
||
(0 == p_fw_info->local.version)) ||
|
||
(STM32_AUTO_UPD_MAX_TIMES == p_auto_upd->upd_cnt) ||
|
||
(true == p_auto_upd->fw_state)) {
|
||
p_auto_upd->enable = 0;
|
||
goto out;
|
||
}
|
||
|
||
/* If it is the first run, upgrade stm32 fw. */
|
||
if(p_auto_upd->upd_cnt == 0) {
|
||
first_run = dev_get_first_run_val();
|
||
} else {
|
||
first_run = 0;
|
||
}
|
||
|
||
if (first_run) {
|
||
iot_printf("[VC]Fist burned fw so forced to upgrade.\n");
|
||
}
|
||
|
||
/* Check whether stm32 fw needs upgrade at an interval of 1500ms. */
|
||
if (0 == p_auto_upd->upd_timer % VC_PROTO_MAX_TIME_RESPONSE_TIMEOUT) {
|
||
if (p_auto_upd->upd_timer >= VC_PROTO_MAX_TIME_RESPONSE_TIMEOUT) {
|
||
/* Check remote stm32 fw version. */
|
||
vc_module_stm32_check_fw_ver();
|
||
if (false == p_auto_upd->fw_state) {
|
||
/* Get stm32 fw info timeout. */
|
||
p_auto_upd->fwchk_timeout_cnt++;
|
||
}
|
||
}
|
||
|
||
/* Start upgrade stm32 fw img and clean related flags. */
|
||
if (first_run ||
|
||
(STM32_CHECK_FWVER_MAX_TIMES <= p_auto_upd->fwchk_timeout_cnt)){
|
||
/* clean timeout count. */
|
||
p_auto_upd->fwchk_timeout_cnt = 0;
|
||
/* clean timer record. */
|
||
p_auto_upd->upd_timer = 0;
|
||
/* upgrade count increase 1. */
|
||
p_auto_upd->upd_cnt++;
|
||
/* clean remote fw info that k68 record. */
|
||
os_mem_set(&p_fw_info->remote, 0, sizeof(vc_fw_ver_t));
|
||
vc_module_control_start_upgrade();
|
||
iot_printf("[VC]Upgrade stm32 fw #%d, max cnt %d.\n", p_auto_upd->upd_cnt,
|
||
STM32_AUTO_UPD_MAX_TIMES);
|
||
goto out;
|
||
}
|
||
|
||
/* Get remote stm32 fw info. */
|
||
if (false == p_auto_upd->fw_state) {
|
||
vc_module_stm32_get_fw_info();
|
||
}
|
||
}
|
||
|
||
/* Record timer. */
|
||
p_auto_upd->upd_timer += timeout;
|
||
|
||
out:
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_stm32_status_update_timer_fn(uint32_t timeout)
|
||
{
|
||
(void)timeout;
|
||
|
||
/* Query the state. */
|
||
if (vc_task_check_upgrading()) {
|
||
vc_module_stm32_query_upgrading_state();
|
||
if (vc_task.status.stm32_auto_upd.enable) {
|
||
if ((100 == vc_upgrd_get_percentage()) &&
|
||
(VC_UPGRD_STATE_ENDUP == vc_upgrd_get_state())) {
|
||
vc_module_control_stop_upgrade();
|
||
}
|
||
}
|
||
} else {
|
||
if (vc_task.status.stm32_auto_upd.enable) {
|
||
vc_module_stm32_check_auto_upgrade(timeout);
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
uint32_t vc_module_frame_get_next_tx_sequence(void)
|
||
{
|
||
return (++vc_task.tx_seq);
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_frame_alloc() - Alloc packet for frame using. This will :
|
||
* 1. Alloc a packet for caller with reserved space for frame header & tail.
|
||
* 2. Copy data from buffer into packet.
|
||
* @param p_buf: pointer of data buffer.
|
||
* @param len: length of data.
|
||
* @return: Pointer of packet if successfull or NULL if failed.
|
||
*/
|
||
LOCAL iot_pkt_t *vc_module_frame_alloc(uint8_t *p_buf, uint32_t len)
|
||
{
|
||
iot_pkt_t *p_pkt = NULL;
|
||
uint32_t pkt_len;
|
||
|
||
if (NULL == p_buf || 0 == len) {
|
||
goto out;
|
||
}
|
||
|
||
/* Reserve memory for frame header & tail */
|
||
pkt_len = len + VC_COMMAND_FRAME_HEADER_LENGTH + VC_COMMAND_FRAME_TAIL_LENGTH;
|
||
|
||
if (NULL == (p_pkt = iot_pkt_alloc(pkt_len, VC_TASK_MODULE_ID))) {
|
||
goto out;
|
||
}
|
||
|
||
iot_pkt_put(p_pkt, len + VC_COMMAND_FRAME_HEADER_LENGTH);
|
||
|
||
/* Reserved for header. */
|
||
iot_pkt_pull(p_pkt, VC_COMMAND_FRAME_HEADER_LENGTH);
|
||
|
||
/* Copy data from buffer to packet. */
|
||
os_mem_cpy(iot_pkt_data(p_pkt), p_buf, len);
|
||
|
||
out:
|
||
|
||
return p_pkt;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_frame_build() - Makeup frame packet. This will :
|
||
* 1. Check the packet from caller which with reserved space for frame header & tail.
|
||
* 2. Fill the frame information into the packet and return the packet to caller.
|
||
* 3. Input param p_data_pkt will be freed anyway.
|
||
* @param chn: Channel this packet belongs to.
|
||
* @param seq: Sequnce of this frame.
|
||
* @param p_data_pkt: Packet of data.
|
||
* @return: Pointer of packet if successfull or NULL if failed.
|
||
*/
|
||
LOCAL iot_pkt_t *vc_module_frame_build(uint32_t chn, uint16_t seq, iot_pkt_t *p_data_pkt)
|
||
{
|
||
iot_pkt_t *p_frame_pkt = NULL;
|
||
vc_cmd_header_t *p_frame_head;
|
||
vc_cmd_tail_t *p_frame_tail;
|
||
uint16_t data_len, err_flag = 0, crc_calc;
|
||
|
||
vc_dbg("[VC]chn#%d seq#%d pkt%p.\n", chn, seq, p_data_pkt);
|
||
|
||
if (NULL == p_data_pkt || (!vc_chn_valid(chn))) {
|
||
err_flag = 1;
|
||
goto out;
|
||
}
|
||
|
||
data_len = iot_pkt_data_len(p_data_pkt);
|
||
|
||
if (VC_COMMAND_MAX_FRAME_LENGTH < data_len || 0 == data_len) {
|
||
err_flag = 2;
|
||
goto out;
|
||
}
|
||
|
||
/* Check if there are reserved space for header & tail. */
|
||
if (iot_pkt_block_len(p_data_pkt, IOT_PKT_BLOCK_TAIL) < VC_COMMAND_FRAME_TAIL_LENGTH
|
||
|| iot_pkt_block_len(p_data_pkt, IOT_PKT_BLOCK_HEAD) < VC_COMMAND_FRAME_HEADER_LENGTH) {
|
||
err_flag = 3;
|
||
goto out;
|
||
}
|
||
|
||
/* This packet is valid & start to fill informations. */
|
||
p_frame_pkt = p_data_pkt;
|
||
p_data_pkt = NULL;
|
||
|
||
/* Get header & tail pointer. */
|
||
p_frame_head = (vc_cmd_header_t *)iot_pkt_push(p_frame_pkt, VC_COMMAND_FRAME_HEADER_LENGTH);
|
||
p_frame_tail = (vc_cmd_tail_t *)iot_pkt_block_ptr(p_frame_pkt, IOT_PKT_BLOCK_TAIL);
|
||
|
||
iot_pkt_put(p_frame_pkt, VC_COMMAND_FRAME_TAIL_LENGTH);
|
||
|
||
/* Fill the header. */
|
||
p_frame_head->pre_code = VC_COMMAND_PRECODE;
|
||
p_frame_head->channel = chn;
|
||
p_frame_head->sequnce = iot_htons(seq);
|
||
p_frame_head->data_length = iot_htons(data_len);
|
||
p_frame_head->reserved = 0;
|
||
|
||
/* Fill the tail. */
|
||
crc_calc = iot_getcrc16((uint8_t *)&p_frame_head->channel,
|
||
data_len + VC_COMMAND_CRC_LENGTH_IN_HEAD, IOT_CRC16_TYPE_CCITT);
|
||
p_frame_tail->crc16 = iot_ntohs(crc_calc);
|
||
p_frame_tail->pst_code = VC_COMMAND_PSTCODE;
|
||
|
||
return p_frame_pkt;
|
||
|
||
out:
|
||
|
||
if (NULL != p_data_pkt) {
|
||
iot_pkt_free(p_data_pkt);
|
||
}
|
||
|
||
if (NULL != p_frame_pkt) {
|
||
iot_pkt_free(p_frame_pkt);
|
||
p_frame_pkt = NULL;
|
||
}
|
||
|
||
vc_printf("[VC]Build frame failed! err flag %d\n", err_flag);
|
||
|
||
return p_frame_pkt;
|
||
}
|
||
|
||
LOCAL uint32_t vc_module_frame_get_channel(uint8_t *p_frame)
|
||
{
|
||
vc_cmd_header_t *p_head;
|
||
|
||
if (NULL == p_frame) {
|
||
return VC_CHNID_MAX;
|
||
}
|
||
|
||
p_head = (vc_cmd_header_t *)p_frame;
|
||
|
||
return vc_chn_valid(p_head->channel) ? p_head->channel : VC_CHNID_MAX;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_frame_parse() - Parse data in buffer,
|
||
* return complete frames we found, makeup pointer of buffer.
|
||
* @param p_buf: The buffer to parse.
|
||
* @return Pointer of frame if found or NULL if not.
|
||
*/
|
||
LOCAL iot_pkt_t *vc_module_frame_parse(vc_task_drv_buf_t *p_buf)
|
||
{
|
||
iot_pkt_t *p_pkt = NULL;
|
||
vc_cmd_header_t *p_head;
|
||
vc_cmd_tail_t *p_tail;
|
||
uint8_t *pos, *end;
|
||
int data_len, min_len;
|
||
uint16_t calc_crc16, payload_len, payload_crc;
|
||
|
||
if (NULL == p_buf) {
|
||
return NULL;
|
||
}
|
||
|
||
pos = p_buf->base;
|
||
end = p_buf->pos;
|
||
|
||
data_len = pos < end ? end - pos : 0;
|
||
|
||
vc_dbg("Pos %p end %p length %d.", pos, end, data_len);
|
||
|
||
min_len = VC_COMMAND_MIN_FRAME_LENGTH;
|
||
|
||
while (min_len < data_len) {
|
||
|
||
if (data_len < VC_COMMAND_MIN_FRAME_LENGTH) {
|
||
/* Clearup && pending data is not a complete frame, drop it. */
|
||
pos = p_buf->pos = p_buf->base;
|
||
goto search_done;
|
||
}
|
||
|
||
p_head = (vc_cmd_header_t *)pos;
|
||
|
||
/* Now start to search a completed frame. */
|
||
do {
|
||
|
||
if (VC_COMMAND_PRECODE != p_head->pre_code) {
|
||
/* Pre-code mismatch, search from next byte. */
|
||
break;
|
||
}
|
||
|
||
if (!vc_chn_valid(p_head->channel)) {
|
||
/* Channel mismatch, search from next byte. */
|
||
vc_dbg("Channel mismatch %d.", p_head->channel);
|
||
break;
|
||
}
|
||
|
||
payload_len = iot_ntohs(p_head->data_length);
|
||
|
||
if (VC_COMMAND_MAX_PAYLOAD_LENGTH < payload_len || 0 == payload_len) {
|
||
/* Payload length mismatch, search from next byte. */
|
||
vc_dbg("Length mismatch length %d, limited %d.",
|
||
VC_COMMAND_MAX_PAYLOAD_LENGTH, payload_len);
|
||
break;
|
||
}
|
||
|
||
if (data_len < payload_len + VC_COMMAND_MIN_FRAME_LENGTH) {
|
||
/* Wait for coming data. */
|
||
vc_dbg("Uncomplate frame length %d.", payload_len);
|
||
goto search_done;
|
||
}
|
||
|
||
p_tail = (vc_cmd_tail_t *)(pos + VC_COMMAND_FRAME_HEADER_LENGTH + payload_len);
|
||
|
||
if (VC_COMMAND_PSTCODE != p_tail->pst_code) {
|
||
/* Post-code mismatch, search from next byte. */
|
||
vc_dbg("Postcode mismatch %d.", p_tail->pst_code);
|
||
break;
|
||
}
|
||
|
||
calc_crc16 = iot_getcrc16((uint8_t *)&p_head->channel,
|
||
payload_len + VC_COMMAND_CRC_LENGTH_IN_HEAD, IOT_CRC16_TYPE_CCITT);
|
||
|
||
payload_crc = iot_ntohs(p_tail->crc16);;
|
||
|
||
if (calc_crc16 != payload_crc) {
|
||
/* CRC failed, search from next byte. */
|
||
vc_dbg("Crc mismatch calc %p, header %p.", calc_crc16, payload_crc);
|
||
break;
|
||
}
|
||
|
||
/* Finally, we got a completed frame. */
|
||
data_len = payload_len + VC_COMMAND_FRAME_HEADER_LENGTH + VC_COMMAND_FRAME_TAIL_LENGTH;
|
||
|
||
vc_dbg("Got one complated frame,payload length %d, whole length %d.",
|
||
payload_len, data_len);
|
||
|
||
if (NULL != (p_pkt = iot_pkt_alloc(data_len, VC_TASK_MODULE_ID))) {
|
||
os_mem_cpy(iot_pkt_put(p_pkt, data_len), pos, data_len);
|
||
} else {
|
||
vc_dbg("No memory to hold this frame, dropped!");
|
||
}
|
||
pos += data_len;
|
||
/* Return this frame. */
|
||
goto search_done;
|
||
|
||
} while(0);
|
||
pos = pos < end ? pos + 1 : end;
|
||
data_len = end - pos;
|
||
}
|
||
|
||
search_done:
|
||
|
||
/* Makeup the pos pointer. */
|
||
if (pos > p_buf->base) {
|
||
if (pos >= p_buf->pos) {
|
||
p_buf->pos = p_buf->base;
|
||
} else {
|
||
os_mem_cpy(p_buf->base, pos, p_buf->pos - pos);
|
||
p_buf->pos = p_buf->base + (p_buf->pos - pos);
|
||
}
|
||
vc_dbg("Search data length %d, left %d.",
|
||
pos - p_buf->base, p_buf->pos - p_buf->base);
|
||
}
|
||
|
||
return p_pkt;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_frame_process_from_stm32() - Parse new coming & pendging data in buffer,
|
||
* send complete frames to VC-TASK.
|
||
* @param p_drv: Tell the buffer to parse.
|
||
* @param p_data: The new coming data to parse.
|
||
* @param d_len: length of data received.
|
||
*/
|
||
LOCAL void vc_module_frame_process_from_stm32(vc_task_drv_t *p_drv, uint8_t *p_data, uint32_t d_len)
|
||
{
|
||
iot_pkt_t *p_pkt = NULL;
|
||
uint32_t data_left, cp_len, cnt = 0;
|
||
vc_task_drv_buf_t *p_buf;
|
||
uint8_t *p_src;
|
||
|
||
vc_dbg("[VC]drv %d, buf %p, len %d.", p_drv->id, p_data, d_len);
|
||
|
||
if (NULL == p_drv || NULL== p_data || 0 == d_len) {
|
||
return;
|
||
}
|
||
|
||
if (!vc_drv_id_valid(p_drv->id)) {
|
||
return;
|
||
}
|
||
|
||
p_buf = p_drv->p_buf;
|
||
p_src = p_data;
|
||
data_left = d_len;
|
||
|
||
/* Search all frame in buffer. */
|
||
do {
|
||
cp_len = (p_buf->end - p_buf->pos) > data_left
|
||
? data_left : (p_buf->end - p_buf->pos);
|
||
|
||
if (cp_len > 0) {
|
||
os_mem_cpy(p_buf->pos, p_src, cp_len);
|
||
p_buf->pos += cp_len;
|
||
p_src += cp_len;
|
||
data_left -= cp_len;
|
||
}
|
||
|
||
/* Search with new data, wait next coming data if frame uncomplete. */
|
||
while (NULL != (p_pkt = vc_module_frame_parse(p_buf))) {
|
||
vc_module_task_msg_post(VC_MSG_TYPE_FRAME, VC_MSG_FRM_ID_FROM_STM32,
|
||
p_drv->id, p_pkt);
|
||
cnt++;
|
||
}
|
||
|
||
}while(data_left > 0);
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_drv_receive_uart() - Uart driver callback function
|
||
* when data received.
|
||
* @param p_data: pointer of data buffer.
|
||
* @param d_len: length of data received.
|
||
* @param is_full_frame: tell if this is a whole frame in this buffer.
|
||
* @param invalid_data_len: length of invalid data received. we ignore this.
|
||
*/
|
||
LOCAL void vc_module_drv_receive_uart(uint8_t* p_data, uint32_t d_len,
|
||
bool_t is_full_frame, uint32_t invalid_data_len)
|
||
{
|
||
vc_task_drv_t *p_drv;
|
||
|
||
(void)is_full_frame;
|
||
(void)invalid_data_len;
|
||
|
||
/* do not need dump when upgrading. */
|
||
if (!vc_task_check_upgrading()) {
|
||
vc_printf("[VC]Uart received %d bytes.\n", d_len);
|
||
|
||
vc_buffer_dump("Uart-Dump RX", p_data, d_len);
|
||
}
|
||
|
||
if (vc_task_check_upgrading()) {
|
||
/* Upgrading data. */
|
||
if (NULL != vc_task.upg_obj.rcv_fn) {
|
||
vc_task.upg_obj.rcv_fn(p_data, d_len);
|
||
}
|
||
} else {
|
||
/* Parse received data. */
|
||
p_drv = &vc_task.drv_obj.drv[VC_DRVID_UART];
|
||
vc_module_frame_process_from_stm32(p_drv, p_data, d_len);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL uint32_t vc_module_drv_send_to_uart(void *handle_h, iot_pkt_t *p_pkt)
|
||
{
|
||
uint32_t d_len;
|
||
|
||
if (NULL == p_pkt) {
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
d_len = iot_pkt_data_len(p_pkt);
|
||
|
||
if (!vc_task_check_upgrading()) {
|
||
vc_printf("[VC]Uart send %d bytes.\n", d_len);
|
||
vc_buffer_dump("Uart-Dump TX", iot_pkt_data(p_pkt), d_len);
|
||
}
|
||
|
||
if (handle_h) {
|
||
iot_uart_send(handle_h, p_pkt, NULL);
|
||
} else {
|
||
iot_pkt_free(p_pkt);
|
||
}
|
||
|
||
return ERR_OK;
|
||
}
|
||
|
||
LOCAL uint32_t vc_module_drv_init_spi(void *p_drv_pnt)
|
||
{
|
||
/* TODO : inti spi port. */
|
||
(void)p_drv_pnt;
|
||
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
LOCAL uint32_t vc_module_drv_init_uart(void *p_drv_pnt)
|
||
{
|
||
int err_flag;
|
||
uint8_t rx_pin = 0;
|
||
uint8_t port = 0;
|
||
vc_task_drv_t *p_drv = (vc_task_drv_t *)p_drv_pnt;
|
||
|
||
if (NULL == p_drv) {
|
||
err_flag = 0;
|
||
goto err_out;
|
||
}
|
||
|
||
os_mem_set(p_drv, 0x0, sizeof(*p_drv));
|
||
|
||
/*kl3新型cco串口3 RX GPIO默认为低,需要先拉起,避免isp下载时多出现00,导致下载失败*/
|
||
port = iot_board_get_uart(UART_EXT_CHIP);
|
||
rx_pin = iot_board_uart_rx_pin_get(port);
|
||
iot_gpio_open_as_input(rx_pin);
|
||
iot_gpio_set_pull_mode(rx_pin, GPIO_PULL_UP);
|
||
|
||
p_drv->send_fn = vc_module_drv_send_to_uart;
|
||
|
||
/* Uart port. */
|
||
p_drv->hanle_h = iot_uart_open(port, vc_module_drv_receive_uart,
|
||
VC_UART_RX_BUF_LENGTH, (iot_frame_fmt *)&vc_uart_frame);
|
||
|
||
if (NULL == p_drv->hanle_h) {
|
||
err_flag = 2;
|
||
goto err_out;
|
||
}
|
||
|
||
iot_uart_set_config(p_drv->hanle_h, VC_TASK_UART_BAUDRATE,
|
||
VC_TASK_UART_PARITY, VC_TASK_UART_DATA_LEN, VC_TASK_UART_STOP_BIT);
|
||
|
||
/* Received buffer. */
|
||
p_drv->p_buf = os_mem_malloc(VC_TASK_MODULE_ID,
|
||
VC_COMMAND_MAX_FRAME_LENGTH + sizeof(*p_drv->p_buf));
|
||
|
||
if (NULL == p_drv->p_buf) {
|
||
err_flag = 4;
|
||
goto err_out;
|
||
}
|
||
|
||
p_drv->p_buf->base = (uint8_t *)p_drv->p_buf + sizeof(*p_drv->p_buf);
|
||
p_drv->p_buf->end = p_drv->p_buf->base + VC_COMMAND_MAX_FRAME_LENGTH;
|
||
p_drv->p_buf->pos = p_drv->p_buf->base;
|
||
|
||
p_drv->id = VC_DRVID_UART;
|
||
|
||
return ERR_OK;
|
||
|
||
err_out:
|
||
|
||
if (NULL != p_drv) {
|
||
if (NULL != p_drv->hanle_h) {
|
||
iot_uart_close(p_drv->hanle_h);
|
||
}
|
||
os_mem_set(p_drv, 0x0, sizeof(*p_drv));
|
||
}
|
||
|
||
if(err_flag) {
|
||
iot_gpio_close(rx_pin);
|
||
}
|
||
vc_printf("[VC]Uart driver init failed, flag#%d!\n", err_flag);
|
||
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
uint32_t vc_module_upgrade_send_data(uint8_t *p_data, uint32_t len)
|
||
{
|
||
iot_pkt_t *p_pkt;
|
||
|
||
if (NULL == p_data || 0 == len || (!vc_upgd_ready()) || (!vc_task_check_upgrading())) {
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
if (NULL == (p_pkt = iot_pkt_alloc(len, VC_TASK_MODULE_ID))) {
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
os_mem_cpy(iot_pkt_put(p_pkt, len), p_data, len);
|
||
|
||
vc_task.upg_obj.p_drv->send_fn(vc_task.upg_obj.p_drv->hanle_h, p_pkt);
|
||
|
||
return ERR_OK;
|
||
}
|
||
|
||
uint32_t vc_module_upgrade_register_receive(vc_upg_rcv_func fn)
|
||
{
|
||
if (!os_atomic_check_set((int *)&vc_task.upg_obj.rcv_fn , (int)NULL, (int)fn)) {
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
return ERR_OK;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_task_msg_process() - Message process callback function.
|
||
* @task_h : task id with that task who causes this api-call.
|
||
* @msg : message past to this callback api.
|
||
*/
|
||
LOCAL uint32_t vc_module_task_msg_post(uint16_t type, uint16_t id,
|
||
uint32_t data, iot_pkt_t *p_pkt)
|
||
{
|
||
vc_msg_t *vc_msg;
|
||
|
||
vc_msg = (vc_msg_t *)iot_task_alloc_msg_with_reserved(vc_task.p_task_h, 0);
|
||
|
||
if (NULL == vc_msg) {
|
||
if (NULL != p_pkt) {
|
||
iot_pkt_free(p_pkt);
|
||
}
|
||
vc_printf("[VC]msg pool runs out!\n");
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
vc_msg->msg.type = type;
|
||
vc_msg->msg.id = id;
|
||
vc_msg->data = data;
|
||
vc_msg->p_pkt = p_pkt;
|
||
|
||
iot_task_queue_msg(vc_task.p_task_h, &vc_msg->msg, 0);
|
||
|
||
return ERR_OK;
|
||
}
|
||
|
||
uint32_t vc_module_share_timer_register(vc_module_share_timer_func func, uint32_t time_out)
|
||
{
|
||
uint32_t i;
|
||
|
||
if (NULL == func || time_out < VC_TASK_SHARE_TIMER_STEP) {
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
for (i = 0; i < VC_TASK_SHARE_TIMER_COUNT; i++) {
|
||
if (os_atomic_check_set((int *)&g_share_timer[i].fn, (int)NULL, (int)func)) {
|
||
g_share_timer[i].timeout = (time_out % VC_TASK_SHARE_TIMER_STEP) ?
|
||
(time_out / VC_TASK_SHARE_TIMER_STEP + VC_TASK_SHARE_TIMER_STEP) :
|
||
time_out;
|
||
g_share_timer[i].counter = 0;
|
||
vc_dbg("[VC]Share timer reg idx %d, fn %p, timeout %dms.",
|
||
i, func, g_share_timer[i].timeout);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (VC_TASK_SHARE_TIMER_COUNT == i) {
|
||
vc_dbg("[VC]Share timer reg failed, fn %p, timeout %dms.", func, time_out);
|
||
IOT_ASSERT(0);
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
return ERR_OK;
|
||
}
|
||
|
||
LOCAL void vc_module_share_timer_fn(timer_id_t tid, uint32_t timeout)
|
||
{
|
||
if (vc_task.share_timer == tid) {
|
||
vc_module_task_msg_post(VC_MSG_TYPE_TIMER, VC_MSG_TIMER_ID_SHARE_TIMER,
|
||
timeout, NULL);
|
||
} else {
|
||
vc_dbg("[VC]Unknown timer id %d.", tid);
|
||
IOT_ASSERT(0);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_share_timer_process(uint32_t timeout)
|
||
{
|
||
vc_task_share_timer_t *p_stimer;
|
||
uint32_t i;
|
||
|
||
for (i = 0; i < VC_TASK_SHARE_TIMER_COUNT; i++) {
|
||
p_stimer = &g_share_timer[i];
|
||
if (vc_share_timer_active (p_stimer)) {
|
||
p_stimer->counter += timeout;
|
||
if (p_stimer->counter >= p_stimer->timeout) {
|
||
p_stimer->fn(p_stimer->counter);
|
||
p_stimer->counter = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_msg_func_timer(uint16_t id, uint32_t data)
|
||
{
|
||
if (VC_MSG_TIMER_ID_SHARE_TIMER == id) {
|
||
vc_module_share_timer_process(data);
|
||
} else {
|
||
vc_printf("[VC]Unknown timer id %d.\n", id);
|
||
IOT_ASSERT(0);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_data_from_uplink_process(uint32_t chn, iot_pkt_t *p_pkt)
|
||
{
|
||
uint32_t raw_data_len;
|
||
iot_pkt_t *p_frame;
|
||
|
||
if (NULL == p_pkt) {
|
||
return;
|
||
}
|
||
|
||
if (!vc_chn_valid(chn)) {
|
||
iot_pkt_free(p_pkt);
|
||
return;
|
||
}
|
||
|
||
raw_data_len = iot_pkt_data_len(p_pkt);
|
||
|
||
vc_printf("[VC]Channel %d send %d.\n", chn, raw_data_len);
|
||
|
||
vc_buffer_dump("Chn-Dump TX", iot_pkt_data(p_pkt), raw_data_len);
|
||
|
||
/* Fill header & tail in this packet. */
|
||
p_frame = vc_module_frame_build(chn, vc_module_frame_get_next_tx_sequence(), p_pkt);
|
||
|
||
/* Post this frame */
|
||
if (NULL != p_frame) {
|
||
vc_module_task_msg_post(VC_MSG_TYPE_FRAME, VC_MSG_FRM_ID_TO_STM32,
|
||
chn, p_pkt);
|
||
|
||
vc_statistic_tx_byte_add(chn, raw_data_len);
|
||
|
||
vc_statistic_tx_frame_add(chn, 1);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_data_to_uplink_process(uint32_t chn, iot_pkt_t *p_pkt)
|
||
{
|
||
uint32_t d_len;
|
||
vc_task_channel_t *p_chn;
|
||
|
||
if (NULL == p_pkt) {
|
||
return;
|
||
}
|
||
|
||
if (!vc_chn_valid(chn)) {
|
||
iot_pkt_free(p_pkt);
|
||
return;
|
||
}
|
||
|
||
/* Get the data. */
|
||
d_len = iot_pkt_data_len(p_pkt);
|
||
p_chn = vc_task.chn_obj.p_channel[chn];
|
||
|
||
vc_printf("[VC]Channel %d received %d.\n", chn, d_len);
|
||
|
||
vc_statistic_rx_byte_add(chn, d_len);
|
||
|
||
vc_statistic_rx_frame_add(chn, 1);
|
||
|
||
/* Call the callback function to upload data. */
|
||
if (NULL != p_chn && NULL != p_chn->rcv_fn) {
|
||
if (d_len != p_chn->rcv_fn(chn, p_pkt)) {
|
||
vc_printf("[VC]Uplink not receive all data, total length %d.\n", d_len);
|
||
}
|
||
} else {
|
||
vc_printf("[VC]Received data to un-registered channel %d.\n", chn);
|
||
iot_pkt_free(p_pkt);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_msg_func_data() - Process data from/to VP layer.
|
||
* @id : Message id.
|
||
* @chn : Channel of this packet.
|
||
* @p_pkt : Pointer of data packet.
|
||
*/
|
||
LOCAL void vc_module_msg_func_data(uint16_t id, uint32_t chn, iot_pkt_t *p_pkt)
|
||
{
|
||
if (NULL == p_pkt) {
|
||
return;
|
||
}
|
||
|
||
if (!vc_chn_valid(chn)) {
|
||
iot_pkt_free(p_pkt);
|
||
return;
|
||
}
|
||
|
||
vc_dbg("[VC]id %d, chn %d, pkt%p.\n", id, chn, p_pkt);
|
||
|
||
if (VC_MSG_DATA_ID_DOWNLINK == id) {
|
||
vc_module_data_from_uplink_process(chn, p_pkt);
|
||
} else if (VC_MSG_DATA_ID_UPLINK == id) {
|
||
vc_module_data_to_uplink_process(chn, p_pkt);
|
||
} else {
|
||
vc_printf("[VC]Unknown data id %d.\n", id);
|
||
IOT_ASSERT(0);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_frame_from_stm32(uint32_t drv_id, iot_pkt_t *p_frame)
|
||
{
|
||
uint32_t chn;
|
||
|
||
if (NULL == p_frame) {
|
||
return;
|
||
}
|
||
|
||
chn = vc_module_frame_get_channel(iot_pkt_data(p_frame));
|
||
|
||
/* TODO : Check the driver id of channel object. */
|
||
|
||
if ((!vc_drv_id_valid(drv_id))
|
||
|| (!vc_chn_valid(chn))) {
|
||
iot_pkt_free(p_frame);
|
||
return;
|
||
}
|
||
|
||
/* Prepare the payload. */
|
||
iot_pkt_pull(p_frame, VC_COMMAND_FRAME_HEADER_LENGTH);
|
||
iot_pkt_shrink(p_frame, VC_COMMAND_FRAME_TAIL_LENGTH);
|
||
|
||
/* Post as data message. */
|
||
vc_module_task_msg_post(VC_MSG_TYPE_DATA, VC_MSG_DATA_ID_UPLINK,
|
||
chn, p_frame);
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_frame_to_stm32(uint32_t chn, iot_pkt_t *p_frame)
|
||
{
|
||
vc_task_drv_t *p_drv;
|
||
|
||
if (NULL == p_frame) {
|
||
return;
|
||
}
|
||
|
||
if ((!vc_chn_valid(chn))
|
||
|| (NULL == vc_task.chn_obj.p_channel[chn])
|
||
|| (!vc_drv_id_valid(vc_task.chn_obj.p_channel[chn]->drv_id))) {
|
||
iot_pkt_free(p_frame);
|
||
return;
|
||
}
|
||
|
||
/* Get the driver object. */
|
||
p_drv = &vc_task.drv_obj.drv[vc_task.chn_obj.p_channel[chn]->drv_id];
|
||
|
||
/* Send packet to stm32 layer. */
|
||
if (NULL != p_drv && NULL != p_drv->send_fn) {
|
||
if (ERR_OK != p_drv->send_fn(p_drv->hanle_h, p_frame)) {
|
||
vc_printf("[VC]Send frame to stm32 failed, drv id %d.\n",
|
||
vc_task.chn_obj.p_channel[chn]->drv_id);
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_msg_func_frame() - Process frame from/to stm32 layer.
|
||
* @id : Message id.
|
||
* @drv_id : Driver who tx/rx this packet.
|
||
* @p_pkt : Pointer of frame packet.
|
||
*/
|
||
LOCAL void vc_module_msg_func_frame(uint16_t id, uint32_t data, iot_pkt_t *p_pkt)
|
||
{
|
||
if (NULL == p_pkt) {
|
||
return;
|
||
}
|
||
|
||
if (VC_MSG_FRM_ID_FROM_STM32 == id) {
|
||
vc_module_frame_from_stm32(data, p_pkt);
|
||
} else if (VC_MSG_FRM_ID_TO_STM32 == id) {
|
||
vc_module_frame_to_stm32(data, p_pkt);
|
||
} else {
|
||
vc_printf("[VC]Unknown frame id %d.\n", id);
|
||
IOT_ASSERT(0);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_control_start_upgrade(void)
|
||
{
|
||
vc_ack_t *p_ack;
|
||
iot_pkt_t *p_pkt = NULL;
|
||
uint32_t err_flag = 0;
|
||
vc_task_upg_obj_t *p_upg = &vc_task.upg_obj;
|
||
|
||
if (!vc_task_check_upgrading()) {
|
||
p_upg->percentage = 0;
|
||
p_upg->state = VC_UPGRD_STATE_IDLE;
|
||
vc_set_upgrading(vc_task.status.upgrade_sts);
|
||
|
||
iot_uart_set_config(vc_task.upg_obj.p_drv->hanle_h, VC_UPGRD_UART_BAUDRATE,
|
||
IOT_UART_PARITY_EVEN, IOT_UART_DLEN_8_BITS, IOT_UART_STOP_1_BITS);
|
||
if (iot_uart_set_frame(vc_task.upg_obj.p_drv->hanle_h, NULL)) {
|
||
iot_uart_set_threshold(vc_task.upg_obj.p_drv->hanle_h, UART_THR_NO_FMT_TIMEOUT, 0);
|
||
}
|
||
|
||
if (ERR_OK != vc_upgrd_ext_chip_reset(VC_UPGRD_RESET_TO_DOWNLOAD)) {
|
||
vc_printf("[VC]reset ext chip failed!\n");
|
||
}
|
||
/* delay for a period of time to ensure that STM32 program has been working */
|
||
os_delay(50);
|
||
|
||
if (ERR_OK != vc_upgrd_set_start(vc_module_upgrade_send_data)) {
|
||
err_flag = 1;
|
||
}
|
||
}
|
||
|
||
if (NULL == (p_pkt = iot_pkt_alloc(sizeof(*p_ack), VC_TASK_MODULE_ID))) {
|
||
err_flag = 2;
|
||
}
|
||
|
||
if (1 == err_flag) {
|
||
vc_printf("[VC]Start upgrading failed, flag %d!\n", err_flag);
|
||
vc_set_upgrade_fail(vc_task.status.upgrade_sts);
|
||
} else {
|
||
vc_printf("[VC]Start upgrading!\n");
|
||
}
|
||
|
||
if (NULL != p_pkt) {
|
||
p_ack = (vc_ack_t *)iot_pkt_put(p_pkt, sizeof(*p_ack));
|
||
p_ack->ack = VC_ACK_START_UPGD;
|
||
p_ack->payload_len = 0;
|
||
p_ack->ret = err_flag ? ERR_FAIL : ERR_OK;
|
||
|
||
vc_module_msg_func_control_uplink(p_pkt);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_control_stop_upgrade(void)
|
||
{
|
||
vc_ack_t *p_ack;
|
||
iot_pkt_t *p_pkt = NULL;
|
||
uint32_t err_flag = 0;
|
||
vc_task_upg_obj_t *p_upg = &vc_task.upg_obj;
|
||
|
||
if (vc_task_check_upgrading()) {
|
||
if (ERR_OK != vc_upgrd_set_stop()) {
|
||
vc_printf("[VC]Stop upgrading failed!\n");
|
||
err_flag = 1;
|
||
}
|
||
|
||
if (VC_UPGRD_STATE_ERR == p_upg->state) {
|
||
vc_set_upgrade_fail(vc_task.status.upgrade_sts);
|
||
} else {
|
||
vc_set_upgrade_success(vc_task.status.upgrade_sts);
|
||
}
|
||
|
||
p_upg->percentage = 0;
|
||
p_upg->state = VC_UPGRD_STATE_IDLE;
|
||
}
|
||
|
||
iot_uart_set_config(vc_task.upg_obj.p_drv->hanle_h, VC_TASK_UART_BAUDRATE,
|
||
VC_TASK_UART_PARITY, VC_TASK_UART_DATA_LEN, VC_TASK_UART_STOP_BIT);
|
||
iot_uart_set_frame(vc_task.upg_obj.p_drv->hanle_h,
|
||
(iot_frame_fmt *)&vc_uart_frame);
|
||
/* reset stm32 to normal mode. */
|
||
vc_upgrd_ext_chip_reset(VC_UPGRD_RESET_TO_POWERUP);
|
||
|
||
if (NULL == (p_pkt = iot_pkt_alloc(sizeof(*p_ack), VC_TASK_MODULE_ID))) {
|
||
err_flag = 2;
|
||
}
|
||
|
||
if (1 == err_flag) {
|
||
vc_printf("[VC]Stop upgrading failed, flag %d!\n", err_flag);
|
||
vc_set_upgrade_fail(vc_task.status.upgrade_sts);
|
||
} else {
|
||
vc_printf("[VC]Stop upgrading!\n");
|
||
}
|
||
|
||
if (NULL != p_pkt) {
|
||
p_ack = (vc_ack_t *)iot_pkt_put(p_pkt, sizeof(*p_ack));
|
||
p_ack->ack = VC_ACK_STOP_UPGD;
|
||
p_ack->payload_len = 0;
|
||
p_ack->ret = err_flag ? ERR_FAIL : ERR_OK;
|
||
|
||
vc_module_msg_func_control_uplink(p_pkt);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
LOCAL void vc_module_control_get_upgrade_info(void)
|
||
{
|
||
vc_ack_t *p_ack;
|
||
iot_pkt_t *p_pkt = NULL;
|
||
vc_ack_get_upgrade_info_t *p_info;
|
||
vc_task_upg_obj_t *p_upg = &vc_task.upg_obj;
|
||
|
||
if (NULL == (p_pkt = iot_pkt_alloc(sizeof(*p_ack) + sizeof(*p_info), VC_TASK_MODULE_ID))) {
|
||
return;
|
||
}
|
||
|
||
p_ack = (vc_ack_t *)iot_pkt_put(p_pkt, sizeof(*p_ack) + sizeof(*p_info));
|
||
|
||
p_ack->ack = VC_ACK_GET_UPGD_INFO;
|
||
p_ack->ret = ERR_OK;
|
||
p_ack->payload_len = sizeof(*p_info);
|
||
p_info = (vc_ack_get_upgrade_info_t*)p_ack->payload;
|
||
p_info->percentage = p_upg->percentage;
|
||
p_info->state = p_upg->state;
|
||
p_info->rsv[0] = 0;
|
||
p_info->rsv[1] = 0;
|
||
|
||
vc_module_msg_func_control_uplink(p_pkt);
|
||
|
||
return;
|
||
}
|
||
|
||
uint32_t vc_module_command_open(vc_module_ack_rcv_func p_func)
|
||
{
|
||
if ((!vc_task_inited()) || (NULL == p_func)) {
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
vc_task.ack_to_app_fn = p_func;
|
||
|
||
return ERR_OK;
|
||
}
|
||
|
||
LOCAL uint32_t vc_module_command_check_valid(vc_cmd_t *p_cmd)
|
||
{
|
||
uint32_t reason = 0;
|
||
|
||
switch(p_cmd->cmd)
|
||
{
|
||
case VC_CMD_SET_STM32_USB:
|
||
if (p_cmd->payload_len != sizeof(vc_cmd_set_usb_t)) {
|
||
reason = 2;
|
||
}
|
||
break;
|
||
case VC_CMD_SET_STM32_DBG_LOG:
|
||
if (p_cmd->payload_len != sizeof(vc_cmd_set_dbg_log_t)) {
|
||
reason = 2;
|
||
}
|
||
break;
|
||
case VC_CMD_GET_STATISTICS:
|
||
case VC_CMD_GET_STM32_STATUS:
|
||
case VC_CMD_GET_STM32_FW_INFO:
|
||
case VC_CMD_START_UPGD:
|
||
case VC_CMD_STOP_UPGD:
|
||
case VC_CMD_GET_UPGD_INFO:
|
||
if (p_cmd->payload_len != 0) {
|
||
reason = 2;
|
||
}
|
||
break;
|
||
default:
|
||
reason = 1;
|
||
break;
|
||
}
|
||
|
||
if (reason) {
|
||
vc_printf("[VC]Command check failed, cmd=%d, flag=%d.\n",
|
||
p_cmd->cmd, reason);
|
||
}
|
||
|
||
return reason ? 0 : 1;
|
||
}
|
||
|
||
uint32_t vc_module_command_send(vc_cmd_t *p_cmd)
|
||
{
|
||
uint32_t err_flag = 0, pkt_len;
|
||
iot_pkt_t *p_pkt = NULL;
|
||
|
||
if (NULL == p_cmd || (vc_task.status.stm32_auto_upd.enable) ||
|
||
(!vc_module_command_check_valid(p_cmd))) {
|
||
err_flag = 1;
|
||
goto err_out;
|
||
}
|
||
|
||
pkt_len = sizeof(*p_cmd) + p_cmd->payload_len;
|
||
|
||
if (NULL == (p_pkt = iot_pkt_alloc(pkt_len, VC_TASK_MODULE_ID))) {
|
||
err_flag = 2;
|
||
goto err_out;
|
||
}
|
||
|
||
os_mem_cpy(iot_pkt_put(p_pkt, pkt_len), p_cmd, pkt_len);
|
||
|
||
if ( ERR_OK != vc_module_task_msg_post(VC_MSG_TYPE_CONTROL,
|
||
VC_MSG_CTRL_ID_DOWNLINK, 0, p_pkt)) {
|
||
err_flag = 3;
|
||
goto err_out;
|
||
}
|
||
|
||
vc_printf("[VC]Command to proto success, cmd %d.\n", p_cmd->cmd);
|
||
|
||
return ERR_OK;
|
||
|
||
err_out:
|
||
|
||
if (NULL != p_pkt) {
|
||
iot_pkt_free(p_pkt);
|
||
}
|
||
|
||
vc_printf("[VC]Command to proto faild, err_flag=%d.\n", err_flag);
|
||
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_msg_func_control_uplink().
|
||
* @id : Message id.
|
||
* @data : Data from message.
|
||
*/
|
||
LOCAL void vc_module_msg_func_control_uplink(iot_pkt_t *p_pkt)
|
||
{
|
||
vc_ack_t *p_ack;
|
||
|
||
if (NULL == p_pkt) {
|
||
return;
|
||
}
|
||
|
||
p_ack = (vc_ack_t *)iot_pkt_data(p_pkt);
|
||
|
||
vc_printf("[VC]Process ack type %d, ret %d, dlen %d!\n",
|
||
p_ack->ack, p_ack->ret, p_ack->payload_len);
|
||
|
||
switch(p_ack->ack)
|
||
{
|
||
case VC_ACK_GET_STATISTICS:
|
||
{
|
||
vc_chn_statistic_t *p_chn_sts = vc_task.status.statcs;
|
||
vc_ack_get_statistics_t *p_ack_sts = (vc_ack_get_statistics_t *)p_ack->payload;
|
||
uint32_t chn;
|
||
|
||
if (ERR_OK == p_ack->ret
|
||
&& p_ack->payload_len == sizeof(*p_ack_sts) + p_ack_sts->chn_cnt * sizeof(*p_chn_sts)) {
|
||
for (chn = 0; chn < p_ack_sts->chn_cnt; chn++) {
|
||
p_chn_sts = &vc_task.status.statcs[chn];
|
||
/* Keep stm32 info in local mem. */
|
||
p_chn_sts->stm32.recvd.bytes = p_ack_sts->statistics[chn].stm32.recvd.bytes;
|
||
p_chn_sts->stm32.recvd.frames = p_ack_sts->statistics[chn].stm32.recvd.frames;
|
||
p_chn_sts->stm32.sent.bytes = p_ack_sts->statistics[chn].stm32.sent.bytes;
|
||
p_chn_sts->stm32.sent.frames = p_ack_sts->statistics[chn].stm32.sent.frames;
|
||
/* Update K68 info into response data. */
|
||
p_ack_sts->statistics[chn].stm32.recvd.bytes = p_chn_sts->stm32.recvd.bytes;
|
||
p_ack_sts->statistics[chn].stm32.recvd.frames = p_chn_sts->stm32.recvd.frames;
|
||
p_ack_sts->statistics[chn].stm32.sent.bytes = p_chn_sts->stm32.sent.bytes;
|
||
p_ack_sts->statistics[chn].stm32.sent.frames = p_chn_sts->stm32.sent.frames;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case VC_ACK_GET_STM32_FW_INFO:
|
||
{
|
||
vc_ack_get_fw_info_t *p_fw_info = &vc_task.status.fw_info;
|
||
vc_ack_get_fw_info_t *p_ack_info = (vc_ack_get_fw_info_t *)p_ack->payload;
|
||
|
||
if (ERR_OK == p_ack->ret && p_ack->payload_len == sizeof(*p_ack_info)) {
|
||
p_fw_info->remote.crc32 = p_ack_info->remote.crc32;
|
||
p_fw_info->remote.length = p_ack_info->remote.length;
|
||
p_fw_info->remote.version = p_ack_info->remote.version;
|
||
|
||
p_ack_info->local.crc32 = p_fw_info->local.crc32;
|
||
p_ack_info->local.length = p_fw_info->local.length;
|
||
p_ack_info->local.version = p_fw_info->local.version;
|
||
}
|
||
|
||
break;
|
||
}
|
||
case VC_ACK_SET_STM32_USB:
|
||
case VC_ACK_SET_STM32_DBG_LOG:
|
||
case VC_ACK_GET_STM32_STATUS:
|
||
case VC_CMD_START_UPGD:
|
||
case VC_CMD_STOP_UPGD:
|
||
case VC_CMD_GET_UPGD_INFO:
|
||
default:
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (NULL != vc_task.ack_to_app_fn) {
|
||
vc_task.ack_to_app_fn(p_ack);
|
||
}
|
||
|
||
iot_pkt_free(p_pkt);
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_msg_func_control_downlink().
|
||
* @id : Message id.
|
||
* @data : Data from message.
|
||
*/
|
||
LOCAL void vc_module_msg_func_control_downlink(iot_pkt_t *p_pkt)
|
||
{
|
||
vc_cmd_t *p_cmd;
|
||
|
||
if (NULL == p_pkt) {
|
||
IOT_ASSERT(0);
|
||
return;
|
||
}
|
||
|
||
p_cmd = (vc_cmd_t *)iot_pkt_data(p_pkt);
|
||
|
||
vc_printf("[VC]Process command %d.\n", p_cmd->cmd);
|
||
|
||
switch(p_cmd->cmd)
|
||
{
|
||
case VC_CMD_START_UPGD:
|
||
vc_module_control_start_upgrade();
|
||
break;
|
||
case VC_CMD_STOP_UPGD:
|
||
vc_module_control_stop_upgrade();
|
||
break;
|
||
case VC_CMD_GET_UPGD_INFO:
|
||
vc_module_control_get_upgrade_info();
|
||
break;
|
||
default:
|
||
vc_proto_execute_command_from_vc_task(p_cmd);
|
||
break;
|
||
}
|
||
|
||
iot_pkt_free(p_pkt);
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_task_msg_process() - Message process callback function.
|
||
* @task_h : task id with that task who causes this api-call.
|
||
* @msg : message past to this callback api.
|
||
*/
|
||
LOCAL void vc_module_task_msg_process(iot_task_h task_h, iot_task_msg_t *msg)
|
||
{
|
||
vc_msg_t *p_vc_msg = (vc_msg_t *)msg;
|
||
|
||
if (NULL == p_vc_msg) {
|
||
return;
|
||
}
|
||
|
||
switch (p_vc_msg->msg.type) {
|
||
case VC_MSG_TYPE_TIMER :
|
||
vc_module_msg_func_timer(p_vc_msg->msg.id, p_vc_msg->data);
|
||
break;
|
||
case VC_MSG_TYPE_DATA :
|
||
vc_module_msg_func_data(p_vc_msg->msg.id, p_vc_msg->data, p_vc_msg->p_pkt);
|
||
break;
|
||
case VC_MSG_TYPE_FRAME :
|
||
vc_module_msg_func_frame(p_vc_msg->msg.id, p_vc_msg->data, p_vc_msg->p_pkt);
|
||
break;
|
||
case VC_MSG_TYPE_CONTROL :
|
||
if (VC_MSG_CTRL_ID_DOWNLINK == p_vc_msg->msg.id) {
|
||
vc_module_msg_func_control_downlink(p_vc_msg->p_pkt);
|
||
} else {
|
||
vc_module_msg_func_control_uplink(p_vc_msg->p_pkt);
|
||
}
|
||
break;
|
||
default :
|
||
{
|
||
vc_printf("[VC]Process unknown msg type %d!\n", p_vc_msg->msg.type);
|
||
IOT_ASSERT(0);
|
||
break;
|
||
}
|
||
}
|
||
|
||
iot_task_free_msg(task_h, &p_vc_msg->msg);
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief vc_module_task_msg_cancel() - Message cancel callback function.
|
||
* @task_h : task id with that task who causes this api-call.
|
||
* @msg : message past to this callback api.
|
||
*/
|
||
LOCAL void vc_module_task_msg_cancel(iot_task_h task_h, iot_task_msg_t *msg)
|
||
{
|
||
vc_msg_t *p_vc_msg = (vc_msg_t *)msg;
|
||
|
||
if (NULL == p_vc_msg) {
|
||
return;
|
||
}
|
||
|
||
vc_dbg("[VC]MSG cancel tp %d id %d data 0x%x pkt %p.",
|
||
p_vc_msg->msg.type, p_vc_msg->msg.id, p_vc_msg->data, p_vc_msg->p_pkt);
|
||
|
||
switch (p_vc_msg->msg.type) {
|
||
case VC_MSG_TYPE_TIMER :
|
||
case VC_MSG_TYPE_CONTROL :
|
||
case VC_MSG_TYPE_FRAME :
|
||
case VC_MSG_TYPE_DATA :
|
||
{
|
||
if (NULL != p_vc_msg->p_pkt) {
|
||
iot_pkt_free(p_vc_msg->p_pkt);
|
||
}
|
||
break;
|
||
}
|
||
default :
|
||
{
|
||
vc_printf("[VC]Cancel unknown msg type %d!\n", p_vc_msg->msg.type);
|
||
IOT_ASSERT(0);
|
||
break;
|
||
}
|
||
}
|
||
|
||
iot_task_free_msg(task_h, &p_vc_msg->msg);
|
||
|
||
return;
|
||
}
|
||
|
||
uint32_t vc_module_response_send_to_K68(vc_ack_t *p_ack)
|
||
{
|
||
iot_pkt_t *p_pkt;
|
||
uint32_t len, err_flag = 0;
|
||
|
||
if (NULL == p_ack) {
|
||
err_flag = 1;
|
||
goto out;
|
||
}
|
||
|
||
vc_printf("[VC]Response from proto ack %d!\n", p_ack->ack);
|
||
|
||
len = sizeof(*p_ack) + p_ack->payload_len;
|
||
|
||
if (NULL == (p_pkt = iot_pkt_alloc(len, VC_TASK_MODULE_ID))) {
|
||
err_flag = 2;
|
||
goto out;
|
||
}
|
||
|
||
os_mem_cpy(iot_pkt_put(p_pkt, len), p_ack, len);
|
||
|
||
if ( ERR_OK != vc_module_task_msg_post(VC_MSG_TYPE_CONTROL,
|
||
VC_MSG_CTRL_ID_UPLINK, 0, p_pkt)) {
|
||
err_flag = 3;
|
||
goto out;
|
||
}
|
||
|
||
out:
|
||
|
||
if (err_flag) {
|
||
vc_printf("[VC]Send ack failed, flag %d.\n", err_flag);
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
return ERR_OK;
|
||
}
|
||
|
||
uint32_t vc_channel_open(vc_chn_id_e chn, vc_chn_rcv_func p_func, vc_drv_id_e drv_id)
|
||
{
|
||
vc_task_channel_t *p_chn = NULL;
|
||
vc_task_drv_t *p_drv;
|
||
int err_flag;
|
||
|
||
/* It is NOT allowed to open before init. */
|
||
if (!vc_task_inited()) {
|
||
err_flag = 0;
|
||
goto failed_out;
|
||
}
|
||
|
||
if ((!vc_chn_valid(chn))
|
||
|| (!vc_drv_id_valid(drv_id))
|
||
|| (NULL == p_func)
|
||
|| vc_channel_inited(chn)) {
|
||
vc_dbg("Param invalid.\n");
|
||
err_flag = 1;
|
||
goto failed_out;
|
||
}
|
||
|
||
if (NULL == (p_chn = (vc_task_channel_t *)os_mem_malloc(VC_TASK_MODULE_ID,
|
||
sizeof(*p_chn)))) {
|
||
vc_dbg("Channel malloc failed.\n");
|
||
err_flag = 2;
|
||
goto failed_out;
|
||
}
|
||
|
||
os_mem_set(p_chn, 0x0, sizeof(*p_chn));
|
||
|
||
if (!vc_port_inited(drv_id)) {
|
||
p_drv = &vc_task.drv_obj.drv[drv_id];
|
||
if (ERR_OK != p_drv->init_fn(p_drv)) {
|
||
vc_dbg("Driver %d init failed.\n", drv_id);
|
||
err_flag = 3;
|
||
goto failed_out;
|
||
}
|
||
}
|
||
|
||
p_chn->drv_id = drv_id;
|
||
p_chn->rcv_fn = p_func;
|
||
|
||
if (!os_atomic_check_set((int *)&vc_task.chn_obj.p_channel[chn], (int)NULL, (int)p_chn)) {
|
||
vc_dbg("Channel already in use.\n");
|
||
err_flag = 4;
|
||
goto failed_out;
|
||
}
|
||
|
||
vc_printf("[VC]Channel %d open successfully.\n", chn);
|
||
|
||
return ERR_OK;
|
||
|
||
failed_out:
|
||
|
||
if (NULL != p_chn) {
|
||
os_mem_free(p_chn);
|
||
}
|
||
|
||
vc_printf("[VC]Channel %d open failed, flag#%d.\n", chn, err_flag);
|
||
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
uint32_t vc_channel_send(vc_chn_id_e chn, uint8_t *p_buf, uint32_t len)
|
||
{
|
||
int err_flag;
|
||
iot_pkt_t *p_pkt = NULL;
|
||
uint32_t send_len = 0, data_len;
|
||
uint8_t *data_pos = NULL;
|
||
|
||
if ((!vc_task_inited())
|
||
||(!vc_channel_inited(chn))
|
||
|| (NULL == p_buf)
|
||
|| (0 == len)) {
|
||
err_flag = 0;
|
||
goto failed_out;
|
||
}
|
||
|
||
if (vc_task_check_upgrading() || (vc_task.status.stm32_auto_upd.enable &&
|
||
(VC_CMD_CHNID != chn))) {
|
||
err_flag = 1;
|
||
goto failed_out;
|
||
}
|
||
|
||
vc_dbg("[VC]Channel#%d buf%p len#%d.\n", chn, p_buf, len);
|
||
|
||
data_len = len;
|
||
data_pos = p_buf;
|
||
|
||
do {
|
||
if (VC_COMMAND_MAX_PAYLOAD_LENGTH < data_len) {
|
||
send_len = VC_COMMAND_MAX_PAYLOAD_LENGTH;
|
||
} else {
|
||
send_len = data_len;
|
||
}
|
||
|
||
if (NULL == (p_pkt = vc_module_frame_alloc(data_pos, send_len))) {
|
||
err_flag = 2;
|
||
goto failed_out;
|
||
}
|
||
|
||
vc_module_task_msg_post(VC_MSG_TYPE_DATA, VC_MSG_DATA_ID_DOWNLINK,
|
||
chn, p_pkt);
|
||
|
||
data_len -= send_len;
|
||
data_pos += send_len;
|
||
} while(data_len > 0);
|
||
|
||
return len;
|
||
|
||
failed_out:
|
||
|
||
if (NULL != p_pkt) {
|
||
iot_pkt_free(p_pkt);
|
||
}
|
||
|
||
vc_printf("[VC]Channel %d droped data len#%d, flag#%d.\n", chn, len, err_flag);
|
||
|
||
return 0;
|
||
}
|
||
|
||
uint32_t vc_module_init(void)
|
||
{
|
||
int err_flag = 0;
|
||
iot_task_h iot_task_handle = NULL;
|
||
iot_task_config_t task_cfg;
|
||
vc_task_drv_t *p_drv;
|
||
|
||
if (iot_board_get_virtual_uart_port_num() == 0) {
|
||
vc_printf("[VC]Virtual channel not supported on this board!.\n");
|
||
return ERR_OK;
|
||
}
|
||
|
||
if (vc_task_inited()) {
|
||
err_flag = 0;
|
||
goto failed_out;
|
||
}
|
||
|
||
os_mem_set(&task_cfg, 0x0, sizeof(task_cfg));
|
||
os_mem_set(&vc_task, 0x0, sizeof(vc_task));
|
||
|
||
task_cfg.stack_size = VC_TASK_STACK_SIZE;
|
||
task_cfg.task_prio = VC_TASK_PRIORITY;
|
||
task_cfg.msg_size = VC_TASK_MSG_SIZE;
|
||
task_cfg.msg_cnt = VC_TASK_MSG_CNT;
|
||
task_cfg.queue_cnt = 1;
|
||
task_cfg.queue_cfg[0].quota = 0;
|
||
task_cfg.msg_exe_func = vc_module_task_msg_process;
|
||
task_cfg.msg_cancel_func = vc_module_task_msg_cancel;
|
||
|
||
iot_task_handle = iot_task_create(VC_TASK_MODULE_ID, &task_cfg);
|
||
|
||
if (NULL == iot_task_handle) {
|
||
err_flag = 1;
|
||
goto failed_out;
|
||
}
|
||
|
||
vc_task.share_timer = os_create_timer(VC_TASK_MODULE_ID, 1,
|
||
(void *)vc_module_share_timer_fn, (void *)VC_TASK_SHARE_TIMER_STEP);
|
||
|
||
if ((timer_id_t)NULL == vc_task.share_timer) {
|
||
err_flag = 2;
|
||
goto failed_out;
|
||
}
|
||
|
||
if (!os_atomic_check_set((int *)&vc_task.p_task_h, 0, (int)iot_task_handle)) {
|
||
err_flag = 3;
|
||
goto failed_out;
|
||
}
|
||
|
||
/* Uart driver. */
|
||
p_drv = &(vc_task.drv_obj.drv[VC_DRVID_UART]);
|
||
p_drv->init_fn = (p_drv_init_fn)vc_module_drv_init_uart;
|
||
|
||
/* Spi driver. */
|
||
p_drv = &(vc_task.drv_obj.drv[VC_DRVID_SPI]);
|
||
p_drv->init_fn = (p_drv_init_fn)vc_module_drv_init_spi;
|
||
|
||
os_mem_set(g_share_timer, 0x0, sizeof(g_share_timer));
|
||
|
||
if (ERR_OK != vc_module_share_timer_register(vc_module_stm32_status_update_timer_fn,
|
||
VC_TASK_UPDATE_TIMER_TIMEOUT)) {
|
||
err_flag = 4;
|
||
goto failed_out;
|
||
}
|
||
|
||
/* Uart for upgrading. */
|
||
vc_task.upg_obj.p_drv = &vc_task.drv_obj.drv[VC_DRVID_UART];
|
||
|
||
vc_task.status.upgrade_sts = VC_FLAG_UPGRADE_READY;
|
||
vc_task.status.error_status.k68 = VC_STS_HST_READY;
|
||
vc_task.status.error_status.stm32 = 0;
|
||
|
||
#if STM32_CHECK_UPGRADE
|
||
vc_task.status.stm32_auto_upd.enable = 1;
|
||
#endif
|
||
|
||
if (ERR_OK != vc_proto_init()) {
|
||
vc_printf("[VC]VC-TASK proto init failed!\n");
|
||
err_flag = 5;
|
||
goto failed_out;
|
||
}
|
||
|
||
if (ERR_OK != vc_upgrade_module_init()) {
|
||
vc_printf("[VC]VC-TASK upgrade init failed!\n");
|
||
err_flag = 6;
|
||
goto failed_out;
|
||
}
|
||
|
||
/* Get local fimware information. */
|
||
vc_upgrd_get_firmware_info(&vc_task.status.fw_info.local);
|
||
|
||
os_start_timer(vc_task.share_timer, VC_TASK_SHARE_TIMER_STEP);
|
||
|
||
vc_printf("[VC]VC-TASK initialization successful!\n");
|
||
|
||
return ERR_OK;
|
||
|
||
failed_out:
|
||
|
||
if (NULL != iot_task_handle) {
|
||
iot_task_delete(iot_task_handle);
|
||
vc_task.p_task_h = NULL;
|
||
}
|
||
|
||
if ((timer_id_t)NULL == vc_task.share_timer) {
|
||
os_delete_timer(vc_task.share_timer);
|
||
vc_task.share_timer = (timer_id_t)NULL;
|
||
}
|
||
|
||
vc_printf("[VC]VC-TASK initialization faild, flag %d!\n", err_flag);
|
||
|
||
return ERR_FAIL;
|
||
}
|
||
|
||
#endif /* INCLUDE_VIRTUAL_CHANNEL */
|