changeset 130:654093a9a1e3

Added icons, improved device explorer
author Windel Bouwman
date Sat, 19 Jan 2013 18:16:04 +0100
parents 9e350a7dde98
children 04e45faafd1d
files python/chip.png python/hardware.png python/ide.py python/lsusb.py python/st-flash.py python/st-util.py python/stlink.py python/stm32.py python/usb.py
diffstat 9 files changed, 147 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
Binary file python/chip.png has changed
Binary file python/hardware.png has changed
--- a/python/ide.py	Fri Jan 18 12:52:11 2013 +0100
+++ b/python/ide.py	Sat Jan 19 18:16:04 2013 +0100
@@ -117,7 +117,7 @@
   def __init__(self, parent=None):
     super(Ide, self).__init__(parent)
     self.setWindowTitle('LCFOS IDE')
-    self.compiler = KsCompiler()
+    self.compiler = None # TODO
     icon = QPixmap()
     icon.loadFromData(lcfospng)
     self.setWindowIcon(QIcon(icon))
--- a/python/lsusb.py	Fri Jan 18 12:52:11 2013 +0100
+++ b/python/lsusb.py	Sat Jan 19 18:16:04 2013 +0100
@@ -2,6 +2,29 @@
 
 from usb import UsbContext
 
+# try to read usb.ids:
+vids = {}
+pids = {}
+try:
+   with open('usb.ids', 'r', errors='ignore') as f:
+      vid = 0
+      for l in f:
+         if l.startswith('#') or not l.strip():
+            continue
+         if l.startswith('\t\t'):
+            print('iface:', l)
+         elif l.startswith('\t'):
+            print('product', l)
+            pid = int(l[1:5], 16)
+            print('product', hex(pid), l)
+         else:
+            print('vendor', l)
+            vid = int(l[0:4], 16)
+            print('vendor', hex(vid), l)
+
+except IOError as e:
+   print("Error loading usb id's: {0}".format(e))
+
 context = UsbContext()
 for d in context.DeviceList:
    print(d)
--- a/python/st-flash.py	Fri Jan 18 12:52:11 2013 +0100
+++ b/python/st-flash.py	Sat Jan 19 18:16:04 2013 +0100
@@ -30,7 +30,6 @@
 eraseparser = subparsers.add_parser('erase', help='erase flash contents')
 
 args = parser.parse_args()
-print(args)
 if not args.command:
    parser.print_usage()
    sys.exit(1)
--- a/python/st-util.py	Fri Jan 18 12:52:11 2013 +0100
+++ b/python/st-util.py	Sat Jan 19 18:16:04 2013 +0100
@@ -21,7 +21,7 @@
    def __init__(self):
       super().__init__()
       self.chipPixmap = QPixmap('chip.png').scaled(32, 32)
-      self.usbPixmap = QPixmap('usb.png').scaled(32, 32)
+      self.hardwarePixmap = QPixmap('hardware.png').scaled(32, 32)
       self.refresh()
    def refresh(self):
       """ Check all usb interfaces for interfaces """
@@ -34,7 +34,6 @@
          return
       self.devices.append(device)
       self.modelReset.emit()
-
    def index(self, row, column, parent):
       if parent.isValid():
          ip = parent.internalPointer()
@@ -42,7 +41,6 @@
             devs = [d for d in self.devices if d.iface is ip]
             return self.createIndex(row, column, devs[row])
       else:
-         # root level
          iface = self.interfaces[row]
          return self.createIndex(row, column, iface)
       return idx
@@ -76,10 +74,54 @@
             return str(ip)
          elif role == Qt.DecorationRole:
             if isinstance(ip, Interface):
-               return self.usbPixmap
+               return self.hardwarePixmap
             if isinstance(ip, Device):
                return self.chipPixmap
 
