Files
kunlun/driver/extern/virtualchannel/src/vc_task.c
2024-09-28 14:24:04 +08:00

2087 lines
59 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
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 */