694 lines
24 KiB
C
694 lines
24 KiB
C
/*==========================================================================================================
|
|
Copyright (c) 2021, Quectel Wireless Solutions Co., Ltd. All rights reserved.
|
|
Quectel Wireless Solutions Proprietary and Confidential.
|
|
===========================================================================================================*/
|
|
|
|
#include <stdio.h>
|
|
#include "ql_uart.h"
|
|
#include "ql_application.h"
|
|
#include "ql_log.h"
|
|
#include "ql_fs.h"
|
|
|
|
#define ymodem_log(fmt, args...) printf(fmt, ##args)
|
|
|
|
//#define TX_FWCTRL_ENBLE
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
README!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
// 1. This is a simple YModem receive example, which receives file from PC and saves to NVM file system.
|
|
// 2. Increase customer.fs partition size flash layout if the file to be received is lare, otherwise it
|
|
// may cause "No space left on device" error when saving file to NVM.
|
|
// 3. After finished upload file to NVM, next step download, untick customer_fs in Aboot software to avoid
|
|
// file stored deleted during flashing.
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
USER CONFIG
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
#define NVM_SAVE_PATH "U:/received_file.bin" // <-- rename the received file if needed
|
|
#define DELETE_AFTER_DOWNLOAD 0 // <-- 1 = delete after send, 0 = keep
|
|
|
|
static int uartportchoose = QL_MAIN_UART_PORT; // <-- modify UART PORT if needed
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
DEBUG CONFIG
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
#define CHECK_CHAR_RECEIVED 0 //default 0
|
|
//1 = Show log every received char in wait_char, 0 = disable log every received char in wait_char
|
|
#define CHECK_CHAR_SEND 0 //default 0
|
|
//1 = Show log every sent char in send_char, 0 = disable log every sent char in send_char
|
|
|
|
#if CHECK_CHAR_SEND
|
|
#define CHECK_CHAR_SEND_LOG(fmt, args...) printf(fmt, ##args)
|
|
#else
|
|
#define CHECK_CHAR_SEND_LOG(fmt, args...)
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
YModem constants
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
#define Ymodem_SOH 0x01
|
|
#define Ymodem_STX 0x02
|
|
#define Ymodem_EOT 0x04
|
|
#define Ymodem_ACK 0x06
|
|
#define Ymodem_NAK 0x15
|
|
|
|
#define Ymodem_PACKET_STX_DATA_SIZE 1024
|
|
#define Ymodem_PACKET_SOH_DATA_SIZE 128
|
|
#define Ymodem_PACKET_STX_SEZE 1029
|
|
#define Ymodem_PACKET_SOH_SEZE 133
|
|
|
|
#define Ymodem_RECV_FILENAME 0
|
|
#define Ymodem_TRANS_DATA 1
|
|
#define Ymodem_TRANS_END_EOT1 2
|
|
#define Ymodem_TRANS_END_EOT2 3
|
|
|
|
#define Ymodem_RECV_HEAD 1
|
|
#define Ymodem_RECV_NUMBER 2
|
|
#define Ymodem_RECV_NON_NUMBER 3
|
|
#define Ymodem_RECV_DATA 4
|
|
#define Ymodem_RECEIVE_MAX_TIMES 30
|
|
|
|
#define DOWNLOAD_WAIT_C_TIMEOUT_MS 30000
|
|
#define DOWNLOAD_ACK_TIMEOUT_MS 3000
|
|
|
|
static unsigned char ch_ACK = Ymodem_ACK;
|
|
static unsigned char ch_NAK = Ymodem_NAK;
|
|
static unsigned char ch_eot = Ymodem_EOT;
|
|
|
|
static unsigned char sequence_num = 1;
|
|
static unsigned int receiving_progress = 0;
|
|
static unsigned int total_progress = 0;
|
|
static int state = Ymodem_RECV_FILENAME;
|
|
|
|
static QFILE * fp = 0;
|
|
static int g_receive_done = 0;
|
|
|
|
static unsigned int total_file_size = 0;
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
UART initialization for YModem transfer
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
static void ql_Ymodem_uart_init(void)
|
|
{
|
|
#ifndef TX_FWCTRL_ENBLE
|
|
ql_uart_open(uartportchoose, QL_UART_BAUD_115200, QL_FC_NONE);
|
|
#else
|
|
ql_uart_open(uartportchoose, QL_UART_BAUD_115200, QL_FC_HW);
|
|
#endif
|
|
|
|
ql_uart_config_t dcb;
|
|
ql_uart_get_dcbconfig(uartportchoose, &dcb);
|
|
ymodem_log("[%s][%d]baudrate:%d, data_bit:%d, stop_bit:%d, parity_bit:%d, flow_ctrl:%d \r\n",
|
|
__func__, __LINE__, dcb.baudrate, dcb.data_bit, dcb.stop_bit, dcb.parity_bit, dcb.flow_ctrl);
|
|
dcb.baudrate = QL_UART_BAUD_115200;
|
|
ql_uart_set_dcbconfig(uartportchoose, &dcb);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
CRC16 CCITT
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
static unsigned short crc16_ccitt(const unsigned char *data, size_t length)
|
|
{
|
|
int crc = 0;
|
|
int i, j;
|
|
for(i = 0; i < length; i++)
|
|
{
|
|
crc = crc ^ (data[i] << 8);
|
|
for(j = 0; j < 8; j++)
|
|
{
|
|
if((crc & ((int)0x8000)) != 0)
|
|
crc = ((crc << 1) ^ 0x1021);
|
|
else
|
|
crc = crc << 1;
|
|
}
|
|
}
|
|
return (crc & 0xFFFF);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
parse_filename and file length from the first packet, and save them to global variables for later use
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
int ql_Ymodem_parse_filename(unsigned char *buf)
|
|
{
|
|
int filename_offset = 0;
|
|
unsigned char name_buf[128] = {0};
|
|
unsigned char length_buf[128] = {0};
|
|
int catch_name_offset = 0;
|
|
unsigned int file_length = 0;
|
|
|
|
while(filename_offset < Ymodem_PACKET_SOH_SEZE - 3)
|
|
{
|
|
if(buf[filename_offset] == 0x00 && catch_name_offset == 0)
|
|
{
|
|
memcpy(name_buf, buf, filename_offset);
|
|
ymodem_log("**********filename:%s ************\r\n", name_buf);
|
|
catch_name_offset = filename_offset;
|
|
}
|
|
else if(catch_name_offset != 0)
|
|
{
|
|
if(buf[filename_offset] == 0x00 || buf[filename_offset] == ' ')
|
|
{
|
|
memcpy(length_buf, buf + catch_name_offset + 1, filename_offset - catch_name_offset);
|
|
ymodem_log("**********file length:%s bytes************\r\n", length_buf);
|
|
file_length = atoi(length_buf);
|
|
total_file_size = file_length;
|
|
total_progress = file_length / 1024;
|
|
if((file_length % 1024) != 0)
|
|
total_progress++;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
filename_offset++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
Write data packet to NVM file, return 0 if success, -1 if fail (e.g. CRC error)
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
int ql_Ymodem_write_data(unsigned char *buf, unsigned char type)
|
|
{
|
|
unsigned short p_crc;
|
|
unsigned short r_crc;
|
|
int data_size = 0;
|
|
static unsigned int offset = 0;
|
|
|
|
if(type == Ymodem_SOH)
|
|
data_size = Ymodem_PACKET_SOH_DATA_SIZE;
|
|
else
|
|
data_size = Ymodem_PACKET_STX_DATA_SIZE;
|
|
|
|
p_crc = crc16_ccitt(buf, data_size);
|
|
r_crc = *(buf + data_size) << 8 | *(buf + data_size + 1);
|
|
|
|
if(r_crc != p_crc)
|
|
{
|
|
ymodem_log("r_crc:%x p_crc:%x \r\n", r_crc, p_crc);
|
|
return -1;
|
|
}
|
|
|
|
// End of transfer — null packet with CRC=0
|
|
if(r_crc == 0 && state == Ymodem_TRANS_END_EOT2)
|
|
{
|
|
ql_uart_write(uartportchoose, &ch_ACK, 1);
|
|
CHECK_CHAR_SEND_LOG("ACK SEND\r\n");
|
|
|
|
// Close file
|
|
if(fp != NULL)
|
|
{
|
|
ql_fclose(fp);
|
|
fp = NULL;
|
|
ymodem_log("File closed. Total written: %u bytes\r\n", offset);
|
|
}
|
|
|
|
ymodem_log("End transfer!!!! Saved to %s\r\n", NVM_SAVE_PATH);
|
|
g_receive_done = 1;
|
|
offset = 0; // reset for next transfer
|
|
return 0;
|
|
}
|
|
|
|
// Write chunk to NVM file
|
|
if(fp != NULL)
|
|
{
|
|
int write_size = data_size;
|
|
|
|
if(offset < total_file_size)
|
|
{
|
|
// Trim last packet if needed
|
|
if((offset + data_size) > total_file_size)
|
|
write_size = total_file_size - offset;
|
|
|
|
int written = ql_fwrite(buf, 1, write_size, fp);
|
|
if(written != write_size)
|
|
{
|
|
ymodem_log("ql_fwrite error! written:%d expected:%d\r\n", written, write_size);
|
|
return -1;
|
|
}
|
|
ymodem_log("written:%d bytes\r\n", write_size);
|
|
offset += write_size;
|
|
}
|
|
else
|
|
{
|
|
// Exceed file size, skip write, just continue
|
|
ymodem_log("exceed file size, skip write\r\n");
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
Wait for specific char from PC with timeout
|
|
Returns: 0 = got expected char
|
|
-1 = unexpected char
|
|
-2 = timeout
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
static int ql_Ymodem_wait_char(unsigned char expected, int timeout_ms)
|
|
{
|
|
unsigned char ch;
|
|
int elapsed = 0;
|
|
|
|
while(elapsed < timeout_ms)
|
|
{
|
|
ql_uart_read(uartportchoose, &ch, 1);
|
|
|
|
if(ch == expected){
|
|
#if CHECK_CHAR_RECEIVED
|
|
ymodem_log("wait_char: got 0x%02X expected 0x%02X\r\n", ch, expected);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
ql_rtos_task_sleep_ms(10);
|
|
elapsed += 10;
|
|
}
|
|
ymodem_log("wait_char: timeout waiting for 0x%02X\r\n", expected);
|
|
return -2;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
Main YModem receive loop: handles receiving filename packet, data packets, and EOT, and writes to NVM file
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
static int ql_Ymodem_upload_file(void)
|
|
{
|
|
unsigned char ch;
|
|
unsigned char package_type = 0;
|
|
unsigned char seq_num = 0;
|
|
unsigned int data_size = 0;
|
|
unsigned char recv_buf[1100];
|
|
int get_filename = 0;
|
|
int read_package_state = Ymodem_RECV_HEAD;
|
|
|
|
while(1)
|
|
{
|
|
if(state == Ymodem_RECV_FILENAME && read_package_state == Ymodem_RECV_HEAD)
|
|
{
|
|
if(get_filename != 1)
|
|
{
|
|
ql_uart_write(uartportchoose, "C", 1);
|
|
ymodem_log("C SEND, waiting for host...\r\n");
|
|
ql_rtos_task_sleep_ms(1000);
|
|
}
|
|
}
|
|
|
|
int nread_size = ql_uart_get_rxrb_data_len(uartportchoose);
|
|
if(nread_size == 0)
|
|
{
|
|
ql_rtos_task_sleep_ms(5);
|
|
continue;
|
|
}
|
|
|
|
if(read_package_state != Ymodem_RECV_DATA)
|
|
{
|
|
ql_uart_read(uartportchoose, &ch, 1);
|
|
}
|
|
|
|
if(read_package_state == Ymodem_RECV_HEAD)
|
|
{
|
|
if(ch == Ymodem_SOH || ch == Ymodem_STX || ch == Ymodem_EOT)
|
|
{
|
|
if(ch == Ymodem_EOT)
|
|
{
|
|
if(state != Ymodem_TRANS_END_EOT2)
|
|
{
|
|
state = Ymodem_TRANS_END_EOT2;
|
|
ql_uart_write(uartportchoose, &ch_NAK, 1);
|
|
CHECK_CHAR_SEND_LOG("NACK SEND\r\n");
|
|
ql_rtos_task_sleep_ms(100);
|
|
ymodem_log("receive EOT 1 !!!!\r\n");
|
|
}
|
|
else
|
|
{
|
|
ql_uart_write(uartportchoose, &ch_ACK, 1);
|
|
CHECK_CHAR_SEND_LOG("ACK SEND\r\n");
|
|
ql_rtos_task_sleep_ms(100);
|
|
ql_uart_write(uartportchoose, "C", 1);
|
|
CHECK_CHAR_SEND_LOG("C SEND\r\n");
|
|
sequence_num = 0;
|
|
ymodem_log("receive EOT 2 !!!!\r\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
package_type = ch;
|
|
read_package_state = Ymodem_RECV_NUMBER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ymodem_log("package type error!!!\r\n");
|
|
continue;
|
|
}
|
|
}
|
|
else if(read_package_state == Ymodem_RECV_NUMBER)
|
|
{
|
|
read_package_state = Ymodem_RECV_NON_NUMBER;
|
|
seq_num = ch;
|
|
ymodem_log("sequence number:%u\r\n", seq_num);
|
|
}
|
|
else if(read_package_state == Ymodem_RECV_NON_NUMBER)
|
|
{
|
|
if((char)(~ch) == (char)seq_num)
|
|
{
|
|
read_package_state = Ymodem_RECV_DATA;
|
|
if(package_type == Ymodem_STX)
|
|
data_size = Ymodem_PACKET_STX_SEZE - 3;
|
|
else
|
|
data_size = Ymodem_PACKET_SOH_SEZE - 3;
|
|
}
|
|
else
|
|
{
|
|
ymodem_log("receive inverse number error number 1:%x number 2:%x\r\n", seq_num, ch);
|
|
read_package_state = Ymodem_RECV_HEAD;
|
|
ql_uart_flush_fifo(uartportchoose);
|
|
ql_uart_write(uartportchoose, &ch_NAK, 1);
|
|
CHECK_CHAR_SEND_LOG("NACK SEND\r\n");
|
|
continue;
|
|
}
|
|
}
|
|
else if(read_package_state == Ymodem_RECV_DATA)
|
|
{
|
|
static int get_times = 0;
|
|
int length = ql_uart_get_rxrb_data_len(uartportchoose);
|
|
if(length < data_size)
|
|
{
|
|
ql_rtos_task_sleep_ms(5);
|
|
if(get_times++ > Ymodem_RECEIVE_MAX_TIMES)
|
|
{
|
|
get_times = 0;
|
|
read_package_state = Ymodem_RECV_HEAD;
|
|
ql_uart_flush_fifo(uartportchoose);
|
|
if(state == Ymodem_RECV_FILENAME)
|
|
{
|
|
ql_uart_write(uartportchoose, "C", 1);
|
|
CHECK_CHAR_SEND_LOG("C SEND\r\n");
|
|
ql_rtos_task_sleep_ms(2000);
|
|
}
|
|
else
|
|
{
|
|
ql_uart_write(uartportchoose, &ch_NAK, 1);
|
|
CHECK_CHAR_SEND_LOG("NACK SEND\r\n");
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
get_times = 0;
|
|
length = data_size;
|
|
ql_uart_read(uartportchoose, recv_buf, length);
|
|
|
|
if(state == Ymodem_RECV_FILENAME)
|
|
{
|
|
if(package_type != Ymodem_SOH)
|
|
{
|
|
ymodem_log(" receive filename packet error\r\n");
|
|
ql_uart_flush_fifo(uartportchoose);
|
|
ql_uart_write(uartportchoose, &ch_NAK, 1);
|
|
CHECK_CHAR_SEND_LOG("NACK SEND\r\n");
|
|
continue;
|
|
}
|
|
|
|
ql_Ymodem_parse_filename(recv_buf);
|
|
ql_uart_flush_fifo(uartportchoose);
|
|
get_filename = 1;
|
|
state = Ymodem_TRANS_DATA;
|
|
|
|
// Open NVM file for writing — overwrite if exists
|
|
fp = ql_fopen(NVM_SAVE_PATH, "wb");
|
|
if(fp == NULL)
|
|
{
|
|
ymodem_log("ql_fopen failed! path:%s\r\n", NVM_SAVE_PATH);
|
|
ql_uart_write(uartportchoose, &ch_NAK, 1);
|
|
CHECK_CHAR_SEND_LOG("NACK SEND\r\n");
|
|
continue;
|
|
}
|
|
ymodem_log("File opened for writing: %s\r\n", NVM_SAVE_PATH);
|
|
|
|
ql_uart_write(uartportchoose, &ch_ACK, 1);
|
|
CHECK_CHAR_SEND_LOG("ACK SEND\r\n");
|
|
ql_rtos_task_sleep_ms(10);
|
|
ql_uart_write(uartportchoose, "C", 1);
|
|
CHECK_CHAR_SEND_LOG("C SEND\r\n");
|
|
read_package_state = Ymodem_RECV_HEAD;
|
|
}
|
|
else if(state == Ymodem_TRANS_DATA || state == Ymodem_TRANS_END_EOT2)
|
|
{
|
|
read_package_state = Ymodem_RECV_HEAD;
|
|
if(seq_num == sequence_num)
|
|
{
|
|
if(ql_Ymodem_write_data(recv_buf, package_type) == 0)
|
|
{
|
|
ql_uart_write(uartportchoose, &ch_ACK, 1);
|
|
CHECK_CHAR_SEND_LOG("ACK SEND\r\n");
|
|
sequence_num++;
|
|
|
|
if(g_receive_done != 1)
|
|
{
|
|
receiving_progress++;
|
|
ymodem_log("progress receiving:total %u:%u\r\n", receiving_progress, total_progress);
|
|
}
|
|
|
|
if(g_receive_done == 1)
|
|
{
|
|
ymodem_log("File saved to NVM: %s\r\n", NVM_SAVE_PATH);
|
|
return; // done, exit task
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ymodem_log("crc error\r\n");
|
|
ql_uart_flush_fifo(uartportchoose);
|
|
ql_uart_write(uartportchoose, &ch_NAK, 1);
|
|
CHECK_CHAR_SEND_LOG("NACK SEND\r\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ymodem_log("error sequence \r\n");
|
|
ql_uart_flush_fifo(uartportchoose);
|
|
ql_uart_write(uartportchoose, &ch_NAK, 1);
|
|
CHECK_CHAR_SEND_LOG("NACK SEND\r\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------------
|
|
Send file from NVM via YModem to PC
|
|
Returns: 0 = success
|
|
-1 = failed
|
|
----------------------------------------------------------------------------------------------------------*/
|
|
static int ql_Ymodem_send_file(void)
|
|
{
|
|
unsigned char send_buf[Ymodem_PACKET_STX_SEZE];
|
|
unsigned char data_buf[Ymodem_PACKET_STX_DATA_SIZE];
|
|
unsigned char seq = 0;
|
|
unsigned short crc;
|
|
int ret;
|
|
int file_size = 0;
|
|
int bytes_sent = 0;
|
|
int read_len = 0;
|
|
QFILE *fp = NULL;
|
|
|
|
/*--- Step 1: Open NVM file ---*/
|
|
fp = ql_fopen(NVM_SAVE_PATH, "rb");
|
|
if(fp == NULL)
|
|
{
|
|
ymodem_log("YModem send: failed to open %s\r\n", NVM_SAVE_PATH);
|
|
return -1;
|
|
}
|
|
|
|
file_size = ql_fsize(fp);
|
|
if(file_size <= 0)
|
|
{
|
|
ymodem_log("YModem send: file empty or error, size=%d\r\n", file_size);
|
|
ql_fclose(fp);
|
|
return -1;
|
|
}
|
|
ymodem_log("YModem send: file size = %d bytes\r\n", file_size);
|
|
|
|
/*--- Step 2: Wait for 'C' from TeraTerm ---*/
|
|
ymodem_log("In TeraTerm: File -> Transfer -> YMODEM -> Receive\r\n");
|
|
ymodem_log("Waiting for C (timeout 30s)...\r\n");
|
|
|
|
ret = ql_Ymodem_wait_char('C', DOWNLOAD_WAIT_C_TIMEOUT_MS);
|
|
if(ret != 0)
|
|
{
|
|
ymodem_log("YModem send: no C received, aborting\r\n");
|
|
ql_fclose(fp);
|
|
return -1;
|
|
}
|
|
ymodem_log("YModem send: got C, starting transfer\r\n");
|
|
|
|
/*--- Step 3: Send filename packet (seq=0) ---*/
|
|
memset(send_buf, 0, Ymodem_PACKET_SOH_SEZE);
|
|
send_buf[0] = Ymodem_SOH;
|
|
send_buf[1] = 0x00;
|
|
send_buf[2] = 0xFF;
|
|
snprintf((char *)send_buf + 3, 64, NVM_SAVE_PATH);
|
|
snprintf((char *)send_buf + 3 + strlen(NVM_SAVE_PATH) + 1, 16, "%d", file_size);
|
|
crc = crc16_ccitt(send_buf + 3, Ymodem_PACKET_SOH_DATA_SIZE);
|
|
send_buf[3 + Ymodem_PACKET_SOH_DATA_SIZE] = (crc >> 8) & 0xFF;
|
|
send_buf[3 + Ymodem_PACKET_SOH_DATA_SIZE + 1] = crc & 0xFF;
|
|
ql_uart_write(uartportchoose, send_buf, Ymodem_PACKET_SOH_SEZE);
|
|
ymodem_log("YModem send: filename packet sent\r\n");
|
|
|
|
ret = ql_Ymodem_wait_char(Ymodem_ACK, DOWNLOAD_ACK_TIMEOUT_MS);
|
|
if(ret != 0) {
|
|
ymodem_log("No ACK after filename\r\n");
|
|
ql_fclose(fp); return -1;
|
|
}
|
|
|
|
ret = ql_Ymodem_wait_char('C', DOWNLOAD_ACK_TIMEOUT_MS);
|
|
if(ret != 0) {
|
|
ymodem_log("No C after filename ACK\r\n");
|
|
ql_fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
/*--- Step 4: Send data packets ---*/
|
|
seq = 1;
|
|
while(bytes_sent < file_size)
|
|
{
|
|
int remaining = file_size - bytes_sent;
|
|
unsigned char pkt_type;
|
|
unsigned int pkt_data_size;
|
|
unsigned int pkt_total_size;
|
|
|
|
if(remaining >= Ymodem_PACKET_STX_DATA_SIZE)
|
|
{
|
|
pkt_type = Ymodem_STX;
|
|
pkt_data_size = Ymodem_PACKET_STX_DATA_SIZE;
|
|
pkt_total_size = Ymodem_PACKET_STX_SEZE;
|
|
}
|
|
else
|
|
{
|
|
pkt_type = Ymodem_SOH;
|
|
pkt_data_size = Ymodem_PACKET_SOH_DATA_SIZE;
|
|
pkt_total_size = Ymodem_PACKET_SOH_SEZE;
|
|
}
|
|
|
|
// Read chunk from NVM
|
|
memset(data_buf, 0x1A, pkt_data_size);
|
|
read_len = ql_fread(data_buf, 1, pkt_data_size, fp);
|
|
if(read_len <= 0)
|
|
{
|
|
ymodem_log("YModem send: ql_fread error at offset %d\r\n", bytes_sent);
|
|
ql_fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
// Build packet
|
|
send_buf[0] = pkt_type;
|
|
send_buf[1] = seq;
|
|
send_buf[2] = (unsigned char)(~seq);
|
|
memcpy(send_buf + 3, data_buf, pkt_data_size);
|
|
crc = crc16_ccitt(send_buf + 3, pkt_data_size);
|
|
send_buf[3 + pkt_data_size] = (crc >> 8) & 0xFF;
|
|
send_buf[3 + pkt_data_size + 1] = crc & 0xFF;
|
|
|
|
ql_uart_write(uartportchoose, send_buf, pkt_total_size);
|
|
|
|
ret = ql_Ymodem_wait_char(Ymodem_ACK, DOWNLOAD_ACK_TIMEOUT_MS);
|
|
if(ret != 0)
|
|
{
|
|
ymodem_log("No ACK for seq=%u, aborting\r\n", seq);
|
|
ql_fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
bytes_sent += read_len;
|
|
seq++;
|
|
ymodem_log("sent seq=%u progress=%d/%d bytes\r\n", seq - 1, bytes_sent, file_size);
|
|
}
|
|
|
|
ql_fclose(fp);
|
|
fp = NULL;
|
|
|
|
/*--- Step 5: EOT sequence ---*/
|
|
ql_uart_write(uartportchoose, &ch_eot, 1);
|
|
CHECK_CHAR_SEND_LOG("EOT1 sent\r\n");
|
|
ql_Ymodem_wait_char(Ymodem_NAK, DOWNLOAD_ACK_TIMEOUT_MS);
|
|
|
|
ql_uart_write(uartportchoose, &ch_eot, 1);
|
|
CHECK_CHAR_SEND_LOG("EOT2 sent\r\n");
|
|
ql_Ymodem_wait_char(Ymodem_ACK, DOWNLOAD_ACK_TIMEOUT_MS);
|
|
ql_Ymodem_wait_char('C', DOWNLOAD_ACK_TIMEOUT_MS);
|
|
|
|
/*--- Step 6: Null filename packet to end session ---*/
|
|
memset(send_buf, 0, Ymodem_PACKET_SOH_SEZE);
|
|
send_buf[0] = Ymodem_SOH;
|
|
send_buf[1] = 0x00;
|
|
send_buf[2] = 0xFF;
|
|
crc = crc16_ccitt(send_buf + 3, Ymodem_PACKET_SOH_DATA_SIZE);
|
|
send_buf[3 + Ymodem_PACKET_SOH_DATA_SIZE] = (crc >> 8) & 0xFF;
|
|
send_buf[3 + Ymodem_PACKET_SOH_DATA_SIZE + 1] = crc & 0xFF;
|
|
ql_uart_write(uartportchoose, send_buf, Ymodem_PACKET_SOH_SEZE);
|
|
|
|
ql_Ymodem_wait_char(Ymodem_ACK, DOWNLOAD_ACK_TIMEOUT_MS);
|
|
|
|
ymodem_log("YModem send: transfer complete!\r\n");
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************************************************
|
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Upload main task!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
***********************************************************************************************************/
|
|
void quec_Ymodem_upload_main()
|
|
{
|
|
ymodem_log("***********Ymodem upload start\r\n");
|
|
ymodem_log("Save path: %s\r\n", NVM_SAVE_PATH);
|
|
|
|
ql_Ymodem_uart_init();
|
|
ql_uart_flush_fifo(uartportchoose);
|
|
|
|
ql_Ymodem_upload_file();
|
|
}
|
|
|
|
/***********************************************************************************************************
|
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Download main task!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
***********************************************************************************************************/
|
|
void quec_Ymodem_download_main()
|
|
{
|
|
ymodem_log("***********Ymodem download task start\r\n");
|
|
ymodem_log("NVM path : %s\r\n", NVM_SAVE_PATH);
|
|
ymodem_log("Delete after : %d\r\n", DELETE_AFTER_DOWNLOAD);
|
|
ql_Ymodem_uart_init();
|
|
ql_uart_flush_fifo(uartportchoose);
|
|
|
|
// Check file exists before starting
|
|
if(ql_access(NVM_SAVE_PATH, 0) != 0)
|
|
{
|
|
ymodem_log("File not found: %s\r\n", NVM_SAVE_PATH);
|
|
ymodem_log("Run upload first, then run download.\r\n");
|
|
return;
|
|
}
|
|
|
|
int result = ql_Ymodem_send_file();
|
|
|
|
if(result == 0)
|
|
{
|
|
ymodem_log("Transfer successful!\r\n");
|
|
|
|
#if DELETE_AFTER_DOWNLOAD
|
|
int del = ql_remove(NVM_SAVE_PATH);
|
|
if(del == 0)
|
|
ymodem_log("File deleted from NVM: %s\r\n", NVM_SAVE_PATH);
|
|
else
|
|
ymodem_log("Failed to delete, ret=%d\r\n", del);
|
|
#else
|
|
ymodem_log("File kept in NVM: %s\r\n", NVM_SAVE_PATH);
|
|
#endif
|
|
}
|
|
else
|
|
ymodem_log("Transfer failed! File kept in NVM.\r\n");
|
|
|
|
ymodem_log("Download task done.\r\n");
|
|
}
|
|
|
|
//application_init(quec_Ymodem_upload_main, "quec_Ymodem_upload_main", 20, 0);
|
|
//application_init(quec_Ymodem_download_main, "quec_Ymodem_download_main", 20, 0);
|