+class DeviceExplorer(QTreeView):
+   """ Lists all interfaces plugged in and allows selection """
+   deviceSelected = pyqtSignal(Device)
+   def __init__(self):
+      super().__init__()
+      self.mdl = DeviceTreeModel()
+      self.setModel(self.mdl)
+      self.activated.connect(self.openItem)
+      self.header().close()
+      self.customContextMenuRequested.connect(self.openMenu)
+      self.setContextMenuPolicy(Qt.CustomContextMenu)
+   def openItem(self, idx):
+      if idx.isValid():
+         ip = idx.internalPointer()
+         if isinstance(ip, Interface):
+            if not ip.IsOpen:
+               ip.open()
+               # Try to get a device:
+               self.mdl.addDevice(ip.createDevice())
+         if isinstance(ip, Device):
+            self.deviceSelected.emit(ip)
+   def openMenu(self, pt):
+      idx = self.indexAt(pt)
+      menu = QMenu()
+      menu.addAction('Refresh', self.mdl.refresh)
+      if idx.isValid():
+         ip = idx.internalPointer()
+         if isinstance(ip, Interface):
+            if ip.IsOpen:
+               def closeInterface():
+                  self.mdl.closeInterface(ip)
+               menu.addAction('Close', closeInterface)
+            else:
+               def openInterface():
+                  ip.open()
+                  # Try to get a device:
+                  self.mdl.addDevice(ip.createDevice())
+               menu.addAction('Open', openInterface)
+         elif isinstance(ip, Device):
+            def selectDevice():
+               self.deviceSelected.emit(ip)
+            menu.addAction('Select', selectDevice)
+      menu.exec(self.mapToGlobal(pt))
+
 class StUtil(QMainWindow):
    connected = pyqtSignal(bool)
    def __init__(self):
@@ -104,23 +146,15 @@
 
       sb = self.statusBar()
 
-      tv = QTreeView()
-      self.setCentralWidget(tv)
-      self.mdl = DeviceTreeModel()
-      tv.setModel(self.mdl)
-      tv.activated.connect(self.openItem)
+      devexplr = DeviceExplorer()
+      self.setCentralWidget(devexplr)
+      devexplr.deviceSelected.connect(self.handleDeviceSelected)
 
       self.connected.connect(self.handleConnectedChange)
       self.connected.emit(False)
-   def openItem(self, idx):
-      if idx.isValid():
-         ip = idx.internalPointer()
-         if isinstance(ip, Interface):
-            ip.open()
-            # Try to get a device:
-            self.mdl.addDevice(ip.createDevice())
-         if isinstance(ip, Device):
-            self.device = ip
+   def handleDeviceSelected(self, dev):
+      self.dev = dev
+      self.handleConnectedChange(True)
    def handleConnectedChange(self, state):
       self.miscMenu.setEnabled(state)
       self.connectAction.setEnabled(not state)
--- a/python/stlink.py	Fri Jan 18 12:52:11 2013 +0100
+++ b/python/stlink.py	Sat Jan 19 18:16:04 2013 +0100
@@ -57,13 +57,18 @@
       assert isinstance(stlink2, UsbDevice) # Nifty type checking
       assert checkDevice(stlink2)
       self.stlink2 = stlink2
+   def __del__(self):
+      if self.IsOpen:
+         if self.CurrentMode == DEBUG_MODE:
+            self.exitDebugMode()
+         self.close()
    def __str__(self):
-      if self.devHandle:
+      if self.IsOpen:
          return 'STlink2 device version {0}'.format(self.Version)
       else:
          return 'STlink2 device'
    def open(self):
-      if self.devHandle:
+      if self.IsOpen:
          return
       self.devHandle = self.stlink2.open()
       if self.devHandle.Configuration != 1:
@@ -77,9 +82,12 @@
          self.enterSwdMode()
       self.reset()
    def close(self):
