tehmaze / xmodem

XMODEM protocol implementation for Python
https://pypi.org/project/xmodem/
MIT License
98 stars 57 forks source link

Fails on large files #43

Open rwskinner opened 4 years ago

rwskinner commented 4 years ago

I've tried this over and over in my python 2.7 script and it works perfect up to the point about 24 packets. This is sending xmodem to an older machine, which will fill it's memory, stop the transfer, then when there is more room it receives more xmodem packets. Xmodem code here doesn't seem to handle that and just goes crazy trying to send the same packet over and over then things go south.

2020-05-24 16:15:15,646 ERROR send error: expected ACK; got None for block 24

Block 23 06 01 17 E8 20 59 2D 31 2E 38 30 31 0D 0A 4E 35 39 30 20 58 31 2E 38 31 37 33 20 59 2D 31 2E 37 35 36 35 0D 0A 4E 35 39 35 20 58 31 2E 38 36 30 34 20 59 2D 31 2E 37 31 30 38 0D 0A 4E 36 30 30 20 58 31 2E 39 30 32 33 20 59 2D 31 2E 36 36 33 39 0D 0A 4E 36 30 35 20 58 31 2E 39 34 33 31 20 59 2D 31 2E 36 31 36 32 0D 0A 4E 36 31 30 20 58 31 2E 39 38 32 37 20 59 2D 31 2E 35 36 37 34 0D 0A 4E 36 31 FA (OKAY)

Block 24 06 01 18 E7 35 20 58 32 2E 30 32 31 20 59 2D 31 2E 35 31 37 35 0D 0A 4E 36 32 30 20 58 32 2E 30 35 38 31 20 59 2D 31 2E 34 36 36 38 0D 0A 4E 36 32 35 20 58 32 2E 30 39 34 20 59 2D 31 2E 34 31 35 33 0D 0A 4E 36 33 30 20 58 32 2E 31 32 38 35 20 59 2D 31 2E 33 36 32 37 0D 0A 4E 36 33 35 20 58 32 2E 31 36 31 37 20 59 2D 31 2E 33 30 39 34 0D 0A 4E 36 34 30 20 58 32 2E 31 39 33 37 20 59 2D 31 2E 32 1E

Block 24 retry 01 18 E7 35 20 58 32 2E 30 32 31 20 59 2D 31 2E 35 31 37 35 0D 0A 4E 36 32 30 20 58 32 2E 30 35 38 31 20 59 2D 31 2E 34 36 36 38 0D 0A 4E 36 32 35 20 58 32 2E 30 39 34 20 59 2D 31 2E 34 31 35 33 0D 0A 4E 36 33 30 20 58 32 2E 31 32 38 35 20 59 2D 31 2E 33 36 32 37 0D 0A 4E 36 33 35 20 58 32 2E 31 36 31 37 20 59 2D 31 2E 33 30 39 34 0D 0A 4E 36 34 30 20 58 32 2E 31 39 33 37 20 59 2D 31 2E 32 1E

Below is a packet send with SZ 06 01 18 E7 0A 4E 36 31 35 20 58 32 2E 30 32 31 20 59 2D 31 2E 35 31 37 35 0D 0A 4E 36 32 30 20 58 32 2E 30 35 38 31 20 59 2D 31 2E 34 36 36 38 0D 0A 4E 36 32 35 20 58 32 2E 30 39 34 20 59 2D 31 2E 34 31 35 33 0D 0A 4E 36 33 30 20 58 32 2E 31 32 38 35 20 59 2D 31 2E 33 36 32 37 0D 0A 4E 36 33 35 20 58 32 2E 31 36 31 37 20 59 2D 31 2E 33 30 39 34 0D 0A 4E 36 34 30 20 58 32 2E 31 39 33 37 20 59 1F

How is the last part of the packet getting corrupt identical each time? Here it is with this xmodem, in ascii.... that resends the same block each time... N61úç5 X2.021 Y-1.5175 N620 X2.0581 Y-1.4668 N625 X2.094 Y-1.4153 N630 X2.1285 Y-1.3627 N635 X2.1617 Y-1.3094 N640 X2.1937 Y-1.2_ç5 X2.021 Y-1.5175 N620 X2.0581 Y-1.4668 N625 X2.094 Y-1.4153 N630 X2.1285 Y-1.3627 N635 X2.1617 Y-1.3094 N640 X2.1937 Y-1.2_ç5 X2.021 Y-1.5175 N620 X2.0581 Y-1.4668 N625 X2.094 Y-1.4153 N630 X2.1285 Y-1.3627 N635 X2.1617 Y-1.3094 N640 X2.1937 Y-1.2__ç5 X2.021 Y-1.5175

I used the Linux sz -X from the cli and it worked perfect. I've also used hyperterminal xmodem from windows and another terminal program to send and it also works perfect.

I have ascii and hex logging of the transactions, and I also have the debug log from xmodem that I can send whomever is interested.

jquast commented 4 years ago

I just wanted to let you know that your issue is received, I've just got a list of FOSS work a mile long, and xmodem is somewhere in the middle, which might be months away for me.

What this repository really needs is a lot more automated tests, and that's where any attention would be focused, and would really aide in fixing your issue in particular

rwskinner commented 4 years ago

I have it working by adjusting the read timeout.

Being a novice I could be wrong, but if you pass a timeout value to the send function, it really doesn't do anything they way the example is written, because it's passed to the external getc but getc never sets it for the serial.timeout. When I assign the timeout value to ser.timeout, then timeout is honored and everything works.

def getc(size, timeout=1): ser.timeout = timeout <<<<<<<<<<<<<<< return ser.read(size) or None

def putc(data, timeout=1): return ser.write(data) or None # note that this ignores the timeout

I added some additional checks for CAN CAN to cancel the transaction in the packet send section and it makes it respond to a cancel also.

nekromant commented 3 years ago

Just throwing in my two cents - giving this implementation a try on a very badly and hastily made board with messy uart connection, a silicon bug that sometimes broke things and big chunks of data, I've made a simple adjustment that (along with a few hacks on the receiver side) drastically improved things. See #52, perhaps it'll work. For some reason it was sitting in my closet for a while, so I'm sending it along with #53