osd-contiki/tools/stm32w/stm32w_flasher/py_files/rs232_interface.py

1056 lines
34 KiB
Python

# See comment in stm32w_flasher.py.
# Extraction and little adaptation performed by E.Duble (CNRS, LIG).
import ftdi
import os
import pyudev
import serial
import struct
import subprocess
import sys
import time
import ymodem
from messages import errorMessage
from file_utils import fileFormatReader
from messages import infoMessage
from messages import warningMessage
ACK = 121
BOOTLOADER_COMMAND_BAUDRATE = 50
CBUS_IOMODE = 10
FT232R_PRODUCT = 24577
FT232R_VENDOR = 1027
NAK = 31
STM32F103_PRODUCT = 22337
STM32F103_PRODUCT_OLD = 22336
STM32F103_VENDOR = 1155
StringTypes = None
TIMEOUT_TO_SWITCH_BETWEEN_APPLICATION_AND_BOOTLOADER = 10
commands = {'WRITE': [49, 3], 'GO': [33, 3], 'GET_ID': [2, 5], 'ERASE': [67, 2], 'GET': [0, 2], 'READ': [17, 259], 'WRITE_INCREMENTAL': [54, 2], 'GET_VERSION': [1, 5], 'READOUT_PROTECT': [130, 2], 'READOUT_UNPROTECT': [146, 2]}
pcIfHandle = None
rs232PortsList = None
class FTDI_Interface(object):
def __init__(self, port):
self.port = port
self.resetValue = None
self.nBootValue = None
def close(self):
return None
def getFTDIIdFromComPort(self, port):
returnValue = None
deviceIDs = None
mapping = self.mapComPortsToFTDIId()
if deviceIDs == None:
returnValue = (mapping[port])
else:
for id in deviceIDs:
if (mapping[port]) == id:
returnValue = id
break
else:
continue
if returnValue is None:
for id in deviceIDs:
if (mapping[port]).upper() == id.upper():
returnValue = id
break
else:
continue
return returnValue
def getFTDIIdFromDevPort(self, port):
device = pyudev.Device.from_device_file(pyudev.Context(), port)
return device['ID_SERIAL']
def guessResetDirection(self, h):
if (self.resetValue is None or self.nBootValue is None):
CBUS_2 = 4
CBUS_0 = 1
RESET_LINE = CBUS_2
GPIO5_LINE = CBUS_0
resetLow = ((RESET_LINE << 4) | 0)
resetHigh = ((RESET_LINE << 4) | RESET_LINE)
GPIO5Low = ((GPIO5_LINE << 4) | 0)
GPIO5High = ((GPIO5_LINE << 4) | GPIO5_LINE)
h.usb_write_timeout = 1000
h.usb_read_timeout = 1000
ret = ftdi.ftdi_set_baudrate(h, 115200)
ret = (ret + ftdi.ftdi_setflowctrl(h, ftdi.SIO_DISABLE_FLOW_CTRL))
ret = (ret + ftdi.ftdi_set_line_property(h, ftdi.BITS_8, ftdi.STOP_BIT_1, ftdi.NONE))
for i in range(2):
if (i % 2) == 0:
resetValue = resetHigh
nbootValue = GPIO5High
else:
resetValue = resetLow
nbootValue = GPIO5Low
ftdi.ftdi_set_bitmode(h, resetValue, ftdi.BITMODE_CBUS)
time.sleep(0.10000000000000001)
ftdi.ftdi_set_bitmode(h, nbootValue, ftdi.BITMODE_CBUS)
time.sleep(0.10000000000000001)
ftdi.ftdi_set_bitmode(h, 0, ftdi.BITMODE_CBUS)
ftdi.ftdi_usb_purge_rx_buffer(h)
ftdi.ftdi_usb_purge_tx_buffer(h)
ftdi.ftdi_write_data(h, struct.pack('B', 127), 1)
startTime = time.time()
inbuff = '\x00'
nbyte_rcvd = 0
while (nbyte_rcvd == 0 and (time.time() - startTime) < 1):
nbyte_rcvd = ftdi.ftdi_read_data(h, inbuff, 1)
continue
if nbyte_rcvd > 0:
reply = struct.unpack('B', inbuff)
if (reply[0]) == 121:
self.resetValue = resetValue
self.nBootValue = nbootValue
break
else:
continue
continue
return (self.resetValue, self.nBootValue)
def open(self):
return 0
def reset(self, bootloader=False):
handle = ftdi.ftdi_context()
if ftdi.ftdi_init(handle) < 0:
print 'Initialization error.',
print
sys.exit(-1)
serialnum = self.getFTDIIdFromDevPort(self.port)
if subprocess.call(['rmmod', 'ftdi_sio']) != 0:
print 'Close all processes that may access serial ports. You may also need to run the program as root.',
print
sys.exit(-1)
error = ftdi.ftdi_usb_open_desc(handle, FT232R_VENDOR, FT232R_PRODUCT, None, serialnum)
if error < 0:
print ('Unable to open port. Error:' + str(error)),
print
subprocess.call(['modprobe', 'ftdi_sio'])
sys.exit(-1)
item0, item1 = self.guessResetDirection(handle)
resetValue = item0
nBootValue = item1
if (resetValue, nBootValue) == (None, None):
ftdi.ftdi_usb_close(handle)
subprocess.call(['modprobe', 'ftdi_sio'])
return 1
else:
ftdi.ftdi_set_bitmode(handle, resetValue, ftdi.BITMODE_CBUS)
time.sleep(0.5)
if bootloader:
ftdi.ftdi_set_bitmode(handle, nBootValue, ftdi.BITMODE_CBUS)
time.sleep(0.10000000000000001)
ftdi.ftdi_set_bitmode(handle, 0, ftdi.BITMODE_CBUS)
ftdi.ftdi_usb_close(handle)
subprocess.call(['modprobe', 'ftdi_sio'])
time.sleep(1)
return None
def setNBOOT(self, value=1):
returnValue = True
return returnValue
class STBL(object):
def __init__(self, serialPort, inputFile=None, startAddress=None, verboseMode=None, packetSize=256, serialMode=True):
self.serialPort = serialPort
self.inputFile = inputFile
self.startAddress = startAddress
self.verbose = verboseMode
self.packetSize = packetSize
self.serialMode = serialMode
def bootloaderInit(self):
returnValue = True
if (returnValue and self.serialMode):
reply = None
if self.verbose:
infoMessage('Sending byte 7f\n')
self.serialPort.write(struct.pack('B', 127))
startTime = time.time()
while (self.serialPort.inWaiting() == 0 and (time.time() - startTime) < 1):
continue
r = self.serialPort.read(1)
if r:
reply = struct.unpack(('B' * len(r)), r)
else:
reply = None
if self.verbose:
infoMessage(("Reply received '%s'\n" % hexString(reply)))
if reply == None:
errorMessage('No reply received\n')
returnValue = False
else:
if (reply[0]) != ACK:
errorMessage(('Unexpected reply %s\n' % hexString(reply)))
returnValue = False
if returnValue:
reply = self.sendCommand('GET', [], 2)
if (len(reply) < 4 or ((reply[0]) != ACK or (reply[-1]) != ACK)):
errorMessage(('Unexpected reply %s\n' % hexString(reply)))
returnValue = False
else:
if self.verbose:
infoMessage(('Bootloader version %d.%d\n' % (((reply[2]) & 15), ((reply[2]) >> 4))))
if returnValue:
reply = self.sendCommand('GET_ID')
if (len(reply) == 0 or ((reply[0]) != ACK or (reply[-1]) != ACK)):
errorMessage(('Unexpected reply %s\n' % hexString(reply)))
returnValue = False
else:
if self.verbose:
infoMessage((('Product ID = 0x' + ''.join(('%02X' % a) for a in reply[2:-1])) + '\n'))
return returnValue
def checksum(self, packet):
if len(packet) > 1:
checksum = 0
for p in packet:
checksum = (checksum ^ p)
continue
else:
checksum = ((~(packet[0])) & 255)
return checksum
def enableReadProtection(self, enable):
returnValue = True
if enable == False:
reply = self.sendCommand('READOUT_UNPROTECT')
if reply != [ACK, ACK]:
errorMessage((('Unexpected reply (' + ','.join(('%02x' % a) for a in reply)) + ') \n'))
returnValue = False
else:
item0, item1 = self.memoryRead(134481920, 512)
returnValue = item0
cibData = item1
if returnValue:
reply = self.sendCommand('ERASE', [[254]], timeout=5)
if reply != [ACK, ACK]:
errorMessage(('Unexpected reply %s\n' % repr(reply)))
returnValue = False
if returnValue:
arg1 = u32ToArray(134481922)
arg1.reverse()
packet = cibData[2:256]
packet = ([(len(packet) - 1)] + packet)
reply = self.sendCommand('WRITE', [arg1, packet], 5)
if reply != [ACK, ACK, ACK]:
errorMessage((('Unexpected reply (' + ','.join(('%02x' % a) for a in reply)) + ') \n'))
returnValue = False
if returnValue:
arg1 = u32ToArray(134482176)
arg1.reverse()
packet = cibData[256:]
packet = ([(len(packet) - 1)] + packet)
reply = self.sendCommand('WRITE', [arg1, packet], 5)
if reply != [ACK, ACK, ACK]:
errorMessage((('Unexpected reply (' + ','.join(('%02x' % a) for a in reply)) + ') \n'))
returnValue = False
if returnValue:
reply = self.sendCommand('READOUT_PROTECT')
if reply != [ACK, ACK]:
errorMessage((('Unexpected reply (' + ','.join(('%02x' % a) for a in reply)) + ') \n'))
returnValue = False
return returnValue
def eraseUserFlash(self):
returnValue = True
reply = self.sendCommand('ERASE', [[255]], timeout=5)
if reply != [ACK, ACK]:
errorMessage(('Unexpected reply %s\n' % repr(reply)))
returnValue = False
return returnValue
def isReadProtectionActive(self):
returnValue, memread = self.memoryRead(134479872, 4)
return (not returnValue)
def loadFile(self, inputFile=None, startAddress=None, progressReport=None, doErase=True):
if inputFile is not None:
self.inputFile = inputFile
if startAddress is not None:
self.startAddress = startAddress
returnValue = True
f = fileFormatReader(self.inputFile, self.startAddress)
try:
item0, item1 = f.getRawBinary()
self.startAddress = item0
file_content = item1
except IOError:
errorMessage((('File ' + self.inputFile) + ' open failed\n'))
returnValue = False
if returnValue:
file_size = len(file_content)
packet = []
address = self.startAddress
pages = int(((file_size + 1023) / 1024))
startPage = (((self.startAddress & 4294966272L) - 134217728) / 1024)
eraseArg = ([(pages - 1)] + range(startPage, (startPage + pages), 1))
infoMessage(('Erasing pages from %d to %d...' % (startPage, ((startPage + pages) - 1))))
if ('STM32W_FLASHER_JLINK_DONT_ERASE' in os.environ or (not doErase)):
infoMessage('(skipped)', False)
else:
reply = self.sendCommand('ERASE', [eraseArg], timeout=10)
if reply != [ACK, ACK]:
errorMessage(('Unexpected reply %s\n' % repr(reply)))
returnValue = False
if returnValue:
infoMessage('done\n', False)
size = 0
while returnValue:
packet = []
packet_size = self.packetSize
packet_string = file_content[size:(size + packet_size)]
packet_size = len(packet_string)
if packet_size == 0:
infoMessage('\n')
break
else:
size = (size + packet_size)
packet.extend(packet_string)
if (len(packet) % 2) != 0:
packet = (packet + [255])
packet = ([(len(packet) - 1)] + packet)
if progressReport:
progressReport(size, file_size)
else:
infoMessage(('Programming %05d/%05d\r' % (size, file_size)))
arg1 = u32ToArray(address)
arg1.reverse()
if (self.serialMode or size == packet_size):
reply = self.sendCommand('WRITE', [arg1, packet])
if reply != [ACK, ACK, ACK]:
errorMessage(('\n\n+Unexpected reply %s, packet_size=%d\n' % (repr(reply), packet_size)))
returnValue = False
else:
retries = 0
MAX_RETRIES = 3
while returnValue:
reply = self.sendCommand('WRITE_INCREMENTAL', [packet])
if reply != [ACK, ACK]:
retries = (retries + 1)
if retries > MAX_RETRIES:
errorMessage(('\n\nUnexpected reply %s, packet_size=%d\n' % (repr(reply), packet_size)))
returnValue = False
break
else:
errorMessage(('\n\nUnexpected reply %s, packet_size=%d\n' % (repr(reply), packet_size)))
infoMessage('Retrying...\n')
continue
else:
break
address = (address + packet_size)
continue
if returnValue:
if progressReport == None:
infoMessage('Done\n')
return returnValue
def memoryRead(self, address, size):
returnValue = True
currentSize = 0
memRead = []
while (returnValue and currentSize < size):
packet_size = min(self.packetSize, (size - currentSize))
arg1 = u32ToArray((address + currentSize))
arg1.reverse()
reply = self.sendCommand('READ', [arg1, [(packet_size - 1)]])
if reply == [NAK]:
returnValue = False
else:
if reply[:3] != [ACK, ACK, ACK]:
errorMessage(('\n\nXXUnexpected reply %s, packet_size=%d\n' % (repr(reply), packet_size)))
returnValue = False
else:
memRead = (memRead + reply[3:])
currentSize = (currentSize + packet_size)
continue
return (returnValue, memRead)
def programCibData(self, cibData):
returnValue = True
if returnValue:
reply = self.sendCommand('ERASE', [[254]], timeout=5)
if reply != [ACK, ACK]:
errorMessage(('Unexpected reply %s\n' % repr(reply)))
returnValue = False
if returnValue:
arg1 = u32ToArray(134481920)
arg1.reverse()
packet = cibData[:256]
packet = ([(len(packet) - 1)] + packet)
reply = self.sendCommand('WRITE', [arg1, packet], 5)
if reply != [ACK, ACK, ACK]:
errorMessage((('Unexpected reply (' + ','.join(('%02x' % a) for a in reply)) + ') \n'))
returnValue = False
if returnValue:
arg1 = u32ToArray(134482176)
arg1.reverse()
packet = cibData[256:]
packet = ([(len(packet) - 1)] + packet)
reply = self.sendCommand('WRITE', [arg1, packet], 5)
if reply != [ACK, ACK, ACK]:
errorMessage((('Unexpected reply (' + ','.join(('%02x' % a) for a in reply)) + ') \n'))
returnValue = False
return returnValue
def programUserFlash(self, inputFile, startAddress=134217728, progressReport=None, doErase=True):
return self.loadFile(inputFile, startAddress, progressReport, doErase)
def sendCommand(self, command, args=[], timeout=2, traceCommands=False):
def timedRead(port, timeout, serialMode, bytes=1):
reply = []
r = ''
for byte in range(bytes):
startTime = time.time()
r1 = ''
while (time.time() - startTime) < timeout:
r1 = port.read(1)
if len(r1) > 0:
r = (r + r1)
startTime = time.time()
break
else:
if serialMode:
continue
else:
time.sleep(0.001)
continue
if len(r1) == 0:
break
else:
continue
if len(r) > 0:
reply.extend(struct.unpack(('B' * len(r)), r))
return reply
reply = []
error = False
if command in commands:
item0, item1 = (commands[command])
commandID = item0
replyLength = item1
if command == 'READ':
replyLength = (((args[1])[0]) + 4)
else:
error = True
if error:
pass
else:
if traceCommands:
infoMessage(('Sending command: %02x %02x\n' % (commandID, (255 - commandID))))
self.serialPort.write(struct.pack('BB', commandID, (255 - commandID)))
r = timedRead(self.serialPort, timeout, self.serialMode, 1)
reply = (reply + r)
if (len(r) != 1 or (r[0]) != ACK):
error = True
if error:
pass
else:
for arg in args:
arg = (arg + [self.checksum(arg)])
if traceCommands:
infoMessage((('Sending arg:' + ','.join(('%02x' % a) for a in arg)) + '\n'))
self.serialPort.write(struct.pack(('B' * len(arg)), *arg))
r = timedRead(self.serialPort, timeout, self.serialMode, 1)
reply = (reply + r)
if (len(r) != 1 or (r[0]) != ACK):
error = True
break
else:
continue
if ((not error) and len(reply) < replyLength):
reply = (reply + timedRead(self.serialPort, timeout, self.serialMode, (replyLength - len(reply))))
if (command == 'GET' and len(reply) == replyLength):
reply = (reply + timedRead(self.serialPort, timeout, self.serialMode, ((reply[1]) + 2)))
if traceCommands:
infoMessage(('Reply was %s\n' % hexString(reply)))
return reply
def setPort(self, serialPort):
self.serialPort = serialPort
def startApplication(self, startAddress=134217728):
returnValue = True
if (self.startAddress is not None and startAddress != 0):
startAddress = self.startAddress
arg1 = u32ToArray(startAddress)
arg1.reverse()
reply = self.sendCommand('GO', [arg1])
if reply != [ACK, ACK, ACK]:
errorMessage(('\n\nUnexpected reply %s\n' % repr(reply)))
returnValue = False
return returnValue
def verifyFile(self, inputFile=None, startAddress=None, progressReport=None):
if inputFile is not None:
self.inputFile = inputFile
if startAddress is not None:
self.startAddress = startAddress
returnValue = True
f = fileFormatReader(self.inputFile, self.startAddress)
try:
item0, item1 = f.getRawBinary()
self.startAddress = item0
file_content = item1
except IOError:
errorMessage((('File ' + self.inputFile) + ' open failed\n'))
returnValue = False
if returnValue:
file_size = len(file_content)
packet = []
address = self.startAddress
size = 0
errors = 0
while returnValue:
packet = []
packet_size = self.packetSize
packet_string = file_content[size:(size + packet_size)]
packet_size = len(packet_string)
if packet_size == 0:
infoMessage('\n')
break
else:
size = (size + packet_size)
packet.extend(packet_string)
if progressReport:
progressReport(size, file_size)
else:
infoMessage(('Verifying %05d/%05d\r' % (size, file_size)))
arg1 = u32ToArray(address)
arg1.reverse()
reply = self.sendCommand('READ', [arg1, [(len(packet) - 1)]])
if reply[:3] != [ACK, ACK, ACK]:
errorMessage(('\n\nUnexpected reply %s, packet_size=%d\n' % (repr(reply), packet_size)))
returnValue = False
if len(reply[3:]) != len(packet):
errorMessage(('Invalid data read, expected length = %d, received bytes = %d\n' % (len(packet), len(reply[3:]))))
returnValue = False
if (returnValue and reply[3:] != packet):
returnValue = False
infoMessage('Verify failed \n')
infoMessage(('%-8s: %5s %5s\n' % ('Addr', 'Flash', 'file')))
for i in range(len(packet)):
if (reply[(3 + i)]) != (packet[i]):
infoMessage(('%08x: %02x %02x\n' % ((address + i), (reply[(i + 3)]), (packet[i]))))
errors = (errors + 1)
if errors > 64:
break
else:
continue
else:
continue
address = (address + packet_size)
continue
if returnValue:
if progressReport == None:
infoMessage('Done\n')
return returnValue
def verifyFlash(self, inputFile, startAddress=134217728, progressReport=None):
return self.verifyFile(inputFile, startAddress, progressReport)
class STM32F_Interface(object):
APP_RUNNING = 1
BL_RUNNING = 0
DOWNLOAD_BL_IMAGE = 10
DOWNLOAD_IMAGE = 5
FAIL = 0
FIRMWARE_VERSION_NONE = 4294967295L
GET_APP_VERSION = 3
GET_BL_VERSION = 9
GET_CODE_TYPE = 2
IS_APP_PRESENT = 4
IS_BL_VERSION_OLD = 11
OK = 1
REPLY_START_BYTE = 187
RUN_APPLICATION = 6
RUN_BOOTLOADER = 7
SET_nBOOTMODE = 1
SET_nRESET = 0
START_BYTE = 170
STOP_BYTE = 85
UNKNOWN_COMMAND = 15
UPLOAD_IMAGE = 8
replyLength = [4, 4, 4, 7, 4, 4, 4, 4, 4, 7, 4, 4]
def __init__(self, port, firmwareName):
self.port = port
self.bootloaderPort = port
self.firmwareName = firmwareName
self.serialPort = None
def close(self):
if self.serialPort:
self.serialPort.close()
def getBootloaderFirmwareVersion(self):
returnValue = self.FIRMWARE_VERSION_NONE
reply = self.sendCommand(self.GET_BL_VERSION)
if reply:
returnValue = ((((reply[2]) + ((reply[3]) << 8)) + ((reply[4]) << 16)) + ((reply[5]) << 24))
return returnValue
def getFirmwareType(self):
returnValue = None
reply = self.sendCommand(self.GET_CODE_TYPE)
if reply:
returnValue = (reply[2])
return returnValue
def getFirmwareVersion(self):
returnValue = self.FIRMWARE_VERSION_NONE
reply = self.sendCommand(self.GET_APP_VERSION)
if reply:
returnValue = ((((reply[2]) + ((reply[3]) << 8)) + ((reply[4]) << 16)) + ((reply[5]) << 24))
return returnValue
def getFirmwareVersionFromFile(self, filename=None, stringMode=False):
version = None
if filename is None:
filename = self.firmwareName
f = open(filename)
f.seek(28, 0)
tag = f.read(4)
versionValue = f.read(4)
versionValue = struct.unpack(('B' * len(versionValue)), versionValue)
f.close()
if tag == '\xaaU\xaaU':
version = ((((versionValue[0]) + ((versionValue[1]) << 8)) + ((versionValue[2]) << 16)) + ((versionValue[3]) << 24))
if stringMode:
version = self.versionInStringFormat(version)
return version
def isBootloaderFirmwareVersionOld(self):
returnValue = False
reply = self.sendCommand(self.IS_BL_VERSION_OLD)
if reply:
returnValue = (reply[2]) == self.FAIL
return returnValue
def isFirmwarePresent(self):
returnValue = None
reply = self.sendCommand(self.IS_APP_PRESENT)
if reply:
returnValue = (reply[2])
return returnValue
def isSTMicroelectronics(self, port):
return port in self.getSTMPorts()
def mapSTMCompositeComPortToBootloaderCOMPort(self, port):
warningMessage('The following procedure may fail if there are other attached USB devices.\nIn this case, try to unplug all the devices and insert only the one to be programmed, then run the command again.\n')
return port
def open(self):
error = 0
try:
self.serialPort = serial.Serial(port=self.port, baudrate=BOOTLOADER_COMMAND_BAUDRATE, timeout=1)
time.sleep(0.10000000000000001)
self.serialPort.flushInput()
except:
errorMessage((('Trouble opening port : ' + repr(self.port)) + '\n'))
error = 1
return error
def reset(self, bootloader=False):
returnValue = True
if returnValue:
reply = self.sendCommand(self.SET_nBOOTMODE, [1])
returnValue = reply != None
if returnValue:
reply = self.sendCommand(self.SET_nRESET, [0])
returnValue = reply != None
if returnValue:
if bootloader:
reply = self.sendCommand(self.SET_nBOOTMODE, [0])
returnValue = reply != None
time.sleep(0.10000000000000001)
if returnValue:
reply = self.sendCommand(self.SET_nRESET, [1])
returnValue = reply != None
time.sleep(0.10000000000000001)
time.sleep(0.10000000000000001)
return returnValue
def runBootloader(self):
returnValue = None
reply = self.sendCommand(self.RUN_BOOTLOADER, [], True)
if reply:
commandReturnValue = (reply[2])
time.sleep(TIMEOUT_TO_SWITCH_BETWEEN_APPLICATION_AND_BOOTLOADER)
for i in range(5):
try:
self.serialPort = serial.Serial(port=self.bootloaderPort, baudrate=BOOTLOADER_COMMAND_BAUDRATE, timeout=1)
self.serialPort = checkSerialPort(self.bootloaderPort, self.serialPort)
time.sleep(0.5)
self.serialPort.flushInput()
if self.serialPort is None:
returnValue = None
else:
returnValue = commandReturnValue
break
except Exception, inst:
errorMessage((' '.join(repr(a) for a in inst.args) + '\n'))
time.sleep(0.5)
continue
return returnValue
def runFirmware(self):
returnValue = None
reply = self.sendCommand(self.RUN_APPLICATION, [], True)
if reply:
commandReturnValue = (reply[2])
time.sleep(TIMEOUT_TO_SWITCH_BETWEEN_APPLICATION_AND_BOOTLOADER)
for i in range(5):
try:
self.serialPort = serial.Serial(port=self.port, baudrate=BOOTLOADER_COMMAND_BAUDRATE, timeout=1)
self.serialPort = checkSerialPort(self.port, self.serialPort)
if self.serialPort is None:
returnValue = None
else:
returnValue = commandReturnValue
break
except Exception, inst:
errorMessage((' '.join(repr(a) for a in inst.args) + '\n'))
time.sleep(0.5)
continue
return returnValue
def sendCommand(self, command, args=[], closePort=False):
verbose = False
returnValue = None
if command == self.DOWNLOAD_IMAGE:
filename = (args[0])
args = []
replyLength = self.replyLength
packet = (([self.START_BYTE, (1 + len(args)), command] + args) + [self.STOP_BYTE])
if verbose:
print '==>',
print ':'.join(('%02X' % a) for a in packet),
print
packedCommand = struct.pack(('B' * len(packet)), *packet)
self.serialPort.write(packedCommand)
if command == self.DOWNLOAD_IMAGE:
yModem = ymodem.Ymodem(self.serialPort, None)
if yModem.loadFile(filename):
returnValue = None
r = self.serialPort.read((replyLength[command]))
if closePort:
self.serialPort.close()
if len(r) == (replyLength[command]):
reply = struct.unpack(('B' * len(r)), r)
if ((reply[0]) == self.REPLY_START_BYTE and ((reply[1]) == ((replyLength[command]) - 3) and (reply[-1]) == self.STOP_BYTE)):
returnValue = reply
if verbose:
if r:
reply = struct.unpack(('B' * len(r)), r)
print '<==',
print ':'.join(('%02X' % a) for a in reply),
print
else:
print '<==',
print
return returnValue
def setNBOOT(self, value=1):
returnValue = True
if returnValue:
reply = self.sendCommand(self.SET_nBOOTMODE, [value])
returnValue = reply != None
return returnValue
def upgradeBootloaderFirmwareVersion(self):
returnValue = True
reply = self.sendCommand(self.DOWNLOAD_BL_IMAGE)
if reply:
returnValue = (reply[2]) == self.OK
else:
returnValue = False
return returnValue
def upgradeFirmwareVersion(self, filename=None):
returnValue = True
if filename is None:
filename = self.firmwareName
if returnValue:
firmwareType = self.getFirmwareType()
if firmwareType == self.APP_RUNNING:
reply = self.runBootloader()
if reply is None:
returnValue = False
else:
if firmwareType == self.BL_RUNNING:
pass
else:
returnValue = False
if returnValue:
if self.getFirmwareType() != self.BL_RUNNING:
errorMessage('Unable to read from port, please use a USB HUB 1.1 and rerun the command\n')
returnValue = False
else:
reply = self.sendCommand(self.DOWNLOAD_IMAGE, [filename])
returnValue = (reply[2]) == self.OK
return returnValue
def versionInStringFormat(self, version):
return ('%d.%d.%d' % (((version >> 16) & 255), ((version >> 8) & 255), (version & 255)))
class rs232Interface(object):
def __init__(self, port, noReset=False, rfMode=False, eui64=0):
self.port = port
self.noReset = noReset
self.rfMode = rfMode
self.eui64 = eui64
self.serialPort = None
self.portType = portType(port)
if self.portType == 'FTDI':
self.portHandle = FTDI_Interface(port)
else:
if self.portType == 'STM32':
firmwareName = 'CompositeForSTM32W.bin'
if 'STM32W_FLASHER_FORCE_FIRMWARE_NAME' in os.environ:
firmwareName = (os.environ['STM32W_FLASHER_FORCE_FIRMWARE_NAME'])
flasher_py_files = os.path.dirname(os.path.abspath(sys.argv[0]))
firmware_dir = os.path.dirname(flasher_py_files) # parent directory
self.portHandle = STM32F_Interface(port, os.path.join(firmware_dir, firmwareName))
def closePort(self):
self.serialPort.close()
def enableReadProtection(self, flag):
return self.STBL.enableReadProtection(flag)
def eraseUserFlash(self):
return self.STBL.eraseUserFlash()
def init(self, checkFirmwareImage=True):
error = 0
if self.noReset:
if self.rfMode:
error = self.reset(False)
time.sleep(0.10000000000000001)
else:
error = 0
else:
error = self.reset(True, checkFirmwareImage)
if error == 1:
errorMessage((('Trouble while resetting board on port : ' + repr(self.port)) + '\n'))
if error == 0:
error = self.openPort()
if error == 0:
if self.rfMode:
self.packetSize = 96
def sendBinary(port, data, length):
for i in range(length):
port.write(chr(((data >> (i * 8)) & 255)))
continue
sendBinary(self.serialPort, self.eui64, 8)
sendBinary(self.serialPort, 45067, 2)
sendBinary(self.serialPort, 15, 1)
time.sleep(0.5)
while self.serialPort.inWaiting() > 0:
sys.stdout.write(self.serialPort.read(self.serialPort.inWaiting()))
continue
else:
self.packetSize = 256
self.STBL = STBL(self.serialPort, packetSize=self.packetSize, serialMode=(not self.rfMode))
if self.STBL is not None:
tmp = self.STBL.bootloaderInit()
if tmp:
pass
else:
error = 1
return error
def isReadProtectionActive(self):
return self.STBL.isReadProtectionActive()
def memoryRead(self, address, size):
return self.STBL.memoryRead(address, size)
def openPort(self):
error = 0
try:
self.serialPort = serial.Serial(port=self.port, bytesize=8, baudrate=115200, parity='N', timeout=0)
except:
errorMessage((('Trouble opening port : ' + repr(self.port)) + '\n'))
error = 1
return error
def programCibData(self, cibData):
return self.STBL.programCibData(cibData)
def programUserFlash(self, inputFile, startAddress=134217728, progressReport=None, doErase=True):
return self.STBL.programUserFlash(inputFile, startAddress, progressReport, doErase)
def reset(self, bootloader=False, checkSTM32FFirmware=True):
returnValue = 0
if self.portType == 'FTDI':
self.portHandle.reset(bootloader)
else:
if self.portType == 'STM32':
returnValue = self.portHandle.open()
if checkSTM32FFirmware:
if returnValue == 0:
firmwareVersionCurrent = self.portHandle.getFirmwareVersionFromFile(stringMode=False)
if returnValue == 0:
firmwareType = self.portHandle.getFirmwareType()
if (firmwareType is None or (firmwareType != self.portHandle.BL_RUNNING and firmwareType != self.portHandle.APP_RUNNING)):
errorMessage('Failed to get firmware type: Invalid reply\n')
returnValue = 1
if returnValue == 0:
firmwareVersion = self.portHandle.getFirmwareVersion()
if firmwareVersion is None:
errorMessage('Failed to get firmware version:Invalid reply\n')
returnValue = 1
else:
if (firmwareVersion & 4278190080L):
firmwareVersion = self.portHandle.FIRMWARE_VERSION_NONE
if returnValue == 0:
bootloaderFirmwareVersion = self.portHandle.getBootloaderFirmwareVersion()
if bootloaderFirmwareVersion is None:
errorMessage('Failed to get bootloader firmware version:Invalid reply\n')
returnValue = 1
if bootloaderFirmwareVersion == self.portHandle.FIRMWARE_VERSION_NONE:
self.portHandle.bootloaderPort = self.portHandle.mapSTMCompositeComPortToBootloaderCOMPort(self.portHandle.port)
if returnValue == 0:
if (firmwareType == self.portHandle.BL_RUNNING and (firmwareVersion != self.portHandle.FIRMWARE_VERSION_NONE and firmwareVersion >= firmwareVersionCurrent)):
if bootloaderFirmwareVersion == self.portHandle.FIRMWARE_VERSION_NONE:
errorMessage('Please unplug and replug the board to the PC\n')
returnValue = 2
else:
result = self.portHandle.runFirmware()
if result is not self.portHandle.OK:
errorMessage('Failed to run firmware: Invalid reply\n')
returnValue = 1
if returnValue == 0:
if (firmwareVersion == self.portHandle.FIRMWARE_VERSION_NONE or firmwareVersion < firmwareVersionCurrent):
if firmwareVersion == self.portHandle.FIRMWARE_VERSION_NONE:
infoMessage(('Missing STM32F103 firmware, upgrading to version %s\n' % self.portHandle.getFirmwareVersionFromFile(stringMode=True)))
else:
infoMessage(('Old STM32F103 firmware version %s, upgrading to version %s\n' % (self.portHandle.versionInStringFormat(firmwareVersion), self.portHandle.getFirmwareVersionFromFile(stringMode=True))))
warningMessage('Changing firmware version can break backward compatibility and older version of stm32w_flasher may not work\n')
if self.portHandle.upgradeFirmwareVersion():
if ((firmwareVersion == self.portHandle.FIRMWARE_VERSION_NONE or firmwareVersion < 131072) and firmwareVersionCurrent >= 131072):
errorMessage(('Switching to firmware %s may change your COM port number, please unplug and replug your USB device and re-run this command again\n' % self.portHandle.getFirmwareVersionFromFile(stringMode=True)))
returnValue = 2
else:
result = self.portHandle.runFirmware()
if result is not self.portHandle.OK:
errorMessage('Failed to run firmware: Invalid reply\n')
returnValue = 1
else:
errorMessage('Failed to upgrade firmware version: Invalid reply\n')
returnValue = 1
if returnValue == 0:
firmwareVersion = self.portHandle.getFirmwareVersion()
if firmwareVersion is None:
errorMessage('Invalid reply\n')
returnValue = 1
if returnValue == 0:
if firmwareVersion >= 131076:
if self.portHandle.isBootloaderFirmwareVersionOld():
infoMessage('Upgrading STM32F Bootloader firmware\n')
if self.portHandle.upgradeBootloaderFirmwareVersion():
pass
else:
errorMessage('Upgrade of the STM32F bootloader failed. This is a CRITICAL error and your board may brick your board\n')
returnValue = 1
if returnValue == 0:
if firmwareVersion > firmwareVersionCurrent:
warningMessage('Device firmware is more recent than expected. Are you using an old version of this software ?\n')
if returnValue == 0:
result = self.portHandle.reset(bootloader)
if result is None:
errorMessage('Failed to reset STM32W: Invalid reply\n')
returnValue = 1
self.portHandle.close()
else:
errorMessage(('Failed to detect port type for %s\n' % self.port))
returnValue = 1
return returnValue
def setNBOOT(self, value):
returnValue = 0
if (self.portHandle and self.portType == 'STM32'):
self.portHandle.open()
returnValue = self.portHandle.setNBOOT(value)
self.portHandle.close()
return returnValue
def startApplication(self, address=134217728):
if self.noReset is False:
self.closePort()
self.setNBOOT(1)
self.openPort()
self.STBL.setPort(self.serialPort)
return self.STBL.startApplication(address)
def terminate(self):
if self.noReset is False:
self.closePort()
self.setNBOOT(1)
self.openPort()
def verifyFlash(self, inputFile, startAddress, progressReport):
return self.STBL.verifyFlash(inputFile, startAddress, progressReport)
def checkSerialPort(portName, serialPort):
returnValue = serialPort
try:
serialPort.write(' ')
except serial.serialutil.SerialException, inst:
errorMessage((' '.join(repr(a) for a in inst.args) + '\n'))
infoMessage('Write to serial port failed: please try a different USB port or a USB hub 1.1\n')
returnValue = None
return returnValue
def getAvailableSerialPorts(refreshList=True):
global rs232PortsList
if (refreshList or rs232PortsList is None):
returnValue = {}
context = pyudev.Context()
id = [{ 'vendor': FT232R_VENDOR , 'product': FT232R_PRODUCT , 'type': 'FTDI' }, { 'vendor': STM32F103_VENDOR , 'product': STM32F103_PRODUCT , 'type': 'STM32' }, { 'vendor': STM32F103_VENDOR , 'product': STM32F103_PRODUCT_OLD , 'type': 'STM32' }]
for device in context.list_devices(subsystem='tty', ID_BUS='usb'):
for serialId in id:
#device['ID_VENDOR_ID'] (VID) and device['ID_MODEL_ID'] (PID) are in hex, but without the 0x prefix
if (int(device['ID_VENDOR_ID'], 16) == serialId['vendor']) and (int(device['ID_MODEL_ID'], 16) == serialId['product']):
#e.g. returnValue[/dev/ttyACM0] = [STM32, serial number]
returnValue[(device.device_node)] = [(serialId['type']), (device['ID_SERIAL'])]
rs232PortsList = returnValue
return rs232PortsList
def getFirstAvailableSerialPort():
returnValue = None
ports = getAvailableSerialPorts(False)
if ports != {}:
returnValue = (sorted(ports.keys())[0])
return returnValue
def hexString(reply):
if reply is None:
return ''
else:
return ' '.join(('%02x' % a) for a in reply)
def portType(port):
returnValue = None
ports = getAvailableSerialPorts(False)
if port in ports:
returnValue = ((ports[port])[0])
return returnValue
def u32ToArray(v):
return [(v & 255), ((v >> 8) & 255), ((v >> 16) & 255), ((v >> 24) & 255)]