-      # TODO
-      pass
-
+      if self.IsOpen:
+         self.devHandle.close()
+         self.devHandle = None
+   @property
+   def IsOpen(self):
+      return self.devHandle != None
    # modes:
    def getCurrentMode(self):
       cmd = bytearray(16)
@@ -159,7 +167,6 @@
       cmd[0:2] = DEBUG_COMMAND, DEBUG_RUNCORE
       self.send_recv(cmd, 2)
 
-
    # Helper 1 functions:
    def write_debug32(self, address, value):
       cmd = bytearray(16)
--- a/python/stm32.py	Fri Jan 18 12:52:11 2013 +0100
+++ b/python/stm32.py	Sat Jan 19 18:16:04 2013 +0100
@@ -5,9 +5,6 @@
 STM32_FLASH_BASE = 0x08000000
 STM32_SRAM_BASE  = 0x20000000
 
-FLASH_KEY1 = 0x45670123
-FLASH_KEY2 = 0xcdef89ab
-
 # flash registers:
 FLASH_F4_REGS_ADDR = 0x40023c00
 FLASH_F4_KEYR = FLASH_F4_REGS_ADDR + 0x04
@@ -23,48 +20,63 @@
 FLASH_F4_CR_SNB_MASK = 0x38
 FLASH_F4_SR_BSY = 16
 
-def calculate_F4_sector(address):
-   """
-      from 0x8000000 to 0x80FFFFF
-      4 sectors of 0x4000 (16 kB)
-      1 sector of 0x10000 (64 kB)
-      7 of 0x20000 (128 kB)
-   """
-   sectorsizes = [0x4000] * 4 + [0x10000] + [0x20000] * 7
-   sectorstarts = []
-   a = STM32_FLASH_BASE
-   for sectorsize in sectorsizes:
-      sectorstarts.append(a)
-      a += sectorsize
-   # linear search:
-   sec = 0
-   while sec < len(sectorsizes) and address >= sectorstarts[sec]:
-      sec += 1
-   sec -= 1 # one back.
-   return sec, sectorsizes[sec]
-
-def calcSectors(address, size):
-   off = 0
-   sectors = []
-   while off < size:
-      sectornum, sectorsize = calculate_F4_sector(address + off)
-      sectors.append((sectornum, sectorsize))
-      off += sectorsize
-   return sectors
-
 @registerDevice(0x10016413)
 class Stm32F4(Device):
+   """
+      Implementation of the specifics of the STM32F4xx device series.
+   """
    def __init__(self, iface):
       super().__init__(iface)
+      # Assert the proper size for this device:
+      assert self.FlashSize == 0x100000
+      """
+         from 0x8000000 to 0x80FFFFF
+         4 sectors of 0x4000 (16 kB)
+         1 sector of 0x10000 (64 kB)
+         7 of 0x20000 (128 kB)
+      """
+      self.sectorsizes = [0x4000] * 4 + [0x10000] + [0x20000] * 7
    def __str__(self):
-      return 'STM32F4 device'
+      return 'STM32F4 device size=0x{1:X} id=0x{0:X}'.format(\
+         self.UID, self.FlashSize)
+   def calculate_F4_sector(self, address):
+      sectorstarts = []
+      a = STM32_FLASH_BASE
+      for sectorsize in self.sectorsizes:
+         sectorstarts.append(a)
+         a += sectorsize
+      # linear search:
+      sec = 0
+      while sec < len(self.sectorsizes) and address >= sectorstarts[sec]:
+         sec += 1
+      sec -= 1 # one back.
+      return sec, self.sectorsizes[sec]
+
+   def calcSectors(self, address, size):
+      off = 0
+      sectors = []
+      while off < size:
+         sectornum, sectorsize = self.calculate_F4_sector(address + off)
+         sectors.append((sectornum, sectorsize))
+         off += sectorsize
+      return sectors
+   # Device registers:
+   @property
+   def UID(self):
+      uid_base = 0x1FFF7A10
+      uid1 = self.iface.read_debug32(uid_base)
+      uid2 = self.iface.read_debug32(uid_base + 0x4)
+      uid3 = self.iface.read_debug32(uid_base + 0x8)
+      return (uid3 << 64) | (uid2 << 32) | uid1
+   @property
+   def FlashSize(self):
+      f_id = self.iface.read_debug32(0x1FFF7A22)
+      f_id = f_id >> 16
+      return f_id * 1024
    # flashing commands:
    def writeFlash(self, address, content):
