mcu_hi3321_watch/middleware/utils/dfx/diag_transmit/transmit_item.c
2025-05-26 20:15:20 +08:00

554 lines
16 KiB
C

/*
* Copyright (c) @CompanyNameMagicTag 2021-2021. All rights reserved.
* Description: transmit data
* This file should be changed only infrequently and with great care.
*/
#include "transmit_item.h"
#include "securec.h"
#include "transmit_st.h"
#include "transmit_send_recv_pkt.h"
#include "soc_osal.h"
#include "zdiag_adapt_layer.h"
#include "transmit_src.h"
#include "transmit_dst.h"
#include "dfx_adapt_layer.h"
#include "errcode.h"
#if CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_YES
#include "dfx_file_operation.h"
#endif
#include "transmit_debug.h"
#include "transmit_cmd_id.h"
#include "transmit.h"
#include "diag_msg.h"
#include "diag_dfx.h"
#define TRANSMIT_ITEM_CNT 3
#define TRANSMIT_TIMER_PERIOD 1000
#define TRANSMIT_ITEM_BUF_LEN 0x600
#define TRANSMIT_MSG_PROC_MAX 10
typedef struct {
void *is_busy;
uint32_t transmit_id;
uint8_t used_cnt;
uint8_t period_cnt;
uint32_t buf_used : 1;
uint32_t pkt_size;
uint8_t *pkt_buf;
uint8_t timer_cnt;
osal_timer timer;
transmit_item_t item[TRANSMIT_ITEM_CNT];
} transmit_ctrl_t;
transmit_ctrl_t g_transmit_ctrl;
static transmit_msg_proc_t g_transmit_msg_proc[TRANSMIT_MSG_PROC_MAX] = {0};
STATIC void transmit_timer_stop(void);
errcode_t transmit_send_invalid_id(uint32_t transmit_id, diag_option_t *option, bool down_machine)
{
errcode_t ret;
uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + (uint32_t)sizeof(transmit_state_notify_pkt_t);
transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(NULL, pkt_size);
if (tlv == NULL) {
return ERRCODE_MALLOC;
}
tlv->type = transmit_build_tlv_type(1, 1);
tlv->len = transmit_build_tlv_len(sizeof(transmit_state_notify_pkt_t));
transmit_state_notify_pkt_t *pkt = (transmit_state_notify_pkt_t *)tlv->data;
pkt->transmit_id = transmit_id;
pkt->state_code = TRANSMIT_STATE_NOTIFY_INVALID_ID;
pkt->len = 0;
ret = transmit_send_packet(DIAG_CMD_ID_TRANSMIT_NOTIFY, (uint8_t *)tlv, pkt_size, option, down_machine);
transmit_item_free_pkt_buf(NULL, tlv);
return ret;
}
errcode_t transmit_send_finish_pkt(uint32_t transmit_id, diag_option_t *option, bool down_machine)
{
errcode_t ret;
uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + (uint32_t)sizeof(transmit_state_notify_pkt_t);
transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(NULL, pkt_size);
if (tlv == NULL) {
return ERRCODE_MALLOC;
}
tlv->type = transmit_build_tlv_type(1, 1);
tlv->len = transmit_build_tlv_len(sizeof(transmit_state_notify_pkt_t));
transmit_state_notify_pkt_t *pkt = (transmit_state_notify_pkt_t *)tlv->data;
pkt->transmit_id = transmit_id;
pkt->state_code = TRANSMIT_STATE_NOTIFY_FINISH;
pkt->len = 0;
ret = transmit_send_packet(DIAG_CMD_ID_TRANSMIT_NOTIFY, (uint8_t *)tlv, pkt_size, option, down_machine);
transmit_item_free_pkt_buf(NULL, tlv);
return ret;
}
errcode_t transmit_send_failed_pkt(uint32_t transmit_id, diag_option_t *option, bool down_machine)
{
errcode_t ret;
uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + (uint32_t)sizeof(transmit_state_notify_pkt_t);
transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(NULL, pkt_size);
if (tlv == NULL) {
return ERRCODE_MALLOC;
}
tlv->type = transmit_build_tlv_type(1, 1);
tlv->len = transmit_build_tlv_len(sizeof(transmit_state_notify_pkt_t));
transmit_state_notify_pkt_t *pkt = (transmit_state_notify_pkt_t *)tlv->data;
pkt->transmit_id = transmit_id;
pkt->state_code = TRANSMIT_STATE_NOTIFY_SAVE_FAILED_ID;
pkt->len = 0;
ret = transmit_send_packet(DIAG_CMD_ID_TRANSMIT_NOTIFY, (uint8_t *)tlv, pkt_size, option, down_machine);
transmit_item_free_pkt_buf(NULL, tlv);
return ret;
}
void transmit_item_process_notify_frame(transmit_state_notify_pkt_t *pkt, diag_option_t *option,
bool from_upper_machine)
{
dfx_assert(pkt);
transmit_item_t *item = transmit_item_match_id(pkt->transmit_id);
if (item == NULL) {
if (pkt->state_code != TRANSMIT_STATE_NOTIFY_INVALID_ID) {
dfx_log_err("[ERR]notify_frame match id failed!, id = 0x%x\r\n", pkt->transmit_id);
transmit_send_invalid_id(pkt->transmit_id, option, from_upper_machine);
}
return;
}
transmit_result_hook result_hook = (transmit_result_hook)item->result_hook;
switch (pkt->state_code) {
case TRANSMIT_STATE_NOTIFY_INVALID_ID:
transmit_item_finish(item, TRANSMIT_DISABLE_RECV_INVALID_ID);
break;
case TRANSMIT_STATE_NOTIFY_FINISH:
case TRANSMIT_STATE_NOTIFY_FINISH_2:
transmit_item_finish(item, TRANSMIT_DISABLE_RECV_FINISH);
if (item->remote_type == TRANSMIT_TYPE_READ_FILE || item->remote_type == TRANSMIT_TYPE_DUMP) {
transmit_send_finish_pkt(item->transmit_id, &item->option, item->down_machine);
}
if (result_hook != NULL && item->local_start == true) {
result_hook(true, (uintptr_t)NULL);
}
break;
case TRANSMIT_STATE_NOTIFY_DUPLICATE_ID:
break;
default:
break;
}
}
transmit_item_t *transmit_item_match_id(uint32_t transmit_id)
{
transmit_item_t *item = NULL;
for (int i = 0; i < TRANSMIT_ITEM_CNT; i++) {
item = &g_transmit_ctrl.item[i];
if ((item->used != 0) && (item->transmit_id == transmit_id) && (transmit_id != 0)) {
return item;
}
}
return NULL;
}
transmit_item_t *transmit_item_match_type_and_dst(transmit_type_t transmit_type, diag_addr dst)
{
transmit_item_t *item = NULL;
for (int i = 0; i < TRANSMIT_ITEM_CNT; i++) {
item = &g_transmit_ctrl.item[i];
if ((item->used != 0) && (item->remote_type == transmit_type) && (item->option.peer_addr == dst)) {
return item;
}
}
return NULL;
}
transmit_item_t *transmit_item_init(uint32_t transmit_id)
{
transmit_item_t *item = NULL;
for (int i = 0; i < TRANSMIT_ITEM_CNT; i++) {
item = &g_transmit_ctrl.item[i];
if (item->used == true) {
continue;
}
memset_s(item, sizeof(transmit_item_t), 0x0, sizeof(transmit_item_t));
if (transmit_id == 0) {
item->transmit_id = g_transmit_ctrl.transmit_id++;
} else {
item->transmit_id = transmit_id;
}
item->used = true;
if (item->pm_veto == 0) {
(void)dfx_pm_add_sleep_veto();
item->pm_veto = 1;
}
return item;
}
return NULL;
}
void transmit_item_init_permanent(transmit_item_t *item, bool permanent)
{
dfx_assert(item);
item->permanent = permanent;
}
void transmit_item_init_local_start(transmit_item_t *item, bool local_start)
{
dfx_assert(item);
item->local_start = local_start;
}
void transmit_item_init_local_src(transmit_item_t *item, bool local_src)
{
dfx_assert(item);
item->local_src = local_src;
}
void transmit_item_init_remote_type(transmit_item_t *item, transmit_type_t remote_type)
{
dfx_assert(item);
item->remote_type = remote_type;
}
void transmit_item_init_local_type(transmit_item_t *item, transmit_local_type_t local_type)
{
dfx_assert(item);
item->local_type = local_type;
}
void transmit_item_init_write_handler(transmit_item_t *item, transmit_write_hook handler, uintptr_t usr_data)
{
dfx_assert(item);
item->write_read = (uintptr_t)handler;
item->usr_wr_data = usr_data;
}
void transmit_item_init_read_handler(transmit_item_t *item, transmit_read_hook handler, uintptr_t usr_data)
{
dfx_assert(item);
item->write_read = (uintptr_t)handler;
item->usr_wr_data = usr_data;
}
void transmit_item_init_result_handler(transmit_item_t *item, transmit_result_hook handler, uintptr_t usr_data)
{
dfx_assert(item);
unused(usr_data);
item->result_hook = (uintptr_t)handler;
}
void transmit_item_init_local_bus_addr(transmit_item_t *item, uint32_t bus_addr)
{
dfx_assert(item);
item->bus_addr = bus_addr;
}
void transmit_item_init_file_name(transmit_item_t *item, const char *file_name, uint16_t name_len)
{
dfx_assert(file_name);
dfx_assert(item);
uint32_t name_size = name_len + 1;
item->file_name = dfx_malloc(0, name_size);
if (item->file_name == NULL) {
item->init_fail = true;
return;
}
memset_s(item->file_name, name_size, 0, name_size);
memcpy_s(item->file_name, name_len, file_name, name_len);
}
void transmit_item_init_option(transmit_item_t *item, diag_option_t *option)
{
dfx_assert(item);
item->option = *option;
}
void transmit_item_init_down_machine(transmit_item_t *item, bool down_machine)
{
dfx_assert(item);
item->down_machine = down_machine;
}
void transmit_item_init_received_size(transmit_item_t *item, uint32_t offset)
{
dfx_assert(item);
item->received_size = offset;
}
void transmit_item_init_total_size(transmit_item_t *item, uint32_t total_size)
{
dfx_assert(item);
item->total_size = total_size;
}
void transmit_item_init_re_trans(transmit_item_t *item, bool re_trans)
{
dfx_assert(item);
item->re_trans = re_trans;
}
void transmit_item_init_data_block_size(transmit_item_t *item, uint16_t data_block_size)
{
dfx_assert(item);
item->data_block_size = data_block_size;
}
void transmit_item_init_data_block_number(transmit_item_t *item, uint16_t data_block_number)
{
dfx_assert(item);
item->data_block_number = data_block_number;
}
bool transmit_item_init_is_success(const transmit_item_t *item)
{
dfx_assert(item);
if (item->init_fail != 0) {
return false;
} else {
return true;
}
}
void transmit_item_deinit(transmit_item_t *item)
{
dfx_assert(item);
if (item->file_name) {
dfx_free(0, item->file_name);
item->file_name = NULL;
}
if (item->pm_veto == 1) {
(void)dfx_pm_remove_sleep_veto();
item->pm_veto = 0;
}
item->used = false;
}
void transmit_item_disable(transmit_item_t *item, transmit_disable_reason_t reason)
{
dfx_assert(item);
if (item->permanent == false) {
g_transmit_ctrl.timer_cnt--;
if (g_transmit_ctrl.timer_cnt == 0) {
transmit_timer_stop();
}
}
unused(reason);
item->enable = false;
}
void transmit_item_enable(transmit_item_t *item)
{
dfx_assert(item);
uint32_t cur_time = dfx_get_cur_second();
if ((item->local_start) != 0) {
item->step = TRANSMIT_STEP_START;
transmit_src_item_send_start_frame(item, cur_time);
} else {
item->step = TRANSMIT_STEP_TRANSMIT;
}
if (item->permanent == false) {
item->last_rcv_pkt_time = cur_time;
item->last_send_pkt_time = cur_time;
item->expiration = cur_time + TRANSMIT_RETRY_TIME;
g_transmit_ctrl.timer_cnt++;
if (g_transmit_ctrl.timer_cnt == 1) {
transmit_timer_start();
}
}
item->enable = true;
}
void transmit_item_finish(transmit_item_t *item, transmit_disable_reason_t reason)
{
dfx_assert(item);
transmit_item_disable(item, reason);
if (item->file_fd != 0) {
#if CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_YES
dfx_file_fsync(item->file_fd);
dfx_file_close(item->file_fd);
#endif
item->file_fd = 0;
}
transmit_item_deinit(item);
}
void* transmit_item_get_pkt_buf(const transmit_item_t *item, uint32_t buf_size)
{
dfx_assert(item);
unused(item);
if (g_transmit_ctrl.pkt_size == 0) {
g_transmit_ctrl.pkt_size = TRANSMIT_ITEM_BUF_LEN;
g_transmit_ctrl.pkt_buf = dfx_malloc(0, TRANSMIT_ITEM_BUF_LEN);
}
if ((buf_size < g_transmit_ctrl.pkt_size) && (g_transmit_ctrl.buf_used == 0)) {
g_transmit_ctrl.buf_used = true;
return g_transmit_ctrl.pkt_buf;
}
return NULL;
}
void transmit_item_free_pkt_buf(const transmit_item_t *item, const void *buf)
{
g_transmit_ctrl.buf_used = false;
unused(item);
unused(buf);
}
typedef struct {
osal_timer g_transmit_timer;
bool start;
} transmit_timer_t;
transmit_timer_t g_transmit_timer;
STATIC void transmit_item_time_out(transmit_item_t *item, uint32_t cur_time)
{
dfx_assert(item);
if ((item->local_src) != 0) {
transmit_src_item_process_timer(item, cur_time);
} else {
transmit_dst_item_process_timer(item, cur_time);
}
}
STATIC void transmit_period_msg_proc(void)
{
transmit_item_t *item = NULL;
uint32_t cur_sec = dfx_get_cur_second();
for (int i = 0; i < TRANSMIT_ITEM_CNT; i++) {
item = &g_transmit_ctrl.item[i];
if ((item->enable != 0) && (item->permanent == false) && (cur_sec > item->expiration)) {
transmit_item_time_out(item, cur_sec);
}
}
return;
}
errcode_t transmit_msg_proc_hook_register(uint32_t msg_id_start, uint32_t msg_id_end, transmit_register_hook hook)
{
if (msg_id_start >= msg_id_end || hook == NULL) {
return ERRCODE_FAIL;
}
transmit_msg_proc_t *msg_proc;
for (int i = 0; i < TRANSMIT_MSG_PROC_MAX; i++) {
msg_proc = &g_transmit_msg_proc[i];
if (!((msg_id_end < msg_proc->id_start) || (msg_id_start > msg_proc->id_end))) {
// 有msg_id范围重叠
return ERRCODE_FAIL;
}
if (msg_proc->used != 1) {
msg_proc->id_start = msg_id_start;
msg_proc->id_end = msg_id_end;
msg_proc->used = 1;
msg_proc->hook = (uintptr_t)hook;
return ERRCODE_SUCC;
}
}
return ERRCODE_FAIL;
}
errcode_t transmit_msg_proc_hook_unregister(transmit_register_hook hook)
{
transmit_msg_proc_t *msg_proc;
for (int i = 0; i < TRANSMIT_MSG_PROC_MAX; i++) {
msg_proc = &g_transmit_msg_proc[i];
if ((msg_proc->used == 1) && (((transmit_register_hook)msg_proc->hook) == hook)) {
msg_proc->id_start = 0;
msg_proc->id_end = 0;
msg_proc->used = 0;
msg_proc->hook = (uintptr_t)NULL;
return ERRCODE_SUCC;
}
}
return ERRCODE_FAIL;
}
static errcode_t transmit_run_hook(uint32_t msg_id, const uint8_t *msg, uint32_t msg_len)
{
transmit_msg_proc_t *msg_proc;
for (int i = 0; i < TRANSMIT_MSG_PROC_MAX; i++) {
msg_proc = &g_transmit_msg_proc[i];
if ((msg_proc->used == 1) && (msg_id > msg_proc->id_start) &&
(msg_id < msg_proc->id_end) && (((transmit_register_hook)msg_proc->hook) != NULL)) {
((transmit_register_hook)msg_proc->hook)(msg_id, msg, msg_len);
return ERRCODE_SUCC;
}
}
return ERRCODE_FAIL;
}
errcode_t transmit_msg_proc(uint32_t msg_id, const uint8_t *msg, uint32_t msg_len)
{
diag_dfx_transmit_rev_msg();
if (msg_id > DFX_MSG_ID_RESERVE_MAX) {
return transmit_run_hook(msg_id, msg, msg_len);
}
switch (msg_id) {
case DFX_MSG_ID_DIAG_PKT:
diag_msg_proc((uint16_t)msg_id, (uint8_t *)msg, msg_len);
break;
case DFX_MSG_ID_TRANSMIT_FILE:
transmit_period_msg_proc();
break;
default:
break;
}
return ERRCODE_SUCC;
}
STATIC void transmit_timer_handler(unsigned long data)
{
osal_timer *timer = &g_transmit_ctrl.timer;
transmit_msg_write(DFX_MSG_ID_TRANSMIT_FILE, (uint8_t *)(uintptr_t)data, sizeof(data), false);
if ((g_transmit_ctrl.timer_cnt) != 0) {
osal_timer_start(timer);
}
}
void transmit_timer_start(void)
{
osal_timer *timer = &g_transmit_ctrl.timer;
osal_timer_start(timer);
}
STATIC void transmit_timer_stop(void) {}
STATIC errcode_t transmit_timer_init(void)
{
osal_timer *timer = &g_transmit_ctrl.timer;
timer->handler = transmit_timer_handler;
timer->data = 0;
timer->interval = TRANSMIT_TIMER_PERIOD;
if (osal_timer_init(timer) < 0) {
return ERRCODE_FAIL;
}
return ERRCODE_SUCC;
}
errcode_t transmit_item_module_init(void)
{
errcode_t ret;
ret = transmit_timer_init();
if (ret != ERRCODE_SUCC) {
return ret;
}
g_transmit_ctrl.transmit_id = 0x10;
return ERRCODE_SUCC;
}