Fix: stm32w flasher for Ubuntu 12.04 and later

This commit is contained in:
Etienne Duble 2012-11-09 14:14:57 +01:00
parent ecdbbaec9a
commit 7905316c54
9 changed files with 1975 additions and 1 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@
*.log
*.elf
*.ihex
*.pyc
obj_*
symbols.*
Makefile.target

View File

@ -168,7 +168,7 @@ endif
FLASHER = sudo $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher
FLASHER = sudo $(CONTIKI)/tools/stm32w/stm32w_flasher/py_files/stm32w_flasher.py
# Check if we are running under Windows
ifeq ($(HOST_OS),Windows)

View File

@ -0,0 +1,83 @@
# See comment in stm32w_flasher.py.
# Extraction and little adaptation performed by E.Duble (CNRS, LIG).
import struct
class Error(Exception):
"""Base class for exceptions in this module."""
args = None
message = None
class FileFormatError(Error):
"""
Exception raised for errors in the file format
Attributes:
filename -- filename with unknown format
message -- format error message
"""
args = None
message = None
def __init__(self, filename, message):
self.filename = filename
self.message = message
class fileFormatReader(object):
def __init__(self, filename, startAddress=None):
self.filename = filename
self.startAddress = startAddress
def getRawBinary(self):
fileContent = None
bytes = None
f = open(self.filename, 'rb')
if self.filename[-4:] == '.bin':
bytesRaw = f.read()
bytes = []
bytes.extend(struct.unpack(('B' * len(bytesRaw)), bytesRaw))
f.close()
else:
if self.filename[-4:] == '.s37':
fillChar = 255
fileContent = f.readlines()
f.close()
startAddress = None
currentAddress = None
bytes = []
for line in fileContent:
if line[:2] == 'S3':
count = int(line[2:4], 16)
if startAddress is None:
startAddress = int(line[4:12], 16)
currentAddress = startAddress
address = int(line[4:12], 16)
if currentAddress < address:
bytes = (bytes + ([fillChar] * (address - currentAddress)))
currentAddress = address
else:
if currentAddress > address:
raise FileFormatError(self.filename, 'S37, Non progressing addresses detected')
for i in range((count - 5)):
bytes = (bytes + [int(line[(12 + (i * 2)):((12 + (i * 2)) + 2)], 16)])
continue
currentAddress = (currentAddress + (count - 5))
continue
else:
if line[:2] == 'S0':
continue
else:
if line[:2] == 'S7':
break
else:
raise FileFormatError(self.filename, 'S37: unknown field type')
self.startAddress = startAddress
else:
raise FileFormatError(self.filename, 'Unknown extension')
return (self.startAddress, bytes)

View File