-      # TODO:
-      flashsize = 0x100000 # fixed 1 MB for now..
-      print('WARNING: using 1 MB as flash size')
-      pagesize = 0x4000 # fixed for now!
-      print('warning: page size hardcoded')
+      flashsize = self.FlashSize
+      pagesize = min(self.sectorsizes)
 
       # Check address range:
       if address < STM32_FLASH_BASE:
@@ -78,19 +90,16 @@
          content += bytes([0])
       if address & (pagesize - 1) != 0:
          raise STLinkException('Address not aligned with pagesize')
-      
       # erase required space
-      sectors = calcSectors(address, len(content))
+      sectors = self.calcSectors(address, len(content))
       print('erasing {0} sectors'.format(len(sectors)))
       for sector, secsize in sectors:
          print('erasing sector {0} of {1} bytes'.format(sector, secsize))
          self.eraseFlashSector(sector)
-
       # program pages:
       self.unlockFlashIf()
       self.writeFlashCrPsiz(2) # writes are 32 bits aligned
       self.setFlashCrPg()
-
       print('writing {0} bytes'.format(len(content)), end='')
       offset = 0
       t1 = time.time()
@@ -98,23 +107,17 @@
          size = len(content) - offset
          if size > 0x8000:
             size = 0x8000
-
          chunk = content[offset:offset + size]
          while len(chunk) % 4 != 0:
-            print('padding chunk')
             chunk = chunk + bytes([0])
-
          # Use simple mem32 writes:
          self.iface.write_mem32(address + offset, chunk)
-
          offset += size
          print('.', end='', flush=True)
       t2 = time.time()
       print('Done!')
       print('Speed: {0} bytes/second'.format(len(content)/(t2-t1)))
-
       self.lockFlash()
-
       # verfify program:
       self.verifyFlash(address, content)
    def eraseFlashSector(self, sector):
@@ -175,6 +178,7 @@
       mask = 1 << FLASH_F4_CR_LOCK
       return cr & mask == mask
    def unlockFlashIf(self):
+      FLASH_KEY1, FLASH_KEY2 = 0x45670123, 0xcdef89ab
       if self.isFlashLocked():
          self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY1)
          self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY2)
@@ -183,7 +187,6 @@
    def lockFlash(self):
       x = self.readFlashCr() | (1 << FLASH_F4_CR_LOCK)
       self.writeFlashCr(x)
-
    def readFlashSr(self):
       return self.iface.read_debug32(FLASH_F4_SR)
    def readFlashCr(self):
--- a/python/usb.py	Fri Jan 18 12:52:11 2013 +0100
+++ b/python/usb.py	Sat Jan 19 18:16:04 2013 +0100
@@ -107,7 +107,6 @@
 buildfunc('libusb_set_configuration', [libusb_device_handle_p, c_int])
 buildfunc('libusb_claim_interface', [libusb_device_handle_p, c_int])
 
-
 buildfunc('libusb_get_device_descriptor',\
    [libusb_device_p, libusb_device_descriptor_p])
 
@@ -193,6 +192,12 @@
    def __init__(self, device, handle_p):
       self.device = device
       self.handle_p = handle_p
+   def __del__(self):
+      self.close()
+   def close(self):
+      if self.handle_p:
+         libusb_close(self.handle_p)
+         self.handle_p = None
    def getConfiguration(self):
       config = c_int()
       r = libusb_get_configuration(self.handle_p, byref(config))