mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-01 20:29:00 +00:00
ymodem:set the transport retry as optional
The waiting duration of the rb/sb command can be determined based on the number of retransmissions, so that ymodem can restart to the normal system after running in the bootloader for a short period of time. Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
parent
e4e46c3f53
commit
85ae6f0dfd
5 changed files with 114 additions and 63 deletions
|
|
@ -330,6 +330,12 @@ static void show_usage(FAR const char *progname)
|
|||
fprintf(stderr,
|
||||
"\t-t|--threshold <size>: Threshold for writing asynchronously."
|
||||
"Threshold must be less than or equal buffersize, Default: 0kB\n");
|
||||
fprintf(stderr,
|
||||
"\t-i|--interval <time>: Waiting interval for transmitting data."
|
||||
"Max:255 Min:1 Default:15 unit: 100 milliseconds\n");
|
||||
fprintf(stderr,
|
||||
"\t-r|--retry <retry>: Number of retries."
|
||||
"Will try <retry> times to transmitting, Default:100\n");
|
||||
fprintf(stderr,
|
||||
"\t-k <size>: Use a custom size to tansfer, Default: 1kB\n");
|
||||
|
||||
|
|
@ -352,13 +358,17 @@ int main(int argc, FAR char *argv[])
|
|||
{"buffersize", 1, NULL, 'b'},
|
||||
{"skip_prefix", 1, NULL, 'p'},
|
||||
{"skip_suffix", 1, NULL, 's'},
|
||||
{"threshold", 1, NULL, 't'}
|
||||
{"threshold", 1, NULL, 't'},
|
||||
{"interval", 1, NULL, 'i'},
|
||||
{"retry", 1, NULL, 'r'},
|
||||
};
|
||||
|
||||
memset(&priv, 0, sizeof(priv));
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
while ((ret = getopt_long(argc, argv, "b:d:f:hk:p:s:t:", options, NULL))
|
||||
!= ERROR)
|
||||
ctx.interval = 15;
|
||||
ctx.retry = 100;
|
||||
while ((ret = getopt_long(argc, argv, "b:d:f:hk:p:s:t:i:r:",
|
||||
options, NULL)) != ERROR)
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
|
|
@ -391,6 +401,12 @@ int main(int argc, FAR char *argv[])
|
|||
case 't':
|
||||
priv.threshold = atoi(optarg) * 1024;
|
||||
break;
|
||||
case 'i':
|
||||
ctx.interval = atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
ctx.retry = atoi(optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -275,6 +275,12 @@ static void show_usage(FAR const char *progname)
|
|||
fprintf(stderr,
|
||||
"\t-b|--buffersize <size>: Asynchronously send buffer size."
|
||||
"If greater than 0, accept data asynchronously, Default: 0kB\n");
|
||||
fprintf(stderr,
|
||||
"\t-i|--interval <time>: Waiting interval for transmitting data."
|
||||
"Max:255 Min:1 Default:15 unit: 100 milliseconds\n");
|
||||
fprintf(stderr,
|
||||
"\t-r|--retry <retry>: Number of retries."
|
||||
"Will try <retry> times to transmitting, Default:100\n");
|
||||
fprintf(stderr,
|
||||
"\t-k <size>: Use a custom size to tansfer, Default: 1kB\n");
|
||||
|
||||
|
|
@ -294,10 +300,14 @@ int main(int argc, FAR char *argv[])
|
|||
struct option options[] =
|
||||
{
|
||||
{"buffersize", 1, NULL, 'b'},
|
||||
{"interval", 1, NULL, 'i'},
|
||||
{"retry", 1, NULL, 'r'},
|
||||
};
|
||||
|
||||
memset(&priv, 0, sizeof(priv));
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.interval = 15;
|
||||
ctx.retry = 100;
|
||||
while ((ret = getopt_long(argc, argv, "b:d:k:h", options, NULL))
|
||||
!= ERROR)
|
||||
{
|
||||
|
|
@ -317,6 +327,13 @@ int main(int argc, FAR char *argv[])
|
|||
}
|
||||
|
||||
break;
|
||||
case 'i':
|
||||
ctx.interval = atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
ctx.retry = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import binascii
|
|||
import datetime
|
||||
import io
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import termios
|
||||
|
||||
|
|
@ -54,47 +53,35 @@ def format_time(seconds):
|
|||
return time
|
||||
|
||||
|
||||
class Timeout(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def timeout_handle(signum, frame):
|
||||
sys.stderr.write("timeout!\n")
|
||||
sys.stderr.flush()
|
||||
raise Timeout("Timeout")
|
||||
|
||||
|
||||
def ymodem_stdread(size):
|
||||
fd = sys.stdin.fileno()
|
||||
old_settings = termios.tcgetattr(fd)
|
||||
signal.signal(signal.SIGALRM, timeout_handle)
|
||||
signal.alarm(3)
|
||||
try:
|
||||
new_settings = termios.tcgetattr(fd)
|
||||
new_settings[3] &= ~(termios.ICANON | termios.ECHO)
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, new_settings)
|
||||
data = sys.stdin.buffer.read(size)
|
||||
sys.stdin.flush()
|
||||
return data
|
||||
except Timeout:
|
||||
return
|
||||
finally:
|
||||
signal.alarm(0)
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
new_settings = termios.tcgetattr(fd)
|
||||
new_settings[3] &= ~(termios.ICANON | termios.ECHO)
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, new_settings)
|
||||
data = sys.stdin.buffer.read(size)
|
||||
termios.tcflush(sys.stdin, termios.TCIFLUSH)
|
||||
sys.stdin.flush()
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
return data
|
||||
|
||||
|
||||
def ymodem_stdwrite(data):
|
||||
fd = sys.stdout.fileno()
|
||||
old_settings = termios.tcgetattr(fd)
|
||||
try:
|
||||
new_settings = termios.tcgetattr(fd)
|
||||
new_settings[3] &= ~(termios.ICANON | termios.ECHO)
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, new_settings)
|
||||
data = sys.stdout.buffer.write(data)
|
||||
sys.stdout.flush()
|
||||
return data
|
||||
finally:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
new_settings = termios.tcgetattr(fd)
|
||||
new_settings[3] &= ~(termios.ICANON | termios.ECHO)
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, new_settings)
|
||||
data = sys.stdout.buffer.write(data)
|
||||
termios.tcflush(sys.stdout, termios.TCIFLUSH)
|
||||
sys.stdout.flush()
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
return data
|
||||
|
||||
|
||||
def ymodem_stdclear():
|
||||
sys.stdin.flush()
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def ymodem_stdprogress(data):
|
||||
|
|
@ -115,6 +102,13 @@ def ymodem_ser_write(data):
|
|||
fd_serial.flush()
|
||||
|
||||
|
||||
def ymodem_ser_clear():
|
||||
global fd_serial
|
||||
|
||||
fd_serial.reset_input_buffer()
|
||||
fd_serial.reset_output_buffer()
|
||||
|
||||
|
||||
def calc_crc16(data, crc=0):
|
||||
crctable = [
|
||||
0x0000,
|
||||
|
|
@ -388,15 +382,21 @@ class ymodem:
|
|||
read=ymodem_stdread,
|
||||
write=ymodem_stdwrite,
|
||||
progress=ymodem_stdprogress,
|
||||
clear=ymodem_stdclear,
|
||||
timeout=100,
|
||||
maxretry=RETRIESMAX,
|
||||
debug="",
|
||||
customsize=0,
|
||||
):
|
||||
self.read = read
|
||||
self.write = write
|
||||
self.clear = clear
|
||||
self.timeout = timeout
|
||||
self.maxretry = maxretry
|
||||
self.progress = progress
|
||||
self.customsize = customsize
|
||||
self.retries = 0
|
||||
|
||||
if debug != "":
|
||||
self.debugfd = open(debug, "w+")
|
||||
else:
|
||||
|
|
@ -460,24 +460,28 @@ class ymodem:
|
|||
|
||||
return 0
|
||||
|
||||
def send_handshake(self):
|
||||
self.write(CRC)
|
||||
while self.retries < self.maxretry:
|
||||
chunk = self.read(1)
|
||||
if chunk == CRC:
|
||||
return True
|
||||
else:
|
||||
self.retries += 1
|
||||
self.clear()
|
||||
|
||||
self.progress("too many retries\n")
|
||||
return False
|
||||
|
||||
def send(self, filelist):
|
||||
retries = 0
|
||||
need_sendfile_num = len(filelist)
|
||||
cnt = 0
|
||||
now = datetime.datetime.now()
|
||||
base = float(int(now.timestamp() * 1000)) / 1000
|
||||
totolbytes = 0
|
||||
|
||||
while retries < 10:
|
||||
self.write(CRC)
|
||||
chunk = self.read(1)
|
||||
if chunk == CRC:
|
||||
break
|
||||
else:
|
||||
retries += 1
|
||||
|
||||
if retries == 10:
|
||||
return False
|
||||
if not self.send_handshake():
|
||||
return -EINVAL
|
||||
|
||||
while need_sendfile_num != 0:
|
||||
now = datetime.datetime.now()
|
||||
|
|
@ -485,13 +489,10 @@ class ymodem:
|
|||
self.init_pkt()
|
||||
self.head = SOH
|
||||
filename = os.path.basename(filelist[cnt])
|
||||
|
||||
self.progress("name:" + filename)
|
||||
self.data = filename.encode("utf-8")
|
||||
self.data = self.data + bytes([0x00] * 1)
|
||||
filesize = os.path.getsize(filelist[cnt])
|
||||
sendfilesize = 0
|
||||
self.progress(" filesize:%d\n" % (filesize))
|
||||
self.data = self.data + str(filesize).encode("utf-8")
|
||||
self.data = self.data.ljust(self.get_pkt_size(), b"\x00")
|
||||
self.send_pkt()
|
||||
|
|
@ -500,14 +501,21 @@ class ymodem:
|
|||
if ret == -EAGAIN:
|
||||
continue
|
||||
elif ret == -EINVAL:
|
||||
if self.send_handshake():
|
||||
continue
|
||||
return ret
|
||||
|
||||
ret = self.recv_cmd(CRC)
|
||||
if ret == -EAGAIN:
|
||||
continue
|
||||
elif ret == -EINVAL:
|
||||
if self.send_handshake():
|
||||
continue
|
||||
return ret
|
||||
|
||||
self.progress("name:" + filename)
|
||||
self.progress(" filesize:%d\n" % (filesize))
|
||||
|
||||
self.add_seq()
|
||||
readfd = open(filelist[cnt], "rb")
|
||||
self.progress(" ")
|
||||
|
|
@ -656,7 +664,6 @@ class ymodem:
|
|||
return 0
|
||||
|
||||
def recv(self):
|
||||
retries = 0
|
||||
now = datetime.datetime.now()
|
||||
base = float(int(now.timestamp() * 1000)) / 1000
|
||||
totolbytes = 0
|
||||
|
|
@ -673,12 +680,12 @@ class ymodem:
|
|||
continue
|
||||
|
||||
elif ret < 0:
|
||||
if retries > RETRIESMAX:
|
||||
if self.retries > self.maxretry:
|
||||
return -1
|
||||
|
||||
self.progress("recv ret %d\n" % ret)
|
||||
self.debug("recv frist packet\n")
|
||||
retries += 1
|
||||
self.retries += 1
|
||||
continue
|
||||
|
||||
filename = bytes.decode(self.data.split(b"\x00")[0], "utf-8")
|
||||
|
|
@ -699,9 +706,9 @@ class ymodem:
|
|||
ret = self.recv_packet()
|
||||
if ret < 0:
|
||||
self.debug("recv a bad data packet\n")
|
||||
if retries > RETRIESMAX:
|
||||
if self.retries > self.maxretry:
|
||||
return -1
|
||||
retries += 1
|
||||
self.retries += 1
|
||||
continue
|
||||
|
||||
size = 0
|
||||
|
|
@ -791,6 +798,13 @@ if __name__ == "__main__":
|
|||
""",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--maxretry",
|
||||
type=int,
|
||||
default=RETRIESMAX,
|
||||
help="This opthin set max retry for transmission",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--debug", help="This opthin is save debug log on host", default=""
|
||||
)
|
||||
|
|
@ -821,9 +835,13 @@ if __name__ == "__main__":
|
|||
customsize=args.kblocksize * 1024,
|
||||
read=ymodem_ser_read,
|
||||
write=ymodem_ser_write,
|
||||
clear=ymodem_ser_clear,
|
||||
maxretry=args.maxretry,
|
||||
)
|
||||
else:
|
||||
sbrb = ymodem(debug=args.debug, customsize=args.kblocksize * 1024)
|
||||
sbrb = ymodem(
|
||||
debug=args.debug, customsize=args.kblocksize * 1024, maxretry=args.maxretry
|
||||
)
|
||||
|
||||
if len(args.filelist) == 0:
|
||||
sbrb.progress("receiving\n")
|
||||
|
|
|
|||
|
|
@ -60,8 +60,6 @@
|
|||
#define CAN 0x18 /* Two of these in succession aborts transfer */
|
||||
#define CRC 0x43 /* 'C' == 0x43, request 16-bit CRC */
|
||||
|
||||
#define MAX_RETRIES 100
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
|
@ -216,7 +214,7 @@ recv_packet:
|
|||
/* other errors, like ETIMEDOUT, EILSEQ, EBADMSG... */
|
||||
|
||||
tcflush(ctx->recvfd, TCIOFLUSH);
|
||||
if (++retries > MAX_RETRIES)
|
||||
if (++retries > ctx->retry)
|
||||
{
|
||||
ymodem_debug("recv_file: too many errors, cancel!!\n");
|
||||
goto cancel;
|
||||
|
|
@ -340,7 +338,7 @@ static int ymodem_send_file(FAR struct ymodem_ctx_s *ctx)
|
|||
int ret;
|
||||
|
||||
ymodem_debug("waiting handshake\n");
|
||||
for (retries = 0; retries < MAX_RETRIES; retries++)
|
||||
for (retries = 0; retries < ctx->retry; retries++)
|
||||
{
|
||||
ret = ymodem_recv_cmd(ctx, CRC);
|
||||
if (ret >= 0)
|
||||
|
|
@ -349,7 +347,7 @@ static int ymodem_send_file(FAR struct ymodem_ctx_s *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
if (retries >= MAX_RETRIES)
|
||||
if (retries >= ctx->retry)
|
||||
{
|
||||
ymodem_debug("waiting handshake error\n");
|
||||
return -ETIMEDOUT;
|
||||
|
|
@ -581,7 +579,7 @@ int ymodem_recv(FAR struct ymodem_ctx_s *ctx)
|
|||
tcgetattr(ctx->recvfd, &term);
|
||||
memcpy(&saveterm, &term, sizeof(struct termios));
|
||||
cfmakeraw(&term);
|
||||
term.c_cc[VTIME] = 15;
|
||||
term.c_cc[VTIME] = ctx->interval;
|
||||
term.c_cc[VMIN] = 255;
|
||||
tcsetattr(ctx->recvfd, TCSANOW, &term);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ struct ymodem_ctx_s
|
|||
CODE int (*packet_handler)(FAR struct ymodem_ctx_s *ctx);
|
||||
size_t custom_size;
|
||||
FAR void *priv;
|
||||
uint8_t interval;
|
||||
int retry;
|
||||
|
||||
/* Public data */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue