support ymodem transfer on a custom blocksize
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
parent
32e597a136
commit
fd42d811c2
@ -5,9 +5,32 @@ According to it, the sb rb application is realized, which is used to send files
|
||||
|
||||
# Usage
|
||||
|
||||
## Common Usage
|
||||
|
||||
In the ubuntu system, lszrz needs to be installed, can use `sudo apt install lszrz`.
|
||||
Use minicom to communicate with the board.
|
||||
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
In order to achieve a faster transmission speed,
|
||||
I added a specific HEADER `STC` to the YMODEM protocol to represent the custom length.
|
||||
Using the `sb` and `rb` commands on the board, you can use the `-k` option to set the length
|
||||
of the custom packet, and the unit is KB. Therefore, you need to use `sbrb.py` for file transfer,
|
||||
and you need `sbrb.py` -k to set the same length as the board. According to my test,
|
||||
when using -k 32, it can reach 93% of the baud rate,
|
||||
and is fully compatible with the original ymodem protocol.
|
||||
First, you need to add a soft link to sbrb.py, for example `sudo ln -s /home/<name>/.../<nuttxwork>/apps/system/ymodem/sbrb.py /usr/bin`
|
||||
and then sbrb.py can be configured into minicom.`<Ctrl + a> z o` then chose `File transfer protocols` and
|
||||
crate two option cmd is 'sbrb.py -k 32'. like this
|
||||
|
||||
| Name | Program | Name | U/D | FullScr | IO-Red. | Multi |
|
||||
| ---- | ------- | ---- | --- | ------- | ------- | ----- |
|
||||
| ymodem-k | sbrb.py -k 32 | Y | U | N | Y | Y |
|
||||
| ymodem-k | sbrb.py -k 32 | N | D | N | Y | Y |
|
||||
|
||||
usb `sb -k 32` or `rb -k 32` for file transfer on board.
|
||||
|
||||
## Sendfile to pc
|
||||
|
||||
use sb command like this `nsh> sb /tmp/test.c ...`, this command support send multiple files together
|
||||
|
@ -330,6 +330,8 @@ 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-k <size>: Use a custom size to tansfer, Default: 1kB\n");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -355,7 +357,7 @@ int main(int argc, FAR char *argv[])
|
||||
|
||||
memset(&priv, 0, sizeof(priv));
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
while ((ret = getopt_long(argc, argv, "b:d:f:hp:s:t:", options, NULL))
|
||||
while ((ret = getopt_long(argc, argv, "b:d:f:hk:p:s:t:", options, NULL))
|
||||
!= ERROR)
|
||||
{
|
||||
switch (ret)
|
||||
@ -377,6 +379,9 @@ int main(int argc, FAR char *argv[])
|
||||
case 'h':
|
||||
show_usage(argv[0]);
|
||||
break;
|
||||
case 'k':
|
||||
ctx.custom_size = atoi(optarg) * 1024;
|
||||
break;
|
||||
case 'p':
|
||||
priv.skip_perfix = optarg;
|
||||
break;
|
||||
@ -387,13 +392,15 @@ int main(int argc, FAR char *argv[])
|
||||
priv.threshold = atoi(optarg) * 1024;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
show_usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv.threshold > priv.buffersize)
|
||||
if (priv.buffersize && (priv.threshold > priv.buffersize ||
|
||||
ctx.custom_size > priv.buffersize))
|
||||
{
|
||||
show_usage(argv[0]);
|
||||
}
|
||||
|
@ -275,6 +275,9 @@ 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-k <size>: Use a custom size to tansfer, Default: 1kB\n");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -295,7 +298,7 @@ int main(int argc, FAR char *argv[])
|
||||
|
||||
memset(&priv, 0, sizeof(priv));
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
while ((ret = getopt_long(argc, argv, "b:d:h", options, NULL))
|
||||
while ((ret = getopt_long(argc, argv, "b:d:k:h", options, NULL))
|
||||
!= ERROR)
|
||||
{
|
||||
switch (ret)
|
||||
@ -306,6 +309,14 @@ int main(int argc, FAR char *argv[])
|
||||
case 'd':
|
||||
devname = optarg;
|
||||
break;
|
||||
case 'k':
|
||||
ctx.custom_size = atoi(optarg) * 1024;
|
||||
if (ctx.custom_size == 0)
|
||||
{
|
||||
show_usage(argv[0]);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
@ -314,6 +325,11 @@ int main(int argc, FAR char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (priv.buffersize && ctx.custom_size > priv.buffersize)
|
||||
{
|
||||
show_usage(argv[0]);
|
||||
}
|
||||
|
||||
ctx.packet_handler = handler;
|
||||
if (devname)
|
||||
{
|
||||
|
760
system/ymodem/sbrb.py
Executable file
760
system/ymodem/sbrb.py
Executable file
@ -0,0 +1,760 @@
|
||||
#!/bin/python3
|
||||
# apps/system/ymodem/sbrb.py
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
import argparse
|
||||
import binascii
|
||||
import datetime
|
||||
import io
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import termios
|
||||
|
||||
SOH = b"\x01" # Start of 128-byte data packet
|
||||
STX = b"\x02" # Start of 1024-byte data packet
|
||||
STC = b"\x03" # Start of a customsize data packet
|
||||
EOT = b"\x04" # End of transmission
|
||||
ACK = b"\x06" # Acknowledge
|
||||
NAK = b"\x15" # Negative acknowledge
|
||||
CAN = b"\x18" # Two of these in succession aborts transfer
|
||||
CRC = b"\x43" # "C" == 0x43, request 16-bit CRC
|
||||
|
||||
PACKET_SIZE = 128
|
||||
PACKET_1K_SIZE = 1024
|
||||
EAGAIN = 1
|
||||
EINVAL = 2
|
||||
EEOT = 3
|
||||
RETRIESMAX = 200
|
||||
|
||||
|
||||
def format_time(seconds):
|
||||
hours = seconds / 3600
|
||||
seconds %= 3600
|
||||
minutes = seconds / 60
|
||||
seconds %= 60
|
||||
|
||||
time = "%02dh%02dm%02ds" % (int(hours), int(minutes), int(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)
|
||||
sys.stdin.flush()
|
||||
data = sys.stdin.buffer.read(size)
|
||||
return data
|
||||
except Timeout:
|
||||
return
|
||||
finally:
|
||||
signal.alarm(0)
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def ymodem_stdprogress(data):
|
||||
sys.stderr.write(data)
|
||||
sys.stderr.flush()
|
||||
|
||||
|
||||
def calc_crc16(data, crc=0):
|
||||
crctable = [
|
||||
0x0000,
|
||||
0x1021,
|
||||
0x2042,
|
||||
0x3063,
|
||||
0x4084,
|
||||
0x50A5,
|
||||
0x60C6,
|
||||
0x70E7,
|
||||
0x8108,
|
||||
0x9129,
|
||||
0xA14A,
|
||||
0xB16B,
|
||||
0xC18C,
|
||||
0xD1AD,
|
||||
0xE1CE,
|
||||
0xF1EF,
|
||||
0x1231,
|
||||
0x0210,
|
||||
0x3273,
|
||||
0x2252,
|
||||
0x52B5,
|
||||
0x4294,
|
||||
0x72F7,
|
||||
0x62D6,
|
||||
0x9339,
|
||||
0x8318,
|
||||
0xB37B,
|
||||
0xA35A,
|
||||
0xD3BD,
|
||||
0xC39C,
|
||||
0xF3FF,
|
||||
0xE3DE,
|
||||
0x2462,
|
||||
0x3443,
|
||||
0x0420,
|
||||
0x1401,
|
||||
0x64E6,
|
||||
0x74C7,
|
||||
0x44A4,
|
||||
0x5485,
|
||||
0xA56A,
|
||||
0xB54B,
|
||||
0x8528,
|
||||
0x9509,
|
||||
0xE5EE,
|
||||
0xF5CF,
|
||||
0xC5AC,
|
||||
0xD58D,
|
||||
0x3653,
|
||||
0x2672,
|
||||
0x1611,
|
||||
0x0630,
|
||||
0x76D7,
|
||||
0x66F6,
|
||||
0x5695,
|
||||
0x46B4,
|
||||
0xB75B,
|
||||
0xA77A,
|
||||
0x9719,
|
||||
0x8738,
|
||||
0xF7DF,
|
||||
0xE7FE,
|
||||
0xD79D,
|
||||
0xC7BC,
|
||||
0x48C4,
|
||||
0x58E5,
|
||||
0x6886,
|
||||
0x78A7,
|
||||
0x0840,
|
||||
0x1861,
|
||||
0x2802,
|
||||
0x3823,
|
||||
0xC9CC,
|
||||
0xD9ED,
|
||||
0xE98E,
|
||||
0xF9AF,
|
||||
0x8948,
|
||||
0x9969,
|
||||
0xA90A,
|
||||
0xB92B,
|
||||
0x5AF5,
|
||||
0x4AD4,
|
||||
0x7AB7,
|
||||
0x6A96,
|
||||
0x1A71,
|
||||
0x0A50,
|
||||
0x3A33,
|
||||
0x2A12,
|
||||
0xDBFD,
|
||||
0xCBDC,
|
||||
0xFBBF,
|
||||
0xEB9E,
|
||||
0x9B79,
|
||||
0x8B58,
|
||||
0xBB3B,
|
||||
0xAB1A,
|
||||
0x6CA6,
|
||||
0x7C87,
|
||||
0x4CE4,
|
||||
0x5CC5,
|
||||
0x2C22,
|
||||
0x3C03,
|
||||
0x0C60,
|
||||
0x1C41,
|
||||
0xEDAE,
|
||||
0xFD8F,
|
||||
0xCDEC,
|
||||
0xDDCD,
|
||||
0xAD2A,
|
||||
0xBD0B,
|
||||
0x8D68,
|
||||
0x9D49,
|
||||
0x7E97,
|
||||
0x6EB6,
|
||||
0x5ED5,
|
||||
0x4EF4,
|
||||
0x3E13,
|
||||
0x2E32,
|
||||
0x1E51,
|
||||
0x0E70,
|
||||
0xFF9F,
|
||||
0xEFBE,
|
||||
0xDFDD,
|
||||
0xCFFC,
|
||||
0xBF1B,
|
||||
0xAF3A,
|
||||
0x9F59,
|
||||
0x8F78,
|
||||
0x9188,
|
||||
0x81A9,
|
||||
0xB1CA,
|
||||
0xA1EB,
|
||||
0xD10C,
|
||||
0xC12D,
|
||||
0xF14E,
|
||||
0xE16F,
|
||||
0x1080,
|
||||
0x00A1,
|
||||
0x30C2,
|
||||
0x20E3,
|
||||
0x5004,
|
||||
0x4025,
|
||||
0x7046,
|
||||
0x6067,
|
||||
0x83B9,
|
||||
0x9398,
|
||||
0xA3FB,
|
||||
0xB3DA,
|
||||
0xC33D,
|
||||
0xD31C,
|
||||
0xE37F,
|
||||
0xF35E,
|
||||
0x02B1,
|
||||
0x1290,
|
||||
0x22F3,
|
||||
0x32D2,
|
||||
0x4235,
|
||||
0x5214,
|
||||
0x6277,
|
||||
0x7256,
|
||||
0xB5EA,
|
||||
0xA5CB,
|
||||
0x95A8,
|
||||
0x8589,
|
||||
0xF56E,
|
||||
0xE54F,
|
||||
0xD52C,
|
||||
0xC50D,
|
||||
0x34E2,
|
||||
0x24C3,
|
||||
0x14A0,
|
||||
0x0481,
|
||||
0x7466,
|
||||
0x6447,
|
||||
0x5424,
|
||||
0x4405,
|
||||
0xA7DB,
|
||||
0xB7FA,
|
||||
0x8799,
|
||||
0x97B8,
|
||||
0xE75F,
|
||||
0xF77E,
|
||||
0xC71D,
|
||||
0xD73C,
|
||||
0x26D3,
|
||||
0x36F2,
|
||||
0x0691,
|
||||
0x16B0,
|
||||
0x6657,
|
||||
0x7676,
|
||||
0x4615,
|
||||
0x5634,
|
||||
0xD94C,
|
||||
0xC96D,
|
||||
0xF90E,
|
||||
0xE92F,
|
||||
0x99C8,
|
||||
0x89E9,
|
||||
0xB98A,
|
||||
0xA9AB,
|
||||
0x5844,
|
||||
0x4865,
|
||||
0x7806,
|
||||
0x6827,
|
||||
0x18C0,
|
||||
0x08E1,
|
||||
0x3882,
|
||||
0x28A3,
|
||||
0xCB7D,
|
||||
0xDB5C,
|
||||
0xEB3F,
|
||||
0xFB1E,
|
||||
0x8BF9,
|
||||
0x9BD8,
|
||||
0xABBB,
|
||||
0xBB9A,
|
||||
0x4A75,
|
||||
0x5A54,
|
||||
0x6A37,
|
||||
0x7A16,
|
||||
0x0AF1,
|
||||
0x1AD0,
|
||||
0x2AB3,
|
||||
0x3A92,
|
||||
0xFD2E,
|
||||
0xED0F,
|
||||
0xDD6C,
|
||||
0xCD4D,
|
||||
0xBDAA,
|
||||
0xAD8B,
|
||||
0x9DE8,
|
||||
0x8DC9,
|
||||
0x7C26,
|
||||
0x6C07,
|
||||
0x5C64,
|
||||
0x4C45,
|
||||
0x3CA2,
|
||||
0x2C83,
|
||||
0x1CE0,
|
||||
0x0CC1,
|
||||
0xEF1F,
|
||||
0xFF3E,
|
||||
0xCF5D,
|
||||
0xDF7C,
|
||||
0xAF9B,
|
||||
0xBFBA,
|
||||
0x8FD9,
|
||||
0x9FF8,
|
||||
0x6E17,
|
||||
0x7E36,
|
||||
0x4E55,
|
||||
0x5E74,
|
||||
0x2E93,
|
||||
0x3EB2,
|
||||
0x0ED1,
|
||||
0x1EF0,
|
||||
]
|
||||
|
||||
crc = 0x0
|
||||
for char in bytearray(data):
|
||||
crctbl_idx = ((crc >> 8) ^ char) & 0xFF
|
||||
crc = ((crc << 8) ^ crctable[crctbl_idx]) & 0xFFFF
|
||||
return crc & 0xFFFF
|
||||
|
||||
|
||||
class ymodem:
|
||||
def __init__(
|
||||
self,
|
||||
read=ymodem_stdread,
|
||||
write=ymodem_stdwrite,
|
||||
progress=ymodem_stdprogress,
|
||||
timeout=100,
|
||||
debug="",
|
||||
customsize=0,
|
||||
):
|
||||
self.read = read
|
||||
self.write = write
|
||||
self.timeout = timeout
|
||||
self.progress = progress
|
||||
self.customsize = customsize
|
||||
if debug != "":
|
||||
self.debugfd = open(debug, "w+")
|
||||
else:
|
||||
self.debugfd = 0
|
||||
|
||||
def debug(self, data):
|
||||
if isinstance(self.debugfd, io.RawIOBase):
|
||||
self.debugfd.write(data)
|
||||
self.debugfd.flush()
|
||||
|
||||
def init_pkt(self):
|
||||
self.head = SOH
|
||||
self.seq0 = b"\x00"
|
||||
self.seq1 = b"\xff"
|
||||
self.data = b""
|
||||
self.crch = b""
|
||||
self.crcl = b""
|
||||
|
||||
def send_pkt(self):
|
||||
crc16 = calc_crc16(self.data)
|
||||
self.crch = bytes([(crc16 >> 8) & 0xFF])
|
||||
self.crcl = bytes([crc16 & 0xFF])
|
||||
pkt = self.head + self.seq0 + self.seq1 + self.data + self.crch + self.crcl
|
||||
|
||||
self.write(pkt)
|
||||
|
||||
def add_seq(self):
|
||||
seq0 = bytearray(self.seq0)
|
||||
if seq0[0] == 0xFF:
|
||||
seq0[0] = 0x00
|
||||
else:
|
||||
seq0[0] += 1
|
||||
|
||||
seq1 = bytearray(self.seq1)
|
||||
if seq1[0] == 0x00:
|
||||
seq1[0] = 0xFF
|
||||
else:
|
||||
seq1[0] -= 1
|
||||
|
||||
self.seq0 = bytes(seq0)
|
||||
self.seq1 = bytes(seq1)
|
||||
|
||||
def get_pkt_size(self):
|
||||
if self.head == SOH:
|
||||
return PACKET_SIZE
|
||||
elif self.head == STX:
|
||||
return PACKET_1K_SIZE
|
||||
elif self.head == STC:
|
||||
return self.customsize
|
||||
|
||||
return PACKET_SIZE
|
||||
|
||||
def recv_cmd(self, cmd):
|
||||
chunk = self.read(1)
|
||||
if chunk == NAK:
|
||||
return -EAGAIN
|
||||
if chunk != cmd:
|
||||
self.debug("should be " + binascii.hexlify(cmd).decode("utf-8"))
|
||||
self.debug("but receive " + binascii.hexlify(chunk).decode("utf-8") + "\n")
|
||||
return -EINVAL
|
||||
|
||||
return 0
|
||||
|
||||
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 need_sendfile_num != 0:
|
||||
now = datetime.datetime.now()
|
||||
start = float(int(now.timestamp() * 1000)) / 1000
|
||||
while retries < 10:
|
||||
self.write(CRC)
|
||||
chunk = self.read(1)
|
||||
if chunk == CRC:
|
||||
break
|
||||
else:
|
||||
retries += 1
|
||||
|
||||
if retries == 10:
|
||||
return False
|
||||
|
||||
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()
|
||||
|
||||
ret = self.recv_cmd(ACK)
|
||||
if ret == -EAGAIN:
|
||||
continue
|
||||
elif ret == -EINVAL:
|
||||
return ret
|
||||
|
||||
ret = self.recv_cmd(CRC)
|
||||
if ret == -EAGAIN:
|
||||
continue
|
||||
elif ret == -EINVAL:
|
||||
return ret
|
||||
|
||||
self.add_seq()
|
||||
readfd = open(filelist[cnt], "rb")
|
||||
self.progress(" ")
|
||||
while sendfilesize < filesize:
|
||||
if sendfilesize + 128 >= filesize:
|
||||
self.head = SOH
|
||||
elif self.customsize != 0:
|
||||
self.head = STC
|
||||
else:
|
||||
self.head = STX
|
||||
|
||||
self.data = readfd.read(self.get_pkt_size())
|
||||
sendbytes = len(self.data)
|
||||
self.data = self.data.ljust(self.get_pkt_size(), b"\x00")
|
||||
|
||||
self.send_pkt()
|
||||
ret = self.recv_cmd(ACK)
|
||||
if ret == -EAGAIN:
|
||||
continue
|
||||
elif ret == -EINVAL:
|
||||
return ret
|
||||
|
||||
self.add_seq()
|
||||
sendfilesize += sendbytes
|
||||
totolbytes += sendbytes
|
||||
self.progress("\r")
|
||||
self.progress("%2.1f%%" % (float(sendfilesize) / filesize * 100))
|
||||
self.progress(" %d:%d" % (sendfilesize, filesize))
|
||||
now = datetime.datetime.now()
|
||||
usedtime = float(int(now.timestamp() * 1000) / 1000) - start
|
||||
realspeed = sendfilesize / 1024 / usedtime
|
||||
left = (filesize - sendfilesize) / 1024 / (realspeed)
|
||||
self.progress(" left:" + format_time(left))
|
||||
|
||||
retries = 0
|
||||
while True:
|
||||
if retries == 2:
|
||||
return -EINVAL
|
||||
retries += 1
|
||||
|
||||
self.write(EOT)
|
||||
ret = self.recv_cmd(ACK)
|
||||
if ret == -EAGAIN:
|
||||
continue
|
||||
elif ret < 0:
|
||||
return ret
|
||||
ret = self.recv_cmd(CRC)
|
||||
if ret == -EAGAIN:
|
||||
continue
|
||||
elif ret < 0:
|
||||
return ret
|
||||
break
|
||||
|
||||
need_sendfile_num = need_sendfile_num - 1
|
||||
readfd.close()
|
||||
now = datetime.datetime.now()
|
||||
time = float(int(now.timestamp() * 1000) / 1000)
|
||||
time = time - start
|
||||
self.progress("\ntime used:%.1fs" % time)
|
||||
self.progress(" speed %.1fkB/s\n" % (float(sendfilesize) / 1024 / time))
|
||||
if need_sendfile_num != 0:
|
||||
cnt += 1
|
||||
continue
|
||||
|
||||
retries = 0
|
||||
while True:
|
||||
if retries == 2:
|
||||
return -EINVAL
|
||||
retries += 1
|
||||
self.head = SOH
|
||||
self.seq0 = b"\x00"
|
||||
self.seq1 = b"\xff"
|
||||
self.data = bytes([0x00] * self.get_pkt_size())
|
||||
self.send_pkt()
|
||||
|
||||
ret = self.recv_cmd(ACK)
|
||||
if ret == -EAGAIN:
|
||||
continue
|
||||
elif ret < 0:
|
||||
return ret
|
||||
break
|
||||
|
||||
now = datetime.datetime.now()
|
||||
time = float(int(now.timestamp() * 1000) / 1000)
|
||||
totaltime = time - base
|
||||
arvgspeed = float(totolbytes) / 1024 / totaltime
|
||||
self.progress(
|
||||
"\n all time:%.2fs average speed:%.2fkB/s" % (totaltime, arvgspeed)
|
||||
)
|
||||
|
||||
def recv_packet(self):
|
||||
chunk = self.read(1)
|
||||
if chunk == SOH:
|
||||
self.packetsize = PACKET_SIZE
|
||||
elif chunk == STX:
|
||||
self.packetsize = PACKET_1K_SIZE
|
||||
elif chunk == STC:
|
||||
self.packetsize = self.customsize
|
||||
elif chunk == NAK:
|
||||
return -EAGAIN
|
||||
elif chunk == EOT:
|
||||
return -EEOT
|
||||
else:
|
||||
self.debug("recv EBADMSG" + str(chunk) + "\n")
|
||||
return -EINVAL
|
||||
|
||||
seq0 = self.read(1)
|
||||
seq1 = self.read(1)
|
||||
|
||||
self.data = self.read(self.packetsize)
|
||||
|
||||
crch = self.read(1)
|
||||
crcl = self.read(1)
|
||||
|
||||
if seq0 != self.seq0:
|
||||
self.debug("recv bad seq0" + binascii.hexlify(seq0).decode("utf-8") + "\n")
|
||||
return -EINVAL
|
||||
if seq1 != self.seq1:
|
||||
self.debug("recv bad seq1" + binascii.hexlify(seq1).decode("utf-8") + "\n")
|
||||
return -EINVAL
|
||||
|
||||
crc16 = calc_crc16(self.data)
|
||||
|
||||
crch_b = (crc16 >> 8).to_bytes(1, byteorder="little")
|
||||
if crch != crch_b:
|
||||
self.debug(
|
||||
"recv bad crch_b" + binascii.hexlify(crch_b).decode("utf-8") + "\n"
|
||||
)
|
||||
self.debug("recv bad crch" + binascii.hexlify(crch).decode("utf-8") + "\n")
|
||||
return -EINVAL
|
||||
|
||||
crcl_b = (crc16 & 0xFF).to_bytes(1, byteorder="little")
|
||||
if crcl != crcl_b:
|
||||
self.debug(
|
||||
"recv bad crcl_b" + binascii.hexlify(crcl_b).decode("utf-8") + "\n"
|
||||
)
|
||||
self.debug("recv bad crcl" + binascii.hexlify(crcl).decode("utf-8") + "\n")
|
||||
return -EINVAL
|
||||
|
||||
self.add_seq()
|
||||
return 0
|
||||
|
||||
def recv(self):
|
||||
retries = 0
|
||||
start_recv = False
|
||||
now = datetime.datetime.now()
|
||||
base = float(int(now.timestamp() * 1000)) / 1000
|
||||
totolbytes = 0
|
||||
while True:
|
||||
self.write(CRC)
|
||||
now = datetime.datetime.now()
|
||||
start = float(int(now.timestamp() * 1000)) / 1000
|
||||
self.init_pkt()
|
||||
ret = self.recv_packet()
|
||||
if ret < 0:
|
||||
if retries > RETRIESMAX:
|
||||
return -1
|
||||
retries += 1
|
||||
continue
|
||||
|
||||
self.debug("recv frist packet\n")
|
||||
filename = bytes.decode(self.data.split(b"\x00")[0], "utf-8")
|
||||
if not filename:
|
||||
if start_recv:
|
||||
self.debug("recv last packet\n")
|
||||
break
|
||||
|
||||
self.debug("recv a none file\n")
|
||||
retries += 1
|
||||
continue
|
||||
|
||||
start_recv = True
|
||||
self.progress("name:" + filename + " ")
|
||||
size_str = bytes.decode(self.data.split(b"\x00")[1], "utf-8")
|
||||
filesize = int(size_str)
|
||||
self.progress("size:%d" % (filesize) + "\n")
|
||||
|
||||
self.write(ACK)
|
||||
self.write(CRC)
|
||||
fd = open(filename, "wb+")
|
||||
writensize = 0
|
||||
while writensize < filesize:
|
||||
ret = self.recv_packet()
|
||||
if ret < 0:
|
||||
self.debug("recv a bad data packet\n")
|
||||
if retries > RETRIESMAX:
|
||||
return -1
|
||||
retries += 1
|
||||
continue
|
||||
|
||||
size = 0
|
||||
if self.packetsize > filesize - writensize:
|
||||
self.debug("last data packet\n")
|
||||
size = self.packetsize - (filesize - writensize)
|
||||
else:
|
||||
size = self.packetsize
|
||||
|
||||
data = self.data[0:size]
|
||||
fd.write(data)
|
||||
writensize += size
|
||||
|
||||
self.progress("\r%.2f%%" % (float(writensize) / filesize * 100))
|
||||
self.progress(" %d:%d" % (writensize, filesize))
|
||||
now = datetime.datetime.now()
|
||||
usedtime = float(int(now.timestamp() * 1000) / 1000) - start
|
||||
realspeed = writensize / 1024 / usedtime
|
||||
left = (filesize - writensize) / 1024 / (realspeed)
|
||||
self.progress(" left:" + format_time(left))
|
||||
|
||||
self.write(ACK)
|
||||
|
||||
ret = self.recv_packet()
|
||||
if ret == -EEOT:
|
||||
self.debug("recv EOT cmd\n")
|
||||
elif ret < 0:
|
||||
self.debug("recv error packet")
|
||||
return -EINVAL
|
||||
|
||||
self.write(ACK)
|
||||
self.write(CRC)
|
||||
now = datetime.datetime.now()
|
||||
time = float(now.timestamp() * 1000) / 1000
|
||||
time = time - start
|
||||
self.progress("\ntime used:%.1fs" % time)
|
||||
self.progress(" speed %.1fkB/s\n" % (float(filesize) / 1024 / time))
|
||||
totolbytes += filesize
|
||||
|
||||
fd.close()
|
||||
|
||||
now = datetime.datetime.now()
|
||||
time = float(int(now.timestamp() * 1000) / 1000)
|
||||
totaltime = time - base
|
||||
arvgspeed = float(totolbytes) / 1024 / totaltime
|
||||
self.progress(
|
||||
"\n all time:%.2fs average speed:%.2fkB/s" % (totaltime, arvgspeed)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"filelist", help="if filelist is valid, that is sb, else is rb", nargs="*"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-k",
|
||||
"--kblocksize",
|
||||
help="This opthin can set a customsize block size to transfer",
|
||||
type=int,
|
||||
default=0,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--debug", help="This opthin is save debug log on host", default=""
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
sbrb = ymodem(debug=args.debug, customsize=args.kblocksize * 1024)
|
||||
if len(args.filelist) == 0:
|
||||
sbrb.progress("receiving\n")
|
||||
sbrb.recv()
|
||||
else:
|
||||
sbrb.progress("sending\n")
|
||||
sbrb.send(args.filelist)
|
@ -53,6 +53,7 @@
|
||||
|
||||
#define SOH 0x01 /* Start of 128-byte data packet */
|
||||
#define STX 0x02 /* Start of 1024-byte data packet */
|
||||
#define STC 0x03 /* Start of custom byte data packet */
|
||||
#define EOT 0x04 /* End of transmission */
|
||||
#define ACK 0x06 /* Acknowledge */
|
||||
#define NAK 0x15 /* Negative acknowledge */
|
||||
@ -133,6 +134,9 @@ static int ymodem_recv_packet(FAR struct ymodem_ctx_s *ctx)
|
||||
case STX:
|
||||
ctx->packet_size = YMODEM_PACKET_1K_SIZE;
|
||||
break;
|
||||
case STC:
|
||||
ctx->packet_size = ctx->custom_size;
|
||||
break;
|
||||
case EOT:
|
||||
return -EAGAIN;
|
||||
case CAN:
|
||||
@ -411,6 +415,11 @@ send_packet:
|
||||
ctx->header[0] = SOH;
|
||||
ctx->packet_size = YMODEM_PACKET_SIZE;
|
||||
}
|
||||
else if (ctx->custom_size != 0)
|
||||
{
|
||||
ctx->header[0] = STC;
|
||||
ctx->packet_size = ctx->custom_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->header[0] = STX;
|
||||
@ -542,7 +551,15 @@ int ymodem_recv(FAR struct ymodem_ctx_s *ctx)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctx->header = calloc(1, 3 + YMODEM_PACKET_1K_SIZE + 2);
|
||||
if (ctx->custom_size != 0)
|
||||
{
|
||||
ctx->header = calloc(1, + ctx->custom_size + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->header = calloc(1, + YMODEM_PACKET_1K_SIZE + 2);
|
||||
}
|
||||
|
||||
if (ctx->header == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
@ -588,7 +605,15 @@ int ymodem_send(FAR struct ymodem_ctx_s *ctx)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctx->header = calloc(1, 3 + YMODEM_PACKET_1K_SIZE + 2);
|
||||
if (ctx->custom_size != 0)
|
||||
{
|
||||
ctx->header = calloc(1, + ctx->custom_size + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->header = calloc(1, + YMODEM_PACKET_1K_SIZE + 2);
|
||||
}
|
||||
|
||||
if (ctx->header == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
|
@ -48,6 +48,7 @@ struct ymodem_ctx_s
|
||||
int recvfd;
|
||||
int sendfd;
|
||||
CODE int (*packet_handler)(FAR struct ymodem_ctx_s *ctx);
|
||||
size_t custom_size;
|
||||
FAR void *priv;
|
||||
|
||||
/* Public data */
|
||||
|
Loading…
Reference in New Issue
Block a user