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

445 lines
17 KiB
C
Raw Permalink 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) @CompanyNameMagicTag 2021-2021. All rights reserved.
* Description: transmit data
* This file should be changed only infrequently and with great care.
*/
#include "transmit_src.h"
#include "transmit_dst.h"
#include "transmit_st.h"
#include "transmit_item.h"
#include "transmit_send_recv_pkt.h"
#include "transmit_write_read.h"
#include "dfx_feature_config.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 "string.h"
#include "securec.h"
#include "zdiag_adapt_layer.h"
#include "errcode.h"
STATIC uint32_t transmit_data_read(transmit_item_t *item, uint32_t offset, uint8_t *buf, uint32_t size)
{
transmit_read_hook read_handler = (transmit_read_hook)item->write_read;
return (uint32_t)read_handler(item->usr_wr_data, offset, buf, size);
}
/* 作为源端(读取数据并发送数据的一端)读取并发送数据 */
STATIC errcode_t transmit_process_data_request_one(transmit_item_t *item, uint32_t offset, uint32_t size,
diag_option_t *option, bool down_machine)
{
transmit_data_reply_pkt_t *pkt = NULL;
uint32_t data_size;
uint32_t tlv_ext_len;
uint32_t pkt_size;
int32_t send_size = 0;
int32_t left_size = (int32_t)size;
int32_t read_size, readed_size;
uint16_t block_size = (item->data_block_size == 0) ? DEFAULT_TRANSMIT_BLOCK_SIZE : item->data_block_size;
transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item,
sizeof(transmit_pkt_tlv_t) + sizeof(uint16_t) + sizeof(transmit_data_reply_pkt_t) + block_size);
if (tlv == NULL) {
return ERRCODE_MALLOC;
}
while ((left_size) != 0) {
read_size = uapi_min(left_size, block_size);
data_size = (uint32_t)sizeof(transmit_data_reply_pkt_t) + (uint32_t)read_size;
tlv_ext_len = transmit_get_tlv_ext_len(data_size);
pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + tlv_ext_len + data_size;
tlv->type = transmit_build_tlv_type(1, 1);
tlv->len = transmit_build_tlv_len(data_size);
if (tlv_ext_len > 0) {
(void)memcpy_s(tlv->data, tlv_ext_len, ((uint8_t *)&data_size), tlv_ext_len);
}
pkt = (transmit_data_reply_pkt_t *)((uint8_t *)tlv + sizeof(transmit_pkt_tlv_t) + tlv_ext_len);
(void)memset_s(pkt->data, (uint32_t)read_size, 0, (uint32_t)read_size);
readed_size = (int32_t)transmit_data_read(item, offset + send_size, pkt->data, (uint32_t)read_size);
if (readed_size <= 0) {
dfx_log_err("[ERR][transmit src] read data failed!, offset = 0x%x, read_size = %d readed_size = %d\r\n",
offset + send_size, read_size, readed_size);
transmit_send_failed_pkt(item->transmit_id, &item->option, item->down_machine);
goto end;
}
pkt->transmit_id = item->transmit_id;
pkt->offset = offset + (uint32_t)send_size;
pkt->size = (uint32_t)readed_size;
transmit_send_packet(DIAG_CMD_ID_TRANSMIT_REPLY, (uint8_t *)tlv, pkt_size, option, down_machine);
left_size -= readed_size;
send_size += readed_size;
}
end:
transmit_item_free_pkt_buf(item, (void *)tlv);
return ERRCODE_SUCC;
}
/* 作为源端读取数据并发送数据的一端发送NEGOTIATE(协商)ACK帧 */
STATIC void transmit_src_item_send_negotiate_ack(transmit_item_t *item)
{
uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + (uint32_t)sizeof(transmit_negotiate_ack_pkt_t);
transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item, pkt_size);
if (tlv == NULL) {
return;
}
tlv->type = transmit_build_tlv_type(1, 2); /* the type is assigned 2 in ack command */
tlv->len = transmit_build_tlv_len(sizeof(transmit_negotiate_ack_pkt_t));
transmit_negotiate_ack_pkt_t *pkt = (transmit_negotiate_ack_pkt_t *)tlv->data;
(void)memset_s((uint8_t *)pkt, sizeof(transmit_negotiate_ack_pkt_t), 0, sizeof(transmit_negotiate_ack_pkt_t));
pkt->transmit_id = item->transmit_id;
pkt->data_block_number = item->data_block_number;
pkt->data_block_size = item->data_block_size;
pkt->info_size = 0;
(void)transmit_send_packet(DIAG_CMD_ID_TRANSMIT_NEGOTIATE, (uint8_t *)tlv, pkt_size,
&item->option, item->down_machine);
transmit_item_free_pkt_buf(item, (void *)tlv);
}
STATIC void transmit_src_item_send_negotiate(transmit_item_t *item)
{
uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + (uint32_t)sizeof(transmit_negotiate_pkt_t);
transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item, pkt_size);
if (tlv == NULL) {
return;
}
tlv->type = transmit_build_tlv_type(1, 1);
tlv->len = transmit_build_tlv_len(sizeof(transmit_negotiate_pkt_t));
transmit_negotiate_pkt_t *pkt = (transmit_negotiate_pkt_t *)tlv->data;
(void)memset_s((uint8_t *)pkt, sizeof(transmit_negotiate_pkt_t), 0, sizeof(transmit_negotiate_pkt_t));
pkt->transmit_id = item->transmit_id;
pkt->src_send = 0;
pkt->transmit_type = item->remote_type;
pkt->total_size = item->total_size;
(void)transmit_send_packet(DIAG_CMD_ID_TRANSMIT_NEGOTIATE, (uint8_t *)tlv, pkt_size,
&item->option, item->down_machine);
transmit_item_free_pkt_buf(item, (void *)tlv);
}
STATIC transmit_item_t *transmit_src_item_init(uint32_t transmit_id)
{
transmit_item_t *item = transmit_item_match_id(transmit_id);
if (item != NULL) {
transmit_item_disable(item, 0);
transmit_item_deinit(item);
}
item = transmit_item_init(transmit_id);
return item;
}
STATIC void transmit_src_item_init_info(transmit_item_t *item, uint16_t transmit_type,
uint32_t total_size, bool re_trans)
{
unused(re_trans);
transmit_item_init_permanent(item, false);
transmit_item_init_local_start(item, false);
transmit_item_init_local_src(item, true);
transmit_item_init_remote_type(item, transmit_type);
switch (transmit_type) {
case TRANSMIT_TYPE_READ_FILE:
case TRANSMIT_TYPE_DUMP:
case TRANSMIT_TYPE_READ_MEMORY:
transmit_item_init_local_type(item, TRANSMIT_LOCAL_TYPE_READ_FILE);
break;
case TRANSMIT_TYPE_READ_FLASH:
transmit_item_init_local_type(item, TRANSMIT_LOCAL_TYPE_READ_DATA);
break;
default:
break;
}
transmit_item_init_read_handler(item, file_read_data, (uintptr_t)item);
transmit_item_init_total_size(item, total_size);
}
STATIC errcode_t transmit_src_item_start_negotiate_ack(transmit_item_t *item)
{
if (transmit_item_init_is_success(item) == false) {
transmit_item_deinit(item);
dfx_log_err("[ERR][transmit src]init is failed\r\n");
return ERRCODE_FAIL;
}
#if (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_YES)
item->file_fd = dfx_file_open_for_read(item->file_name);
if (item->file_fd < 0) {
dfx_log_err("[ERR][transmit src]file : %s open failed, fd = %d\r\n", item->file_name, item->file_fd);
transmit_send_failed_pkt(item->transmit_id, &item->option, item->down_machine);
item->file_fd = 0;
transmit_item_deinit(item);
return ERRCODE_FAIL;
}
#endif
transmit_item_enable(item);
if (item->data_block_number == DEFAULT_TRANSMIT_BLOCK_NUMBER &&
item->data_block_size == DEFAULT_TRANSMIT_BLOCK_SIZE) {
transmit_src_item_send_negotiate(item);
} else {
transmit_src_item_send_negotiate_ack(item);
}
return ERRCODE_SUCC;
}
/* 作为源端读取数据并发送数据的一端处理REQUEST帧 */
errcode_t transmit_src_item_process_data_request_frame(transmit_data_request_pkt_t *request_pkt,
diag_option_t *option, bool from_upper_machine)
{
uint32_t i;
uint32_t cur_time = dfx_get_cur_second();
transmit_item_t *item = transmit_item_match_id(request_pkt->transmit_id);
if (item == NULL) {
dfx_log_err("[ERR][transmit src]request match id failed!, id = 0x%x\r\n", request_pkt->transmit_id);
return transmit_send_invalid_id(request_pkt->transmit_id, option, from_upper_machine);
}
item->last_rcv_pkt_time = cur_time;
item->last_send_pkt_time = cur_time;
if ((item->local_start != 0) && (item->step == TRANSMIT_STEP_START)) {
item->step = TRANSMIT_STEP_TRANSMIT;
}
for (i = 0; i < request_pkt->cnt; i++) {
transmit_process_data_request_one(item, request_pkt->item[i].offset, request_pkt->item[i].size, option,
from_upper_machine);
}
return ERRCODE_SUCC;
}
/* 作为源端读取数据并发送数据的一端处理START帧 */
errcode_t transmit_src_item_process_start_frame(transmit_start_pkt_t *start_pkt, diag_option_t *option,
bool from_upper_machine)
{
dfx_assert(start_pkt);
transmit_save_info_t *file_info = (transmit_save_info_t *)start_pkt->info;
transmit_save_data_info_t *data_info = (transmit_save_data_info_t *)start_pkt->info;
transmit_item_t *item = transmit_src_item_init(start_pkt->transmit_id);
if (item == NULL) {
dfx_log_err("[ERR][transmit src]init failed\r\n");
return ERRCODE_FAIL;
}
switch (start_pkt->transmit_type) {
case TRANSMIT_TYPE_READ_FILE:
case TRANSMIT_TYPE_DUMP:
case TRANSMIT_TYPE_READ_MEMORY:
transmit_src_item_init_info(item, start_pkt->transmit_type, start_pkt->total_size, start_pkt->re_trans);
transmit_item_init_file_name(item, file_info->file_name, file_info->name_size);
break;
case TRANSMIT_TYPE_READ_FLASH:
transmit_src_item_init_info(item, start_pkt->transmit_type, start_pkt->total_size, start_pkt->re_trans);
transmit_item_init_local_bus_addr(item, data_info->start_addr);
break;
default:
break;
}
transmit_item_init_option(item, option);
transmit_item_init_down_machine(item, from_upper_machine);
transmit_item_init_data_block_size(item, DEFAULT_TRANSMIT_BLOCK_SIZE);
transmit_item_init_data_block_number(item, DEFAULT_TRANSMIT_BLOCK_NUMBER);
return transmit_src_item_start_negotiate_ack(item);
}
/* 作为源端读取数据并发送数据的一端处理START帧 */
errcode_t transmit_src_item_process_negotiate_frame(transmit_negotiate_pkt_t *negotiate_pkt,
diag_option_t *option, bool from_upper_machine)
{
dfx_assert(negotiate_pkt);
transmit_save_info_t *file_info = (transmit_save_info_t *)negotiate_pkt->info;
transmit_item_t *item = transmit_src_item_init(negotiate_pkt->transmit_id);
if (item == NULL) {
dfx_log_err("[ERR][transmit src]init failed\r\n");
return ERRCODE_FAIL;
}
transmit_src_item_init_info(item, negotiate_pkt->transmit_type, negotiate_pkt->total_size, negotiate_pkt->re_trans);
transmit_item_init_option(item, option);
transmit_item_init_down_machine(item, from_upper_machine);
transmit_item_init_file_name(item, file_info->file_name, file_info->name_size);
transmit_item_init_data_block_size(item, negotiate_pkt->data_block_size);
transmit_item_init_data_block_number(item, negotiate_pkt->data_block_number);
return transmit_src_item_start_negotiate_ack(item);
}
#if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES)
STATIC void zdiag_save_file_send_start_pkt(transmit_item_t *item)
{
transmit_start_pkt_t *start_pkt = NULL;
transmit_save_info_t *save_file_info = NULL;
uint32_t name_size = 0;
uint32_t info_size = 0;
if (item->file_name != NULL) {
name_size = (uint32_t)strlen(item->file_name) + 1;
info_size = (uint32_t)sizeof(transmit_save_info_t) + name_size;
}
uint32_t data_size = (uint32_t)sizeof(transmit_start_pkt_t) + info_size;
uint32_t tlv_ext_len = transmit_get_tlv_ext_len(data_size);
uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + tlv_ext_len + data_size;
transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item, pkt_size);
if (tlv == NULL) {
goto end;
}
tlv->type = transmit_build_tlv_type(1, 1);
tlv->len = transmit_build_tlv_len(data_size);
if (tlv_ext_len > 0) {
(void)memcpy_s(tlv->data, tlv_ext_len, ((uint8_t *)&data_size), tlv_ext_len);
}
start_pkt = (transmit_start_pkt_t *)((uint8_t *)tlv + sizeof(transmit_pkt_tlv_t) + tlv_ext_len);
if (item->file_name != NULL) {
save_file_info = (transmit_save_info_t *)start_pkt->info;
save_file_info->name_size = (uint16_t)name_size;
memcpy_s(save_file_info->file_name, name_size, item->file_name, name_size);
}
start_pkt->transmit_id = item->transmit_id;
start_pkt->transmit_type = item->remote_type;
start_pkt->total_size = item->total_size;
start_pkt->info_size = info_size;
start_pkt->pad = 0;
start_pkt->re_trans = item->re_trans;
start_pkt->src_send = 1;
start_pkt->struct_ver = 0;
transmit_send_packet(DIAG_CMD_ID_TRANSMIT_START, (uint8_t *)tlv, pkt_size, &item->option, item->down_machine);
end:
transmit_item_free_pkt_buf(item, tlv);
return;
}
#endif
void transmit_src_item_send_start_frame(transmit_item_t *item, uint32_t cur_time)
{
#if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES)
switch (item->remote_type) {
case TRANSMIT_TYPE_SAVE_FILE:
case TRANSMIT_TYPE_SAVE_OTA_IMG:
case TRANSMIT_TYPE_WRITE_MEMORY:
case TRANSMIT_TYPE_WRITE_FLASH:
zdiag_save_file_send_start_pkt(item);
break;
default:
break;
}
#endif
item->last_send_pkt_time = cur_time;
return;
}
void transmit_src_item_process_timer(transmit_item_t *item, uint32_t cur_time)
{
uint32_t out_time = item->last_rcv_pkt_time + TRANSMIT_OUT_TIME;
if (cur_time > out_time) {
transmit_item_finish(item, TRANSMIT_DISABLE_TIME_OUT);
#if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES)
transmit_result_hook result_hook = (transmit_result_hook)item->result_hook;
if (result_hook != NULL && item->local_start == true) {
result_hook(false, (uintptr_t)NULL);
}
#endif
return;
}
#if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES)
uint32_t retry_time = uapi_min(item->last_send_pkt_time, item->last_rcv_pkt_time) + TRANSMIT_RETRY_TIME;
if ((item->local_start != 0) && (item->step == TRANSMIT_STEP_START) && (cur_time > retry_time)) {
/* send pkt and modify retry time */
transmit_src_item_send_start_frame(item, cur_time);
}
#endif
}
#if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES)
/* 作为上位机源端接收数据端发送START帧 */
errcode_t transmit_src_send_file_start(transmit_type_t transmit_type, diag_addr dst, uint32_t total_size,
bool re_transmit, transmit_result_hook handler)
{
diag_option_t option = DIAG_OPTION_INIT_VAL;
option.peer_addr = dst;
switch (transmit_type) {
case TRANSMIT_TYPE_SAVE_FILE:
case TRANSMIT_TYPE_SAVE_OTA_IMG:
case TRANSMIT_TYPE_WRITE_MEMORY:
case TRANSMIT_TYPE_WRITE_FLASH:
break;
default:
return ERRCODE_INVALID_PARAM;
}
transmit_item_t *item = transmit_item_init(0);
if (item == NULL) {
return ERRCODE_FAIL;
}
transmit_item_init_permanent(item, false);
transmit_item_init_local_start(item, true);
transmit_item_init_local_src(item, true);
transmit_item_init_remote_type(item, transmit_type);
transmit_item_init_local_type(item, TRANSMIT_LOCAL_TYPE_READ_FILE);
transmit_item_init_read_handler(item, file_read_data, (uintptr_t)item);
transmit_item_init_option(item, &option);
transmit_item_init_down_machine(item, false);
transmit_item_init_total_size(item, total_size);
transmit_item_init_result_handler(item, handler, (uintptr_t)item);
transmit_item_init_re_trans(item, re_transmit);
if (transmit_item_init_is_success(item) == false) {
transmit_item_deinit(item);
return ERRCODE_FAIL;
}
transmit_item_enable(item);
return ERRCODE_SUCC;
}
/* 作为上位机源端接收数据端发送STOP帧 */
errcode_t transmit_src_send_file_stop(transmit_type_t transmit_type, diag_addr dst)
{
errcode_t ret;
diag_option_t option = DIAG_OPTION_INIT_VAL;
option.peer_addr = dst;
transmit_item_t *item = transmit_item_match_type_and_dst(transmit_type, dst);
if (item == NULL) {
dfx_log_debug("stop match id failed!, type = 0x%x, dst = 0x%x\r\n", transmit_type, dst);
return transmit_send_invalid_id(0, &option, false);
}
transmit_item_finish(item, TRANSMIT_DISABLE_USER_STOP);
uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + (uint32_t)sizeof(transmit_stop_pkt_t);
transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item, pkt_size);
tlv->type = transmit_build_tlv_type(1, 2); /* the type is assigned 2 in ack command */
tlv->len = transmit_build_tlv_len(sizeof(transmit_stop_pkt_t));
transmit_stop_pkt_t *stop_pkt = (transmit_stop_pkt_t *)tlv->data;
stop_pkt->transmit_id = item->transmit_id;
stop_pkt->reason = ERRCODE_SUCC;
ret = transmit_send_packet(DIAG_CMD_ID_TRANSMIT_STOP, (uint8_t *)tlv, pkt_size, &option, false);
transmit_item_free_pkt_buf(item, tlv);
return ret;
}
#endif