From 86a760c14c7745571275fdbe79ca58a6121e8ef0 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 2 Nov 2010 12:05:18 +0900 Subject: [PATCH] DfuSe: verify supported. --- ChangeLog | 12 ++ ...microelectronics_extention.py => dfuse.py} | 145 +++++++++++++++--- tool/intel_hex.py | 9 ++ 3 files changed, 142 insertions(+), 24 deletions(-) rename tool/{dfu_stmicroelectronics_extention.py => dfuse.py} (60%) diff --git a/ChangeLog b/ChangeLog index 5f78e3d..6b0464e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2010-11-02 NIIBE Yutaka + + * 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 * tool/intel_hex.py: New file. diff --git a/tool/dfu_stmicroelectronics_extention.py b/tool/dfuse.py similarity index 60% rename from tool/dfu_stmicroelectronics_extention.py rename to tool/dfuse.py index f43aefa..773845b 100755 --- a/tool/dfu_stmicroelectronics_extention.py +++ b/tool/dfuse.py @@ -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 + +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 . +""" + 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) - sys.stdout.write("#") - sys.stdout.flush() + 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]) - sys.stdout.write("#") - sys.stdout.flush() + 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() + print s if s[4] == STATE_DFU_IDLE: - print s 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]) diff --git a/tool/intel_hex.py b/tool/intel_hex.py index b397b5c..a2b0e28 100644 --- a/tool/intel_hex.py +++ b/tool/intel_hex.py @@ -1,3 +1,12 @@ +""" +intel_hex.py - Intel Hex file reader. + +Copyright (C) 2010 Free Software Initiative of Japan +Author: NIIBE Yutaka + +You can use/distribute/modify/etc. this for any purpose. +""" + import binascii class intel_hex: