9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
1030 lines
36 KiB
C
1030 lines
36 KiB
C
/**
|
||
* @file lwip_ftp_upgrade.c
|
||
* @brief 基于 LwIP socket 的 FTP 固件升级状态机实现(网线远程升级)
|
||
*/
|
||
#include "publicdata/public_define.h"
|
||
#include "plat_comm/lwip_module/lwip_ftp_upgrade.h"
|
||
#include "plat_comm/lwip_module/lwip_module.h"
|
||
|
||
#include "plat_comm/impl/bs_public_impl.h" /* T_FTP_UPDATE_INFO / t_ftp_update_info */
|
||
#include "plat_comm/plat_comm_task.h" /* Plat_Comm_LOG */
|
||
#include "bsp_include.h"
|
||
#include "main.h"
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include <errno.h>
|
||
#include <stdlib.h>
|
||
#include "FreeRTOS.h"
|
||
#include "task.h"
|
||
#include "lwip/sockets.h" /* fd_set, lwip_select, SOL_SOCKET, SO_ERROR */
|
||
#ifndef EINPROGRESS
|
||
#define EINPROGRESS 115
|
||
#endif
|
||
|
||
#if LWIP_FTP_UPGRADE_ENABLE
|
||
|
||
/* FTP 协议常量 */
|
||
#define FTP_CTRL_DEFAULT_PORT 21
|
||
#define FTP_CTRL_RX_BUF_SIZE 512
|
||
#define FTP_LINE_MAX 256
|
||
#define FTP_DATA_RX_BUF_SIZE 1460 /* 一帧以太网接近 MTU */
|
||
#define FTP_STEP_FAIL_MAX 3 /* 每个状态连续失败此次数后才进入 FAIL */
|
||
|
||
/* ====================== FTP 升级状态机定义 ====================== */
|
||
|
||
typedef enum
|
||
{
|
||
LWIP_FTP_STEP_IDLE = 0, /* 空闲,未开始 */
|
||
LWIP_FTP_STEP_CONNECT, /* 发起控制连接(非阻塞) */
|
||
LWIP_FTP_STEP_WAIT_CTRL_CONNECT, /* 等待控制连接完成(select,不阻塞任务) */
|
||
LWIP_FTP_STEP_WAIT_WELCOME, /* 等待 220 欢迎语 */
|
||
LWIP_FTP_STEP_SEND_USER, /* 发送 USER */
|
||
LWIP_FTP_STEP_WAIT_USER, /* 等待 USER 响应 */
|
||
LWIP_FTP_STEP_SEND_PASS, /* 发送 PASS */
|
||
LWIP_FTP_STEP_WAIT_PASS, /* 等待 PASS 响应 */
|
||
LWIP_FTP_STEP_SEND_TYPE, /* 发送 TYPE I */
|
||
LWIP_FTP_STEP_WAIT_TYPE, /* 等待 TYPE 响应 */
|
||
LWIP_FTP_STEP_SEND_CWD, /* 发送 CWD(可选) */
|
||
LWIP_FTP_STEP_WAIT_CWD, /* 等待 CWD 响应 */
|
||
LWIP_FTP_STEP_SEND_SIZE, /* 发送 SIZE */
|
||
LWIP_FTP_STEP_WAIT_SIZE, /* 等待 SIZE 响应,获取文件大小 */
|
||
LWIP_FTP_STEP_PREPARE_FLASH, /* 擦除升级区 + 写 IDLE 头 */
|
||
LWIP_FTP_STEP_SEND_PASV, /* 发送 PASV */
|
||
LWIP_FTP_STEP_WAIT_PASV, /* 等待 227,解析数据地址 */
|
||
LWIP_FTP_STEP_CONNECT_DATA, /* 发起数据连接(非阻塞) */
|
||
LWIP_FTP_STEP_WAIT_DATA_CONNECT, /* 等待数据连接完成(select) */
|
||
LWIP_FTP_STEP_SEND_RETR, /* 发送 RETR */
|
||
LWIP_FTP_STEP_WAIT_RETR, /* 等待 150/125 等开始传输响应 */
|
||
LWIP_FTP_STEP_RECV_DATA, /* 分包接收数据 + 每包 1024 写 Flash */
|
||
LWIP_FTP_STEP_SEND_QUIT, /* 发送 QUIT,关闭连接 */
|
||
LWIP_FTP_STEP_DONE, /* 升级完成 */
|
||
LWIP_FTP_STEP_FAIL /* 升级失败 */
|
||
} E_LWIP_FTP_STEP;
|
||
|
||
typedef struct
|
||
{
|
||
E_LWIP_FTP_STEP step; /* 当前步骤 */
|
||
|
||
int ctrl_sock; /* 控制通道 socket */
|
||
int data_sock; /* 数据通道 socket */
|
||
|
||
/* PASV 解析得到的数据通道地址 */
|
||
struct in_addr data_ip;
|
||
uint16_t data_port;
|
||
|
||
/* 文件信息 */
|
||
uint32_t file_size; /* 升级文件总大小 */
|
||
uint32_t downloaded; /* 已下载字节数 */
|
||
|
||
/* PACKET_SIZE=1024 的分包写入状态 */
|
||
uint32_t packet_index; /* 当前包索引(从 0 开始) */
|
||
uint8_t *packet_buf; /* 动态申请的 1024 字节缓存 */
|
||
uint32_t packet_used; /* 当前包已写入的字节数 */
|
||
|
||
/* 当前控制命令等待截止时间(用于 1 秒超时控制) */
|
||
uint32_t step_deadline_ms;
|
||
|
||
uint8_t step_fail_cnt; /* 当前步骤连续失败次数,满 FTP_STEP_FAIL_MAX 次才进入 FAIL */
|
||
int last_err; /* 最近一次失败时的错误码(errno 或 SO_ERROR),便于日志 */
|
||
uint8_t fail_stage; /* 控制连接失败阶段:1=resolve 2=socket 3=nonblock 4=connect */
|
||
} LWIP_FTP_UPGRADE_CTX;
|
||
|
||
static LWIP_FTP_UPGRADE_CTX s_ctx;
|
||
|
||
/* ====================== 工具函数 ====================== */
|
||
|
||
static uint32_t ftp_now_ms(void)
|
||
{
|
||
return (uint32_t)HAL_GetTick();
|
||
}
|
||
|
||
static void ftp_close_sock(int *psock)
|
||
{
|
||
if (psock && *psock >= 0) {
|
||
lwip_tcp_close(*psock);
|
||
*psock = -1;
|
||
}
|
||
}
|
||
|
||
/* 发送完整命令字符串(一次性) */
|
||
static int ftp_send_all(int sock, const char *s)
|
||
{
|
||
size_t left = strlen(s);
|
||
const char *p = s;
|
||
while (left > 0) {
|
||
int n = lwip_tcp_send(sock, p, left);
|
||
if (n <= 0) return -1;
|
||
p += (size_t)n;
|
||
left -= (size_t)n;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 发送命令(不等待响应) */
|
||
static int ftp_send_cmd(int sock, const char *fmt, const char *arg)
|
||
{
|
||
char buf[256];
|
||
if (arg) {
|
||
snprintf(buf, sizeof(buf), fmt, arg);
|
||
} else {
|
||
snprintf(buf, sizeof(buf), "%s", fmt);
|
||
}
|
||
return ftp_send_all(sock, buf);
|
||
}
|
||
|
||
/* 解析 PASV 响应,得到 data_ip/data_port */
|
||
static int ftp_parse_pasv(const char *msg, struct in_addr *out_ip, uint16_t *out_port)
|
||
{
|
||
const char *p = strchr(msg, '(');
|
||
const char *q = strchr(msg, ')');
|
||
if (!p || !q || q <= p) return -1;
|
||
int h1,h2,h3,h4,p1,p2;
|
||
if (sscanf(p + 1, "%d,%d,%d,%d,%d,%d", &h1,&h2,&h3,&h4,&p1,&p2) != 6) return -1;
|
||
if (h1<0||h1>255||h2<0||h2>255||h3<0||h3>255||h4<0||h4>255) return -1;
|
||
if (p1<0||p1>255||p2<0||p2>255) return -1;
|
||
char ip_str[32];
|
||
snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d", h1,h2,h3,h4);
|
||
unsigned long addr = inet_addr(ip_str);
|
||
if (addr == INADDR_NONE) return -1;
|
||
out_ip->s_addr = addr;
|
||
*out_port = (uint16_t)((p1 << 8) | p2);
|
||
return 0;
|
||
}
|
||
|
||
/* 单次尝试接收并解析一条 FTP 响应(非阻塞,只 recv 一次) */
|
||
static int ftp_recv_reply_once(int sock, int *out_code, char *out_msg, size_t out_msg_sz)
|
||
{
|
||
char buf[FTP_CTRL_RX_BUF_SIZE];
|
||
char line[FTP_LINE_MAX];
|
||
int code = -1;
|
||
|
||
if (out_code) *out_code = -1;
|
||
if (out_msg && out_msg_sz) out_msg[0] = '\0';
|
||
|
||
int n = lwip_tcp_recv(sock, buf, sizeof(buf));
|
||
if (n > 0) {
|
||
/* 先截成一行(找到第一个 \r 或 \n) */
|
||
int i;
|
||
for (i = 0; i < n; i++) {
|
||
if (buf[i] == '\r' || buf[i] == '\n') {
|
||
break;
|
||
}
|
||
}
|
||
if (i >= (int)sizeof(line)) i = (int)sizeof(line) - 1;
|
||
memcpy(line, buf, (size_t)i);
|
||
line[i] = '\0';
|
||
|
||
/* 解析前三位数字为响应码 */
|
||
size_t ln = strlen(line);
|
||
if (ln >= 3 &&
|
||
line[0] >= '0' && line[0] <= '9' &&
|
||
line[1] >= '0' && line[1] <= '9' &&
|
||
line[2] >= '0' && line[2] <= '9') {
|
||
code = (line[0]-'0')*100 + (line[1]-'0')*10 + (line[2]-'0');
|
||
if (out_msg && out_msg_sz) {
|
||
strncpy(out_msg, line, out_msg_sz - 1);
|
||
out_msg[out_msg_sz - 1] = '\0';
|
||
}
|
||
if (out_code) *out_code = code;
|
||
return 1; /* 成功解析到一条响应 */
|
||
}
|
||
/* 收到但未解析出合法 code,当作暂时无效数据 */
|
||
return 0;
|
||
}
|
||
if (n == 0) {
|
||
return -1; /* 对端关闭 */
|
||
}
|
||
if (errno != 0 && errno != EWOULDBLOCK && errno != EAGAIN) {
|
||
return -1; /* 真正错误 */
|
||
}
|
||
return 0; /* 暂无数据 */
|
||
}
|
||
|
||
/* 建立控制连接(非阻塞 connect:0=成功,1=进行中需等 WAIT_CTRL_CONNECT,-1=失败) */
|
||
static int ftp_connect_ctrl(LWIP_FTP_UPGRADE_CTX *ctx, const char *host, uint16_t port)
|
||
{
|
||
struct in_addr ip;
|
||
ctx->last_err = 0;
|
||
ctx->fail_stage = 0;
|
||
if (lwip_resolve_host(host, &ip) != 0) {
|
||
ctx->last_err = errno;
|
||
ctx->fail_stage = 1; /* resolve */
|
||
return -1;
|
||
}
|
||
int sock = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
||
if (sock < 0) {
|
||
ctx->last_err = errno;
|
||
ctx->fail_stage = 2; /* socket */
|
||
return -1;
|
||
}
|
||
if (lwip_set_nonblock(sock) != 0) {
|
||
ctx->last_err = errno;
|
||
ctx->fail_stage = 3; /* nonblock */
|
||
lwip_close(sock);
|
||
return -1;
|
||
}
|
||
struct sockaddr_in sa;
|
||
memset(&sa, 0, sizeof(sa));
|
||
sa.sin_family = AF_INET;
|
||
sa.sin_addr.s_addr = ip.s_addr;
|
||
sa.sin_port = htons(port);
|
||
if (lwip_connect(sock, (struct sockaddr*)&sa, sizeof(sa)) == 0) {
|
||
ctx->ctrl_sock = sock;
|
||
return 0; /* 立即连接成功(本机或极快网络) */
|
||
}
|
||
if (errno == EINPROGRESS) {
|
||
ctx->ctrl_sock = sock;
|
||
return 1; /* 进行中,需在 WAIT_CTRL_CONNECT 中 select 等待 */
|
||
}
|
||
/* connect 同步失败:优先用 errno;若为 0 则用 SO_ERROR(部分 LwIP 不设 errno) */
|
||
ctx->fail_stage = 4; /* connect */
|
||
{
|
||
int err = errno;
|
||
if (err == 0) {
|
||
int so_err = 0;
|
||
socklen_t len = (socklen_t)sizeof(so_err);
|
||
if (lwip_getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_err, &len) == 0)
|
||
err = so_err;
|
||
}
|
||
ctx->last_err = err;
|
||
lwip_close(sock);
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/* 轮询非阻塞 connect 是否完成(不阻塞:select 超时 0 或很短),0=未就绪,1=已连接,-1=失败/超时 */
|
||
static int ftp_poll_connect_done(int sock, uint32_t deadline_ms)
|
||
{
|
||
fd_set wfds;
|
||
struct timeval tv;
|
||
int err = 0;
|
||
socklen_t len = (socklen_t)sizeof(err);
|
||
|
||
FD_ZERO(&wfds);
|
||
FD_SET(sock, &wfds);
|
||
tv.tv_sec = 0;
|
||
tv.tv_usec = 50000; /* 最多等 50ms,避免卡死任务 */
|
||
int n = lwip_select(sock + 1, NULL, &wfds, NULL, &tv);
|
||
if (n > 0 && FD_ISSET(sock, &wfds)) {
|
||
if (lwip_getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) != 0 || err != 0) {
|
||
return -1;
|
||
}
|
||
return 1; /* 已连接 */
|
||
}
|
||
if (ftp_now_ms() >= deadline_ms) {
|
||
return -1; /* 超时 */
|
||
}
|
||
return 0; /* 未就绪,下次周期再试 */
|
||
}
|
||
|
||
/* 建立数据连接 socket(非阻塞:0=成功,1=进行中,-1=失败) */
|
||
static int ftp_connect_data(LWIP_FTP_UPGRADE_CTX *ctx)
|
||
{
|
||
int sock = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
||
if (sock < 0) return -1;
|
||
|
||
if (lwip_set_nonblock(sock) != 0) {
|
||
lwip_close(sock);
|
||
return -1;
|
||
}
|
||
|
||
struct sockaddr_in sa;
|
||
memset(&sa, 0, sizeof(sa));
|
||
sa.sin_family = AF_INET;
|
||
sa.sin_addr.s_addr = ctx->data_ip.s_addr;
|
||
sa.sin_port = htons(ctx->data_port);
|
||
|
||
if (lwip_connect(sock, (struct sockaddr*)&sa, sizeof(sa)) == 0) {
|
||
ctx->data_sock = sock;
|
||
return 0;
|
||
}
|
||
if (errno == EINPROGRESS) {
|
||
ctx->data_sock = sock;
|
||
return 1;
|
||
}
|
||
lwip_close(sock);
|
||
return -1;
|
||
}
|
||
|
||
/* 擦除升级区 + 写 IDLE 头 */
|
||
static int ftp_prepare_flash(LWIP_FTP_UPGRADE_CTX *ctx)
|
||
{
|
||
if (ctx->file_size == 0) return -1;
|
||
if (upgrade_erase_program_area() != 0) {
|
||
return -1;
|
||
}
|
||
upgrade_header_t header;
|
||
memset(&header, 0, sizeof(header));
|
||
header.upgrade_flag = UPGRADE_FLAG_IDLE;
|
||
header.file_size = ctx->file_size;
|
||
header.packet_count = (ctx->file_size + PACKET_SIZE - 1) / PACKET_SIZE;
|
||
header.crc32 = 0;
|
||
header.timestamp = 0;
|
||
if (upgrade_success_update_header(&header) != 0) {
|
||
return -1;
|
||
}
|
||
ctx->packet_index = 0;
|
||
ctx->packet_used = 0;
|
||
ctx->downloaded = 0;
|
||
return 0;
|
||
}
|
||
|
||
/* 写一包(<=1024 字节)到升级区 */
|
||
static int ftp_flash_write_one_packet(uint32_t index, const uint8_t *data, uint32_t len)
|
||
{
|
||
return upgrade_write_packet(index, data, len);
|
||
}
|
||
|
||
/* 接收数据通道数据,按 1024 分包写 Flash;本函数只调一次,读少量数据即可 */
|
||
static int ftp_recv_data_step(LWIP_FTP_UPGRADE_CTX *ctx)
|
||
{
|
||
if (ctx->data_sock < 0) return -1;
|
||
|
||
uint8_t buf[FTP_DATA_RX_BUF_SIZE];
|
||
int n = lwip_tcp_recv(ctx->data_sock, buf, sizeof(buf));
|
||
if (n > 0) {
|
||
size_t pos = 0;
|
||
while (pos < (size_t)n) {
|
||
uint32_t space = PACKET_SIZE - ctx->packet_used;
|
||
uint32_t take = (uint32_t)(((size_t)n - pos) > space ? space : ((size_t)n - pos));
|
||
memcpy(&ctx->packet_buf[ctx->packet_used], &buf[pos], take);
|
||
ctx->packet_used += take;
|
||
pos += take;
|
||
ctx->downloaded += take;
|
||
|
||
/* 接收进度打印 */
|
||
if (ctx->file_size > 0) {
|
||
uint32_t percent = (ctx->downloaded * 100U) / ctx->file_size;
|
||
Plat_Comm_LOG("lwip ftp: recv %lu/%lu (%u%%)\r\n",
|
||
(unsigned long)ctx->downloaded,
|
||
(unsigned long)ctx->file_size,
|
||
(unsigned)percent);
|
||
}
|
||
|
||
if (ctx->packet_used == PACKET_SIZE) {
|
||
if (ftp_flash_write_one_packet(ctx->packet_index, ctx->packet_buf, ctx->packet_used) != 0) {
|
||
return -1;
|
||
}
|
||
ctx->packet_index++;
|
||
ctx->packet_used = 0;
|
||
}
|
||
}
|
||
return 0; /* 还有后续数据,下一次 step 再收 */
|
||
}
|
||
if (n == 0) {
|
||
/* 数据通道关闭:刷写最后一包(不足 1024) */
|
||
if (ctx->packet_used > 0) {
|
||
if (ftp_flash_write_one_packet(ctx->packet_index, ctx->packet_buf, ctx->packet_used) != 0) {
|
||
return -1;
|
||
}
|
||
ctx->packet_index++;
|
||
ctx->packet_used = 0;
|
||
}
|
||
ftp_close_sock(&ctx->data_sock);
|
||
return 1; /* 表示数据接收完毕 */
|
||
}
|
||
if (errno != 0 && errno != EWOULDBLOCK && errno != EAGAIN) {
|
||
return -1;
|
||
}
|
||
return 0; /* 暂无数据 */
|
||
}
|
||
|
||
/* 写完成标志:NEED_UP */
|
||
static int ftp_flash_finish(LWIP_FTP_UPGRADE_CTX *ctx)
|
||
{
|
||
if (ctx->file_size == 0) return -1;
|
||
upgrade_header_t header;
|
||
memset(&header, 0, sizeof(header));
|
||
header.upgrade_flag = UPGRADE_FLAG_NEED_UP;
|
||
header.file_size = ctx->file_size;
|
||
header.packet_count = (ctx->file_size + PACKET_SIZE - 1) / PACKET_SIZE;
|
||
header.crc32 = 0;
|
||
header.timestamp = 0;
|
||
if (upgrade_success_update_header(&header) != 0) {
|
||
return -1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* ====================== 对外接口实现 ====================== */
|
||
|
||
void lwip_ftp_upgrade_init_from_tftp(void)
|
||
{
|
||
uint8_t *old_buf = s_ctx.packet_buf; /* 保留之前的动态缓存指针(如有) */
|
||
memset(&s_ctx, 0, sizeof(s_ctx));
|
||
s_ctx.ctrl_sock = -1;
|
||
s_ctx.data_sock = -1;
|
||
s_ctx.packet_buf = old_buf;
|
||
s_ctx.step = LWIP_FTP_STEP_CONNECT;
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.file_size = 0;
|
||
s_ctx.downloaded = 0;
|
||
s_ctx.packet_index = 0;
|
||
s_ctx.packet_used = 0;
|
||
s_ctx.step_deadline_ms = 0;
|
||
|
||
/* 使用 FreeRTOS 堆动态申请 1024 字节缓存(仅申请一次,后续重复使用) */
|
||
if (s_ctx.packet_buf == NULL) {
|
||
s_ctx.packet_buf = (uint8_t *)pvPortMalloc(PACKET_SIZE);
|
||
if (s_ctx.packet_buf == NULL) {
|
||
Plat_Comm_LOG("lwip ftp: pvPortMalloc packet_buf fail\r\n");
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
return;
|
||
}
|
||
}
|
||
|
||
Plat_Comm_LOG("lwip ftp: init from t_ftp_update_info, host=%s, file=%s\r\n",
|
||
(char *)t_ftp_update_info.u8_update_server_addr,
|
||
(char *)t_ftp_update_info.u8_file_name);
|
||
}
|
||
|
||
int lwip_ftp_upgrade_step(void)
|
||
{
|
||
switch (s_ctx.step) {
|
||
case LWIP_FTP_STEP_IDLE:
|
||
return 0;
|
||
|
||
case LWIP_FTP_STEP_CONNECT: {
|
||
/* 发起控制连接(非阻塞,避免 connect 卡死任务) */
|
||
const char *host = (const char *)t_ftp_update_info.u8_update_server_addr;
|
||
uint16_t port = (t_ftp_update_info.u16_update_server_port == 0)
|
||
? FTP_CTRL_DEFAULT_PORT
|
||
: t_ftp_update_info.u16_update_server_port;
|
||
int cr = ftp_connect_ctrl(&s_ctx, host, port);
|
||
if (cr < 0) {
|
||
Plat_Comm_LOG("lwip ftp: connect ctrl fail stage=%u err=%d (retry %u/%u)\r\n",
|
||
(unsigned)s_ctx.fail_stage, s_ctx.last_err,
|
||
(unsigned)(s_ctx.step_fail_cnt + 1), (unsigned)FTP_STEP_FAIL_MAX);
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
if (cr == 0) {
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_WELCOME;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
} else {
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_CTRL_CONNECT;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 15000; /* 控制连接最多等 15 秒 */
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_CTRL_CONNECT: {
|
||
int r = ftp_poll_connect_done(s_ctx.ctrl_sock, s_ctx.step_deadline_ms);
|
||
if (r == 1) {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_WELCOME;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
} else if (r < 0) {
|
||
Plat_Comm_LOG("lwip ftp: ctrl connect timeout or error (retry %u/%u)\r\n", (unsigned)(s_ctx.step_fail_cnt + 1), (unsigned)FTP_STEP_FAIL_MAX);
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 15000;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_WELCOME: {
|
||
int code;
|
||
char msg[FTP_LINE_MAX];
|
||
int r = ftp_recv_reply_once(s_ctx.ctrl_sock, &code, msg, sizeof(msg));
|
||
if (r < 0) {
|
||
Plat_Comm_LOG("lwip ftp: welcome error r=%d (retry %u/%u)\r\n", r, (unsigned)(s_ctx.step_fail_cnt + 1), (unsigned)FTP_STEP_FAIL_MAX);
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (r == 1) {
|
||
if (code < 200 || code >= 400) {
|
||
Plat_Comm_LOG("lwip ftp: welcome fail code=%d msg=%s (retry %u/%u)\r\n", code, msg, (unsigned)(s_ctx.step_fail_cnt + 1), (unsigned)FTP_STEP_FAIL_MAX);
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_USER;
|
||
}
|
||
} else { /* r == 0, 暂无完整响应 */
|
||
if (ftp_now_ms() >= s_ctx.step_deadline_ms) {
|
||
Plat_Comm_LOG("lwip ftp: welcome timeout (retry %u/%u)\r\n", (unsigned)(s_ctx.step_fail_cnt + 1), (unsigned)FTP_STEP_FAIL_MAX);
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_SEND_USER: {
|
||
const char *user = (const char *)t_ftp_update_info.u8_user;
|
||
if (user == NULL || user[0] == 0) user = "anonymous";
|
||
if (ftp_send_cmd(s_ctx.ctrl_sock, "USER %s\r\n", user) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_USER;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000; /* USER 响应最长等待 1 秒 */
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_USER: {
|
||
int code;
|
||
char msg[FTP_LINE_MAX];
|
||
int r = ftp_recv_reply_once(s_ctx.ctrl_sock, &code, msg, sizeof(msg));
|
||
if (r < 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (r == 1) {
|
||
if (code >= 400) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (code == 331) {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_PASS;
|
||
} else {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_TYPE;
|
||
}
|
||
} else {
|
||
if (ftp_now_ms() >= s_ctx.step_deadline_ms) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_SEND_PASS: {
|
||
const char *pass = (const char *)t_ftp_update_info.u8_pwd;
|
||
const char *user = (const char *)t_ftp_update_info.u8_user;
|
||
if (user == NULL || user[0] == 0) {
|
||
pass = "anonymous@";
|
||
} else if (pass == NULL) {
|
||
pass = "";
|
||
}
|
||
if (ftp_send_cmd(s_ctx.ctrl_sock, "PASS %s\r\n", pass) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_PASS;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000; /* PASS 响应最长等待 1 秒 */
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_PASS: {
|
||
int code;
|
||
char msg[FTP_LINE_MAX];
|
||
int r = ftp_recv_reply_once(s_ctx.ctrl_sock, &code, msg, sizeof(msg));
|
||
if (r < 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (r == 1) {
|
||
if (code >= 400) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_TYPE;
|
||
}
|
||
} else {
|
||
if (ftp_now_ms() >= s_ctx.step_deadline_ms) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_SEND_TYPE: {
|
||
if (ftp_send_cmd(s_ctx.ctrl_sock, "TYPE I\r\n", NULL) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_TYPE;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000; /* TYPE 响应最长等待 1 秒 */
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_TYPE: {
|
||
int code;
|
||
char msg[FTP_LINE_MAX];
|
||
int r = ftp_recv_reply_once(s_ctx.ctrl_sock, &code, msg, sizeof(msg));
|
||
if (r < 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (r == 1) {
|
||
if (code >= 400) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (t_ftp_update_info.u8_path[0] != 0) {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_CWD;
|
||
} else {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_SIZE;
|
||
}
|
||
} else {
|
||
if (ftp_now_ms() >= s_ctx.step_deadline_ms) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_SEND_CWD: {
|
||
const char *path = (const char *)t_ftp_update_info.u8_path;
|
||
if (ftp_send_cmd(s_ctx.ctrl_sock, "CWD %s\r\n", path) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_CWD;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000; /* CWD 响应最长等待 1 秒 */
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_CWD: {
|
||
int code;
|
||
char msg[FTP_LINE_MAX];
|
||
int r = ftp_recv_reply_once(s_ctx.ctrl_sock, &code, msg, sizeof(msg));
|
||
if (r < 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (r == 1) {
|
||
if (code >= 400) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_SIZE;
|
||
}
|
||
} else {
|
||
if (ftp_now_ms() >= s_ctx.step_deadline_ms) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_SEND_SIZE: {
|
||
const char *file = (const char *)t_ftp_update_info.u8_file_name;
|
||
if (ftp_send_cmd(s_ctx.ctrl_sock, "SIZE %s\r\n", file) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_SIZE;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000; /* SIZE 响应最长等待 1 秒 */
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_SIZE: {
|
||
int code;
|
||
char msg[FTP_LINE_MAX];
|
||
int r = ftp_recv_reply_once(s_ctx.ctrl_sock, &code, msg, sizeof(msg));
|
||
if (r < 0) {
|
||
Plat_Comm_LOG("lwip ftp: SIZE error r=%d (retry %u/%u)\r\n", r, (unsigned)(s_ctx.step_fail_cnt + 1), (unsigned)FTP_STEP_FAIL_MAX);
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (r == 1) {
|
||
if (code != 213) {
|
||
Plat_Comm_LOG("lwip ftp: SIZE fail code=%d msg=%s (retry %u/%u)\r\n", code, msg, (unsigned)(s_ctx.step_fail_cnt + 1), (unsigned)FTP_STEP_FAIL_MAX);
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else {
|
||
unsigned long sz = 0;
|
||
if (sscanf(msg, "213 %lu", &sz) != 1 || sz == 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.file_size = (uint32_t)sz;
|
||
t_ftp_update_info.u32_file_size = s_ctx.file_size;
|
||
s_ctx.step = LWIP_FTP_STEP_PREPARE_FLASH;
|
||
}
|
||
}
|
||
} else {
|
||
if (ftp_now_ms() >= s_ctx.step_deadline_ms) {
|
||
Plat_Comm_LOG("lwip ftp: SIZE timeout (retry %u/%u)\r\n", (unsigned)(s_ctx.step_fail_cnt + 1), (unsigned)FTP_STEP_FAIL_MAX);
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_PREPARE_FLASH: {
|
||
if (ftp_prepare_flash(&s_ctx) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_PASV;
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_SEND_PASV: {
|
||
if (ftp_send_cmd(s_ctx.ctrl_sock, "PASV\r\n", NULL) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_PASV;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000; /* PASV 响应最长等待 1 秒 */
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_PASV: {
|
||
int code;
|
||
char msg[FTP_LINE_MAX];
|
||
int r = ftp_recv_reply_once(s_ctx.ctrl_sock, &code, msg, sizeof(msg));
|
||
if (r < 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (r == 1) {
|
||
if (code != 227) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (ftp_parse_pasv(msg, &s_ctx.data_ip, &s_ctx.data_port) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_CONNECT_DATA;
|
||
}
|
||
} else {
|
||
if (ftp_now_ms() >= s_ctx.step_deadline_ms) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_CONNECT_DATA: {
|
||
int dr = ftp_connect_data(&s_ctx);
|
||
if (dr < 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
if (dr == 0) {
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_RETR;
|
||
} else {
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_DATA_CONNECT;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 10000; /* 数据连接最多等 10 秒 */
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_DATA_CONNECT: {
|
||
int r = ftp_poll_connect_done(s_ctx.data_sock, s_ctx.step_deadline_ms);
|
||
if (r == 1) {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_RETR;
|
||
} else if (r < 0) {
|
||
Plat_Comm_LOG("lwip ftp: data connect timeout or error (retry %u/%u)\r\n", (unsigned)(s_ctx.step_fail_cnt + 1), (unsigned)FTP_STEP_FAIL_MAX);
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 10000;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_SEND_RETR: {
|
||
const char *file = (const char *)t_ftp_update_info.u8_file_name;
|
||
if (ftp_send_cmd(s_ctx.ctrl_sock, "RETR %s\r\n", file) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
break;
|
||
}
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_WAIT_RETR;
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000; /* RETR 响应最长等待 1 秒 */
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_WAIT_RETR: {
|
||
int code;
|
||
char msg[FTP_LINE_MAX];
|
||
int r = ftp_recv_reply_once(s_ctx.ctrl_sock, &code, msg, sizeof(msg));
|
||
if (r < 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else if (r == 1) {
|
||
if (code >= 400) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
} else {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_RECV_DATA;
|
||
}
|
||
} else {
|
||
if (ftp_now_ms() >= s_ctx.step_deadline_ms) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
} else {
|
||
s_ctx.step_deadline_ms = ftp_now_ms() + 1000;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_RECV_DATA: {
|
||
int r = ftp_recv_data_step(&s_ctx);
|
||
if (r < 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
} else if (r == 1) {
|
||
s_ctx.step_fail_cnt = 0;
|
||
/* 数据接收完成,等待 226 */
|
||
s_ctx.step = LWIP_FTP_STEP_SEND_QUIT; /* 简化:直接发送 QUIT,认为传输成功 */
|
||
}
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_SEND_QUIT: {
|
||
/* 发送 QUIT,忽略响应 */
|
||
(void)ftp_send_cmd(s_ctx.ctrl_sock, "QUIT\r\n", NULL);
|
||
ftp_close_sock(&s_ctx.ctrl_sock);
|
||
if (ftp_flash_finish(&s_ctx) != 0) {
|
||
s_ctx.step_fail_cnt++;
|
||
if (s_ctx.step_fail_cnt >= FTP_STEP_FAIL_MAX) {
|
||
s_ctx.step = LWIP_FTP_STEP_FAIL;
|
||
}
|
||
/* 否则保持 SEND_QUIT,下一周期会再次 QUIT 并再次 flash_finish(一般不重试) */
|
||
} else {
|
||
s_ctx.step_fail_cnt = 0;
|
||
s_ctx.step = LWIP_FTP_STEP_DONE;
|
||
}
|
||
v_sys_reboot(); //系统重启 默认此时未充电
|
||
break;
|
||
}
|
||
|
||
case LWIP_FTP_STEP_DONE:
|
||
return 1;
|
||
|
||
case LWIP_FTP_STEP_FAIL:
|
||
ftp_close_sock(&s_ctx.ctrl_sock);
|
||
ftp_close_sock(&s_ctx.data_sock);
|
||
if (s_ctx.packet_buf != NULL) {
|
||
vPortFree(s_ctx.packet_buf);
|
||
s_ctx.packet_buf = NULL;
|
||
}
|
||
return -1;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
#else /* !LWIP_FTP_UPGRADE_ENABLE */
|
||
|
||
void lwip_ftp_upgrade_init_from_tftp(void) {}
|
||
int lwip_ftp_upgrade_step(void) { return 0; }
|
||
|
||
#endif /* LWIP_FTP_UPGRADE_ENABLE */
|
||
|