242 lines
6.7 KiB
Python
242 lines
6.7 KiB
Python
|
|
||
|
# See comment in stm32w_flasher.py.
|
||
|
# Extraction and little adaptation performed by E.Duble (CNRS, LIG).
|
||
|
|
||
|
import os
|
||
|
import serial
|
||
|
import struct
|
||
|
import time
|
||
|
from messages import errorMessage
|
||
|
from messages import infoMessage
|
||
|
|
||
|
|
||
|
class Ymodem():
|
||
|
ABORT1 = 65
|
||
|
ABORT2 = 97
|
||
|
ACK = 6
|
||
|
CA = 24
|
||
|
CRC16 = 67
|
||
|
EOT = 4
|
||
|
NAK = 21
|
||
|
PACKET_1K_SIZE = 1024
|
||
|
PACKET_HEADER = 3
|
||
|
PACKET_OVERHEAD = 5
|
||
|
PACKET_SIZE = 128
|
||
|
PACKET_TRAILER = 2
|
||
|
SOH = 1
|
||
|
STATE_DONE = 6
|
||
|
STATE_READY = 2
|
||
|
STATE_SEND_EOT = 3
|
||
|
STATE_SEND_SESSION_DONE = 4
|
||
|
STATE_START_APPLICATION = 5
|
||
|
STATE_WAITING_ACK = 1
|
||
|
STATE_WAITING_CRC16 = 0
|
||
|
STX = 2
|
||
|
YMODEM_RX_TO_TX = 2
|
||
|
YMODEM_TX_TO_RX = 0
|
||
|
YMODEM_TX_TO_RX2 = 1
|
||
|
def Crc16X(self, packet, count):
|
||
|
j = 0
|
||
|
crc = 0
|
||
|
for j in range(count):
|
||
|
crc = (crc ^ ((packet[j]) << 8))
|
||
|
for i in range(8):
|
||
|
if (crc & 32768):
|
||
|
crc = ((crc << 1) ^ 4129)
|
||
|
continue
|
||
|
else:
|
||
|
crc = (crc << 1)
|
||
|
continue
|
||
|
continue
|
||
|
return crc
|
||
|
|
||
|
def __init__(self, serialPort, port, updateAction=None):
|
||
|
self.serialPort = serialPort
|
||
|
self.updateAction = updateAction
|
||
|
self.port = port
|
||
|
return None
|
||
|
|
||
|
def bootloaderInit(self):
|
||
|
returnValue = False
|
||
|
systemRestartPacket = [170, 1, 7, 85]
|
||
|
self.serialPort.write(struct.pack(('B' * len(systemRestartPacket)), *systemRestartPacket))
|
||
|
self.serialPort.close()
|
||
|
time.sleep(5)
|
||
|
self.serialPort = serial.Serial(port, 10, timeout=4)
|
||
|
self.serialPort.flushInput()
|
||
|
systemRestartPacket = [170, 1, 5, 85]
|
||
|
self.serialPort.write(struct.pack(('B' * len(systemRestartPacket)), *systemRestartPacket))
|
||
|
self.serialPort.read(4)
|
||
|
for i in range(10):
|
||
|
startTime = time.time()
|
||
|
while (time.time() - startTime) < 0.5:
|
||
|
if self.serialPort.inWaiting() > 0:
|
||
|
c = self.serialPort.read(1)
|
||
|
c = (struct.unpack('B', c)[0])
|
||
|
if c == ord('C'):
|
||
|
returnValue = True
|
||
|
break
|
||
|
time.sleep(0.01)
|
||
|
continue
|
||
|
continue
|
||
|
return returnValue
|
||
|
|
||
|
def getByte(self):
|
||
|
data = None
|
||
|
if self.serialPort.inWaiting() > 0:
|
||
|
data = (struct.unpack('B', self.serialPort.read(1))[0])
|
||
|
if data:
|
||
|
pass
|
||
|
return data
|
||
|
|
||
|
def loadFile(self, name):
|
||
|
returnValue = True
|
||
|
state = self.STATE_WAITING_CRC16
|
||
|
filename = os.path.basename(name)
|
||
|
startTime = time.time()
|
||
|
try:
|
||
|
f = open(name, 'rb')
|
||
|
infoMessage((('File ' + name) + ' opened\n'))
|
||
|
f.seek(0, 2)
|
||
|
file_size = f.tell()
|
||
|
f.seek(0, 0)
|
||
|
packet_number = 0
|
||
|
loop_counter = 1
|
||
|
size = file_size
|
||
|
retry = 0
|
||
|
packet = []
|
||
|
prevState = self.STATE_READY
|
||
|
while True:
|
||
|
newState = state
|
||
|
if state == self.STATE_WAITING_CRC16:
|
||
|
if self.updateAction:
|
||
|
self.updateAction((file_size - max(size, 0)), file_size)
|
||
|
data = self.getByte()
|
||
|
if data == self.CRC16:
|
||
|
newState = self.STATE_READY
|
||
|
else:
|
||
|
if state == self.STATE_WAITING_ACK:
|
||
|
if self.updateAction:
|
||
|
self.updateAction((file_size - max(size, 0)), file_size)
|
||
|
data = self.getByte()
|
||
|
if data is not None:
|
||
|
if data == self.ACK:
|
||
|
if prevState == self.STATE_READY:
|
||
|
retry = 0
|
||
|
if loop_counter > 1:
|
||
|
size = (size - packet_size)
|
||
|
packet_number = ((packet_number + 1) % 256)
|
||
|
loop_counter = (loop_counter + 1)
|
||
|
packet_done = True
|
||
|
if self.updateAction:
|
||
|
self.updateAction((file_size - max(size, 0)), file_size)
|
||
|
else:
|
||
|
infoMessage(('Sent %05d/%05d\r' % ((file_size - max(size, 0)), file_size)))
|
||
|
newState = self.STATE_READY
|
||
|
else:
|
||
|
if prevState == self.STATE_SEND_EOT:
|
||
|
newState = self.STATE_SEND_SESSION_DONE
|
||
|
else:
|
||
|
if prevState == self.STATE_SEND_SESSION_DONE:
|
||
|
newState = self.STATE_START_APPLICATION
|
||
|
else:
|
||
|
if data == self.CA:
|
||
|
errorMessage('Transaction aborted by client\n')
|
||
|
newState = self.STATE_DONE
|
||
|
else:
|
||
|
if data == self.CRC16:
|
||
|
pass
|
||
|
else:
|
||
|
if prevState == self.STATE_READY:
|
||
|
infoMessage('Retrying\n')
|
||
|
retry = (retry + 1)
|
||
|
if retry > 3:
|
||
|
errorMessage('Too many retry exiting\n')
|
||
|
newState = self.STATE_DONE
|
||
|
else:
|
||
|
newState = self.STATE_READY
|
||
|
else:
|
||
|
if state == self.STATE_READY:
|
||
|
if size <= 0:
|
||
|
newState = self.STATE_SEND_EOT
|
||
|
else:
|
||
|
if retry == 0:
|
||
|
packet = []
|
||
|
if loop_counter == 1:
|
||
|
packet.extend(struct.unpack(('%uB' % len(filename)), filename))
|
||
|
packet = (packet + [0])
|
||
|
size_string = ('%d ' % file_size)
|
||
|
packet.extend(struct.unpack(('%uB' % len(size_string)), size_string))
|
||
|
packet_size = self.PACKET_SIZE
|
||
|
else:
|
||
|
packet_size = self.PACKET_1K_SIZE
|
||
|
packet_string = f.read(packet_size)
|
||
|
packet.extend(struct.unpack(('%uB' % len(packet_string)), packet_string))
|
||
|
packet = (packet + ([0] * (packet_size - len(packet))))
|
||
|
if self.sendYModemPacket(packet, packet_number):
|
||
|
newState = self.STATE_DONE
|
||
|
else:
|
||
|
newState = self.STATE_WAITING_ACK
|
||
|
else:
|
||
|
if state == self.STATE_SEND_EOT:
|
||
|
if self.updateAction:
|
||
|
self.updateAction((file_size - max(size, 0)), file_size)
|
||
|
else:
|
||
|
infoMessage(('Sent %05d/%05d\r' % ((file_size - max(size, 0)), file_size)))
|
||
|
self.sendByte(self.EOT)
|
||
|
newState = self.STATE_WAITING_ACK
|
||
|
else:
|
||
|
if state == self.STATE_SEND_SESSION_DONE:
|
||
|
self.sendYModemPacket(([0] * 128), 0)
|
||
|
newState = self.STATE_WAITING_ACK
|
||
|
else:
|
||
|
if state == self.STATE_START_APPLICATION:
|
||
|
self.startApplication()
|
||
|
newState = self.STATE_DONE
|
||
|
else:
|
||
|
if state == self.STATE_DONE:
|
||
|
returnValue = False
|
||
|
endTime = time.time()
|
||
|
infoMessage('\nDone\n')
|
||
|
break
|
||
|
else:
|
||
|
errorMessage(('Unknonw state = %d' % state))
|
||
|
newState = self.STATE_DONE
|
||
|
if state != newState:
|
||
|
prevState = state
|
||
|
state = newState
|
||
|
continue
|
||
|
else:
|
||
|
continue
|
||
|
return returnValue
|
||
|
except:
|
||
|
errorMessage((('File ' + name) + ' open failed\n'))
|
||
|
if self.updateAction:
|
||
|
self.updateAction(0, 0)
|
||
|
return returnValue
|
||
|
|
||
|
def sendByte(self, byte):
|
||
|
self.serialPort.write(struct.pack('B', byte))
|
||
|
return None
|
||
|
|
||
|
def sendYModemPacket(self, myPacket, packet_number):
|
||
|
returnValue = 0
|
||
|
packet = myPacket[:]
|
||
|
packet_crc = self.Crc16X(packet, len(packet))
|
||
|
packet.append(((packet_crc >> 8) & 255))
|
||
|
packet.append((packet_crc & 255))
|
||
|
packet.insert(0, (255 - packet_number))
|
||
|
packet.insert(0, packet_number)
|
||
|
if len(myPacket) == self.PACKET_SIZE:
|
||
|
packet.insert(0, self.SOH)
|
||
|
else:
|
||
|
packet.insert(0, self.STX)
|
||
|
self.serialPort.write(struct.pack(('B' * len(packet)), *packet))
|
||
|
return returnValue
|
||
|
|
||
|
def startApplication(self):
|
||
|
return None
|
||
|
|
||
|
|
||
|
|