Mercurial > lcfOS
comparison python/ide/st-util.py @ 292:534b94b40aa8
Fixup reorganize
author | Windel Bouwman |
---|---|
date | Wed, 27 Nov 2013 08:06:42 +0100 |
parents | python/st-util.py@2ccd57b1d78c |
children | dcae6574c974 |
comparison
equal
deleted
inserted
replaced
290:7b38782ed496 | 292:534b94b40aa8 |
---|---|
1 #!/usr/bin/python | |
2 | |
3 import sys | |
4 from PyQt4.QtCore import * | |
5 from PyQt4.QtGui import * | |
6 import stlink, devices, stm32, usb | |
7 from devices import Interface, Device | |
8 from hexedit import HexEdit | |
9 | |
10 | |
11 class InformationDialog(QDialog): | |
12 def __init__(self, parent): | |
13 super().__init__(parent) | |
14 self.setWindowTitle('Info') | |
15 fl = QFormLayout(self) | |
16 if parent.stl: | |
17 fl.addRow('ST link version:', QLabel(parent.stl.Version)) | |
18 fl.addRow('Chip id:', QLabel('0x{0:X}'.format(parent.stl.ChipId))) | |
19 fl.addRow('Current mode:', QLabel(parent.stl.CurrentModeString)) | |
20 fl.addRow('Status:', QLabel(parent.stl.StatusString)) | |
21 | |
22 | |
23 class RegisterModel(QAbstractTableModel): | |
24 def __init__(self): | |
25 super().__init__() | |
26 self.regCount = 15 | |
27 self.device = None | |
28 | |
29 def rowCount(self, parent): | |
30 if parent.isValid(): | |
31 return 0 | |
32 if self.device: | |
33 return 21 # TODO make variable | |
34 else: | |
35 return 0 | |
36 | |
37 def setDevice(self, dev): | |
38 self.device = dev | |
39 self.modelReset.emit() | |
40 | |
41 def columnCount(self, parent): | |
42 if parent.isValid(): | |
43 return 0 | |
44 return 2 | |
45 | |
46 def data(self, index, role): | |
47 if index.isValid(): | |
48 row, col = index.row(), index.column() | |
49 if role == Qt.DisplayRole: | |
50 if col == 0: | |
51 if row == 15: | |
52 return 'PC' | |
53 elif row == 14: | |
54 return 'LR' | |
55 elif row == 13: | |
56 return 'SP' | |
57 else: | |
58 return 'R{0}'.format(row) | |
59 elif col == 1: | |
60 v = self.device.iface.read_reg(row) | |
61 return '0x{0:X}'.format(v) | |
62 | |
63 def setData(self, index, value, role): | |
64 if index.isValid(): | |
65 row = index.row() | |
66 col = index.column() | |
67 if role == Qt.EditRole and col == 1: | |
68 value = int(value, 16) | |
69 self.device.iface.write_reg(row, value) | |
70 return True | |
71 return False | |
72 | |
73 def flags(self, index): | |
74 if index.isValid(): | |
75 row = index.row() | |
76 col = index.column() | |
77 if col == 1: | |
78 return super().flags(index) | Qt.ItemIsEditable | |
79 return super().flags(index) | |
80 | |
81 def refresh(self): | |
82 if self.device: | |
83 fromIndex = self.index(0, 1) | |
84 toIndex = self.index(21, 1) | |
85 self.dataChanged.emit(fromIndex, toIndex) | |
86 | |
87 | |
88 class RegisterView(QTableView): | |
89 def __init__(self): | |
90 super().__init__() | |
91 self.mdl = RegisterModel() | |
92 self.setModel(self.mdl) | |
93 | |
94 def refresh(self): | |
95 if self.mdl.device: | |
96 self.setEnabled(not self.mdl.device.Running) | |
97 self.mdl.refresh() | |
98 | |
99 | |
100 class MemoryView(QWidget): | |
101 BlockSize = 0x100 | |
102 def __init__(self): | |
103 super().__init__() | |
104 l = QVBoxLayout(self) | |
105 l2 = QHBoxLayout() | |
106 l2.addWidget(QLabel('Address')) | |
107 self.addressLine = QLineEdit() | |
108 self.addressLine.setInputMask('Hhhhhhhh') | |
109 l2.addWidget(self.addressLine) | |
110 upButton = QPushButton('up') | |
111 l2.addWidget(upButton) | |
112 upButton.clicked.connect(self.doUp) | |
113 downButton = QPushButton('down') | |
114 downButton.clicked.connect(self.doDown) | |
115 l2.addWidget(downButton) | |
116 l.addLayout(l2) | |
117 self.device = None | |
118 self.hexEdit = HexEdit() | |
119 self.Address = 0x8000000 | |
120 l.addWidget(self.hexEdit) | |
121 self.addressLine.returnPressed.connect(self.refresh) | |
122 | |
123 def refresh(self): | |
124 address = self.Address | |
125 if self.device: | |
126 data = self.device.iface.read_mem32(address, self.BlockSize) | |
127 else: | |
128 data = bytearray(self.BlockSize) | |
129 self.hexEdit.bv.Data = data | |
130 self.hexEdit.bv.Offset = address | |
131 | |
132 def getAddress(self): | |
133 txt = self.addressLine.text() | |
134 return int(txt, 16) | |
135 | |
136 def doUp(self): | |
137 self.Address -= self.BlockSize | |
138 | |
139 def doDown(self): | |
140 self.Address += self.BlockSize | |
141 | |
142 def setAddress(self, address): | |
143 self.addressLine.setText('{0:08X}'.format(address)) | |
144 self.refresh() | |
145 Address = property(getAddress, setAddress) | |
146 def setDevice(self, dev): | |
147 self.device = dev | |
148 self.Address = 0x8000000 | |
149 | |
150 | |
151 class DebugToolbar(QToolBar): | |
152 statusChange = pyqtSignal() | |
153 codePosition = pyqtSignal(int) | |
154 def __init__(self): | |
155 super().__init__() | |
156 self.device = None | |
157 # generate actions: | |
158 def genAction(name, callback): | |
159 a = QAction(name, self) | |
160 a.triggered.connect(callback) | |
161 self.addAction(a) | |
162 return a | |
163 self.stepAction = genAction('Step', self.doStep) | |
164 self.runAction = genAction('Run', self.doRun) | |
165 self.stopAction = genAction('Stop', self.doHalt) | |
166 self.resetAction = genAction('Reset', self.doReset) | |
167 self.enableTraceAction = genAction('Enable trace', self.doEnableTrace) | |
168 self.updateEnables() | |
169 def updateEnables(self): | |
170 if self.device: | |
171 self.resetAction.setEnabled(True) | |
172 self.enableTraceAction.setEnabled(True) | |
173 self.runAction.setEnabled(not self.device.Running) | |
174 self.stepAction.setEnabled(not self.device.Running) | |
175 self.stopAction.setEnabled(self.device.Running) | |
176 self.statusChange.emit() | |
177 if not self.device.Running: | |
178 PC = 15 | |
179 v = self.device.iface.read_reg(PC) | |
180 self.codePosition.emit(v) | |
181 else: | |
182 self.resetAction.setEnabled(False) | |
183 self.enableTraceAction.setEnabled(False) | |
184 self.runAction.setEnabled(False) | |
185 self.stepAction.setEnabled(False) | |
186 self.stopAction.setEnabled(False) | |
187 def doStep(self): | |
188 self.device.iface.step() | |
189 self.updateEnables() | |
190 def doReset(self): | |
191 self.device.iface.reset() | |
192 self.updateEnables() | |
193 def doRun(self): | |
194 self.device.iface.run() | |
195 self.updateEnables() | |
196 def doHalt(self): | |
197 self.device.iface.halt() | |
198 self.updateEnables() | |
199 def doEnableTrace(self): | |
200 self.device.iface.traceEnable() | |
201 self.updateEnables() | |
202 def setDevice(self, dev): | |
203 self.device = dev | |
204 self.updateEnables() | |
205 | |
206 | |
207 class FlashTool(QWidget): | |
208 def __init__(self): | |
209 super().__init__() | |
210 # TODO! | |
211 | |
212 | |
213 class DeviceTreeModel(QAbstractItemModel): | |
214 def __init__(self): | |
215 super().__init__() | |
216 self.chipPixmap = QPixmap('icons/chip.png').scaled(32, 32) | |
217 self.hardwarePixmap = QPixmap('icons/hardware.png').scaled(32, 32) | |
218 self.refresh() | |
219 def refresh(self): | |
220 """ Check all usb interfaces for interfaces """ | |
221 self.interfaces = devices.createInterfaces() | |
222 self.devices = [] | |
223 self.modelReset.emit() | |
224 def addDevice(self, device): | |
225 if device.iface in [lambda d: d.iface for d in self.devices]: | |
226 print('device already open') | |
227 return | |
228 self.devices.append(device) | |
229 self.modelReset.emit() | |
230 def index(self, row, column, parent): | |
231 if parent.isValid(): | |
232 ip = parent.internalPointer() | |
233 if isinstance(ip, Interface): | |
234 devs = [d for d in self.devices if d.iface is ip] | |
235 return self.createIndex(row, column, devs[row]) | |
236 else: | |
237 iface = self.interfaces[row] | |
238 return self.createIndex(row, column, iface) | |
239 return idx | |
240 def parent(self, index): | |
241 if index.isValid(): | |
242 ip = index.internalPointer() | |
243 if isinstance(ip, Interface): | |
244 return QModelIndex() | |
245 elif isinstance(ip, Device): | |
246 iface = ip.iface | |
247 row = self.interfaces.index(iface) | |
248 return self.createIndex(row, 0, iface) | |
249 return QModelIndex() | |
250 def rowCount(self, parent): | |
251 if parent.isValid(): | |
252 # non-root level: | |
253 ip = parent.internalPointer() | |
254 if isinstance(ip, Interface): | |
255 devs = [d for d in self.devices if d.iface is ip] | |
256 return len(devs) | |
257 else: | |
258 # root level: | |
259 return len(self.interfaces) | |
260 return 0 | |
261 def columnCount(self, parent): | |
262 return 1 | |
263 def data(self, index, role): | |
264 if index.isValid(): | |
265 ip = index.internalPointer() | |
266 if role == Qt.DisplayRole: | |
267 return str(ip) | |
268 elif role == Qt.DecorationRole: | |
269 if isinstance(ip, Interface): | |
270 return self.hardwarePixmap | |
271 if isinstance(ip, Device): | |
272 return self.chipPixmap | |
273 | |
274 class DeviceExplorer(QTreeView): | |
275 """ Lists all interfaces plugged in and allows selection """ | |
276 deviceSelected = pyqtSignal(Device) | |
277 def __init__(self): | |
278 super().__init__() | |
279 self.mdl = DeviceTreeModel() | |
280 self.setModel(self.mdl) | |
281 self.activated.connect(self.openItem) | |
282 self.header().close() | |
283 self.customContextMenuRequested.connect(self.openMenu) | |
284 self.setContextMenuPolicy(Qt.CustomContextMenu) | |
285 def openItem(self, idx): | |
286 if idx.isValid(): | |
287 ip = idx.internalPointer() | |
288 if isinstance(ip, Interface): | |
289 if not ip.IsOpen: | |
290 try: | |
291 ip.open() | |
292 except usb.UsbError as e: | |
293 QMessageBox.critical(self, "Error", 'Error opening interface: "{0}"'.format(e)) | |
294 else: | |
295 # Try to get a device: | |
296 self.mdl.addDevice(ip.createDevice()) | |
297 if isinstance(ip, Device): | |
298 self.deviceSelected.emit(ip) | |
299 def openMenu(self, pt): | |
300 idx = self.indexAt(pt) | |
301 menu = QMenu() | |
302 menu.addAction('Refresh', self.mdl.refresh) | |
303 if idx.isValid(): | |
304 ip = idx.internalPointer() | |
305 if isinstance(ip, Interface): | |
306 if ip.IsOpen: | |
307 def closeInterface(): | |
308 self.mdl.closeInterface(ip) | |
309 menu.addAction('Close', closeInterface) | |
310 else: | |
311 def openInterface(): | |
312 ip.open() | |
313 # Try to get a device: | |
314 self.mdl.addDevice(ip.createDevice()) | |
315 menu.addAction('Open', openInterface) | |
316 elif isinstance(ip, Device): | |
317 def selectDevice(): | |
318 self.deviceSelected.emit(ip) | |
319 menu.addAction('Select', selectDevice) | |
320 menu.exec(self.mapToGlobal(pt)) | |
321 | |
322 | |
323 class StUtil(QMainWindow): | |
324 connected = pyqtSignal(bool) | |
325 def __init__(self): | |
326 super().__init__() | |
327 self.stl = None | |
328 def buildAction(name, callback, shortcut=None): | |
329 a = QAction(name, self) | |
330 a.triggered.connect(callback) | |
331 if shortcut: | |
332 a.setShortcut(shortcut) | |
333 return a | |
334 mb = self.menuBar() | |
335 fileMenu = mb.addMenu("File") | |
336 self.connectAction = buildAction('Connect', self.connect) | |
337 fileMenu.addAction(self.connectAction) | |
338 self.disconnectAction = buildAction('Disconnect', self.disconnect) | |
339 fileMenu.addAction(self.disconnectAction) | |
340 | |
341 self.miscMenu = mb.addMenu("Misc") | |
342 infoAction = buildAction('Info', self.info) | |
343 self.miscMenu.addAction(infoAction) | |
344 | |
345 sb = self.statusBar() | |
346 | |
347 devexplr = DeviceExplorer() | |
348 self.setCentralWidget(devexplr) | |
349 devexplr.deviceSelected.connect(self.handleDeviceSelected) | |
350 | |
351 self.connected.connect(self.handleConnectedChange) | |
352 self.connected.emit(False) | |
353 def handleDeviceSelected(self, dev): | |
354 self.dev = dev | |
355 self.handleConnectedChange(True) | |
356 def handleConnectedChange(self, state): | |
357 self.miscMenu.setEnabled(state) | |
358 self.connectAction.setEnabled(not state) | |
359 self.disconnectAction.setEnabled(state) | |
360 msg = 'Connected!' if state else 'Disconnected!' | |
361 self.statusBar().showMessage(msg) | |
362 def info(self): | |
363 infoDialog = InformationDialog(self) | |
364 infoDialog.exec() | |
365 def connect(self): | |
366 try: | |
367 self.stl = stlink.STLink() | |
368 self.stl.open() | |
369 except (stlink.STLinkException, usb.UsbError) as e: | |
370 QMessageBox.warning(self, "Error", str(e)) | |
371 self.stl = None | |
372 if self.stl: | |
373 self.connected.emit(True) | |
374 def disconnect(self): | |
375 if self.stl: | |
376 self.stl.close() | |
377 self.connected.emit(False) | |
378 self.stl = None | |
379 | |
380 if __name__ == '__main__': | |
381 app = QApplication(sys.argv) | |
382 stu = StUtil() | |
383 stu.show() | |
384 app.exec() | |
385 |