DfuSe: verify supported.

This commit is contained in:
NIIBE Yutaka
2010-11-02 12:05:18 +09:00
parent bdcff41b7c
commit 86a760c14c
3 changed files with 142 additions and 24 deletions

View File

@@ -1,3 +1,15 @@
2010-11-02 NIIBE Yutaka <gniibe@fsij.org>
* tool/dfuse.py (DFU_STM32.download): Put '#' for each 4-KiB.
Added 0-length write to finish download.
Take intel_hex object as argument.
(DFU_STM32.ll_upload_block): New method.
(DFU_STM32.dfuse_read_memory): New method.
(DFU_STM32.verify): New method.
(get_device): Support DFU_STM32PROTOCOL_0 too (for CQ STARM).
* tool/dfuse.py: Renamed from dfu_stmicroelectronics_extention.py.
2010-11-01 NIIBE Yutaka <gniibe@fsij.org>
* tool/intel_hex.py: New file.

View File

@@ -1,16 +1,37 @@
#! /usr/bin/python
"""
dfuse.py - DFU (Device Firmware Upgrade) tool for STM32 Processor.
"SE" in DfuSe stands for "STmicroelectronics Extention".
Copyright (C) 2010 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from intel_hex import *
import sys, time, struct
"""
DFU tool for STM32 Processor.
"""
# INPUT: intel hex file
# Seems that following is not supported current DfuSe implementation on
# As of October 2010 (DfuSe V3.0.1 - 06/18/2010), it seems that
# following features are not supported by DfuSe implementation on
# target:
#
# unprotect
# leave_dfu_mode
# write to option bytes
@@ -26,7 +47,8 @@ import usb
# USB DFU class, subclass, protocol
DFU_CLASS = 0xFE
DFU_SUBCLASS = 0x01
DFU_STM32PROTOCOL = 2
DFU_STM32PROTOCOL_0 = 0
DFU_STM32PROTOCOL_2 = 2
# DFU request
DFU_DETACH = 0x00
@@ -77,14 +99,14 @@ class DFU_STM32:
"""
__init__(device, configuration, interface) -> None
Initialize the device.
device: printer usb.Device object.
device: usb.Device object.
configuration: configuration number.
interface: printer usb.Interface object representing the interface and altenate setting.
interface: usb.Interface object representing the interface and altenate setting.
"""
if interface.interfaceClass != DFU_CLASS:
raise TypeError, "Wrong interface class"
raise ValueError, "Wrong interface class"
if interface.interfaceSubClass != DFU_SUBCLASS:
raise TypeError, "Wrong interface sub class"
raise ValueError, "Wrong interface sub class"
self.__devhandle = device.open()
self.__devhandle.setConfiguration(configuration)
@@ -127,6 +149,16 @@ class DFU_STM32:
index = self.__intf,
buffer = None)
# Upload: TARGET -> HOST
def ll_upload_block(self, block_num):
return self.__devhandle.controlMsg(requestType = 0xa1,
request = DFU_UPLOAD,
value = block_num,
index = self.__intf,
buffer = 1024,
timeout = 3000000)
# Download: HOST -> TARGET
def ll_download_block(self, block_num, block):
return self.__devhandle.controlMsg(requestType = 0x21,
request = DFU_DNLOAD,
@@ -134,6 +166,19 @@ class DFU_STM32:
index = self.__intf,
buffer = block)
def dfuse_read_memory(self):
blocknum = self.__blocknum
self.__blocknum = self.__blocknum + 1
try:
block = self.ll_upload_block(blocknum)
return block
except:
s = self.ll_get_status()
while s[4] == STATE_DFU_DOWNLOAD_BUSY:
time.sleep(0.1)
s = self.ll_get_status()
raise ValueError, "Read memory failed (%d)" % s[0]
def dfuse_set_address_pointer(self, address):
bytes = get_four_bytes (address)
self.__blocknum = 2
@@ -156,10 +201,9 @@ class DFU_STM32:
raise ValueError, "Erase failed"
def dfuse_write_memory(self, block):
data_block = [(ord(b) & 0xff) for b in block]
blocknum = self.__blocknum
self.__blocknum = self.__blocknum + 1
self.ll_download_block(blocknum, data_block)
self.ll_download_block(blocknum, block)
s = self.ll_get_status()
while s[4] == STATE_DFU_DOWNLOAD_BUSY:
time.sleep(0.1)
@@ -167,40 +211,90 @@ class DFU_STM32:
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
raise ValueError, "Write memory failed"
def download(self, filename):
ih = intel_hex(filename)
def download(self, ih):
# First, erase pages
sys.stdout.write("Erasing ...")
sys.stdout.write("Erasing: ")
sys.stdout.flush()
for start_addr in sorted(ih.memory.keys()):
data = ih.memory[start_addr]
end_addr = start_addr + len(data)
addr = start_addr & 0xfffffc00
i = 0
while addr < end_addr:
self.dfuse_erase(addr)
if i & 0x03 == 0x03:
sys.stdout.write("#")
sys.stdout.flush()
addr += 1024
i += 1
sys.stdout.write("\n")
sys.stdout.flush()
# Then, write pages
sys.stdout.write("Writing ...")
sys.stdout.write("Writing: ")
sys.stdout.flush()
for start_addr in sorted(ih.memory.keys()):
data = ih.memory[start_addr]
end_addr = start_addr + len(data)
addr = start_addr & 0xfffffc00
#
# XXX: data should be 1-KiB aligned and size should be just KiB.
if addr != start_addr:
raise ValueError, "padding is not supported yet"
self.dfuse_set_address_pointer(addr)
i = 0
while addr < end_addr:
self.dfuse_write_memory(data[i*1024:(i+1)*1024])
if i & 0x03 == 0x03:
sys.stdout.write("#")
sys.stdout.flush()
addr += 1024
i += 1
# 0-length write at the end
self.ll_download_block(self.__blocknum, None)
s = self.ll_get_status()
if s[4] == STATE_DFU_MANIFEST:
time.sleep(1)
try:
s = self.ll_get_status()
except:
self.__devhandle.reset()
elif s[4] == STATE_DFU_MANIFEST_WAIT_RESET:
self.__devhandle.reset()
elif s[4] != STATE_DFU_IDLE:
raise ValueError, "write failed (%d)." % s[4]
sys.stdout.write("\n")
sys.stdout.flush()
def verify(self, ih):
s = self.ll_get_status()
if s[4] != STATE_DFU_IDLE:
self.ll_clear_status()
# Read pages
sys.stdout.write("Reading: ")
sys.stdout.flush()
for start_addr in sorted(ih.memory.keys()):
data = ih.memory[start_addr]
end_addr = start_addr + len(data)
addr = start_addr & 0xfffffc00
# XXX: data should be 1-KiB aligned and size should be just KiB.
if addr != start_addr:
raise ValueError, "padding is not supported yet"
self.dfuse_set_address_pointer(addr)
self.ll_clear_status()
self.ll_clear_status()
i = 0
while addr < end_addr:
block = self.dfuse_read_memory()
j = 0
for d in block:
if d != (ord(data[i*1024+j])&0xff):
raise ValueError, "verify failed at %08x" % (addr + i*1024+j)
j += 1
if i & 0x03 == 0x03:
sys.stdout.write("#")
sys.stdout.flush()
addr += 1024
i += 1
self.ll_clear_status()
sys.stdout.write("\n")
sys.stdout.flush()
@@ -215,7 +309,8 @@ def get_device():
for alt in intf:
if alt.interfaceClass == DFU_CLASS and \
alt.interfaceSubClass == DFU_SUBCLASS and \
alt.interfaceProtocol == DFU_STM32PROTOCOL:
(alt.interfaceProtocol == DFU_STM32PROTOCOL_0 or \
alt.interfaceProtocol == DFU_STM32PROTOCOL_2):
return dev, config, alt
raise ValueError, "Device not found"
@@ -230,14 +325,16 @@ def main(filename):
if s[4] == STATE_DFU_ERROR:
dfu.ll_clear_status()
s = dfu.ll_get_status()
if s[4] == STATE_DFU_IDLE:
print s
if s[4] == STATE_DFU_IDLE:
exit
transfer_size = 1024
if s[0] != DFU_STATUS_OK:
print s
exit
dfu.download(filename)
ih = intel_hex(filename)
dfu.download(ih)
dfu.verify(ih)
if __name__ == '__main__':
main(sys.argv[1])

View File

@@ -1,3 +1,12 @@
"""
intel_hex.py - Intel Hex file reader.
Copyright (C) 2010 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
You can use/distribute/modify/etc. this for any purpose.
"""
import binascii
class intel_hex: