9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
2412 lines
87 KiB
C
2412 lines
87 KiB
C
#include "publicdata/publicdata.h"
|
||
#if EC200A_4G_EN
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include "plat_comm/4g_module/ec200a_4g.h"
|
||
#include "plat_comm/4g_module/ec200a_4g_ftp.h"
|
||
#include "mylog/mylog.h"
|
||
#include "usart.h"
|
||
#include "app_init/app_init.h"
|
||
#include "plat_comm/impl/bs_public_impl.h"
|
||
#if(MY_SHELL_EN) //Shell 使能
|
||
#include "letter_shell/shell_port.h"
|
||
#endif
|
||
#include "plat_comm/plat_comm_task.h"
|
||
#include "plat_comm/impl/bs_connect_impl.h"
|
||
#include "bsp_include.h"
|
||
#include "app_fatfs/app_fatfs.h"
|
||
#include "app_fatfs/fatfs_init.h"
|
||
|
||
/* CCU621_M stubs: upgrade impl not available */
|
||
static int upgrade_erase_program_area(void) { return 0; }
|
||
static int upgrade_success_update_header(upgrade_header_t *h) { (void)h; return 0; }
|
||
static int upgrade_write_packet(uint32_t i, const uint8_t *d, uint32_t l) { (void)i; (void)d; (void)l; return (int)l; }
|
||
static U8_T fatfs_set_write_disable_flag(U8_T m, U8_T e) { (void)m; (void)e; return 0U; }
|
||
/* CCU621_M fs stubs */
|
||
static FS_Status fs_file_exists(const char *p, bool *e) { (void)p; if(e)*e=false; return FS_STATUS_OK; }
|
||
static FS_Status fs_get_file_size(const char *p, uint32_t *s) { (void)p; if(s)*s=0; return FS_STATUS_OK; }
|
||
static FS_Status fs_read_file_content(const char *p, char *b, uint32_t bs, FS_ReadRange *r) { (void)p; (void)b; (void)bs; (void)r; return FS_STATUS_OK; }
|
||
|
||
#if BS_OCPP_EN
|
||
#include "plat_comm/ocpp/BS_ocpp_ctrl.h"
|
||
/** OCPP:STEP_FTP_SAVE 先上送 Installing,再写头、FRAM 置位并复位;Installed 在 BootNotification 后上送 */
|
||
static U8_T s_u8_fw_save_ocpp_arm;
|
||
#endif
|
||
|
||
/** 本文件 FTP/升级/日志 AT 调试:不走 Plat_Comm 的 Plat_Comm_LOG,统一 MYLOG_MSG(0xFF) 直出 */
|
||
#define EC200A_FTP_LOG(fmt, ...) MYLOG_MSG(0xFF, fmt, ##__VA_ARGS__)
|
||
|
||
/* QFREAD 应答(含 CONNECT 与负载)须 ≥ 单包读长 + AT/URC 余量;与 EC200A_FTP_UFS_RW_CHUNK_BYTES 对齐 */
|
||
#define FTP_REAC_DATA_BUF_LEN ((U16_T)((EC200A_FTP_UFS_RW_CHUNK_BYTES) + 512U))
|
||
|
||
#if ((EC200A_FTP_UFS_RW_CHUNK_BYTES) % (PACKET_SIZE)) != 0
|
||
#error EC200A_FTP_UFS_RW_CHUNK_BYTES must be a multiple of PACKET_SIZE (FTP upgrade QFREAD -> flash packets).
|
||
#endif
|
||
|
||
//引出 给ftp升级配置使用
|
||
extern S8_T s8_FindAck(U8_T *src, U8_T *des);
|
||
extern S16_T s16_FindAck_Ex(U8_T *src, U16_T srcLen, U8_T *des, U16_T desLen);
|
||
extern S8_T s8_4g_Send_AT_Cmd(U8_T *sendBuf, U8_T sendLen, U8_T *ack, U8_T resendCnt, U16_T delayTimeMs);
|
||
extern S8_T s8_4g_Send_Recv_Cmd(U8_T *sendBuf, U8_T sendLen,U8_T *rcvBuf,U16_T recvLen, U8_T *ack, U8_T resendCnt, U16_T delayTimeMs);
|
||
extern S8_T s8_cat_reboot(U8_T u8_flag);
|
||
extern S8_T s8_work_mode_cmd(); // 切换到指令模式
|
||
|
||
extern S8_T s8_ec200a_set_cgreg();
|
||
extern S8_T s8_ec200a_cgreg();
|
||
|
||
typedef enum
|
||
{
|
||
STEP_FTP_SWCHTO_CMD_MODE = 0, //切换到指令模式
|
||
|
||
STEP_FTP_SET_CGREG,
|
||
STEP_FTP_QUERY_CGREG,
|
||
STEP_FTP_SET_QIDEACT, //去激活PDP场景
|
||
STEP_FTP_SET_QIACT, //激活PDP场景
|
||
STEP_FTP_FTP_CFG_contextid, //配置 FTP(S) PDP 上下文 ID
|
||
STEP_FTP_FTP_CFG_account, //配置 FTP(S) 设置用户名和密码。
|
||
STEP_FTP_FTP_CFG_filetype, //配置 FTP(S) 设置文件类型为ASCII。
|
||
STEP_FTP_FTP_CFG_transmode, //配置 FTP(S) 设置为被动传输方式。
|
||
STEP_FTP_FTP_CFG_rsptimeout, //配置 FTP(S) 设置最大响应时间(默认为90秒)。
|
||
|
||
STEP_FTP_FTP_CFG_QFTPOPEN, //登录FTP服务器。
|
||
STEP_FTP_FTP_CFG_QFTPCWD, //切换目录
|
||
STEP_FTP_FTP_CFG_QFTPLIST, //获取当前目录的内容,并通过
|
||
STEP_FTP_FTP_GET_QFTPSIZE, //获取 文件大小
|
||
STEP_FTP_FTP_QFDEL, //获取 删除存储区保存的文件内容
|
||
STEP_FTP_FTP_GET_QFTPGET, //获取 文件内容 qflst
|
||
STEP_FTP_FTP_GET_QFLST, //获取 UFS中文件内容 qflst
|
||
|
||
STEP_FTP_FTP_GET_QFOPEN, //打开文件
|
||
STEP_FTP_FTP_GET_QFSEEK, //设置读取文件指针头地址
|
||
STEP_FTP_FTP_GET_QFREAD, //读取文件
|
||
|
||
STEP_FTP_FTP_GET_LOG_INFO, //获取日志信息
|
||
STEP_FTP_FTP_UPLOAD_LOG_UFS, /* 模组 UFS:QFOPEN 覆盖写日志文件,建立句柄 */
|
||
STEP_FTP_FTP_WRITE_LOG_UFS, //写入日志文件到 UFS
|
||
STEP_FTP_FTP_UPLOAD_LOG_FTP, //上传日志文件到 FTP
|
||
/** 日志上传成功后须关闭 FTP 会话,否则 +QFTP* URC 残留易干扰同 UART 上后续 QISEND(break off=0) */
|
||
STEP_FTP_FTP_QFTPCLOSE_AFTER_LOG,
|
||
|
||
STEP_FTP_SAVE, //保存当前设置并重启
|
||
STEP_FTP_INIT_OK, //设置完成
|
||
STEP_FTP_INIT_DEBUG, // 调试
|
||
}E_EC200A_4G_FTP_INIT_STEP;
|
||
E_EC200A_4G_FTP_INIT_STEP e_ec200a_ftp_init_step = STEP_FTP_SWCHTO_CMD_MODE;
|
||
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
/** 日志经 QFWRITE 写入 UFS 时已发送字节累计(QFSEEK 绝对偏移) */
|
||
static uint32_t s_log_ufs_qwrite_total;
|
||
|
||
/**
|
||
* AT+QFREAD:单次调用内发 AT→轮询至应答中出现 OK(与 QFWRITE 同思路,不跨 PlatComm 累加)。
|
||
* @param rsp_out 成功时为 pvPortMalloc 缓冲,调用方须 vPortFree;失败时为 NULL。
|
||
*/
|
||
static S16_T s16_qfread_at_slice(const U8_T *sendBuf, U16_T sendLen, U8_T **rsp_out)
|
||
{
|
||
U8_T *acc;
|
||
U16_T rcv_len = 0U;
|
||
U16_T total_waits = 0U;
|
||
S16_T ack;
|
||
U8_T ackOK[] = "OK";
|
||
|
||
if (rsp_out == NULL || sendBuf == NULL || sendLen == 0U || sendLen > 72U) {
|
||
return -1;
|
||
}
|
||
*rsp_out = NULL;
|
||
|
||
acc = (U8_T *)pvPortMalloc((size_t)FTP_REAC_DATA_BUF_LEN);
|
||
if (acc == NULL) {
|
||
EC200A_FTP_LOG("[FTP] QFREAD malloc fail\r\n");
|
||
return -1;
|
||
}
|
||
memset(acc, 0, (size_t)FTP_REAC_DATA_BUF_LEN);
|
||
|
||
v_4g_send_data((U8_T)0xFF, (U8_T *)(void *)sendBuf, sendLen);
|
||
|
||
while (total_waits < (U16_T)EC200A_FTP_QFREAD_TOTAL_WAITS) {
|
||
mSleep(EC200A_FTP_UART_SLICE_WAIT_MS);
|
||
if (rcv_len + 1U < (U16_T)FTP_REAC_DATA_BUF_LEN) {
|
||
rcv_len += u16_4g_recv_data(
|
||
acc + rcv_len,
|
||
(U16_T)((U16_T)FTP_REAC_DATA_BUF_LEN - 1U - rcv_len));
|
||
} else {
|
||
EC200A_FTP_LOG("[FTP] QFREAD rsp overflow\r\n");
|
||
vPortFree(acc);
|
||
return -1;
|
||
}
|
||
total_waits++;
|
||
|
||
if (rcv_len > 0U) {
|
||
if (strstr((char *)acc, "+CME ERROR") != NULL
|
||
|| strstr((char *)acc, "\r\nERROR\r\n") != NULL) {
|
||
EC200A_FTP_LOG("[FTP] QFREAD modem ERROR\r\n");
|
||
vPortFree(acc);
|
||
return -1;
|
||
}
|
||
ack = s16_FindAck_Ex(acc, rcv_len, ackOK, (U16_T)(sizeof(ackOK) - 1U));
|
||
if (ack != (S16_T)-1) {
|
||
*rsp_out = acc;
|
||
return (S16_T)rcv_len;
|
||
}
|
||
}
|
||
}
|
||
|
||
EC200A_FTP_LOG("[FTP] QFREAD wait total exceeded (single session)\r\n");
|
||
vPortFree(acc);
|
||
return -1;
|
||
}
|
||
|
||
/** 发 QFTPGET 前排空模组 UART 残留,减轻与上一条 QIRD/URC 粘包导致帧头错位 */
|
||
static void v_qftpget_drain_modem_rx(void)
|
||
{
|
||
U8_T junk[128];
|
||
U16_T got;
|
||
uint8_t r;
|
||
|
||
for (r = 0U; r < 48U; r++) {
|
||
got = u16_4g_recv_data(junk, (U16_T)sizeof(junk));
|
||
if (got == 0U) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/** QFTPGET→COM:必须以行格式识别 CONNECT,避免固件二进制内出现子串 "CONNECT" 时负载起点错位 */
|
||
static int s32_qftpget_find_payload_start(const U8_T *raw, uint32_t raw_len, uint32_t *out_data_start)
|
||
{
|
||
static const uint8_t p_crlf[] = "\r\nCONNECT\r\n";
|
||
const uint32_t n_crlf = (uint32_t)(sizeof(p_crlf) - 1U);
|
||
static const uint8_t p_lf[] = "\nCONNECT\n";
|
||
const uint32_t n_lf = (uint32_t)(sizeof(p_lf) - 1U);
|
||
static const uint8_t p_tail[] = "CONNECT\r\n";
|
||
const uint32_t n_tail = (uint32_t)(sizeof(p_tail) - 1U);
|
||
static const char atpfx[] = "AT+QFTPGET";
|
||
const uint32_t n_at = (uint32_t)(sizeof(atpfx) - 1U);
|
||
uint32_t i;
|
||
uint32_t atmin = 0U;
|
||
uint8_t found_at = 0U;
|
||
|
||
if (raw == NULL || out_data_start == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
for (i = 0U; i + n_crlf <= raw_len; i++) {
|
||
if (memcmp(raw + i, p_crlf, (size_t)n_crlf) == 0) {
|
||
*out_data_start = i + n_crlf;
|
||
return 0;
|
||
}
|
||
}
|
||
for (i = 0U; i + n_lf <= raw_len; i++) {
|
||
if (memcmp(raw + i, p_lf, (size_t)n_lf) == 0) {
|
||
*out_data_start = i + n_lf;
|
||
return 0;
|
||
}
|
||
}
|
||
{
|
||
static const uint8_t p_lfcrlf[] = "\nCONNECT\r\n";
|
||
const uint32_t n_lfcrlf = (uint32_t)(sizeof(p_lfcrlf) - 1U);
|
||
for (i = 0U; i + n_lfcrlf <= raw_len; i++) {
|
||
if (memcmp(raw + i, p_lfcrlf, (size_t)n_lfcrlf) == 0) {
|
||
*out_data_start = i + n_lfcrlf;
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
for (i = 0U; i + n_at <= raw_len; i++) {
|
||
if (memcmp(raw + i, atpfx, (size_t)n_at) == 0) {
|
||
atmin = i;
|
||
found_at = 1U;
|
||
break;
|
||
}
|
||
}
|
||
if (found_at != 0U) {
|
||
for (i = atmin; i + n_tail <= raw_len; i++) {
|
||
if (memcmp(raw + i, p_tail, (size_t)n_tail) == 0) {
|
||
*out_data_start = i + n_tail;
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/** 仅在 [0, scan_len) 内查 AT 失败串;CONNECT 之后为固件二进制,勿全缓冲 strstr(易误判) */
|
||
static int s32_qftpget_prefix_has_modem_fail(const U8_T *buf, uint32_t scan_len)
|
||
{
|
||
static const char k_cme[] = "+CME ERROR";
|
||
static const char k_err[] = "\r\nERROR\r\n";
|
||
const uint32_t L1 = (uint32_t)(sizeof(k_cme) - 1U);
|
||
const uint32_t L2 = (uint32_t)(sizeof(k_err) - 1U);
|
||
uint32_t n;
|
||
|
||
if (buf == NULL || scan_len == 0U) {
|
||
return 0;
|
||
}
|
||
if (scan_len >= L1) {
|
||
for (n = 0U; n + L1 <= scan_len; n++) {
|
||
if (memcmp(buf + n, k_cme, (size_t)L1) == 0) {
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
if (scan_len >= L2) {
|
||
for (n = 0U; n + L2 <= scan_len; n++) {
|
||
if (memcmp(buf + n, k_err, (size_t)L2) == 0) {
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* AT+QFTPGET="remote","COM:",off,len:非透传下与 QFREAD 同思路,拼 UART 直至 **CONNECT 后 expect_payload 字节 + \\r\\nOK**。
|
||
* 不得仅因缓冲区内出现「OK」(如 QIRD 的 \\r\\nOK)提前返回,否则会截断固件二进制。
|
||
* @param payload_off_out 成功时输出 CONNECT 负载首字节在 acc 内下标
|
||
*/
|
||
static S16_T s16_qftpget_com_at_slice(const U8_T *sendBuf, U16_T sendLen, U8_T **rsp_out,
|
||
U16_T expect_payload, uint32_t *payload_off_out)
|
||
{
|
||
U8_T *acc;
|
||
U16_T rcv_len = 0U;
|
||
U16_T total_waits = 0U;
|
||
const U16_T max_waits = (U16_T)((EC200A_FTP_QFREAD_TOTAL_WAITS) * 12U);
|
||
|
||
if (rsp_out == NULL || payload_off_out == NULL || sendBuf == NULL || sendLen == 0U || sendLen > 220U
|
||
|| expect_payload == 0U) {
|
||
return -1;
|
||
}
|
||
*rsp_out = NULL;
|
||
*payload_off_out = 0U;
|
||
|
||
acc = (U8_T *)pvPortMalloc((size_t)FTP_REAC_DATA_BUF_LEN);
|
||
if (acc == NULL) {
|
||
EC200A_FTP_LOG("[FTP] QFTPGET(COM) malloc fail\r\n");
|
||
return -1;
|
||
}
|
||
memset(acc, 0, (size_t)FTP_REAC_DATA_BUF_LEN);
|
||
|
||
v_qftpget_drain_modem_rx();
|
||
v_4g_send_data((U8_T)0xFF, (U8_T *)(void *)sendBuf, sendLen);
|
||
|
||
while (total_waits < max_waits) {
|
||
mSleep(EC200A_FTP_UART_SLICE_WAIT_MS);
|
||
if (rcv_len + 1U < (U16_T)FTP_REAC_DATA_BUF_LEN) {
|
||
rcv_len += u16_4g_recv_data(
|
||
acc + rcv_len,
|
||
(U16_T)((U16_T)FTP_REAC_DATA_BUF_LEN - 1U - rcv_len));
|
||
} else {
|
||
EC200A_FTP_LOG("[FTP] QFTPGET(COM) rsp overflow\r\n");
|
||
vPortFree(acc);
|
||
return -1;
|
||
}
|
||
total_waits++;
|
||
|
||
if (rcv_len > 0U) {
|
||
uint32_t ds = 0U;
|
||
int pay_ok;
|
||
uint32_t scan_top;
|
||
|
||
pay_ok = s32_qftpget_find_payload_start(acc, (uint32_t)rcv_len, &ds);
|
||
if (pay_ok == 0) {
|
||
scan_top = ds;
|
||
} else {
|
||
scan_top = (uint32_t)rcv_len;
|
||
if (scan_top > 256U) {
|
||
scan_top = 256U;
|
||
}
|
||
}
|
||
if (s32_qftpget_prefix_has_modem_fail(acc, scan_top)) {
|
||
EC200A_FTP_LOG("[FTP] QFTPGET(COM) modem ERROR (prefix scan top=%u)\r\n",
|
||
(unsigned)scan_top);
|
||
vPortFree(acc);
|
||
return -1;
|
||
}
|
||
if (pay_ok == 0) {
|
||
uint32_t need = ds + (uint32_t)expect_payload + 4U;
|
||
|
||
if (rcv_len >= need) {
|
||
if (memcmp(acc + ds + expect_payload, "\r\nOK", 4U) == 0) {
|
||
*rsp_out = acc;
|
||
*payload_off_out = ds;
|
||
return (S16_T)rcv_len;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
EC200A_FTP_LOG("[FTP] QFTPGET(COM) wait total exceeded (expect_payload=%u)\r\n", (unsigned)expect_payload);
|
||
vPortFree(acc);
|
||
return -1;
|
||
}
|
||
|
||
static void s8_ec200a_qfclose_log_fd(void)
|
||
{
|
||
U8_T b[48];
|
||
int fd = (int)t_ftp_update_info.u32_file_fd;
|
||
|
||
if (fd <= 0) {
|
||
return;
|
||
}
|
||
(void)snprintf((char *)b, sizeof(b), "AT+QFCLOSE=%d\r\n", fd);
|
||
(void)s8_4g_Send_AT_Cmd(b, (U16_T)strlen((char *)b), NULL, 5U, 200U);
|
||
t_ftp_update_info.u32_file_fd = 0U;
|
||
}
|
||
|
||
/** 日志上传:QFOPEN 覆盖写 UFS 裸文件名(与 QFTPPUT 侧 UFS: 名一致) */
|
||
static S8_T s8_ec200a_qfopen_log_ufs(void)
|
||
{
|
||
U8_T u8_sendBuf[96] = {0};
|
||
U8_T rcvBuf[BS_RECV_BUF_LEN] = {0};
|
||
U8_T u8_ack[] = "+QFOPEN:";
|
||
char *last_slash = strrchr((char *)t_ftp_update_info.u8_file_name, '/');
|
||
S8_T s8_ret;
|
||
int fdi = 0;
|
||
|
||
if (last_slash == NULL) {
|
||
return -1;
|
||
}
|
||
(void)snprintf((char *)u8_sendBuf, sizeof(u8_sendBuf), "AT+QFOPEN=\"%s\",1\r\n", last_slash + 1);
|
||
s8_ret = s8_4g_Send_Recv_Cmd(u8_sendBuf, (U16_T)strlen((char *)u8_sendBuf), rcvBuf, BS_RECV_BUF_LEN, u8_ack, 5, 200);
|
||
if (s8_ret < 0) {
|
||
return -1;
|
||
}
|
||
if (sscanf((char *)&rcvBuf[s8_ret], "+QFOPEN: %d", &fdi) != 1 || fdi <= 0) {
|
||
return -1;
|
||
}
|
||
t_ftp_update_info.u32_file_fd = (U32_T)fdi;
|
||
s_log_ufs_qwrite_total = 0U;
|
||
EC200A_FTP_LOG("[FTP-LOG] QFOPEN ok fd=%d file=%s\r\n", fdi, last_slash + 1);
|
||
return 0;
|
||
}
|
||
|
||
static S8_T s8_ec200a_qfseek_log_abs(uint32_t abs_off)
|
||
{
|
||
U8_T u8_sendBuf[64] = {0};
|
||
int fd = (int)t_ftp_update_info.u32_file_fd;
|
||
|
||
if (fd <= 0) {
|
||
return -1;
|
||
}
|
||
(void)snprintf((char *)u8_sendBuf, sizeof(u8_sendBuf), "AT+QFSEEK=%d,%lu,0\r\n", fd, (unsigned long)abs_off);
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, (U16_T)strlen((char *)u8_sendBuf), NULL, 5, 150);
|
||
}
|
||
|
||
/** 单包 QFWRITE:本次调用内发 AT→轮询 CONNECT→发负载→等 OK;UART 应答仅在函数内局部 `acc` 拼接,不跨 PlatComm。
|
||
* 负载用 `pvPortMalloc(wlen)`,超过 `EC200A_FTP_QFWRITE_TOTAL_WAITS` 仍未完成则返回 -1。 */
|
||
static S8_T s8_ec200a_qfwrite_log_bin(const U8_T *data, U16_T wlen)
|
||
{
|
||
U8_T cmd[72] = {0};
|
||
U8_T acc[512];
|
||
U16_T acc_len = 0;
|
||
U8_T phase = 0;
|
||
U16_T total_waits = 0;
|
||
U32_T tout = (U32_T)EC200A_FTP_QFUPL_AT_TIMEOUT_SEC;
|
||
int fd = (int)t_ftp_update_info.u32_file_fd;
|
||
const char *needle_ok = "\r\nOK";
|
||
U8_T *pay = NULL;
|
||
|
||
if (data == NULL || wlen == 0U) {
|
||
return (S8_T)-1;
|
||
}
|
||
if (wlen > (U16_T)EC200A_FTP_UFS_RW_CHUNK_BYTES) {
|
||
return (S8_T)-1;
|
||
}
|
||
if (fd <= 0) {
|
||
return (S8_T)-1;
|
||
}
|
||
if (tout < 5U) {
|
||
tout = 5U;
|
||
}
|
||
if (tout > 65535U) {
|
||
tout = 65535U;
|
||
}
|
||
|
||
pay = (U8_T *)pvPortMalloc((size_t)wlen);
|
||
if (pay == NULL) {
|
||
EC200A_FTP_LOG("[FTP-LOG] QFWRITE malloc pay fail\r\n");
|
||
return (S8_T)-1;
|
||
}
|
||
memcpy(pay, data, (size_t)wlen);
|
||
memset(acc, 0, sizeof(acc));
|
||
|
||
(void)snprintf((char *)cmd, sizeof(cmd), "AT+QFWRITE=%d,%u,%lu\r\n", fd, (unsigned)wlen, (unsigned long)tout);
|
||
v_4g_send_data((U8_T)0xFF, cmd, (U16_T)strlen((char *)cmd));
|
||
|
||
while (total_waits < (U16_T)EC200A_FTP_QFWRITE_TOTAL_WAITS) {
|
||
mSleep(EC200A_FTP_UART_SLICE_WAIT_MS);
|
||
|
||
if (acc_len + 32U < sizeof(acc)) {
|
||
acc_len += u16_4g_recv_data(acc + acc_len,
|
||
(U16_T)(sizeof(acc) - 1U - acc_len));
|
||
} else {
|
||
if (acc_len > 160U) {
|
||
memmove(acc, acc + 160U, (size_t)(acc_len - 160U));
|
||
acc_len = (U16_T)(acc_len - 160U);
|
||
} else {
|
||
acc_len = 0U;
|
||
}
|
||
acc_len += u16_4g_recv_data(acc + acc_len,
|
||
(U16_T)(sizeof(acc) - 1U - acc_len));
|
||
}
|
||
if (acc_len >= sizeof(acc)) {
|
||
acc_len = (U16_T)(sizeof(acc) - 1U);
|
||
}
|
||
acc[acc_len] = '\0';
|
||
total_waits++;
|
||
|
||
if (strstr((char *)acc, "+CME ERROR") != NULL || strstr((char *)acc, "\r\nERROR\r\n") != NULL) {
|
||
EC200A_FTP_LOG("[FTP-LOG] QFWRITE modem ERROR\r\n");
|
||
vPortFree(pay);
|
||
return (S8_T)-1;
|
||
}
|
||
|
||
if (phase == 0U) {
|
||
if (strstr((char *)acc, "CONNECT") != NULL) {
|
||
v_4g_send_data((U8_T)0xFF, pay, wlen);
|
||
acc_len = 0;
|
||
acc[0] = '\0';
|
||
phase = 1U;
|
||
}
|
||
} else {
|
||
if (strstr((char *)acc, needle_ok) != NULL) {
|
||
vPortFree(pay);
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
EC200A_FTP_LOG("[FTP-LOG] QFWRITE wait total exceeded (single session)\r\n");
|
||
vPortFree(pay);
|
||
return (S8_T)-1;
|
||
}
|
||
|
||
#endif /* !EC200A_TCP_USE_TRANSPARENT_MODE */
|
||
|
||
#if 1 //ftp初始化配置
|
||
void v_ftp_ctrl_init()
|
||
{
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
s_log_ufs_qwrite_total = 0U;
|
||
#endif
|
||
#if BS_OCPP_EN
|
||
s_u8_fw_save_ocpp_arm = 0U;
|
||
v_ocpp_clr_fw_installing_fsn_sent();
|
||
#endif
|
||
e_ec200a_ftp_init_step = STEP_FTP_SWCHTO_CMD_MODE;
|
||
}
|
||
#endif
|
||
|
||
#if 1 //数据操作
|
||
/**
|
||
* @brief 解析4G模块FTP下载响应数据(简化版,只需验证\r\nOK)
|
||
* @param raw_data: 原始接收数据
|
||
* @param raw_len: 原始数据长度
|
||
* @param file_len: 输出参数,文件数据长度
|
||
* @retval 成功返回文件数据起始地址,失败返回NULL
|
||
*/
|
||
const uint8_t* parse_4g_ftp_response(const uint8_t *raw_data, uint32_t raw_len, uint32_t *file_len)
|
||
{
|
||
// 改为查找 "CONNECT" 关键字
|
||
const uint8_t connect_keyword[] = "CONNECT";
|
||
const uint8_t ok_footer[] = "\r\nOK";
|
||
const uint8_t connect_keyword_len = sizeof(connect_keyword) - 1; // 7字节
|
||
const uint8_t ok_footer_len = sizeof(ok_footer) - 1; // 4字节
|
||
|
||
int32_t connect_pos = -1;
|
||
int32_t ok_pos = -1;
|
||
const uint8_t *file_start = NULL;
|
||
|
||
if (raw_data == NULL || file_len == NULL) {
|
||
return NULL;
|
||
}
|
||
*file_len = 0;
|
||
|
||
// 1. 查找CONNECT关键字
|
||
for (uint32_t i = 0; i < raw_len - connect_keyword_len; i++) {
|
||
if (memcmp(raw_data + i, connect_keyword, connect_keyword_len) == 0) {
|
||
connect_pos = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (connect_pos < 0) {
|
||
//EC200A_FTP_LOG("Error: CONNECT keyword not found\n");
|
||
return NULL;
|
||
}
|
||
|
||
// 2. 从CONNECT位置开始,找到下一个\r\n,文件数据从这里之后开始
|
||
uint32_t data_start = connect_pos;
|
||
while (data_start < raw_len) {
|
||
if (raw_data[data_start] == '\r' && raw_data[data_start + 1] == '\n') {
|
||
data_start += 2; // 跳过\r\n
|
||
break;
|
||
}
|
||
data_start++;
|
||
}
|
||
|
||
if (data_start >= raw_len) {
|
||
//EC200A_FTP_LOG("Error: Cannot find data start after CONNECT\n");
|
||
return NULL;
|
||
}
|
||
|
||
// 3. 查找OK尾部(从后往前找,找到最后一个\r\nOK)
|
||
ok_pos = -1;
|
||
for (int32_t i = raw_len - ok_footer_len; i >= 0; i--) {
|
||
if (memcmp(raw_data + i, ok_footer, ok_footer_len) == 0) {
|
||
ok_pos = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (ok_pos < 0) {
|
||
//EC200A_FTP_LOG("Error: \\r\\nOK footer not found\n");
|
||
return NULL;
|
||
}
|
||
|
||
// 4. 计算文件数据长度和起始地址
|
||
if (data_start >= (uint32_t)ok_pos) {
|
||
//EC200A_FTP_LOG("Error: Invalid data positions (start=%u, ok=%d)\n", data_start, ok_pos);
|
||
return NULL;
|
||
}
|
||
|
||
*file_len = ok_pos - data_start;
|
||
file_start = raw_data + data_start;
|
||
|
||
if (*file_len == 0) {
|
||
//EC200A_FTP_LOG("Error: No file data found\n");
|
||
return NULL;
|
||
}
|
||
|
||
//EC200A_FTP_LOG("Success: Found file data at offset %u, length %u bytes\n", data_start, *file_len);
|
||
return file_start;
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - FTP 获取文件数据时 自定义发送解析内容
|
||
*
|
||
* @param[in] sendBuf - 发送数据指针
|
||
* @param[in] sendLen - 发送数据长度
|
||
* @param[in] rcvBuf - 接收的数据内容 外部传入,接收赋值后传出 方便外部直接使用
|
||
* @param[in] recvLen - 最大可支持数据内容,防止数组越界
|
||
* @param[in] resendCnt - 重发次数计数
|
||
* @param[in] delayTimeMs - 单次接收等待延时时间
|
||
*
|
||
* @return S16_T - 期望应答有效数据 -1 未接收到 》=0 成功接收到期望应答数据 并返回接收数据长度
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-24
|
||
* ************************************************************************
|
||
*/
|
||
S16_T s16_4g_Send_Recv_Ftp_Get(U8_T *sendBuf, U8_T sendLen,U8_T *rcvBuf,U16_T recvLen, U8_T resendCnt, U16_T delayTimeMs)
|
||
{
|
||
U8_T count = 0;
|
||
U16_T rcvLen = 0;
|
||
S16_T ackIndex = -1;
|
||
U8_T ackOK[] = "OK";
|
||
|
||
// com_write(COM_PORT_BS, sendBuf, sendLen, 0);
|
||
v_4g_send_data((U8_T)0xFF, sendBuf, sendLen);
|
||
memset(rcvBuf, 0, recvLen);
|
||
do
|
||
{
|
||
mSleep(delayTimeMs);
|
||
// rcvLen = com_read(COM_PORT_BS, rcvBuf, 100, 0);
|
||
if(rcvLen < recvLen) //已接收数据满了 不再接收新数据
|
||
rcvLen += u16_4g_recv_data(&rcvBuf[rcvLen], recvLen-rcvLen);
|
||
|
||
if (rcvLen > 0)
|
||
{
|
||
//EC200A_FTP_LOG("recvLen = %d\r\n",rcvLen);
|
||
ackIndex = s16_FindAck_Ex(rcvBuf,rcvLen, ackOK ,sizeof(ackOK)-1);
|
||
if ((ackIndex != -1)) {
|
||
return rcvLen;
|
||
}
|
||
}
|
||
count++;
|
||
} while (count < resendCnt); // 如果没收到期望应答,重新发送
|
||
|
||
//EC200A_FTP_LOG("sendBuf = %s is recv err [%d]\r\n",sendBuf,ackIndex);
|
||
return -1;
|
||
}
|
||
#endif
|
||
|
||
#if 1 //逻辑控制
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 升级头部信息控制
|
||
*
|
||
* @param[in] u8_flag - 0升级前 1升级后
|
||
*
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-12-01
|
||
* ************************************************************************
|
||
*/
|
||
static void v_upgrade_header_data(U8_T u8_flag)
|
||
{
|
||
upgrade_header_t header_data;
|
||
Comm_Time time;
|
||
GetCurrentTime(&time);
|
||
|
||
memset(&header_data , 0, sizeof(upgrade_header_t));
|
||
|
||
header_data.file_size = t_ftp_update_info.u32_file_size; // 升级文件总大小
|
||
header_data.packet_count = (t_ftp_update_info.u32_file_size + (uint32_t)PACKET_SIZE - 1U) /
|
||
(uint32_t)PACKET_SIZE; // 总包数(按 Flash 1KB 包计,与 QFREAD 块大小无关)
|
||
header_data.crc32 = 0; // 文件CRC32校验和
|
||
header_data.timestamp = xDate2Seconds(&time); // 时间戳
|
||
//uint8_t version[16]; // 版本号
|
||
//uint8_t reserved[32]; // 保留字段
|
||
if(u8_flag == 0)
|
||
{
|
||
/* 升级开始前:先清空升级区域所有扇区,写入时就不用再擦除 */
|
||
if (upgrade_erase_program_area() != 0)
|
||
{
|
||
EC200A_FTP_LOG("upgrade_erase_program_area failed\r\n");
|
||
}
|
||
header_data.upgrade_flag = UPGRADE_FLAG_IDLE; // 升级标志 无数据状态
|
||
}
|
||
else
|
||
{
|
||
header_data.upgrade_flag = UPGRADE_FLAG_NEED_UP; // 升级标志 存在需要升级数据
|
||
}
|
||
EC200A_FTP_LOG("upgrade_header flag(%d) fileSize[%d]",header_data.upgrade_flag,t_ftp_update_info.u32_file_size);
|
||
|
||
upgrade_success_update_header(&header_data);
|
||
}
|
||
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 发送一次AT并等待指定ACK(不重发)
|
||
*
|
||
* @param[in] sendBuf - 发送数据指针
|
||
* @param[in] sendLen - 发送数据长度
|
||
* @param[in/out] rcvBuf - 接收缓存
|
||
* @param[in] recvLen - 接收缓存长度
|
||
* @param[in] ack - 期望ACK字符串
|
||
* @param[in] ackLen - ACK长度
|
||
* @param[in] pollDelayMs - 轮询间隔
|
||
* @param[in] pollCount - 轮询次数
|
||
*
|
||
* @return S16_T - ack在rcvBuf中的索引,失败返回-1
|
||
* ************************************************************************
|
||
*/
|
||
static S16_T s16_4g_Send_Once_WaitAck(U8_T *sendBuf, U16_T sendLen,
|
||
U8_T *rcvBuf, U16_T recvLen,
|
||
const U8_T *ack, U16_T ackLen,
|
||
U16_T pollDelayMs, U16_T pollCount)
|
||
{
|
||
U16_T rcvLen = 0;
|
||
S16_T ackIndex = -1;
|
||
|
||
if (sendBuf == NULL || rcvBuf == NULL || ack == NULL || recvLen == 0 || ackLen == 0)
|
||
return -1;
|
||
|
||
v_4g_send_data((U8_T)0xFF, sendBuf, sendLen);
|
||
memset(rcvBuf, 0, recvLen);
|
||
|
||
for (U16_T i = 0; i < pollCount; i++)
|
||
{
|
||
mSleep(pollDelayMs);
|
||
if (rcvLen < recvLen)
|
||
rcvLen += u16_4g_recv_data(&rcvBuf[rcvLen], recvLen - rcvLen);
|
||
|
||
if (rcvLen > 0)
|
||
{
|
||
ackIndex = s16_FindAck_Ex(rcvBuf, rcvLen, (U8_T *)ack, ackLen);
|
||
if (ackIndex != -1)
|
||
return ackIndex;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 发送一次AT并等待ACK1或ACK2(不重发)
|
||
*
|
||
* @return >0 命中ack1; <0 命中ack2; 0/其它 失败
|
||
* ************************************************************************
|
||
*/
|
||
static S16_T s16_4g_Send_Once_WaitAck2(U8_T *sendBuf, U16_T sendLen,
|
||
U8_T *rcvBuf, U16_T recvLen,
|
||
const U8_T *ack1, U16_T ack1Len,
|
||
const U8_T *ack2, U16_T ack2Len,
|
||
U16_T pollDelayMs, U16_T pollCount)
|
||
{
|
||
U16_T rcvLen = 0;
|
||
S16_T idx1 = -1;
|
||
S16_T idx2 = -1;
|
||
|
||
if (sendBuf == NULL || rcvBuf == NULL || recvLen == 0)
|
||
return 0;
|
||
if (ack1 == NULL || ack1Len == 0 || ack2 == NULL || ack2Len == 0)
|
||
return 0;
|
||
|
||
v_4g_send_data((U8_T)0xFF, sendBuf, (U16_T)sendLen);
|
||
memset(rcvBuf, 0, recvLen);
|
||
|
||
for (U16_T i = 0; i < pollCount; i++)
|
||
{
|
||
mSleep(pollDelayMs);
|
||
if (rcvLen < recvLen)
|
||
rcvLen += u16_4g_recv_data(&rcvBuf[rcvLen], recvLen - rcvLen);
|
||
|
||
if (rcvLen > 0)
|
||
{
|
||
idx1 = s16_FindAck_Ex(rcvBuf, rcvLen, (U8_T *)ack1, ack1Len);
|
||
if (idx1 != -1)
|
||
return idx1; // >0: ack1
|
||
|
||
idx2 = s16_FindAck_Ex(rcvBuf, rcvLen, (U8_T *)ack2, ack2Len);
|
||
if (idx2 != -1)
|
||
return (S16_T)(-idx2); // <0: ack2
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
#endif
|
||
|
||
#if 1 //AT指令
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 配置 FTP(S) 使用的 PDP 上下文(恒为 EC200A_FTP_PDP_CTX_ID,与业务 TCP 分场景,见 ec200a_4g_cfg.h)
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpcfg_contextid(void)
|
||
{
|
||
U8_T u8_sendBuf[40];
|
||
unsigned ctx = (unsigned)EC200A_FTP_PDP_CTX_ID;
|
||
int n = snprintf((char *)u8_sendBuf, sizeof(u8_sendBuf), "AT+QFTPCFG=\"contextid\",%u\r\n", ctx);
|
||
if (n <= 0 || n >= (int)sizeof(u8_sendBuf)) {
|
||
return -1;
|
||
}
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, (U16_T)n, NULL, 3, 50);
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 设置用户名和密码。
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpcfg_account()
|
||
{
|
||
U8_T u8_sendBuf[64] = {0};
|
||
//AT+QFTPCFG="account","test","test" //设置用户名和密码。
|
||
snprintf((char *)u8_sendBuf,64,"AT+QFTPCFG=\"account\",\"%s\",\"%s\"\r\n",
|
||
t_ftp_update_info.u8_user , t_ftp_update_info.u8_pwd);
|
||
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1, NULL, 5, 100);
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 设置文件类型为二进制 0 二进制 1 ASCII
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpcfg_filetype()
|
||
{
|
||
U8_T u8_sendBuf[] = "AT+QFTPCFG=\"filetype\",0\r\n";
|
||
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1, NULL, 5, 100);
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 设置为被动传输方式。
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpcfg_transmode()
|
||
{
|
||
U8_T u8_sendBuf[] = "AT+QFTPCFG=\"transmode\",1\r\n";
|
||
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1, NULL, 20, 1000);
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 设置最大响应时间(默认为90秒)。
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpcfg_rsptimeout()
|
||
{
|
||
U8_T u8_sendBuf[] = "AT+QFTPCFG=\"rsptimeout\",90\r\n";
|
||
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1, NULL, 5, 100);
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 登录FTP服务器。
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpopen()
|
||
{
|
||
U8_T u8_sendBuf[64] = {0};
|
||
//AT+QFTPOPEN="192.0.2.0",8309 登录FTP服务器
|
||
snprintf((char *)u8_sendBuf,64,"AT+QFTPOPEN=\"%s\",%d\r\n",
|
||
t_ftp_update_info.u8_update_server_addr , t_ftp_update_info.u16_update_server_port);
|
||
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1, NULL, 5, 100);
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 设置目录
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpcwd()
|
||
{
|
||
const char *p = (const char *)t_ftp_update_info.u8_path;
|
||
U8_T u8_sendBuf[160] = {0};
|
||
S8_T r;
|
||
size_t pl;
|
||
int n;
|
||
|
||
if (p == NULL || p[0] == '\0') {
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPCWD skip (empty path)\r\n");
|
||
return 1;
|
||
}
|
||
pl = strlen(p);
|
||
while (pl > 0U && p[pl - 1U] == '/') {
|
||
pl--;
|
||
}
|
||
if (pl == 0U) {
|
||
return 1;
|
||
}
|
||
|
||
n = snprintf((char *)u8_sendBuf, sizeof(u8_sendBuf), "AT+QFTPCWD=\"%.*s\"\r\n", (int)pl, p);
|
||
if (n <= 0 || n >= (int)sizeof(u8_sendBuf)) {
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPCWD cmd too long, skip (use full remote path)\r\n");
|
||
return 1;
|
||
}
|
||
r = s8_4g_Send_AT_Cmd(u8_sendBuf, (U16_T)n, NULL, 5, 100);
|
||
if (r >= 0) {
|
||
return r;
|
||
}
|
||
if (p[0] == '/') {
|
||
n = snprintf((char *)u8_sendBuf, sizeof(u8_sendBuf), "AT+QFTPCWD=\"%.*s\"\r\n", (int)(pl - 1U), p + 1);
|
||
if (n > 0 && n < (int)sizeof(u8_sendBuf)) {
|
||
r = s8_4g_Send_AT_Cmd(u8_sendBuf, (U16_T)n, NULL, 5, 100);
|
||
if (r >= 0) {
|
||
return r;
|
||
}
|
||
}
|
||
}
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPCWD fail, continue (QFTPSIZE/QFTPGET use full remote path) ret=%d\r\n", (int)r);
|
||
return 1;
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 获取当前目录的内容,并通过 COM 口输出数据。
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftplist()
|
||
{
|
||
U8_T u8_sendBuf[] = "AT+QFTPLIST=\".\"\r\n";
|
||
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1, NULL, 5, 100);
|
||
}
|
||
|
||
/** 远端 path + file,供 QFTPSIZE / QFTPGET(COM)(减少对 QFTPCWD 的依赖) */
|
||
static U8_T s_ftp_remote_get_obj[200];
|
||
|
||
static int s32_ftp_fill_remote_get_object(void)
|
||
{
|
||
const char *p = (const char *)t_ftp_update_info.u8_path;
|
||
const char *f = (const char *)t_ftp_update_info.u8_file_name;
|
||
size_t pl;
|
||
int n;
|
||
|
||
if (f[0] == '\0') {
|
||
return -1;
|
||
}
|
||
pl = (p != NULL) ? strlen(p) : 0U;
|
||
while (pl > 0U && p[pl - 1U] == '/') {
|
||
pl--;
|
||
}
|
||
if (pl == 0U) {
|
||
n = snprintf((char *)s_ftp_remote_get_obj, sizeof(s_ftp_remote_get_obj), "%s", f);
|
||
} else {
|
||
n = snprintf((char *)s_ftp_remote_get_obj, sizeof(s_ftp_remote_get_obj), "%.*s/%s", (int)pl, p, f);
|
||
}
|
||
if (n <= 0 || (size_t)n >= sizeof(s_ftp_remote_get_obj)) {
|
||
EC200A_FTP_LOG("[FTP-UPG] remote object path too long\r\n");
|
||
return -1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 获取文件大小 并计算包数量
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpsize()
|
||
{
|
||
U8_T u8_sendBuf[256] = {0};
|
||
int n, k;
|
||
enum { QFTPSIZE_ACCUM_LEN = 640 };
|
||
U8_T rcvBuf[QFTPSIZE_ACCUM_LEN];
|
||
int cmd_len;
|
||
U16_T rcv_len = 0U;
|
||
U16_T total_waits = 0U;
|
||
/* +QFTPSIZE 常为异步 URC,可与业务 TCP 的 QIRD 应答交错;勿用 s8_4g_Send_Recv_Cmd 仅 2×50ms 等首包 */
|
||
const U16_T max_waits = (U16_T)((EC200A_FTP_QFREAD_TOTAL_WAITS) * 10U);
|
||
|
||
if (s32_ftp_fill_remote_get_object() != 0) {
|
||
return -1;
|
||
}
|
||
|
||
cmd_len = snprintf((char *)u8_sendBuf, sizeof(u8_sendBuf),
|
||
"AT+QFTPSIZE=\"%s\"\r\n", (char *)s_ftp_remote_get_obj);
|
||
if (cmd_len <= 0 || cmd_len >= (int)sizeof(u8_sendBuf))
|
||
{
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPSIZE cmd too long (obj=%s,len=%d)\r\n",
|
||
(char *)s_ftp_remote_get_obj, cmd_len);
|
||
return -1;
|
||
}
|
||
|
||
memset(rcvBuf, 0, sizeof(rcvBuf));
|
||
v_4g_send_data((U8_T)0xFF, u8_sendBuf, (U16_T)cmd_len);
|
||
|
||
while (total_waits < max_waits) {
|
||
mSleep(EC200A_FTP_UART_SLICE_WAIT_MS);
|
||
if (rcv_len + 1U < (U16_T)sizeof(rcvBuf)) {
|
||
rcv_len += u16_4g_recv_data(
|
||
rcvBuf + rcv_len,
|
||
(U16_T)((U16_T)sizeof(rcvBuf) - 1U - rcv_len));
|
||
} else {
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPSIZE accum overflow\r\n");
|
||
return -1;
|
||
}
|
||
total_waits++;
|
||
|
||
if (rcv_len == 0U) {
|
||
continue;
|
||
}
|
||
|
||
if (strstr((char *)rcvBuf, "+CME ERROR") != NULL
|
||
|| strstr((char *)rcvBuf, "\r\nERROR\r\n") != NULL) {
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPSIZE modem ERROR in rsp\r\n");
|
||
return -1;
|
||
}
|
||
|
||
{
|
||
char *p = strstr((char *)rcvBuf, "+QFTPSIZE:");
|
||
if (p != NULL && sscanf(p, "+QFTPSIZE: %d,%d", &n, &k) == 2) {
|
||
if (k <= 0) {
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPSIZE invalid size=%d\r\n", k);
|
||
return -1;
|
||
}
|
||
t_ftp_update_info.u32_file_size = (uint32_t)k;
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPSIZE obj=%s size=%lu (waits=%u)\r\n",
|
||
(char *)s_ftp_remote_get_obj, (unsigned long)t_ftp_update_info.u32_file_size,
|
||
(unsigned)total_waits);
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPSIZE timeout no +QFTPSIZE (obj=%s, rcv_len=%u)\r\n",
|
||
(char *)s_ftp_remote_get_obj, (unsigned)rcv_len);
|
||
return -1;
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - //删除 UFS 中所有文件(不删除目录)。
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qfdel()
|
||
{
|
||
U8_T u8_sendBuf[] = "AT+QFDEL=\"*\"\r\n"; ////删除 UFS 中所有文件(不删除目录)。
|
||
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1, NULL, 5, 100);
|
||
}
|
||
|
||
/** 调试:打印本包负载前 10 / 后 10 字节(与 PC 上 bin 对拍);len≤10 只打一行 */
|
||
static void v_qftpget_log_pkt_data_edges(const U8_T *p, uint32_t len, uint32_t pkt_idx, int byte_off)
|
||
{
|
||
char hbuf[56];
|
||
char tbuf[56];
|
||
uint32_t hlen;
|
||
uint32_t tstart;
|
||
uint32_t ti;
|
||
int pos;
|
||
|
||
if (p == NULL || len == 0U) {
|
||
return;
|
||
}
|
||
|
||
hlen = (len < 10U) ? len : 10U;
|
||
pos = 0;
|
||
for (ti = 0U; ti < hlen && pos < (int)sizeof(hbuf) - 4; ti++) {
|
||
pos += snprintf(hbuf + (size_t)pos, sizeof(hbuf) - (size_t)pos, "%02X ", (unsigned)p[ti]);
|
||
}
|
||
hbuf[sizeof(hbuf) - 1U] = '\0';
|
||
|
||
if (len <= 10U) {
|
||
EC200A_FTP_LOG("[FTP-UPG] pkt%u off=%d len=%lu hex: %s\r\n",
|
||
(unsigned)pkt_idx, byte_off, (unsigned long)len, hbuf);
|
||
return;
|
||
}
|
||
|
||
tstart = len - 10U;
|
||
pos = 0;
|
||
for (ti = tstart; ti < len && pos < (int)sizeof(tbuf) - 4; ti++) {
|
||
pos += snprintf(tbuf + (size_t)pos, sizeof(tbuf) - (size_t)pos, "%02X ", (unsigned)p[ti]);
|
||
}
|
||
tbuf[sizeof(tbuf) - 1U] = '\0';
|
||
|
||
EC200A_FTP_LOG("[FTP-UPG] pkt%u off=%d len=%lu head10: %s tail10: %s\r\n",
|
||
(unsigned)pkt_idx, byte_off, (unsigned long)len, hbuf, tbuf);
|
||
}
|
||
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 周期获取文件内容 并存储
|
||
*
|
||
*
|
||
* @return S8_T - -1 获取失败 0获取中 1获取完成
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpget()
|
||
{
|
||
U8_T u8_sendBuf[224] = {0};
|
||
S16_T s16_ret;
|
||
U32_T file_len = 0U;
|
||
const U8_T *file_data = NULL;
|
||
uint32_t done;
|
||
uint32_t f_sz;
|
||
uint32_t rem;
|
||
U16_T read_size;
|
||
int packAddr;
|
||
int sn;
|
||
|
||
#if EC200A_TCP_USE_TRANSPARENT_MODE
|
||
U8_T rcvBuf[FTP_REAC_DATA_BUF_LEN] = {0};
|
||
#else
|
||
U8_T *qfget_rsp = NULL;
|
||
#endif
|
||
|
||
/* 分片经 COM 拉取并写 Flash(与 QFREAD 分包思路一致),不经 UFS 整文件 */
|
||
if (s32_ftp_fill_remote_get_object() != 0) {
|
||
return -1;
|
||
}
|
||
|
||
f_sz = t_ftp_update_info.u32_file_size;
|
||
done = (uint32_t)t_ftp_update_info.u16_packIndex * (uint32_t)t_ftp_update_info.u16_packSize;
|
||
rem = (f_sz > done) ? (f_sz - done) : 0U;
|
||
read_size = t_ftp_update_info.u16_packSize;
|
||
|
||
if (rem == 0U) {
|
||
return 1;
|
||
}
|
||
if (rem < (uint32_t)read_size) {
|
||
read_size = (U16_T)rem;
|
||
}
|
||
packAddr = (int)((uint32_t)t_ftp_update_info.u16_packIndex * (uint32_t)t_ftp_update_info.u16_packSize);
|
||
|
||
if (t_ftp_update_info.u16_packIndex == 0) {
|
||
v_upgrade_header_data(0);
|
||
}
|
||
|
||
sn = snprintf((char *)u8_sendBuf, sizeof(u8_sendBuf),
|
||
"AT+QFTPGET=\"%s\",\"COM:\",%d,%u\r\n",
|
||
(char *)s_ftp_remote_get_obj, packAddr, (unsigned)read_size);
|
||
if (sn <= 0 || sn >= (int)sizeof(u8_sendBuf)) {
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPGET(COM) cmd too long\r\n");
|
||
return -1;
|
||
}
|
||
|
||
#if EC200A_TCP_USE_TRANSPARENT_MODE
|
||
s16_ret = s16_4g_Send_Recv_Ftp_Get(u8_sendBuf, (U16_T)sn, rcvBuf, (U16_T)FTP_REAC_DATA_BUF_LEN, 12, 200);
|
||
#else
|
||
{
|
||
uint32_t com_pay_off = 0U;
|
||
|
||
s16_ret = s16_qftpget_com_at_slice(u8_sendBuf, (U16_T)sn, &qfget_rsp, read_size, &com_pay_off);
|
||
if (s16_ret >= 0 && qfget_rsp != NULL) {
|
||
uint32_t need = com_pay_off + (uint32_t)read_size + 4U;
|
||
|
||
if ((uint32_t)s16_ret < need) {
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPGET(COM) frame len err off=%lu need=%lu got=%d\r\n",
|
||
(unsigned long)com_pay_off, (unsigned long)need, (int)s16_ret);
|
||
vPortFree(qfget_rsp);
|
||
qfget_rsp = NULL;
|
||
s16_ret = -1;
|
||
} else {
|
||
file_data = qfget_rsp + com_pay_off;
|
||
file_len = (U32_T)read_size;
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPGET(COM) pkt %u/%u off=%d len=%u ret=%d\r\n",
|
||
(unsigned)t_ftp_update_info.u16_packIndex, (unsigned)t_ftp_update_info.u16_packNum,
|
||
packAddr, (unsigned)read_size, (int)s16_ret);
|
||
|
||
if (s16_ret < 0) {
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
if (qfget_rsp != NULL) {
|
||
vPortFree(qfget_rsp);
|
||
}
|
||
#endif
|
||
return -1;
|
||
}
|
||
|
||
#if EC200A_TCP_USE_TRANSPARENT_MODE
|
||
file_data = parse_4g_ftp_response(rcvBuf, (uint32_t)s16_ret, &file_len);
|
||
#else
|
||
/* 非透传:已由 s16_qftpget_com_at_slice 定界,不再 parse(避免尾缀混入 QIRD 时误用「最后一个 \\r\\nOK」) */
|
||
#endif
|
||
|
||
if (file_data == NULL) {
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
if (qfget_rsp != NULL) {
|
||
vPortFree(qfget_rsp);
|
||
}
|
||
#endif
|
||
EC200A_FTP_LOG("[FTP-UPG] QFTPGET(COM) parse fail\r\n");
|
||
#if BS_OCPP_EN
|
||
v_ocpp_set_fw_notify_pending((U8_T)OCPP_FW_NOTIFY_PENDING_DOWNLOAD_FAILED);
|
||
#endif
|
||
s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag = 0U;
|
||
s_bs_task_ctrl.s_bs_ctrl[1].u8_updata_flag = 0U;
|
||
v_ftp_ctrl_init();
|
||
return -1;
|
||
}
|
||
|
||
v_qftpget_log_pkt_data_edges(file_data, (uint32_t)file_len,
|
||
(uint32_t)t_ftp_update_info.u16_packIndex, packAddr);
|
||
|
||
{
|
||
uint32_t flash_base = (uint32_t)t_ftp_update_info.u16_packIndex *
|
||
((uint32_t)t_ftp_update_info.u16_packSize / (uint32_t)PACKET_SIZE);
|
||
uint32_t o = 0U;
|
||
|
||
while (o < file_len) {
|
||
uint32_t sub = file_len - o;
|
||
if (sub > (uint32_t)PACKET_SIZE) {
|
||
sub = (uint32_t)PACKET_SIZE;
|
||
}
|
||
{
|
||
int flash_write = upgrade_write_packet(
|
||
flash_base + (uint32_t)(o / (uint32_t)PACKET_SIZE),
|
||
file_data + o, sub);
|
||
if (flash_write != 0) {
|
||
EC200A_FTP_LOG("[FTP-UPG] flash wr fail sub_off=%lu ret=%d\r\n",
|
||
(unsigned long)o, flash_write);
|
||
#if BS_OCPP_EN
|
||
v_ocpp_set_fw_notify_pending((U8_T)OCPP_FW_NOTIFY_PENDING_INSTALLATION_FAILED);
|
||
#endif
|
||
s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag = 0U;
|
||
s_bs_task_ctrl.s_bs_ctrl[1].u8_updata_flag = 0U;
|
||
v_ftp_ctrl_init();
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
if (qfget_rsp != NULL) {
|
||
vPortFree(qfget_rsp);
|
||
}
|
||
#endif
|
||
return -1;
|
||
}
|
||
}
|
||
o += sub;
|
||
}
|
||
}
|
||
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
if (qfget_rsp != NULL) {
|
||
vPortFree(qfget_rsp);
|
||
}
|
||
#endif
|
||
|
||
t_ftp_update_info.u16_packIndex++;
|
||
|
||
if (t_ftp_update_info.u16_packIndex >= t_ftp_update_info.u16_packNum) {
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 列出 UFS 中所有文件。
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-12-04
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qflst()
|
||
{
|
||
U8_T u8_sendBuf[] = "AT+QFLST=\"*\"\r\n"; //列出 UFS 中所有文件。
|
||
S8_T s8_ret;
|
||
int size;
|
||
char fileName[NUM_64] = {0};
|
||
U8_T u8_ack[] = "+QFLST:";
|
||
U8_T rcvBuf[BS_RECV_BUF_LEN] = {0};
|
||
|
||
s8_ret = s8_4g_Send_Recv_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1,rcvBuf,BS_RECV_BUF_LEN, u8_ack, 1, 1000*6);
|
||
if(s8_ret >= 0)
|
||
{
|
||
/*
|
||
+QFLST: "UFS:CCU601E.bin",584072
|
||
OK
|
||
*/
|
||
if (sscanf((char *)&rcvBuf[s8_ret], "+QFLST: \"UFS:%[^\"]\",%d", fileName, &size) == 2) {
|
||
|
||
if(/*size == t_ftp_update_info.u32_file_size &&*/
|
||
strstr((char *)t_ftp_update_info.u8_file_name,fileName))
|
||
{
|
||
EC200A_FTP_LOG("FTP file ok(%s)[%d], start\r\n",fileName,size);
|
||
t_ftp_update_info.u16_packIndex = 0; //清空当前索引号
|
||
t_ftp_update_info.u32_file_size = (uint32_t)size; // UFS 文件大小
|
||
{
|
||
uint32_t chunk = (uint32_t)EC200A_FTP_UFS_RW_CHUNK_BYTES;
|
||
uint32_t fsz = (uint32_t)size;
|
||
t_ftp_update_info.u16_packSize = (U16_T)chunk;
|
||
t_ftp_update_info.u16_packNum = (U16_T)((fsz + chunk - 1U) / chunk);
|
||
}
|
||
EC200A_FTP_LOG("%s file size= (%d) ,packSize= (%u) ,packNum= (%d) \r\n",
|
||
t_ftp_update_info.u8_file_name, size,
|
||
(unsigned)EC200A_FTP_UFS_RW_CHUNK_BYTES, t_ftp_update_info.u16_packNum);
|
||
|
||
if(t_ftp_update_info.u16_packNum == 0) //异常处理
|
||
s8_ret = -1;
|
||
}
|
||
else
|
||
{
|
||
EC200A_FTP_LOG("文件获取失败(%s)[%d] ,(%s)[%d] \r\n",fileName,size,
|
||
t_ftp_update_info.u8_file_name,t_ftp_update_info.u32_file_size);
|
||
s8_ret = -1;
|
||
}
|
||
|
||
}
|
||
else
|
||
s8_ret = -1;
|
||
}
|
||
return s8_ret;
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 打开文件获取文件指针
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-12-04
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qfopen()
|
||
{
|
||
U8_T u8_sendBuf[64] = {0};
|
||
U8_T rcvBuf[BS_RECV_BUF_LEN] = {0};
|
||
S8_T s8_ret;
|
||
U8_T u8_ack[] = "+QFOPEN:";
|
||
|
||
//AT+QFOPEN="test.txt",2 //打开文件获取文件指针。 2:若文件存在,则作为只读文件直接打开;若文件不存在,则响应错误
|
||
snprintf((char *)u8_sendBuf,64,"AT+QFOPEN=\"%s\",2\r\n",
|
||
t_ftp_update_info.u8_file_name);
|
||
|
||
s8_ret = s8_4g_Send_Recv_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1,rcvBuf,BS_RECV_BUF_LEN, u8_ack, 5, 200);
|
||
|
||
if(s8_ret >= 0)
|
||
{
|
||
if (sscanf((char *)&rcvBuf[s8_ret], "+QFOPEN: %d", &t_ftp_update_info.u32_file_fd) == 1) {
|
||
EC200A_FTP_LOG("FTP open ok[%d], start\r\n",t_ftp_update_info.u32_file_fd);
|
||
v_upgrade_header_data(0); //升级前更新头部信息
|
||
}
|
||
else
|
||
s8_ret = -1;
|
||
}
|
||
|
||
return s8_ret;
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief -设置文件指针为文件的初始位置。
|
||
*
|
||
*
|
||
* @return S8_T -
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-12-04
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qfseek()
|
||
{
|
||
U8_T u8_sendBuf[64] = {0};
|
||
//AT+QFSEEK=1,0,0 //设置文件指针为文件的初始位置。
|
||
snprintf((char *)u8_sendBuf,64,"AT+QFSEEK=%d,0,0\r\n",
|
||
t_ftp_update_info.u32_file_fd);
|
||
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1, NULL, 5, 100);
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 读取文件数据
|
||
*
|
||
*
|
||
* @return S8_T - 0 尚有分包待读 1 已全部读完 -1 失败
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-12-04
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qfread()
|
||
{
|
||
U8_T u8_sendBuf[64] = {0};
|
||
S16_T s16_ret;
|
||
U32_T file_len; // 文件数据长度
|
||
const U8_T *file_data = NULL; // 文件数据起始地址
|
||
int sn;
|
||
#if EC200A_TCP_USE_TRANSPARENT_MODE
|
||
U8_T rcvBuf[FTP_REAC_DATA_BUF_LEN] = {0};
|
||
#else
|
||
U8_T *qfread_rsp = NULL;
|
||
#endif
|
||
int packAddr = t_ftp_update_info.u16_packIndex*t_ftp_update_info.u16_packSize; //获取包地址
|
||
uint32_t done = (uint32_t)t_ftp_update_info.u16_packIndex * (uint32_t)t_ftp_update_info.u16_packSize;
|
||
uint32_t f_sz = t_ftp_update_info.u32_file_size;
|
||
uint32_t rem = (f_sz > done) ? (f_sz - done) : 0U;
|
||
U16_T read_size = t_ftp_update_info.u16_packSize;
|
||
|
||
if (rem == 0U) {
|
||
return 1;
|
||
}
|
||
if (rem < (uint32_t)read_size) {
|
||
read_size = (U16_T)rem;
|
||
}
|
||
|
||
snprintf((char *)u8_sendBuf, sizeof(u8_sendBuf), "AT+QFREAD=%d,%d\r\n",
|
||
t_ftp_update_info.u32_file_fd ,read_size);
|
||
sn = (int)strlen((char *)u8_sendBuf);
|
||
if (sn <= 0 || sn >= (int)sizeof(u8_sendBuf)) {
|
||
return -1;
|
||
}
|
||
|
||
#if EC200A_TCP_USE_TRANSPARENT_MODE
|
||
s16_ret = s16_4g_Send_Recv_Ftp_Get(u8_sendBuf, (U16_T)sn, rcvBuf, FTP_REAC_DATA_BUF_LEN, 6, 200);
|
||
#else
|
||
s16_ret = s16_qfread_at_slice(u8_sendBuf, (U16_T)sn, &qfread_rsp);
|
||
#endif
|
||
|
||
EC200A_FTP_LOG("RX pkt(%d)/(%d), prog %02d%% [%d](%d)\r\n",t_ftp_update_info.u16_packIndex,t_ftp_update_info.u16_packNum,
|
||
(packAddr*100/t_ftp_update_info.u32_file_size),packAddr,t_ftp_update_info.u32_file_size);
|
||
if(s16_ret >= 0)
|
||
{
|
||
#if EC200A_TCP_USE_TRANSPARENT_MODE
|
||
file_data = parse_4g_ftp_response(rcvBuf, (uint32_t)s16_ret, &file_len);
|
||
#else
|
||
file_data = parse_4g_ftp_response(qfread_rsp, (uint32_t)s16_ret, &file_len);
|
||
#endif
|
||
|
||
if (file_data != NULL) {
|
||
EC200A_FTP_LOG("File data ok, len=%uB\r\n", file_len);
|
||
{
|
||
uint32_t flash_base = (uint32_t)t_ftp_update_info.u16_packIndex *
|
||
((uint32_t)t_ftp_update_info.u16_packSize / (uint32_t)PACKET_SIZE);
|
||
uint32_t o = 0U;
|
||
int flash_write = 0;
|
||
|
||
while (o < file_len) {
|
||
uint32_t sub = file_len - o;
|
||
if (sub > (uint32_t)PACKET_SIZE) {
|
||
sub = (uint32_t)PACKET_SIZE;
|
||
}
|
||
flash_write = upgrade_write_packet(
|
||
flash_base + (uint32_t)(o / (uint32_t)PACKET_SIZE),
|
||
file_data + o, sub);
|
||
if (flash_write != 0) {
|
||
EC200A_FTP_LOG("flash wr fail sub_off=%lu ret=%d\r\n", (unsigned long)o, flash_write);
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
if (qfread_rsp != NULL) {
|
||
vPortFree(qfread_rsp);
|
||
qfread_rsp = NULL;
|
||
}
|
||
#endif
|
||
return -1;
|
||
}
|
||
o += sub;
|
||
}
|
||
EC200A_FTP_LOG("flash wr:%d (-1F 0OK) data[%02x %02x %02x %02x %02x %02x %02x %02x]\r\n", flash_write ,
|
||
file_data[0],file_data[1],file_data[2],file_data[3],
|
||
file_data[4],file_data[5],file_data[6],file_data[7]);
|
||
}
|
||
|
||
t_ftp_update_info.u16_packIndex ++;
|
||
|
||
} else {
|
||
EC200A_FTP_LOG("FTP rsp parse fail\r\n");
|
||
}
|
||
|
||
//退出条件判断
|
||
if(t_ftp_update_info.u16_packIndex >= t_ftp_update_info.u16_packNum) // 接收包足够 则退出
|
||
{
|
||
s16_ret = 1;
|
||
}
|
||
else
|
||
s16_ret = 0;
|
||
}
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
if (qfread_rsp != NULL) {
|
||
vPortFree(qfread_rsp);
|
||
}
|
||
#endif
|
||
return (S8_T)s16_ret;
|
||
}
|
||
|
||
static S8_T s8_get_log_info()
|
||
{
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 1);
|
||
|
||
/* v_app_fatfs_log_real_file_name -- CCU601E_D, disabled */
|
||
|
||
EC200A_FTP_LOG("LOG file = %s\r\n",
|
||
t_ftp_update_info.u8_file_name);
|
||
|
||
/* 检查文件是否存在 */
|
||
bool file_exists = false;
|
||
FS_Status fs_status = fs_file_exists((char *)t_ftp_update_info.u8_file_name, &file_exists);
|
||
|
||
if (fs_status != FS_STATUS_OK) {
|
||
EC200A_FTP_LOG("[FileCtrl] Error checking file existence: %s, status=%d\r\n",
|
||
t_ftp_update_info.u8_file_name, fs_status);
|
||
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
|
||
if (!file_exists) {
|
||
EC200A_FTP_LOG("[FileCtrl] File not found: %s\r\n", t_ftp_update_info.u8_file_name);
|
||
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
|
||
/* 获取文件大小 */
|
||
uint32_t file_size = 0;
|
||
fs_status = fs_get_file_size((char *)t_ftp_update_info.u8_file_name, &file_size);
|
||
if (fs_status != FS_STATUS_OK) {
|
||
EC200A_FTP_LOG("[FileCtrl] Failed to get file size: %s, status=%d\r\n",
|
||
t_ftp_update_info.u8_file_name, fs_status);
|
||
/* 恢复文件写入禁用标志(清除TCP调试功能标志位) */
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
t_ftp_update_info.u32_file_size = file_size;
|
||
|
||
if (EC200A_FTP_UFS_RW_CHUNK_BYTES > 65535U) {
|
||
EC200A_FTP_LOG("[FileCtrl] EC200A_FTP_UFS_RW_CHUNK_BYTES too large for u16_packSize\r\n");
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
t_ftp_update_info.u16_packSize = (U16_T)EC200A_FTP_UFS_RW_CHUNK_BYTES;
|
||
/* 向上取整包数(与 u16_packSize 一致,便于 QFSEEK/QFWRITE 分包) */
|
||
t_ftp_update_info.u16_packNum = (U16_T)((file_size + (uint32_t)t_ftp_update_info.u16_packSize - 1U) /
|
||
(uint32_t)t_ftp_update_info.u16_packSize);
|
||
return 1;
|
||
}
|
||
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
/** 当前 FAT 块 QFWRITE 完成后是否为日志文件末尾 */
|
||
static uint8_t s_log_tx_chunk_is_last;
|
||
|
||
static S8_T s8_ec200a_write_log_data(void)
|
||
{
|
||
uint32_t chunk_size = t_ftp_update_info.u16_packSize;
|
||
uint32_t offset = t_ftp_update_info.u16_packIndex * chunk_size;
|
||
uint32_t file_size = t_ftp_update_info.u32_file_size;
|
||
uint32_t remaining = file_size - offset;
|
||
uint32_t read_size = (remaining < chunk_size) ? remaining : chunk_size;
|
||
uint8_t is_last_chunk = (offset + read_size >= file_size) ? 1 : 0;
|
||
uint8_t *read_buffer = NULL;
|
||
char *text_data = NULL;
|
||
uint32_t filtered_size = 0;
|
||
uint32_t dest_index = 0;
|
||
uint32_t i;
|
||
S8_T wr;
|
||
|
||
read_buffer = (uint8_t *)pvPortMalloc(read_size);
|
||
if (read_buffer == NULL) {
|
||
EC200A_FTP_LOG("[FileCtrl] Failed to allocate read buffer (%u bytes)\r\n", read_size);
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
|
||
{
|
||
FS_Status fs_status;
|
||
FS_ReadRange range = {
|
||
.start_pos = offset,
|
||
.end_pos = offset + read_size,
|
||
.actual_read = 0
|
||
};
|
||
fs_status = fs_read_file_content((char *)t_ftp_update_info.u8_file_name, (char *)read_buffer, read_size, &range);
|
||
if (fs_status != FS_STATUS_OK) {
|
||
EC200A_FTP_LOG("[FileCtrl] Failed to read file content: %s, status=%d (offset=%u, size=%u)\r\n",
|
||
(char *)t_ftp_update_info.u8_file_name, fs_status, offset, read_size);
|
||
vPortFree(read_buffer);
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
if (range.actual_read == 0) {
|
||
EC200A_FTP_LOG("[FileCtrl] Read failed: expected %u, got 0\r\n", read_size);
|
||
vPortFree(read_buffer);
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
read_size = range.actual_read;
|
||
is_last_chunk = (offset + read_size >= file_size - 20U) ? 1 : 0;
|
||
}
|
||
|
||
for (i = 0; i < read_size; i++) {
|
||
if (read_buffer[i] != '\0') {
|
||
filtered_size++;
|
||
}
|
||
}
|
||
|
||
text_data = (char *)pvPortMalloc(filtered_size + 1U);
|
||
if (text_data == NULL) {
|
||
EC200A_FTP_LOG("[FileCtrl] Failed to allocate text buffer (%u bytes)\r\n", filtered_size + 1U);
|
||
vPortFree(read_buffer);
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
dest_index = 0;
|
||
for (i = 0; i < read_size; i++) {
|
||
if (read_buffer[i] != '\0') {
|
||
text_data[dest_index++] = read_buffer[i];
|
||
}
|
||
}
|
||
text_data[filtered_size] = '\0';
|
||
|
||
EC200A_FTP_LOG(" Progress: %.1f%% (%u/%u bytes)\r\n",
|
||
(float)(offset + read_size) / (float)file_size * 100.0f,
|
||
offset + read_size, file_size);
|
||
|
||
vPortFree(read_buffer);
|
||
read_buffer = NULL;
|
||
|
||
if (filtered_size == 0U) {
|
||
vPortFree(text_data);
|
||
if (is_last_chunk != 0U) {
|
||
s8_ec200a_qfclose_log_fd();
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
EC200A_FTP_LOG("[FileCtrl] File write disabled flag (TCP debug) disabled after final chunk download operation\r\n");
|
||
return 1;
|
||
}
|
||
EC200A_FTP_LOG("[FileCtrl] File write disabled flag (TCP debug) remains enabled for next chunk download\r\n");
|
||
t_ftp_update_info.u16_packIndex++;
|
||
return 0;
|
||
}
|
||
|
||
if (s8_ec200a_qfseek_log_abs(s_log_ufs_qwrite_total) < 0) {
|
||
EC200A_FTP_LOG("[FTP-LOG] QFSEEK fail off=%lu\r\n", (unsigned long)s_log_ufs_qwrite_total);
|
||
s8_ec200a_qfclose_log_fd();
|
||
vPortFree(text_data);
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
|
||
s_log_tx_chunk_is_last = is_last_chunk;
|
||
wr = s8_ec200a_qfwrite_log_bin((const U8_T *)text_data, (U16_T)filtered_size);
|
||
vPortFree(text_data);
|
||
if (wr < 0) {
|
||
EC200A_FTP_LOG("[FTP-LOG] QFWRITE fail len=%u off=%lu\r\n",
|
||
(unsigned)filtered_size, (unsigned long)s_log_ufs_qwrite_total);
|
||
s8_ec200a_qfclose_log_fd();
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
return -1;
|
||
}
|
||
s_log_ufs_qwrite_total += filtered_size;
|
||
|
||
if (is_last_chunk != 0U) {
|
||
s8_ec200a_qfclose_log_fd();
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
EC200A_FTP_LOG("[FileCtrl] File write disabled flag (TCP debug) disabled after final chunk download operation\r\n");
|
||
return 1;
|
||
}
|
||
EC200A_FTP_LOG("[FileCtrl] File write disabled flag (TCP debug) remains enabled for next chunk download\r\n");
|
||
t_ftp_update_info.u16_packIndex++;
|
||
return 0;
|
||
}
|
||
#else
|
||
static S8_T s8_ec200a_write_log_data(void)
|
||
{
|
||
return -1;
|
||
}
|
||
#endif /* !EC200A_TCP_USE_TRANSPARENT_MODE */
|
||
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 上传文件至FTP服务器
|
||
*
|
||
*
|
||
* @return S8_T - -1 获取失败 0获取中 1获取完成
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-29
|
||
* ************************************************************************
|
||
*/
|
||
static S8_T s8_ec200a_qftpclose(void)
|
||
{
|
||
const U8_T u8_sendBuf[] = "AT+QFTPCLOSE\r\n";
|
||
|
||
return s8_4g_Send_AT_Cmd((U8_T *)(void *)u8_sendBuf, (U16_T)(sizeof(u8_sendBuf) - 1U), NULL, 5U, 400U);
|
||
}
|
||
|
||
static S8_T s8_ec200a_qftpput()
|
||
{
|
||
U8_T u8_sendBuf[128] = {0};
|
||
char *last_slash = strrchr((char *)t_ftp_update_info.u8_file_name, '/'); //带路径的 提取出文件名称
|
||
|
||
#if 1 //使用UFS接收文件
|
||
//AT+QFTPGET="test_my1.txt","UFS:test.txt" //下载文件并将其保存至 UFS,命名为 test.txt。
|
||
snprintf((char *)u8_sendBuf,sizeof(u8_sendBuf) - 1,"AT+QFTPPUT=\"%s\",\"UFS:%s\",0\r\n",
|
||
last_slash+1 ,last_slash+1);
|
||
|
||
return s8_4g_Send_AT_Cmd(u8_sendBuf, sizeof(u8_sendBuf) - 1, NULL, 10, 500);
|
||
#endif
|
||
}
|
||
#endif
|
||
|
||
U8_T u8_ec200a_4g_ftp_update()
|
||
{
|
||
S8_T s8_at_res;
|
||
static U8_T u8_out_cnt = 0;
|
||
static E_EC200A_4G_FTP_INIT_STEP s_last_step = (E_EC200A_4G_FTP_INIT_STEP)0xFF;
|
||
|
||
// static U16_T u16_cnt = 0;
|
||
// if(u16_cnt++ < 10)
|
||
// return 0;
|
||
// u16_cnt = 0;
|
||
|
||
if (s_last_step != e_ec200a_ftp_init_step) {
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d\r\n", (int)e_ec200a_ftp_init_step);
|
||
s_last_step = e_ec200a_ftp_init_step;
|
||
}
|
||
|
||
switch (e_ec200a_ftp_init_step)
|
||
{
|
||
case STEP_FTP_SWCHTO_CMD_MODE:
|
||
{
|
||
s8_at_res = s8_work_mode_cmd();
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_SET_CGREG; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_SET_CGREG: //设置PS域 网络注册状态
|
||
{
|
||
s8_at_res = s8_ec200a_set_cgreg(); //
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_QUERY_CGREG; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_QUERY_CGREG: //查询PS域 网络注册状态
|
||
{
|
||
s8_at_res = s8_ec200a_cgreg(); //查询PS域 网络注册状态
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_SET_QIDEACT; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_SET_QIDEACT: //去激活 FTP 专用 PDP(不碰业务 TCP 场景)
|
||
{
|
||
s8_at_res = s8_ec200a_qideact_ctx((U8_T)EC200A_FTP_PDP_CTX_ID);
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_SET_QIACT; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_SET_QIACT: //配置并激活 FTP 专用 PDP
|
||
{
|
||
s8_at_res = s8_ec200a_qicsgp_ctx((U8_T)EC200A_FTP_PDP_CTX_ID);
|
||
if (s8_at_res >= 0) {
|
||
s8_at_res = s8_ec200a_qiact_ctx((U8_T)EC200A_FTP_PDP_CTX_ID);
|
||
}
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_contextid; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_contextid: //配置 FTP(S) PDP 上下文 ID
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_contextid();
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_account; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_account: //配置 FTP(S) 设置用户名和密码。
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_account();
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d (user=%s)\r\n", (int)e_ec200a_ftp_init_step, s8_at_res, t_ftp_update_info.u8_user);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_filetype; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_filetype: //配置 FTP(S) 设置文件类型为ASCII。
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_filetype();
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_transmode; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_transmode: //配置 FTP(S) 设置为被动传输方式。
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_transmode();
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_rsptimeout; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_rsptimeout: //配置 FTP(S) 设置最大响应时间(默认为90秒
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_rsptimeout();
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_QFTPOPEN; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_QFTPOPEN: //登录FTP服务器。
|
||
{
|
||
s8_at_res = s8_ec200a_qftpopen();
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d (host=%s:%d)\r\n", (int)e_ec200a_ftp_init_step, s8_at_res,
|
||
t_ftp_update_info.u8_update_server_addr, t_ftp_update_info.u16_update_server_port);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_QFTPCWD; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_QFTPCWD: //切换目录
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcwd();
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d (path=%s)\r\n", (int)e_ec200a_ftp_init_step, s8_at_res, t_ftp_update_info.u8_path);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_GET_QFTPSIZE; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_QFTPLIST: //获取当前目录的内容 -- 不使用
|
||
{
|
||
s8_at_res = s8_ec200a_qftplist();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_SAVE; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_GET_QFTPSIZE: //获取 文件名称
|
||
{
|
||
s8_at_res = s8_ec200a_qftpsize();
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d (file=%s size=%lu)\r\n", (int)e_ec200a_ftp_init_step, s8_at_res,
|
||
t_ftp_update_info.u8_file_name, (unsigned long)t_ftp_update_info.u32_file_size);
|
||
if(s8_at_res >= 0){
|
||
{
|
||
uint32_t chunk = (uint32_t)EC200A_FTP_UFS_RW_CHUNK_BYTES;
|
||
uint32_t fsz = t_ftp_update_info.u32_file_size;
|
||
|
||
t_ftp_update_info.u16_packSize = (U16_T)chunk;
|
||
t_ftp_update_info.u16_packNum = (U16_T)((fsz + chunk - 1U) / chunk);
|
||
t_ftp_update_info.u16_packIndex = 0;
|
||
if (t_ftp_update_info.u16_packNum == 0U) {
|
||
EC200A_FTP_LOG("[FTP-UPG] packNum=0, abort\r\n");
|
||
break;
|
||
}
|
||
EC200A_FTP_LOG("[FTP-UPG] COM chunk packSize=%u packNum=%u\r\n",
|
||
(unsigned)t_ftp_update_info.u16_packSize,
|
||
(unsigned)t_ftp_update_info.u16_packNum);
|
||
}
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_QFDEL; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_QFDEL: //获取 删除存储区保存的文件内容
|
||
{
|
||
s8_at_res = s8_ec200a_qfdel();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_GET_QFTPGET; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_GET_QFTPGET: //获取 文件内容
|
||
{
|
||
s8_at_res = s8_ec200a_qftpget(); //返回值 等于1时 成功
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
// 约定:-1 失败;0 正在处理/需要重试;1 完成成功
|
||
/* COM 分片已直接写入 Flash,跳过 QFLST/QFOPEN/QFSEEK/QFREAD(UFS) */
|
||
if(s8_at_res == 1){
|
||
#if BS_OCPP_EN
|
||
v_ocpp_set_fw_notify_pending((U8_T)OCPP_FW_NOTIFY_PENDING_DOWNLOADED);
|
||
#endif
|
||
e_ec200a_ftp_init_step = STEP_FTP_SAVE; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_GET_QFLST: //获取 UFS中文件内容 qflst
|
||
{
|
||
s8_at_res = s8_ec200a_qflst(); //返回值 等于1时 成功
|
||
EC200A_FTP_LOG("[FTP-UPG] step=%d ret=%d\r\n", (int)e_ec200a_ftp_init_step, s8_at_res);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_GET_QFOPEN; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_GET_QFOPEN: //打开文件
|
||
{
|
||
s8_at_res = s8_ec200a_qfopen(); //返回值 等于1时 成功
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_GET_QFSEEK; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_GET_QFSEEK: //设置读取文件指针头地址
|
||
{
|
||
s8_at_res = s8_ec200a_qfseek(); //返回值 等于1时 成功
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_GET_QFREAD; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_GET_QFREAD: //读取文件
|
||
{
|
||
s8_at_res = s8_ec200a_qfread(); //返回值 等于1时 成功
|
||
if (s8_at_res == 1 || s8_at_res == 0)
|
||
{
|
||
u8_out_cnt = 0; //超时计数清空
|
||
if(s8_at_res == 1){
|
||
e_ec200a_ftp_init_step = STEP_FTP_SAVE; //状态跳转
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_SAVE: //保存当前设置并重启
|
||
case STEP_FTP_INIT_OK: //设置完成
|
||
{
|
||
#if BS_OCPP_EN
|
||
if (s_u8_fw_save_ocpp_arm == 0U) {
|
||
/* 仅置 pending;实际上送在 Plat_Comm 联网半周期的 ocpp_send_mag_ctrl */
|
||
v_ocpp_set_fw_notify_pending((U8_T)OCPP_FW_NOTIFY_PENDING_INSTALLING);
|
||
s_u8_fw_save_ocpp_arm = 1U;
|
||
break;
|
||
}
|
||
if (u8_ocpp_fw_installing_fsn_sent() == 0U) {
|
||
/* 须等 FSN(Installing) ws_send 成功;勿在未上送时写头/复位 */
|
||
break;
|
||
}
|
||
#endif
|
||
v_upgrade_header_data(1); //升级后更新头部信息
|
||
#if BS_OCPP_EN
|
||
v_ocpp_fw_eeprom_set_installed_after_boot();
|
||
s_u8_fw_save_ocpp_arm = 0U;
|
||
v_ocpp_clr_fw_installing_fsn_sent();
|
||
v_sys_reboot(); /* Installing 已上送后再复位;Installed 在 BootNotification 后上送 */
|
||
#else
|
||
v_sys_reboot(); //系统重启 默认此时未充电
|
||
#endif
|
||
break;
|
||
}
|
||
case STEP_FTP_INIT_DEBUG: // 调试
|
||
{
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
|
||
u8_out_cnt++ ;
|
||
if(e_ec200a_ftp_init_step == STEP_FTP_QUERY_CGREG) //查询PS域 网络注册状态
|
||
{
|
||
if(u8_out_cnt > 120){
|
||
e_ec200a_ftp_init_step = STEP_FTP_SET_QIDEACT; //强制跳转
|
||
u8_out_cnt = 0;
|
||
}
|
||
}
|
||
else if(u8_out_cnt > 60*3) //停留在其中一个状态 大于3分钟
|
||
{
|
||
#if BS_OCPP_EN
|
||
if (s_bs_task_ctrl.ocpp_data.u8_log_file_upload) {
|
||
v_ocpp_set_diag_upload_notify_pending(OCPP_DIAG_NOTIFY_PENDING_UPLOAD_FAILED);
|
||
} else {
|
||
v_ocpp_set_fw_notify_pending((U8_T)OCPP_FW_NOTIFY_PENDING_DOWNLOAD_FAILED);
|
||
}
|
||
#endif
|
||
s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag = 0; //停止
|
||
s_bs_task_ctrl.s_bs_ctrl[1].u8_updata_flag = 0; //停止
|
||
u8_out_cnt = 0;
|
||
EC200A_FTP_LOG("FTP TO, exit upg\r\n");
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
U8_T u8_ec200a_4g_ftp_log_upload()
|
||
{
|
||
S8_T s8_at_res;
|
||
static U8_T u8_out_cnt = 0;
|
||
|
||
// static U16_T u16_cnt = 0;
|
||
// if(u16_cnt++ < 10)
|
||
// return 0;
|
||
// u16_cnt = 0;
|
||
|
||
EC200A_FTP_LOG("ftp test %d\r\n",e_ec200a_ftp_init_step);
|
||
|
||
switch (e_ec200a_ftp_init_step)
|
||
{
|
||
case STEP_FTP_SWCHTO_CMD_MODE:
|
||
{
|
||
s8_at_res = s8_work_mode_cmd();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_QFDEL; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_QFDEL: //获取 删除存储区保存的文件内容
|
||
{
|
||
s8_at_res = s8_ec200a_qfdel();//
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_GET_LOG_INFO; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_GET_LOG_INFO:
|
||
{
|
||
s8_at_res = s8_get_log_info();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_UPLOAD_LOG_UFS; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_UPLOAD_LOG_UFS:
|
||
{
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
s8_at_res = s8_ec200a_qfopen_log_ufs();
|
||
#else
|
||
s8_at_res = -1;
|
||
#endif
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_WRITE_LOG_UFS; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_WRITE_LOG_UFS: //写入日志文件到 UFS
|
||
{
|
||
#if !EC200A_TCP_USE_TRANSPARENT_MODE
|
||
s8_at_res = s8_ec200a_write_log_data(); //返回值 等于1时 成功
|
||
#else
|
||
s8_at_res = -1;
|
||
#endif
|
||
// 约定:-1 失败;0 进行中;1 完成
|
||
if(s8_at_res == 0){
|
||
// 有进度则刷新超时计数,避免大文件上传过程中误判超时
|
||
u8_out_cnt = 0;
|
||
}else if(s8_at_res == 1){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_GET_QFLST; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_GET_QFLST: //获取 UFS中文件内容 qflst
|
||
{
|
||
s8_at_res = s8_ec200a_qflst(); //返回值 等于1时 成功
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_QUERY_CGREG; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_QUERY_CGREG: //查询PS域 网络注册状态
|
||
{
|
||
s8_at_res = s8_ec200a_cgreg(); //查询PS域 网络注册状态
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_SET_QIDEACT; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_SET_QIDEACT: //去激活 FTP 专用 PDP
|
||
{
|
||
s8_at_res = s8_ec200a_qideact_ctx((U8_T)EC200A_FTP_PDP_CTX_ID);
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_SET_QIACT; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_SET_QIACT: //配置并激活 FTP 专用 PDP
|
||
{
|
||
s8_at_res = s8_ec200a_qicsgp_ctx((U8_T)EC200A_FTP_PDP_CTX_ID);
|
||
if (s8_at_res >= 0) {
|
||
s8_at_res = s8_ec200a_qiact_ctx((U8_T)EC200A_FTP_PDP_CTX_ID);
|
||
}
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_contextid; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_contextid: //配置 FTP(S) PDP 上下文 ID
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_contextid();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_account; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_account: //配置 FTP(S) 设置用户名和密码。
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_account();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_filetype; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_filetype: //配置 FTP(S) 设置文件类型为ASCII。
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_filetype();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_transmode; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_transmode: //配置 FTP(S) 设置为被动传输方式。
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_transmode();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_rsptimeout; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_rsptimeout: //配置 FTP(S) 设置最大响应时间(默认为90秒
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcfg_rsptimeout();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_QFTPOPEN; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_QFTPOPEN: //登录FTP服务器。
|
||
{
|
||
s8_at_res = s8_ec200a_qftpopen();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_CFG_QFTPCWD; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_CFG_QFTPCWD: //切换目录
|
||
{
|
||
s8_at_res = s8_ec200a_qftpcwd();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_UPLOAD_LOG_FTP; //状态跳转
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_UPLOAD_LOG_FTP: //上传日志文件到 FT
|
||
{
|
||
s8_at_res = s8_ec200a_qftpput();
|
||
if(s8_at_res >= 0){
|
||
e_ec200a_ftp_init_step = STEP_FTP_FTP_QFTPCLOSE_AFTER_LOG;
|
||
u8_out_cnt = 0; //超时计数清空
|
||
}
|
||
break;
|
||
}
|
||
case STEP_FTP_FTP_QFTPCLOSE_AFTER_LOG:
|
||
{
|
||
static U8_T u8_qclose_fail_streak;
|
||
|
||
s8_at_res = s8_ec200a_qftpclose();
|
||
if (s8_at_res >= 0) {
|
||
u8_qclose_fail_streak = 0;
|
||
e_ec200a_ftp_init_step = STEP_FTP_INIT_OK;
|
||
u8_out_cnt = 0;
|
||
} else if (++u8_qclose_fail_streak >= 4U) {
|
||
u8_qclose_fail_streak = 0;
|
||
EC200A_FTP_LOG("FTP QFTPCLOSE fail ret=%d, continue\r\n", (int)s8_at_res);
|
||
e_ec200a_ftp_init_step = STEP_FTP_INIT_OK;
|
||
u8_out_cnt = 0;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case STEP_FTP_INIT_OK:
|
||
case STEP_FTP_INIT_DEBUG: // 调试
|
||
{
|
||
if(u8_out_cnt < 20){ //等待 ftp 服务器 处理文件
|
||
break;
|
||
}
|
||
#if BS_OCPP_EN
|
||
v_ocpp_set_diag_upload_notify_pending(OCPP_DIAG_NOTIFY_PENDING_UPLOADED);
|
||
#endif
|
||
EC200A_FTP_LOG("FTP log upload done, keep OCPP (no relink)\r\n");
|
||
s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag = 0;
|
||
s_bs_task_ctrl.s_bs_ctrl[1].u8_updata_flag = 0;
|
||
#if BS_OCPP_EN
|
||
s_bs_task_ctrl.ocpp_data.u8_log_file_upload = 0;
|
||
s_bs_task_ctrl.ocpp_data.ulong_timer = 0;
|
||
#endif
|
||
t_ftp_update_info.u8_init_flag = 0;
|
||
v_ftp_ctrl_init();
|
||
u8_out_cnt = 0;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
|
||
u8_out_cnt++ ;
|
||
if(e_ec200a_ftp_init_step == STEP_FTP_QUERY_CGREG) //查询PS域 网络注册状态
|
||
{
|
||
if(u8_out_cnt > 120){
|
||
e_ec200a_ftp_init_step = STEP_FTP_SET_QIDEACT; //强制跳转
|
||
u8_out_cnt = 0;
|
||
}
|
||
}
|
||
else if(u8_out_cnt > 60*3) //停留在其中一个状态 大于3分钟
|
||
{
|
||
#if BS_OCPP_EN
|
||
if (s_bs_task_ctrl.ocpp_data.u8_log_file_upload) {
|
||
v_ocpp_set_diag_upload_notify_pending(OCPP_DIAG_NOTIFY_PENDING_UPLOAD_FAILED);
|
||
}
|
||
#endif
|
||
s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag = 0; //停止
|
||
s_bs_task_ctrl.s_bs_ctrl[1].u8_updata_flag = 0; //停止
|
||
u8_out_cnt = 0;
|
||
EC200A_FTP_LOG("FTP TO, exit upg\r\n");
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
LTE Standard(A)系列模块支持 FTP(S)协议,因此 FTP(S)服务器上的文件和目录可以通过 FTP(S)相
|
||
关 AT 命令进行操作。FTP(S)相关 AT 命令使用流程如下:
|
||
第一步:配置和激活 PDP 上下文。
|
||
1. 使用 AT+QICSGP 配置 PDP 上下文的<APN>、<username>、<password>和其他参数,详细
|
||
信息可参考文档 [1]。可通过 AT+CGQMIN、AT+CGEQMIN、AT+CGQREQ 和 AT+CGEQREQ
|
||
更新 QoS 设置,详细信息可参考文档 [2];
|
||
2. 通过 AT+QIACT 激活 PDP 上下文,详细信息可参考文档 [1];
|
||
3. 通过 AT+QFTPCFG="contextid",<contextID>配置 FTP(S) PDP 上下文 ID。需提前激活 PDP 上
|
||
下文。
|
||
第二步:配置用户账号和 FTP(S)服务器。
|
||
1. 通过 AT+QFTPCFG="account",<username>,<password>配置账号信息;
|
||
2. 通过 AT+QFTPCFG="filetype",<file_type>配置文件类型。在 FTP(S)服务器和客户端间传输的
|
||
文件类型可以是二进制数据或 ASCII 数据;
|
||
3. 通过 AT+QFTPCFG="transmode",<transmode>配置传输模式,即在 FTP(S)服务器端口或客户
|
||
端 端 口 监 听 数 据 连 接 。 请 注 意 , 因 为 FTPS 当 前 不 支 持 主 动 模 式 , 必 须 设 置
|
||
AT+QFTPCFG="transmode",1 后才能进行 FTPS 操作;
|
||
4. 通过 AT+QFTPCFG="rsptimeout",<timeout>配置命令的最大响应时间;
|
||
5. 若模块作为 FTPS 客户端,需执行如下命令:
|
||
1) 执行 AT+QFTPCFG="ssltype",1;
|
||
2) 执行 AT+QFTPCFG="SSL_ctxID",<SSL_ctxID>设置 SSL 上下文 ID;
|
||
3) AT+QSSLCFG 配置所指定的<SSL_ctxID>,详细信息可参考文档 [3]。
|
||
|
||
第三步:登录 FTP(S)服务器。
|
||
通 过 AT+QFTPOPEN=<hostname>,<port> 登录 FTP(S) 服务器 ,命令执行后, 若 响 应 URC
|
||
+QFTPOPEN: 0,0,表示操作成功。注意 FTPS 和 FTP 端口不同。FTPS 服务器的端口取决于 FTPS
|
||
服务器提供商,通常为 990。
|
||
第四步:文件操作。
|
||
1. 通过 AT+QFTPCWD 设置当前目录;
|
||
2. 上传文件至 FTP(S)服务器;
|
||
1) 通过 AT+QFUPL 可以将文件上传至 UFS 或 SD 卡,再通过 AT+QFTPPUT 将文件上传至
|
||
FTP(S)服务器。文件上传成功后,可通过 AT+QFDEL 将其删除。详细信息可参考文档 [4];
|
||
2) 在 COM 口通过 AT+QFTPPUT 将文件上传至 FTP(S)服务器。执行+++可结束文件上传。
|
||
3. 通过 AT+QFTPGET 从 FTP(S)服务器下载文件。文件将在 COM 口输出或被保存至 UFS 或 SD
|
||
卡。若 COM 口输出文件,模块将进入数据模式;
|
||
4. 通过 AT+QFTPSIZE 获取 FTP(S)服务器文件大小;
|
||
5. 通过 AT+QFTPLEN 获取 FTP(S)服务器和客户端之间传输的数据长度;
|
||
6. 通过 AT+QFTPDEL 删除 FTP(S)服务器文件;
|
||
7. 通过 AT+QFTPRENAME 重命名 FTP(S)服务器文件。
|
||
第五步:FTP(S)服务器目录操作。
|
||
1. 通过 AT+QFTPCWD 设置当前目录;
|
||
2. 通过 AT+QFTPMKDIR 创建文件夹;
|
||
3. 通过 AT+QFTPLIST 列出目录内容;
|
||
4. 通过 AT+QFTPNLST 列出目录文件名;
|
||
5. 通过 AT+QFTPRENAME 重命名文件或文件夹;
|
||
6. 通过 AT+QFTPRMDIR 删除文件夹;
|
||
7. 通过 AT+QFTPMLSD 列出标准文件和目录信息;
|
||
8. 通过 AT+QFTPMDTM 获取 FTP(S)服务器文件修改时间。
|
||
第六步:关闭和 FTP(S)服务器的连接。
|
||
通过 AT+QFTPCLOSE 关闭和 FTP(S)服务器的连接,命令执行后,若响应 URC +QFTPCLOSE: 0,0,
|
||
表明操作成功,即可重复上述第三步至第六步。
|
||
第七步:去激活 PDP 上下文。
|
||
通过 AT+QIDEACT=<contextID>去激活 PDP 上下文,详细信息可参考文档 [1]。
|
||
|
||
*/
|
||
|
||
|
||
|
||
//
|
||
|
||
|
||
#if(MY_SHELL_EN) //Shell 使能
|
||
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 遥控测试函数
|
||
*
|
||
*
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-08-04
|
||
* ************************************************************************
|
||
*/
|
||
|
||
// 命令 type 0 is fan1; 1 is fan2; 2 is acyk1; 3 is acyk2;
|
||
extern int parse_ftp_url(const char* url, T_FTP_UPDATE_INFO* info);
|
||
void ftpFunc()
|
||
{
|
||
//ftp://cpadmin@39.104.96.26/ftpfile/firmareV3.61.rbl
|
||
//ftp://cpadmin@39.104.96.26/AcTest.bin \addtogroup
|
||
//ftp://cpadmin@39.104.96.26/CCU601E.bin
|
||
const char *ftpUrl = "ftp://cpadmin:ieszt1234@39.104.96.26/CCU601E.bin";
|
||
v_shell_print("ftpTest %s\r\n",ftpUrl);
|
||
|
||
if(parse_ftp_url(ftpUrl, &t_ftp_update_info) == 0)
|
||
{
|
||
v_shell_print("ftpTest is ok\r\n");
|
||
v_shell_print("用户名=%s\r\n",t_ftp_update_info.u8_user);
|
||
v_shell_print("密码=%s\r\n",t_ftp_update_info.u8_pwd);
|
||
v_shell_print("域名=%s\r\n",t_ftp_update_info.u8_update_server_addr);
|
||
v_shell_print("文件路径=%s\r\n",t_ftp_update_info.u8_path);
|
||
v_shell_print("文件名=%s\r\n",t_ftp_update_info.u8_file_name);
|
||
|
||
t_ftp_update_info.u8_netType = 0;
|
||
s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag = 1; //开始升级
|
||
|
||
//e_ec200a_ftp_init_step = STEP_FTP_FTP_GET_QFLST;
|
||
}
|
||
else
|
||
v_shell_print("ftpTest is err\r\n");
|
||
}
|
||
// 注册
|
||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), ftpTest,ftpFunc, myshlle-- 4 g cat ftp test);
|
||
// U8_T u8_flash_test[PACKET_SIZE];
|
||
|
||
// void flashFunc(int id)
|
||
// {
|
||
// uint32_t len = PACKET_SIZE;
|
||
// upgrade_header_t header;
|
||
|
||
// memset(u8_flash_test,0,PACKET_SIZE);
|
||
// upgrade_read_packet(id,u8_flash_test,&len);
|
||
|
||
// printf_hex("flash",u8_flash_test,len);
|
||
|
||
// if (upgrade_read_header(&header) == 0)
|
||
// {
|
||
// EC200A_FTP_LOG("flag =[%d] , fileSize =[%d]\r\n",header.upgrade_flag,header.file_size);
|
||
// }
|
||
// else
|
||
// EC200A_FTP_LOG("header err\r\n");
|
||
|
||
// v_shell_print("flashFunc \r\n");
|
||
// }
|
||
// // 注册
|
||
// SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), flashTest,flashFunc, myshlle-- flashTest test);
|
||
|
||
#endif
|
||
#endif /* EC200A_4G_EN */
|
||
|