/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2021. All rights reserved. * Description: Initial Draft * Author: Hisilicon * Create: 2012-12-22 */ #include #include #include #include #include #include "soc_errno.h" #ifndef SOCT_MDBG_VERSION_LINUX // Android version #include #include #endif #include "soc_log.h" #include "securec.h" #include "mpi_dbg_ir_debug.h" #include "mpi_dbg_gpio_debug.h" #include "mpi_dbg_i2c_debug.h" #include "mpi_dbg_pwm_debug.h" #include "mpi_dbg_panel_debug.h" #include "mpi_dbg_pq_debug.h" #include "uapi_uart.h" #include "mpi_mdbg.h" #include "mpi_system_ext.h" #include "uapi_system.h" #include "mpi_dbg_aq.h" #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif /* __cplusplus */ #undef LOG_MODULE_ID #define LOG_MODULE_ID SOC_ID_SYS #define BACKLOG 20 #define MAXLEN 32 #define MDBG_CMDBUF_SIZE (0xFFFF + 0x100) #define mdbg_offset_of(s, m) ((size_t) & (((s *)0)->m)) #define mdbg_size_of(s, m) (sizeof(((s *)0)->m)) #define mdbg_get_value(buf, s, m) ((*(s *)(buf)).m) #define BUFLEN 1000 #define mdbg_check_return_if_fail(param, errno, str) do { \ if (param) { \ fprintf(stderr, "[%s %d] %s\n", __FUNCTION__, __LINE__, (str)); \ return errno; \ } \ } while (0) /* ----------------------------------------------------------------------------- */ /* Local Types Declarations */ /* ----------------------------------------------------------------------------- */ static td_s32 g_server_sock_fd = -1; static td_s32 g_net_process_flag = 1; static td_s32 g_port = 4321; static td_bool g_init = TD_FALSE; static pthread_t g_muart_debug_pid; static pthread_t g_mnet_debug_pid; static td_u8 *g_buf = TD_NULL; static td_bool g_pq_dbg = TD_TRUE; static td_bool g_debug_request = TD_FALSE; static td_bool g_debug_mode = TD_FALSE; static td_bool g_exit_dbg = TD_FALSE; static td_s32 g_net_dev_fd = -1; static td_bool g_net_use = TD_TRUE; static td_bool g_is_cts_enable = TD_FALSE; static td_bool g_uart_open_dev = TD_TRUE; static td_bool g_uart_switch = TD_FALSE; static struct timespec g_delay = { 0 }; static ext_mdbg_chip g_mdbg_chip; static td_u8 g_magic_char[] = {'s', 'o', 'c', 't', '_', 'p', 'q', '_', 't', 'o', 'o', 'l', '.', 's', 'h'}; /* 串口消息数据包 */ /* VRC send "soct_pq_tool.sh" then send 12byte data to dbg thread. */ /* so this message struct should 2 byte alignment. */ #pragma pack(2) typedef struct { td_u8 magic_num[4]; /* 魔数: 'H''L''T''V' 最多4个字符组成 */ td_u16 cmd; /* 命令, 参考MDBG_CMD_E */ td_u16 length; /* mdbg_data 的有效数据长度 */ td_u32 header_check_sum; /* 头校验码 */ td_u8 *mdbg_data; /* 有效数据 */ td_u32 data_check_sum; /* 有效数据校验码 */ } ext_mdbg_msg; #pragma pack() /* PQ命令 */ typedef enum { /* COMMON */ EXT_MDBG_CMD_UART_SWITCH = 0x1000, EXT_MDBG_CMD_ECHO_ACK = 0x1001, /* TV */ EXT_MDBG_CMD_PQ = 0x6000, EXT_MDBG_CMD_AQ = 0x7000, /* PANEL */ EXT_MDBG_CMD_PANEL = 0x8000, /* IR */ EXT_MDBG_CMD_IR = 0x9000, EXT_MDBG_CMD_VIR, /* 新添加COMM,GPIO,I2C,PWM */ EXT_MDBG_CMD_COMM, EXT_MDBG_CMD_GPIO, EXT_MDBG_CMD_I2C, EXT_MDBG_CMD_PWM } ext_mdbg_cmd_type; static td_void *iapi_mdbg_net_server_start(td_void *para); static td_s32 iapi_mdbg_net_create_thread(td_void); static td_void *iapi_mdbg_net_process(td_void *args); static td_void iapi_mdbg_net_send_flag(td_s32 client_sockfd, td_u8 error); static td_void iapi_mdbg_net_read_data(td_u8 *buf, td_s32 count, td_s32 *read_size); static td_void iapi_mdbg_net_write_data(const td_u8 *buf, td_s32 count); static td_s32 iapi_mdbg_net_recv_data(td_s32 client_sockfd, td_u8 *buf, td_u32 count, td_s32 *read_size); static td_s32 iapi_mdbg_net_check_data(const td_u8 *buf); static td_s32 iapi_mdbg_parser_msg(const td_u8 *buf); static td_void iapi_mdbg_uart_read_data(td_u8 *buf, td_s32 count, td_s32 *read_size); static td_void iapi_mdbg_uart_write_data(td_u8 *buf, td_s32 count); static td_s32 iapi_mdbg_uart_open_dev(td_void); static td_void *iapi_mdbg_uart_thread(td_void *para); static td_s32 iapi_mdbg_uart_close_dev(td_void); static td_s32 iapi_mdbg_uart_read_msg(td_u8 *buf); td_bool iapi_mdbg_is_valid_msg(const td_u8 *magic_num) { if (magic_num == TD_NULL) { soc_err_print_null_pointer(magic_num); return TD_FALSE; } /* 判断0,1,2,3个数组元素的值 */ if ((magic_num[0] != 'H') || (magic_num[1] != 'L') || (magic_num[2] != 'T') || (magic_num[3] != 'V')) { return TD_FALSE; } return TD_TRUE; } /* 数据头数据校验 */ td_s32 iapi_mdbg_verify_header_checksum(const td_u8 *buf) { td_size_t total_len, i; td_u32 check_sum1; td_u32 check_sum2 = 0; if (buf == TD_NULL) { soc_err_print_null_pointer(buf); return TD_FAILURE; } /* re-calculate checksum */ total_len = mdbg_offset_of(ext_mdbg_msg, header_check_sum); check_sum1 = mdbg_get_value(buf, ext_mdbg_msg, header_check_sum); for (i = 0; i < total_len; i++) { check_sum2 += buf[i]; } /* compare checksum */ if (check_sum1 != check_sum2) { fprintf(stderr, "check header check_sum error!,check_sum1=%x,check_sum2=%x\n", check_sum1, check_sum2); return TD_FAILURE; } return TD_SUCCESS; } /* 数据有效数据校验 */ td_s32 iapi_mdbg_verify_data_checksum(const td_u8 *buf, td_u32 checksum) { td_u32 total_len, i; td_u32 check_sum1 = 0; td_size_t header_size; if (buf == TD_NULL) { soc_err_print_null_pointer(buf); return TD_FAILURE; } /* re-calculate checksum */ header_size = mdbg_offset_of(ext_mdbg_msg, mdbg_data); total_len = mdbg_get_value(buf, ext_mdbg_msg, length); for (i = 0; i < total_len; i++) { check_sum1 += buf[i + header_size]; } /* compare checksum */ if (checksum != check_sum1) { return TD_FAILURE; } return TD_SUCCESS; } /* 解析数据 */ td_s32 iapi_mdbg_parser_msg(const td_u8 *buf) { td_u32 data_length; td_u16 mdbg_cmd; const td_u8 *cmd_buf = TD_NULL; if (buf == TD_NULL) { soc_err_print_null_pointer(buf); return TD_FAILURE; } mdbg_cmd = mdbg_get_value(buf, ext_mdbg_msg, cmd); cmd_buf = buf + mdbg_offset_of(ext_mdbg_msg, mdbg_data); data_length = mdbg_get_value(buf, ext_mdbg_msg, length); soc_log_info("iapi:%u\n", mdbg_cmd); switch (mdbg_cmd) { case EXT_MDBG_CMD_UART_SWITCH: uapi_uart_switch(0); // switch to system uart g_debug_mode = TD_FALSE; g_net_use = TD_TRUE; break; case EXT_MDBG_CMD_ECHO_ACK: case EXT_MDBG_CMD_VIR: break; case EXT_MDBG_CMD_PQ: mpi_pq_dbg_parser(cmd_buf, data_length); break; case EXT_MDBG_CMD_AQ: mpi_aq_dbg_parser((td_u8 *)cmd_buf, (td_s32)data_length); break; case EXT_MDBG_CMD_PANEL: mpi_panel_dbg_parser(cmd_buf, data_length); break; case EXT_MDBG_CMD_IR: mpi_ir_dbg_parser(cmd_buf, data_length); break; case EXT_MDBG_CMD_COMM: // don't delete mpi_comm_dbg_parser(cmd_buf, data_length); break; case EXT_MDBG_CMD_GPIO: mpi_gpio_dbg_parser(cmd_buf, data_length); break; case EXT_MDBG_CMD_I2C: mpi_i2c_dbg_parser(cmd_buf, data_length); break; case EXT_MDBG_CMD_PWM: // don't delete mpi_pwm_dbg_parser(cmd_buf, data_length); break; default: fprintf(stderr, "MDBG not have this CMD: %X\n", mdbg_cmd); } return TD_SUCCESS; } td_void iapi_mdbg_read_data(td_u8 *buf, td_s32 count, td_s32 *read_size) { if (buf == TD_NULL) { soc_log_err("buf was null!\n"); return; } if (read_size == TD_NULL) { soc_log_err("read_size was null!\n"); return; } if (g_net_use == TD_TRUE) { iapi_mdbg_net_read_data(buf, count, read_size); } else { iapi_mdbg_uart_read_data(buf, count, read_size); } return; } td_void iapi_mdbg_write_data(td_u8 *buf, td_s32 count) { if (buf == TD_NULL) { soc_log_err("buf was null!\n"); return; } if (g_net_use == TD_TRUE) { iapi_mdbg_net_write_data(buf, count); } else { iapi_mdbg_uart_write_data(buf, count); } return; } static td_void iapi_mdbg_reigster_func(td_void) { mpi_pq_dbg_register_uart_func(iapi_mdbg_read_data, iapi_mdbg_write_data); mpi_aq_dbg_register_uart_func(iapi_mdbg_read_data, iapi_mdbg_write_data); mpi_panel_dbg_register_uart_func(iapi_mdbg_read_data, iapi_mdbg_write_data); // don't delete mpi_pwm_dbg_register_uart_func(iapi_mdbg_read_data, iapi_mdbg_write_data); // don't delete mpi_comm_dbg_register_uart_func(iapi_mdbg_read_data, iapi_mdbg_write_data); mpi_ir_dbg_register_uart_func(iapi_mdbg_read_data, iapi_mdbg_write_data); mpi_gpio_dbg_register_uart_func(iapi_mdbg_read_data, iapi_mdbg_write_data); mpi_i2c_dbg_register_uart_func(iapi_mdbg_read_data, iapi_mdbg_write_data); } #ifndef SOCT_MDBG_VERSION_LINUX // Android version static td_void iapi_mdbg_check_user_version(td_bool *cts_enable) { char value[PROPERTY_VALUE_MAX] = {0}; property_get("ro.build.type", value, "eng"); value[PROPERTY_VALUE_MAX - 1] = '\0'; if (strcmp(value, "user") == 0) { *cts_enable = TD_TRUE; fprintf(stderr, "android user version, close port 4321 \n"); } } #endif static td_s32 iapi_mdbg_start_net_server(td_void) { td_s32 ret; if (!g_is_cts_enable) { g_net_process_flag = 1; ret = pthread_create(&g_mnet_debug_pid, NULL, iapi_mdbg_net_server_start, NULL); if (ret != TD_SUCCESS) { /* here free g_buf will make uart fail,so not do it */ soc_log_err("Server thread create error\n"); return TD_FAILURE; } } return TD_SUCCESS; } /* Debug模块初始化 */ td_s32 uapi_mdbg_init(td_void) { td_s32 ret; uapi_sys_init(); if (g_init == TD_TRUE) { return TD_SUCCESS; } ret = ext_mpi_mdbg_get_chipversion(&g_mdbg_chip); if (ret != TD_SUCCESS) { fprintf(stderr, "get chipversion failed...\n"); return TD_FAILURE; } /* alloc cmd buffer memory */ g_buf = (td_u8 *)malloc(MDBG_CMDBUF_SIZE); if (g_buf == TD_NULL) { fprintf(stderr, "mdebug cmd buffer malloc error\n"); return TD_FAILURE; } ret = memset_s(g_buf, MDBG_CMDBUF_SIZE, 0x00, MDBG_CMDBUF_SIZE); if (ret != EOK) { goto ERR_EXIT; } /* 注册回调函数 */ iapi_mdbg_reigster_func(); /* open uart device */ ret = iapi_mdbg_uart_open_dev(); if (ret != TD_SUCCESS) { soc_log_err("iapi_mdbg_uart_open_dev failed!\n"); } /* create uart recv thread */ ret = pthread_create(&g_muart_debug_pid, NULL, iapi_mdbg_uart_thread, g_buf); if (ret != TD_SUCCESS) { g_uart_open_dev = TD_FALSE; // don't delete mpi_pq_dbg_update_uart_status(g_uart_open_dev, g_pq_dbg, g_uart_switch, g_is_cts_enable); fprintf(stderr, "open_uart_dev or mdebug thread create error\n"); goto ERR_EXIT; } /* 4. 启动Net server */ #ifndef SOCT_MDBG_VERSION_LINUX // Android version iapi_mdbg_check_user_version(&g_is_cts_enable); #endif // don't delete mpi_pq_dbg_update_uart_status(g_uart_open_dev, g_pq_dbg, g_uart_switch, g_is_cts_enable); ret = iapi_mdbg_start_net_server(); if (ret != TD_SUCCESS) { goto ERR_EXIT; } g_init = TD_TRUE; // #endif return TD_SUCCESS; ERR_EXIT: free(g_buf); g_buf = TD_NULL; return TD_FAILURE; } /* Debug模块去初始化 */ td_s32 uapi_mdbg_deinit(td_void) { td_s32 ret; soc_dbg_func_enter(); if (g_init == TD_FALSE) { soc_dbg_func_exit(); return TD_SUCCESS; } g_net_process_flag = -1; g_exit_dbg = TD_TRUE; ret = pthread_join(g_muart_debug_pid, NULL); if (ret != TD_SUCCESS) { soc_log_err("uart thread join error\n"); return TD_FAILURE; } soc_log_info("uart thread join success\n"); ret = iapi_mdbg_uart_close_dev(); if (ret != TD_SUCCESS) { soc_log_err("uart device close error\n"); return TD_FAILURE; } soc_log_info("iapi_mdbg_uart_close_dev success\n"); g_debug_mode = TD_FALSE; soc_info_print_bool(g_is_cts_enable); if (!g_is_cts_enable) { ret = pthread_join(g_mnet_debug_pid, NULL); if (ret != TD_SUCCESS) { soc_log_err("net thread join error\n"); return TD_FAILURE; } soc_log_info("net thread join success\n"); shutdown(g_server_sock_fd, 2); // 2代表关屏 soc_log_info("shutdown g_server_sock_fd success\n"); close(g_server_sock_fd); g_server_sock_fd = -1; soc_log_info("close g_server_sock_fd success\n"); } if (g_buf != TD_NULL) { free(g_buf); g_buf = TD_NULL; } g_init = TD_FALSE; uapi_sys_deinit(); soc_dbg_func_exit(); // #endif return TD_SUCCESS; } td_s32 uapi_mdbg_enter_debug_mode(td_bool enable) { g_pq_dbg = enable; return TD_SUCCESS; } /* 获取调试模式 */ td_s32 uapi_mdbg_get_debug_mode(td_bool *enable) { if (enable == TD_NULL) { soc_log_err("enable was null!\n"); return TD_FAILURE; } *enable = g_pq_dbg; return TD_SUCCESS; } td_void *iapi_mdbg_net_server_start(td_void *para) { td_s32 ret, temp_fd; td_u32 client_len; struct sockaddr_in addr_serv, addr_client; (td_void)(para); g_server_sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (g_server_sock_fd < 0) { perror("socket fail"); return NULL; } if (memset_s(&addr_serv, sizeof(addr_serv), 0, sizeof(addr_serv)) != EOK) { perror("call memset_s failed!\n"); close(g_server_sock_fd); g_server_sock_fd = -1; return NULL; } addr_serv.sin_family = AF_INET; addr_serv.sin_port = htons(g_port); addr_serv.sin_addr.s_addr = htonl(INADDR_ANY); client_len = sizeof(struct sockaddr_in); if (bind(g_server_sock_fd, (struct sockaddr *)&addr_serv, sizeof(struct sockaddr_in)) < 0) { perror("bind fail"); } if (listen(g_server_sock_fd, BACKLOG) < 0) { perror("listen fail"); } while (g_net_process_flag == 1) { printf("begin accept:\n"); temp_fd = accept(g_server_sock_fd, (struct sockaddr *)&addr_client, (socklen_t *)&client_len); if (temp_fd < 0) { perror("accept fail"); continue; } if (g_net_dev_fd < 0) { g_net_dev_fd = temp_fd; } else { fprintf(stderr, "last connection is not closed!\n"); (void)close(temp_fd); continue; } ret = iapi_mdbg_net_create_thread(); if (ret != TD_SUCCESS) { fprintf(stderr, "UAPI_MDBG_CreateThread error!\n"); continue; } } return TD_NULL; } td_s32 iapi_mdbg_net_create_thread(td_void) { pthread_t thread; td_s32 ret; pthread_attr_t child_thread_attr; pthread_attr_init(&child_thread_attr); pthread_attr_setdetachstate(&child_thread_attr, PTHREAD_CREATE_DETACHED); ret = pthread_create(&thread, &child_thread_attr, iapi_mdbg_net_process, (void *)g_buf); // 创建子线程 if (ret != TD_SUCCESS) { fprintf(stderr, "pthread_create error!\n"); pthread_attr_destroy(&child_thread_attr); return TD_FAILURE; } pthread_attr_destroy(&child_thread_attr); return TD_SUCCESS; } td_void *iapi_mdbg_net_process(td_void *args) { td_s32 ret; if (args == TD_NULL) { soc_log_err("args was null!\n"); return TD_NULL; } if (g_net_use != TD_TRUE) { fprintf(stderr, "Uart is use, Net can't use!\n"); return TD_NULL; } while (1) { td_s32 readesize = 0; /* 1.接收数据 */ ret = iapi_mdbg_net_recv_data(g_net_dev_fd, (td_u8 *)args, MDBG_CMDBUF_SIZE, &readesize); if (ret != TD_SUCCESS || readesize <= 0) { fprintf(stderr, "iapi_mdbg_net_recv_data failed!\n"); iapi_mdbg_net_send_flag(g_net_dev_fd, 0xC0); break; } /* 2.校验数据 */ ret = iapi_mdbg_net_check_data((td_u8 *)args); if (ret != TD_SUCCESS) { fprintf(stderr, "check data failed! [%i]\n", ret); iapi_mdbg_net_send_flag(g_net_dev_fd, 0xC0); break; } /* 3.解析数据 */ iapi_mdbg_net_send_flag(g_net_dev_fd, 0xD0); ret = iapi_mdbg_parser_msg((td_u8 *)args); if (ret != TD_SUCCESS) { fprintf(stderr, "Parser data failed!\n"); } iapi_mdbg_net_send_flag(g_net_dev_fd, 0xE0); break; } ret = close(g_net_dev_fd); while (errno == EINTR) { g_delay.tv_sec = 0; g_delay.tv_nsec = 10 * 1000; // 10 * 1000 ns = 10us nanosleep(&g_delay, TD_NULL); ret = close(g_net_dev_fd); } if (ret != TD_SUCCESS) { fprintf(stdout, "close net_dev_fd failed!\n"); return TD_NULL; } else { g_net_dev_fd = -1; } fprintf(stdout, "connection close!\n"); return TD_NULL; } td_void iapi_mdbg_net_send_flag(td_s32 client_sockfd, td_u8 error) { td_u8 ack; ack = error; send(client_sockfd, (void *)&ack, 1, 0); while (errno == EINTR || errno == EAGAIN) { g_delay.tv_sec = 0; g_delay.tv_nsec = 10 * 1000; // 10 * 1000 ns = 10us nanosleep(&g_delay, TD_NULL); send(client_sockfd, (void *)&ack, 1, 0); } } static td_u32 mdbg_get_msg_header_size(td_void) { td_u32 header_size; header_size = mdbg_size_of(ext_mdbg_msg, magic_num); header_size += mdbg_size_of(ext_mdbg_msg, cmd); header_size += mdbg_size_of(ext_mdbg_msg, length); header_size += mdbg_size_of(ext_mdbg_msg, header_check_sum); return header_size; } td_s32 iapi_mdbg_net_recv_data(td_s32 client_sockfd, td_u8 *buf, td_u32 count, td_s32 *read_size) { td_s32 recv_cnt; fd_set read_fds; struct timeval timeout; td_s32 ret; td_u32 header_size, data_offset, len; mdbg_check_return_if_fail(buf == TD_NULL, TD_FAILURE, "buf is NULL!"); mdbg_check_return_if_fail(read_size == TD_NULL, TD_FAILURE, "read_size is NULL!"); FD_ZERO(&read_fds); FD_SET(client_sockfd, &read_fds); timeout.tv_sec = 5; // 设置时间5s timeout.tv_usec = 0; if (select(client_sockfd + 1, &read_fds, NULL, NULL, &timeout) <= 0) { fprintf(stderr, "socketfd select failed or time out\n"); return TD_FAILURE; } header_size = mdbg_get_msg_header_size(); if (FD_ISSET(client_sockfd, &read_fds)) { // 测试sock是否可读,即网络上是否有数据 ret = recv(client_sockfd, buf, header_size, MSG_WAITALL); // 前12个字节代表头 while (errno == EINTR || errno == EAGAIN) { g_delay.tv_sec = 0; g_delay.tv_nsec = 10 * 1000; // 10 * 1000ns is 10us nanosleep(&g_delay, TD_NULL); if (recv(client_sockfd, buf, header_size, MSG_WAITALL) >= 0) { break; } } if ((ret < (td_s32)header_size) || (header_size > count)) { return TD_FAILURE; } len = mdbg_get_value(buf, ext_mdbg_msg, length) + sizeof(td_u32); // mdbg_data length+chceksum if (len > count - header_size) { return TD_FAILURE; } data_offset = (td_u32)mdbg_offset_of(ext_mdbg_msg, mdbg_data); do { recv_cnt = recv(client_sockfd, buf + data_offset, len, MSG_WAITALL); } while ((recv_cnt < 0) && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)); mdbg_check_return_if_fail(recv_cnt <= 0, TD_FAILURE, "error! recv_cnt <= 0"); mdbg_check_return_if_fail(recv_cnt != (td_s32)len, TD_FAILURE, "error! recv_cnt != (td_s32)len"); *read_size = (td_s32)(len + header_size); } return TD_SUCCESS; } td_s32 iapi_mdbg_net_check_data(const td_u8 *buf) { td_u32 checksum = 0; td_size_t header_size; td_u32 len; errno_t sec_ret; if (buf == NULL) { soc_err_print_null_pointer(buf); return TD_FAILURE; } /* check Magic number is valid */ if (iapi_mdbg_is_valid_msg(((ext_mdbg_msg *)buf)->magic_num) != TD_TRUE) { fprintf(stderr, "check magic number error\n"); return TD_FAILURE; } /* check header checksum */ if (iapi_mdbg_verify_header_checksum((td_u8 *)buf) != TD_SUCCESS) { fprintf(stderr, "check header checksum error\n"); return TD_FAILURE; } /* verify data checksum */ header_size = mdbg_offset_of(ext_mdbg_msg, mdbg_data); len = mdbg_get_value(buf, ext_mdbg_msg, length); sec_ret = memcpy_s(&checksum, sizeof(td_u32), buf + header_size + len, sizeof(checksum)); if (sec_ret != EOK) { fprintf(stderr, "call memcpy_s failed!errno=%d\n", sec_ret); return TD_FAILURE; } if (iapi_mdbg_verify_data_checksum(buf, checksum) != TD_SUCCESS) { fprintf(stderr, "check valid data checksum error\n"); return TD_FAILURE; } return TD_SUCCESS; } td_void iapi_mdbg_net_read_data(td_u8 *buf, td_s32 count, td_s32 *read_size) { td_s32 recv_cnt; fd_set read_fds; struct timeval timeout; td_s32 ret; if (buf == TD_NULL) { soc_err_print_null_pointer(buf); return; } if (read_size == TD_NULL) { soc_err_print_null_pointer(read_size); return; } FD_ZERO(&read_fds); FD_SET(g_net_dev_fd, &read_fds); timeout.tv_sec = 5; // 设置时间为5s timeout.tv_usec = 0; ret = select(g_net_dev_fd + 1, &read_fds, NULL, NULL, &timeout); if (ret < 0) { fprintf(stderr, "socketfd select failed!\n"); return; } if (ret == 0) { fprintf(stderr, "time out!\n"); return; } if (FD_ISSET(g_net_dev_fd, &read_fds)) { // 测试sock是否可读,即网络上是否有数据 do { recv_cnt = recv(g_net_dev_fd, buf, count, MSG_WAITALL); } while ((recv_cnt < 0) && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)); if (recv_cnt < 0 || recv_cnt != count) { fprintf(stderr, "recv data error!\n"); return; } else if (recv_cnt == 0) { fprintf(stderr, "socket is disconnected!\n"); return; } else { *read_size = count; } } return; } td_void iapi_mdbg_net_write_data(const td_u8 *buf, td_s32 count) { if (buf == TD_NULL) { soc_err_print_null_pointer(buf); return; } send(g_net_dev_fd, buf, count, 0); while (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { g_delay.tv_sec = 0; g_delay.tv_nsec = 10 * 1000; // 10 * 1000 ns = 10us nanosleep(&g_delay, TD_NULL); send(g_net_dev_fd, buf, count, 0); } return; } td_bool iapi_mdbg_uart_is_open_flag(const td_u8 *magic_num) { td_u8 i; if (magic_num == TD_NULL) { soc_err_print_null_pointer(magic_num); return TD_FALSE; } for (i = 0; i < sizeof(g_magic_char) / sizeof(td_u8); i++) { if (magic_num[i] != g_magic_char[i]) { return TD_FALSE; } } return TD_TRUE; } td_void iapi_mdbg_uart_read_data(td_u8 *buf, td_s32 count, td_s32 *read_size) { td_s32 ret_val; td_s32 read_bytes = 0; if (buf == NULL) { soc_err_print_null_pointer(buf); return; } if (read_size == NULL) { soc_err_print_null_pointer(read_size); return; } *read_size = 0; while (1) { if (read_bytes >= count) { break; } ret_val = uapi_uart_read((char *)(buf + read_bytes), 1); if (ret_val <= 0) { break; } else { read_bytes += ret_val; } } *read_size = read_bytes; return; } td_void iapi_mdbg_uart_write_data(td_u8 *buf, td_s32 count) { td_s32 ret_val; if (buf == NULL) { fprintf(stderr, "buf is null!\n"); return; } ret_val = uapi_uart_write((td_char *)buf, (td_u32)count); if (ret_val < count) { fprintf(stderr, "write uart date error!\n"); } } td_s32 iapi_mdbg_uart_open_dev(td_void) { td_s32 ret_val; ret_val = uapi_uart_init(); if (ret_val != TD_SUCCESS && ret_val != SOC_ERR_UART_OPENED) { perror("open uart dev fail!"); return TD_FAILURE; } /* set defaulty baud speed to 115200 */ if (uapi_uart_set_speed(115200) != TD_SUCCESS) { // 设置波特率为115200 uapi_uart_deinit(); return TD_FAILURE; } /* set defaulty uart attribue */ if (uapi_uart_set_attr(8, 1, 'N') != TD_SUCCESS) { // 设置串口的读写数据为8位 uapi_uart_deinit(); return TD_FAILURE; } return TD_SUCCESS; } td_s32 iapi_mdbg_uart_close_dev(td_void) { td_s32 ret; // 把串口切换回系统使用 uapi_uart_switch(0); ret = uapi_uart_deinit(); if (ret < 0) { fprintf(stderr, "Can't close PQ uart\n"); return TD_FAILURE; } return TD_SUCCESS; } static td_s32 iapi_mdbg_send_uart_ack(td_u8 ack) { td_s32 ret_val; ret_val = uapi_uart_write((td_char *)&ack, sizeof(td_u8)); if (ret_val < 0) { fprintf(stderr, "send ack1 error\n"); return TD_FAILURE; } return TD_SUCCESS; } static td_s32 iapi_mdbg_get_uart_data(td_s32 read_size, td_u8 *buf) { td_s32 ret_val = 0; td_u32 checksum = 0; td_s32 read_total_byte = 0; td_u32 tmp_val; /* read data */ read_total_byte += read_size; tmp_val = mdbg_get_value(buf, ext_mdbg_msg, length), read_size = (td_s32)tmp_val; if ((read_size == 0) || (read_size > MDBG_CMDBUF_SIZE - read_total_byte - 4)) { // 读取数据最大size,4握手字节长度 fprintf(stderr, "read size is zero or out of range!\n"); return TD_SUCCESS; } g_delay.tv_sec = 0; g_delay.tv_nsec = 100000 * 1000; // 100000 * 1000 ns = 10 ms nanosleep(&g_delay, TD_NULL); iapi_mdbg_uart_read_data(buf + read_total_byte, read_size, &ret_val); if (ret_val < read_size) { fprintf(stderr, "read data time out\n"); return TD_FAILURE; } /* read data checksum */ read_total_byte += read_size; tmp_val = sizeof(td_u32), read_size = (td_s32)tmp_val; iapi_mdbg_uart_read_data(buf + read_total_byte, read_size, &ret_val); if (ret_val < (td_s32)sizeof(td_u32)) { fprintf(stderr, "read CheckSum error\n"); return TD_FAILURE; } /* verify data checksum */ if (memcpy_s(&checksum, sizeof(td_u32), buf + read_total_byte, sizeof(checksum)) != EOK) { fprintf(stderr, "call memcpy_s failed!"); return TD_FAILURE; } if (iapi_mdbg_verify_data_checksum(buf, checksum) != TD_SUCCESS) { fprintf(stderr, "check data checksum error\n"); return TD_FAILURE; } return TD_SUCCESS; } td_s32 iapi_mdbg_uart_read_msg(td_u8 *buf) { td_s32 read_size; td_s32 ret_val = 0; if (buf == TD_NULL) { soc_err_print_null_pointer(buf); return TD_FAILURE; } /* read msg magic number + cmd + len+headerchecsum */ read_size = (td_s32)mdbg_offset_of(ext_mdbg_msg, mdbg_data); iapi_mdbg_uart_read_data(buf, read_size, &ret_val); if (ret_val < read_size) { if (ret_val > 0) { fprintf(stderr, "read header error\n"); } return TD_FAILURE; } /* check Magic number is valid */ if (iapi_mdbg_is_valid_msg(((ext_mdbg_msg *)buf)->magic_num) != TD_TRUE) { fprintf(stderr, "check magic number error\n"); return TD_FAILURE; } /* check header checksum */ if (iapi_mdbg_verify_header_checksum((td_u8 *)buf) != TD_SUCCESS) { fprintf(stderr, "check header checksum error\n"); return TD_FAILURE; } if (iapi_mdbg_send_uart_ack(0xA0) < 0) { return TD_FAILURE; } ret_val = (td_s32)mdbg_get_value(buf, ext_mdbg_msg, cmd); if (ret_val == EXT_MDBG_CMD_UART_SWITCH) { return TD_SUCCESS; } /* read data */ ret_val = iapi_mdbg_get_uart_data(read_size, buf); if (ret_val != TD_SUCCESS) { return TD_SUCCESS; } /* send ack */ if (iapi_mdbg_send_uart_ack(0xB0) < 0) { return TD_FAILURE; } return TD_SUCCESS; } static td_void iapi_mdbg_uart_switch(td_void) { int ret; td_u32 boardid = 0; ret = ext_mpi_sys_get_board_id(&boardid); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(uapi_sys_get_board_id, ret); return; } boardid &= 0x2000; /* switch to mdbg uart */ if (g_mdbg_chip == MDBG_CHIP_RESERVED5 || g_mdbg_chip == MDBG_CHIP_RESERVED19 || g_mdbg_chip == MDBG_CHIP_HI3751V811) { uapi_uart_switch(1); /* reserved5 use uart1 to mdbg feature */ } else if (g_mdbg_chip == MDBG_CHIP_RESERVED9 || g_mdbg_chip == MDBG_CHIP_RESERVED13) { if (boardid != 0x2000) { uapi_uart_switch(2); /* reserved9 or reserved13 use uart2 to mdbg feature */ } else { uapi_uart_switch(5); /* uart5 */ } } else { fprintf(stdout, "unkown chip version .... \n"); return; } fprintf(stdout, "Start PQ TOOL DBG!\n"); g_uart_switch = TD_TRUE; g_net_use = TD_FALSE; g_debug_request = TD_TRUE; mpi_pq_dbg_update_uart_status(g_uart_open_dev, g_pq_dbg, g_uart_switch, g_is_cts_enable); if (g_debug_request == TD_TRUE) { g_debug_mode = TD_TRUE; g_debug_request = TD_FALSE; } } /* MDGB线程 */ td_void *iapi_mdbg_uart_thread(td_void *para) { td_s32 ret_val = TD_FAILURE; if (para == TD_NULL) { soc_log_err("para was null!\n"); return TD_NULL; } g_delay.tv_sec = 0; g_delay.tv_nsec = 400000 * 1000; // 400000 * 1000 ns = 40ms while (1) { if (g_exit_dbg == TD_TRUE) { break; } if (g_pq_dbg == TD_FALSE) { nanosleep(&g_delay, TD_NULL); continue; } /* Enter the debug mode */ if (g_debug_mode == TD_FALSE) { iapi_mdbg_uart_read_data((td_u8 *)para, 15, &ret_val); // 读取数据的最大长度为15 if (iapi_mdbg_uart_is_open_flag(para) != TD_TRUE) { nanosleep(&g_delay, TD_NULL); continue; } iapi_mdbg_uart_switch(); nanosleep(&g_delay, TD_NULL); continue; } /* recive data */ if (iapi_mdbg_uart_read_msg((td_u8 *)para) != TD_SUCCESS) { continue; } /* parser data */ if (iapi_mdbg_parser_msg((td_u8 *)para) != TD_SUCCESS) { continue; } } return TD_NULL; } #ifdef __cplusplus #if __cplusplus } #endif #endif /* __cplusplus */