@ -0,0 +1,25 @@
# See comment in stm32w_flasher.py.
# Extraction and little adaptation performed by E.Duble (CNRS, LIG).
import sys
def errorMessage(msg, header=True):
if header:
sys.stderr.write('ERROR: ')
sys.stderr.write(msg)
sys.stderr.flush()
def infoMessage(msg, header=True):
if header:
sys.stdout.write('INFO: ')
sys.stdout.write(msg)
sys.stdout.flush()
def warningMessage(msg, header=True):
if header:
sys.stderr.write('WARNING: ')
sys.stderr.write(msg)
sys.stderr.flush()

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,279 @@
#!/usr/bin/env python
import optparse, os, sys, time
# The binary file at [contiki]/tools/stm32w/stm32w_flasher/stm32w_flasher
# contained python code.
# This binary file did not work anymore on Ubuntu 12.04, so
# it was replaced by this extracted python code, as discussed
# with people at ST Crolles (France).
#
# Extraction and little adaptation performed by E.Duble (CNRS, LIG).
try:
import serial
import ftdi
except:
print 'Python modules serial and ftdi could not be loaded.'
print 'Please install these dependencies:'
print '(On Ubuntu) $ sudo apt-get install python-serial python-ftdi'
sys.exit(-1)
from messages import infoMessage, errorMessage
from rs232_interface import rs232Interface, getFirstAvailableSerialPort
versionMajor = 2
versionMinor = 0
versionPatch = 1
versionQualifier = "b2"
version = "%d.%d.%d%s"%(versionMajor, versionMinor, versionPatch, versionQualifier)
commandTable = [
['-i', '--interface', 'store', "<rs232 | rf > specify flasher interface (default rs232)",None],
['-p', '--port', 'store', "</dev/ttyXXX | auto>: specify rs232 port or auto mode (only relevant if interface selected is rs232 or rf)", None],
['-f', '--flash-image', 'store_true', "program flash"],
['-a', '--address', 'store', "0xHHHHHHHH specify baseaddress (only relevat for .bin images)", "0x08000000"],
['-v', '--verify', 'store_true', "verify flash content against file", False],
#['-d', '--device-info', 'store_true', 'print information about the STM32W device', False],
['-r', '--reset', 'store_true', 'Reset device', False],
['-s', '--start', 'store_true', 'Start application', False],
['-m', '--masserase', 'store_true', 'Erase user flash (masserase)', False],
['-b', '--bootloader-mode', 'store_true', 'Device is already in bootloader mode.(Only relevant for rs232 interface)', False],
['-e', '--eui64', 'store', "0xHHHHHHHHHHHHHHHH specify EUI64 (only relevat for rf interface)", "0xFFFFFFFFFFFFFFFF"],
['', '--enable-readout-protection', 'store', "<0|1> Disable or enable readout protection", None],
['', '--set-write-protection', 'store', "0xHHHHHHHH Set write protection to hex value (each bit set to zero is protecting 4K)" , "0xFFFFFFFF"],
]
def initCommandLineParser():
"""Create a command-line parser and return it.
"""
USAGE = '%prog [option...] [filename{.s37|.bin}] ...'
DESCR = """ Flash programming utility for STM32W108 device """
parser = optparse.OptionParser(usage=USAGE, description=DESCR,
version='%%prog %s' % version)
for item in commandTable:
if len(item) > 4:
default = item[4]
else:
default = None
parser.add_option(item[0], item[1], action=item[2], help=item[3], default=default)
return parser
def getFileVersionDate(fname):
returnValue = ""
return returnValue
def initInterface (interface, port, noReset=False, rfMode=False, eui64=0):
returnValue = rs232Interface(port, noReset, rfMode, eui64)
if returnValue.init():
returnValue = None
return returnValue
def terminateInterface(interface):
if (isinstance(interface, rs232Interface)):
interface.terminate()
def flashImage (interface, inputFile, startAddress, doErase=True):
def progressReport(size, fileSize):
infoMessage ("Programming %05d/%05d\r"%(size,fileSize))
infoMessage ("Programming user flash\n")
if not interface.programUserFlash(inputFile, startAddress, progressReport, doErase):
infoMessage("Failed \n")
else:
infoMessage("Done \n")
def verifyFlashImage (interface, inputFile, startAddress):
def progressReport(size, fileSize):
infoMessage ("Verifying %05d/%05d\r"%(size,fileSize))
infoMessage ("Verifying user flash\n")
if not interface.verifyFlash(inputFile, startAddress, progressReport):
infoMessage("Failed \n")
else:
infoMessage("Done \n")
def resetDevice (interface):
infoMessage ("Resetting device\n")
returnValue = not interface.startApplication(0)
if (returnValue):
infoMessage("Failed \n")
else:
infoMessage("Done \n")
def startApplication (interface, startAddress):
infoMessage ("Starting application from address: %08x\n"%startAddress)
if not interface.startApplication(startAddress):
infoMessage("Failed \n")
else:
infoMessage("Done \n")
def eraseUserFlash (interface):
infoMessage ("Erasing user flash (mass erase)\n")
if not interface.eraseUserFlash():
infoMessage("Failed \n")
else:
infoMessage("Done \n")
def printBanner():
infoMessage ("STM32W flasher utility version %s\n"%version)
if __name__ == '__main__':
try:
absolutePath = os.path.abspath(sys.argv[0])
if "frozen" in dir(sys):
version += " " + getFileVersionDate(sys.executable)
else:
version += "-" + time.strftime("%Y%m%d",time.localtime(os.stat(absolutePath).st_ctime))
version += " for Linux"
interfaceHandle = None
printBanner()
parser = initCommandLineParser()
(options, args) = parser.parse_args()
rfMode = False
# Check command line option
if (len(args) == 1):
if (len(sys.argv) == 2):
# No option means flashing by default
options.flash_image = True
options.image = args[0]
if (len(args) > 1):
parser.print_help()
sys.exit(-1)
if (len(sys.argv) == 1):
parser.print_help()
sys.exit(0)
if (options.interface is None):
# Set defualt for interface
if (options.port is None):
options.interface = "rs232"
options.port = "auto"
else:
options.interface = "rs232"
elif (options.interface == "rf"):
rfMode = True
options.address = "0x08003000"
options.interface = "rs232"
options.bootloader_mode = True
options.interface = options.interface.lower()
if ((options.interface == "rs232") and (options.port == None)):
parser.print_help()
sys.exit(-1)
if (options.interface != "rs232" and options.interface != "jlink"):
parser.print_help()
sys.exit(-1)
startAddress = int(options.address,16)
if (options.interface == "rs232"):
optionArg = options.port.upper()
if (optionArg == "AUTO"):
port = getFirstAvailableSerialPort()
if port is None:
errorMessage ("Unable to find serial port in auto mode: no STM32W boards detected\n")
sys.exit(-1)
infoMessage ("Auto mode selected serial port: %s\n"%port)
elif (options.port[:4] == "/dev"): ## For Linux
port = options.port
else:
try:
port = int(optionArg)
except ValueError:
errorMessage("Invalid port: %s\n"%options.port)
sys.exit(-1)
else:
port = None
if (options.interface == "jlink"):
errorMessage("JLink not yet supported.\n")
sys.exit(-1)
if (options.start and options.reset):
errorMessage ("Only one option between -s (--start) and -r (--reset) may be specified")
sys.exit(-1)
interfaceHandle = initInterface(options.interface, port, options.bootloader_mode, rfMode, int(options.eui64, 16))
if interfaceHandle is None:
errorMessage("Error while initiliazing interface\n")
sys.exit(-1)
readoutProtection = interfaceHandle.isReadProtectionActive()
if readoutProtection:
infoMessage("!Warning: Readout protection is active\n")
options.device_info = False
if (options.masserase):
eraseUserFlash(interfaceHandle)
if (options.enable_readout_protection is not None):
if (options.enable_readout_protection == "1"):
if not readoutProtection:
infoMessage("Enabling readout protection\n")
interfaceHandle.enableReadProtection(True)
infoMessage("Done\n")
else:
infoMessage("Readout protection already enabled, no action\n")
elif (options.enable_readout_protection == "0"):
if readoutProtection:
infoMessage("Disabling readout protection (this will clear user flash and CIB)\n")
interfaceHandle.enableReadProtection(False)
infoMessage("Done\n")
else:
infoMessage("Readout protection already disaabled, no action\n")
else:
errorMessage("Invalid value for --enable-readout-protection\n")
terminateInterface(interfaceHandle)
sys.exit(-1)
if options.flash_image:
flashImage(interfaceHandle, options.image, startAddress, not options.masserase)
if options.verify and not readoutProtection:
verifyFlashImage(interfaceHandle, options.image, startAddress)
if (options.start):
startApplication(interfaceHandle, startAddress)
if (options.reset):
resetDevice(interfaceHandle)
terminateInterface(interfaceHandle)
sys.exit (0)
except KeyboardInterrupt:
infoMessage ("User break\n")
terminateInterface(interfaceHandle)
sys.exit(-1)
except Exception, inst:
if not ("frozen" in dir(sys)):
raise
else:
errorMessage("Internal error\n")
errorMessage("%s\n"%repr(type(inst))) # the exception instance
errorMessage("%s\n"%repr(inst.args)) # arguments stored in .args
if interfaceHandle:
terminateInterface(interfaceHandle)
sys.exit(-1)

View File

@ -0,0 +1,241 @@
# 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