QTools  7.4.1
Collection of Host-Based Tools
Loading...
Searching...
No Matches
qview.py
Go to the documentation of this file.
1#!/usr/bin/env python
2
3#=============================================================================
4# QView Monitoring for QP/Spy
5# Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
6#
7# SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
8#
9# This software is dual-licensed under the terms of the open source GNU
10# General Public License version 3 (or any later version), or alternatively,
11# under the terms of one of the closed source Quantum Leaps commercial
12# licenses.
13#
14# The terms of the open source GNU General Public License version 3
15# can be found at: <www.gnu.org/licenses/gpl-3.0>
16#
17# The terms of the closed source Quantum Leaps commercial licenses
18# can be found at: <www.state-machine.com/licensing>
19#
20# Redistributions in source code must retain this top-level comment block.
21# Plagiarizing this software to sidestep the license obligations is illegal.
22#
23# Contact information:
24# <www.state-machine.com>
25# <info@state-machine.com>
26#=============================================================================
27
28# pylint: disable=missing-module-docstring,
29# pylint: disable=missing-class-docstring,
30# pylint: disable=missing-function-docstring
31# pylint: disable=broad-except
32
33from tkinter import *
34from tkinter.ttk import * # override the basic Tk widgets with Ttk widgets
35from tkinter.simpledialog import *
36from struct import pack
37
38import socket
39import time
40import sys
41import struct
42import os
43import traceback
44import webbrowser
45
46#=============================================================================
47# QView GUI
48# https://www.state-machine.com/qtools/qview.html
49#
50class QView:
51 ## current version of QView
52 VERSION = 741
53
54 # public static variables...
55 ## menu to be customized
56 custom_menu = None
57
58 ## canvas to be customized
59 canvas = None
60
61 ## frame to be customized
62 frame = None
63
64 # private class variables...
65 _text_lines = "end - 500 lines"
66 _attach_dialog = None
67 _have_info = False
68 _reset_request = False
69 _gui = None
70 _inst = None
71 _err = 0
72 _glb_filter = 0x00000000000000000000000000000000
73 _loc_filter = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
74
75 _dtypes = ("8-bit", "16-bit", "32-bit")
76 _dsizes = (1, 2, 4)
77
78 #-------------------------------------------------------------------------
79 # main entry point to QView
80 @staticmethod
81 def main(cust):
82 # set the only instance of QView, which might be customized
83 # sublcass of QView
84 QView._inst = cust
85
86 # process command-line arguments...
87 argv = sys.argv
88 argc = len(argv)
89 arg = 1 # skip the "qview" argument
90
91 if "-h" in argv or "--help" in argv or "?" in argv:
92 print("\nUsage: python qview.pyw "
93 "[qspy_host[:udp_port]] [local_port]\n\n"
94 "help at: https://www.state-machine.com/qtools/QView.html")
95 sys.exit(0)
96
97 if arg < argc:
98 host_port = argv[arg].split(":")
99 arg += 1
100 if len(host_port) > 0:
101 QSpy._host_addr[0] = host_port[0]
102 if len(host_port) > 1:
103 QSpy._host_addr[1] = int(host_port[1])
104
105 if arg < argc:
106 QSpy._local_port = int(argv[arg])
107
108 QSpy._host_addr = tuple(QSpy._host_addr) # convert to immutable tuple
109 #print("Connection: ", QSpy._host_addr, QSpy._local_port)
110
111 # create the QView GUI
112 QView._gui = Tk()
113 QView._gui.title("QView " + \
114 "%d.%d.%d"%(QView.VERSION//100, \
115 (QView.VERSION//10) % 10, \
116 QView.VERSION % 10))
117 QView._init_gui(QView._gui)
118
119 err = QSpy._init()
120 if err:
121 sys.exit(err) # simple return: event-loop is not running yet
122
123
124 QView._inst.on_init()
125
126 QSpy._attach()
127 QView._gui.mainloop()
128 QView._gui = None
129 QSpy._detach()
130
131 sys.exit(QView._err)
132
133 #---------------------------------------------------------------------------
134 # DSL for QView customizations
135
136 # kinds of objects for current_obj()...
137 OBJ_SM = 0
138 OBJ_AO = 1
139 OBJ_MP = 2
140 OBJ_EQ = 3
141 OBJ_TE = 4
142 OBJ_AP = 5
143
144 # global filter groups...
145 GRP_ALL= 0xF0
146 GRP_SM = 0xF1
147 GRP_AO = 0xF2
148 GRP_MP = 0xF3
149 GRP_EQ = 0xF4
150 GRP_TE = 0xF5
151 GRP_QF = 0xF6
152 GRP_SC = 0xF7
153 GRP_SEM= 0xF8
154 GRP_MTX= 0xF9
155 GRP_U0 = 0xFA
156 GRP_U1 = 0xFB
157 GRP_U2 = 0xFC
158 GRP_U3 = 0xFD
159 GRP_U4 = 0xFE
160 GRP_UA = 0xFF
161 GRP_ON = GRP_ALL
162 GRP_OFF= -GRP_ALL
163
164 # local filter groups...
165 IDS_ALL= 0xF0
166 IDS_AO = (0x80 + 0)
167 IDS_EP = (0x80 + 64)
168 IDS_EQ = (0x80 + 80)
169 IDS_AP = (0x80 + 96)
170
171 # on_init() callback
172 def on_init(self):
173 pass
174
175 # on_run() callback
176 def on_reset(self):
177 pass
178
179 # on_run() callback
180 def on_run(self):
181 pass
182
183 ## @brief Send the RESET packet to the Target
184 @staticmethod
185 def reset_target(*args):
186 if QView._have_info:
187 QSpy._sendTo(pack("<B", QSpy._TRGT_RESET))
188 else:
189 QView._reset_request = True
190
191 ## @brief executes a given command in the Target
192 # @sa qutest_dsl.command()
193 @staticmethod
194 def command(cmdId, param1 = 0, param2 = 0, param3 = 0):
195 if isinstance(cmdId, int):
196 QSpy._sendTo(pack("<BBIII", QSpy._TRGT_COMMAND,
197 cmdId, param1, param2, param3))
198 else:
199 QSpy._sendTo(pack("<BBIII", QSpy._QSPY_SEND_COMMAND,
200 0, param1, param2, param3),
201 cmdId) # add string command ID to end
202
203 ## @brief trigger system clock tick in the Target
204 # @sa qutest_dsl.tick()
205 @staticmethod
206 def tick(tick_rate = 0):
207 QSpy._sendTo(pack("<BB", QSpy._TRGT_TICK, tick_rate))
208
209 ## @brief peeks data in the Target
210 # @sa qutest_dsl.peek()
211 @staticmethod
212 def peek(offset, size, num):
213 QSpy._sendTo(pack("<BHBB", QSpy._TRGT_PEEK, offset, size, num))
214
215 ## @brief pokes data into the Target
216 # @sa qutest_dsl.poke()
217 @staticmethod
218 def poke(offset, size, data):
219 fmt = "<BHBB" + ("x","B","H","x","I")[size]
220 QSpy._sendTo(pack(fmt, QSpy._TRGT_POKE, offset, size, 1, data))
221
222 ## @brief Set/clear the Global-Filter in the Target.
223 # @sa qutest_dsl.glb_filter()
224 @staticmethod
225 def glb_filter(*args):
226 # internal helper function
227 def _apply(mask, is_neg):
228 if is_neg:
229 QView._glb_filter &= ~mask
230 else:
231 QView._glb_filter |= mask
232
233 QView._glb_filter = 0
234 for arg in args:
235 # NOTE: positive filter argument means 'add' (allow),
236 # negative filter argument meand 'remove' (disallow)
237 is_neg = False
238 if isinstance(arg, str):
239 is_neg = (arg[0] == '-') # is request?
240 if is_neg:
241 arg = arg[1:]
242 try:
243 arg = QSpy._QS.index(arg)
244 except Exception:
245 QView._MessageDialog("Error in glb_filter()",
246 'arg="' + arg + '"\n' +
247 traceback.format_exc(3))
248 sys.exit(-5) # return: event-loop might not be running yet
249 else:
250 is_neg = (arg < 0)
251 if is_neg:
252 arg = -arg
253
254 if arg < 0x7F:
255 _apply(1 << arg, is_neg)
256 elif arg == GRP_ON:
257 _apply(QSpy._GLB_FLT_MASK_ALL, is_neg)
258 elif arg == GRP_SM:
259 _apply(QSpy._GLB_FLT_MASK_SM, is_neg)
260 elif arg == GRP_AO:
261 _apply(QSpy._GLB_FLT_MASK_AO, is_neg)
262 elif arg == GRP_MP:
263 _apply(QSpy._GLB_FLT_MASK_MP, is_neg)
264 elif arg == GRP_EQ:
265 _apply(QSpy._GLB_FLT_MASK_EQ, is_neg)
266 elif arg == GRP_TE:
267 _apply(QSpy._GLB_FLT_MASK_TE, is_neg)
268 elif arg == GRP_QF:
269 _apply(QSpy._GLB_FLT_MASK_QF, is_neg)
270 elif arg == GRP_SC:
271 _apply(QSpy._GLB_FLT_MASK_SC, is_neg)
272 elif arg == GRP_SEM:
273 _apply(QSpy._GLB_FLT_MASK_SEM, is_neg)
274 elif arg == GRP_MTX:
275 _apply(QSpy._GLB_FLT_MASK_MTX, is_neg)
276 elif arg == GRP_U0:
277 _apply(QSpy._GLB_FLT_MASK_U0, is_neg)
278 elif arg == GRP_U1:
279 _apply(QSpy._GLB_FLT_MASK_U1, is_neg)
280 elif arg == GRP_U2:
281 _apply(QSpy._GLB_FLT_MASK_U2, is_neg)
282 elif arg == GRP_U3:
283 _apply(QSpy._GLB_FLT_MASK_U3, is_neg)
284 elif arg == GRP_U4:
285 _apply(QSpy._GLB_FLT_MASK_U4, is_neg)
286 elif arg == GRP_UA:
287 _apply(QSpy._GLB_FLT_MASK_UA, is_neg)
288 else:
289 assert 0, "invalid global filter arg=0x%X"%(arg)
290
291 QSpy._sendTo(pack("<BBQQ", QSpy._TRGT_GLB_FILTER, 16,
292 QView._glb_filter & 0xFFFFFFFFFFFFFFFF,
293 QView._glb_filter >> 64))
294 QView._updateMenus()
295
296 ## @brief Set/clear the Local-Filter in the Target.
297 # @sa qutest_dsl.loc_filter()
298 @staticmethod
299 def loc_filter(*args):
300 # internal helper function
301 def _apply(mask, is_neg):
302 if is_neg:
303 QView._loc_filter &= ~mask
304 else:
305 QView._loc_filter |= mask
306
307 for arg in args:
308 # NOTE: positive filter argument means 'add' (allow),
309 # negative filter argument means 'remove' (disallow)
310 is_neg = (arg < 0)
311 if is_neg:
312 arg = -arg
313
314 if arg < 0x7F:
315 _apply(1 << arg, is_neg)
316 elif arg == IDS_ALL:
317 _apply(QSpy._LOC_FLT_MASK_ALL, is_neg)
318 elif arg == IDS_AO:
319 _apply(QSpy._LOC_FLT_MASK_AO, is_neg)
320 elif arg == IDS_EP:
321 _apply(QSpy._LOC_FLT_MASK_EP, is_neg)
322 elif arg == IDS_EQ:
323 _apply(QSpy._LOC_FLT_MASK_EQ, is_neg)
324 elif arg == IDS_AP:
325 _apply(QSpy._LOC_FLT_MASK_AP, is_neg)
326 else:
327 assert 0, "invalid local filter arg=0x%X"%(arg)
328
329 QSpy._sendTo(pack("<BBQQ", QSpy._TRGT_LOC_FILTER, 16,
330 QView._loc_filter & 0xFFFFFFFFFFFFFFFF,
331 QView._loc_filter >> 64))
332
333 ## @brief Set/clear the Active-Object Local-Filter in the Target.
334 # @sa qutest_dsl.ao_filter()
335 @staticmethod
336 def ao_filter(obj_id):
337 # NOTE: positive obj_id argument means 'add' (allow),
338 # negative obj_id argument means 'remove' (disallow)
339 remove = 0
340 QView._locAO_OBJ.set(obj_id)
341 QView._menu_loc_filter.entryconfig("AO-OBJ...",
342 accelerator=QView._locAO_OBJ.get())
343 if isinstance(obj_id, str):
344 if obj_id[0:1] == '-': # is it remvoe request?
345 obj_id = obj_id[1:]
346 remove = 1
347 QSpy._sendTo(pack("<BB" + QSpy._fmt[QSpy._size_objPtr],
348 QSpy._QSPY_SEND_AO_FILTER, remove, 0),
349 obj_id) # add string object-ID to end
350 else:
351 if obj_id < 0:
352 obj_id = -obj_id
353 remove = 1
354 QSpy._sendTo(pack("<BB" + QSpy._fmt[QSpy._size_objPtr],
355 QSpy._TRGT_AO_FILTER, remove, obj_id))
356
357 ## @brief Set the Current-Object in the Target.
358 # @sa qutest_dsl.current_obj()
359 @staticmethod
360 def current_obj(obj_kind, obj_id):
361 if obj_id == "":
362 return
363 if isinstance(obj_id, int):
364 QSpy._sendTo(pack("<BB" + QSpy._fmt[QSpy._size_objPtr],
365 QSpy._TRGT_CURR_OBJ, obj_kind, obj_id))
366 obj_id = "0x%08X"%(obj_id)
367 else:
368 QSpy._sendTo(pack("<BB" + QSpy._fmt[QSpy._size_objPtr],
369 QSpy._QSPY_SEND_CURR_OBJ, obj_kind, 0), obj_id)
370
371 QView._currObj[obj_kind].set(obj_id)
372 QView._menu_curr_obj.entryconfig(obj_kind, accelerator=obj_id)
373 QView._updateMenus()
374
375 ## @brief query the @ref current_obj() "current object" in the Target
376 # @sa qutest_dsl.query_curr()
377 @staticmethod
378 def query_curr(obj_kind):
379 QSpy._sendTo(pack("<BB", QSpy._TRGT_QUERY_CURR, obj_kind))
380
381 ## @brief publish a given event to subscribers in the Target
382 # @sa qutest_dsl.publish()
383 @staticmethod
384 def publish(signal, params = None):
385 QSpy._sendEvt(QSpy._EVT_PUBLISH, signal, params)
386
387 ## @brief post a given event to the current AO object in the Target
388 # @sa qutest_dsl.post()
389 @staticmethod
390 def post(signal, params = None):
391 QSpy._sendEvt(QSpy._EVT_POST, signal, params)
392
393 ## @brief take the top-most initial transition in the
394 # current SM object in the Target
395 # @sa qutest_dsl.init()
396 @staticmethod
397 def init(signal = 0, params = None):
398 QSpy._sendEvt(QSpy._EVT_INIT, signal, params)
399
400 ## @brief dispatch a given event in the current SM object in the Target
401 # @sa qutest_dsl.dispatch()
402 @staticmethod
403 def dispatch(signal, params = None):
404 QSpy._sendEvt(QSpy._EVT_DISPATCH, signal, params)
405
406 ## @brief Unpack a QS trace record
407 #
408 # @description
409 # The qunpack() facility is similar to Python `struct.unpack()`,
410 # specifically designed for unpacking binary QP/Spy packets.
411 # qunpack() handles all data formats supported by struct.unpack()`,
412 # plus data formats specific to QP/Spy. The main benefit of qunpack()
413 # is that it automatically applies the Target-supplied info about
414 # various the sizes of various elements, such as Target timestamp,
415 # Target object-pointer, Target event-signal, zero-terminated string, etc.
416 ## @brief pokes data into the Target
417 # @sa qutest_dsl.poke()
418 #
419 # @param[in] fmt format string
420 # @param[in] bstr byte-string to unpack
421 #
422 # @returns
423 # The result is a tuple with elements corresponding to the format items.
424 #
425 # The additional format characters have the following meaning:
426 #
427 # - T : QP/Spy timestamp -> integer, 2..4-bytes (Target dependent)
428 # - O : QP/Spy object pointer -> integer, 2..8-bytes (Target dependent)
429 # - F : QP/Spy function pointer -> integer, 2..8-bytes (Target dependent)
430 # - S : QP/Spy event signal -> integer, 1..4-bytes (Target dependent)
431 # - Z : QP/Spy zero-terminated string -> string of n-bytes (variable length)
432 #
433 # @usage
434 # @include qunpack.py
435 #
436 @staticmethod
437 def qunpack(fmt, bstr):
438 n = 0
439 m = len(fmt)
440 bord = "<" # default little-endian byte order
441 if fmt[0:1] in ("@", "=", "<", ">", "!"):
442 bord = fmt[0:1]
443 n += 1
444 data = []
445 offset = 0
446 while n < m:
447 fmt1 = fmt[n:(n+1)]
448 u = ()
449 if fmt1 in ("B", "b", "c", "x", "?"):
450 u = struct.unpack_from(bord + fmt1, bstr, offset)
451 offset += 1
452 elif fmt1 in ("H", "h"):
453 u = struct.unpack_from(bord + fmt1, bstr, offset)
454 offset += 2
455 elif fmt1 in ("I", "L", "i", "l", "f"):
456 u = struct.unpack_from(bord + fmt1, bstr, offset)
457 offset += 4
458 elif fmt1 in ("Q", "q", "d"):
459 u = struct.unpack_from(bord + fmt1, bstr, offset)
460 offset += 8
461 elif fmt1 == "T":
462 u = struct.unpack_from(bord + QSpy._fmt[QSpy._size_tstamp],
463 bstr, offset)
464 offset += QSpy._size_tstamp
465 elif fmt1 == "O":
466 u = struct.unpack_from(bord + QSpy._fmt[QSpy._size_objPtr],
467 bstr, offset)
468 offset += QSpy._size_objPtr
469 elif fmt1 == "F":
470 u = struct.unpack_from(bord + QSpy._fmt[QSpy._size_funPtr],
471 bstr, offset)
472 offset += QSpy._size_funPtr
473 elif fmt1 == "S":
474 u = struct.unpack_from(bord + QSpy._fmt[QSpy._size_sig],
475 bstr, offset)
476 offset += QSpy._size_sig
477 elif fmt1 == "Z": # zero-terminated C-string
478 end = offset
479 while bstr[end]: # not zero-terminator?
480 end += 1
481 u = (bstr[offset:end].decode(),)
482 offset = end + 1 # inclue the terminating zero
483 else:
484 assert 0, "qunpack(): unknown format"
485 data.extend(u)
486 n += 1
487 return tuple(data)
488
489
490 @staticmethod
491 def _init_gui(root):
492 Tk.report_callback_exception = QView._trap_error
493
494 # menus...............................................................
495 main_menu = Menu(root, tearoff=0)
496 root.config(menu=main_menu)
497
498 # File menu...
499 m = Menu(main_menu, tearoff=0)
500 m.add_command(label="Save QSPY Dictionaries",
501 command=QView._onSaveDict)
502 m.add_command(label="Toggle QSPY Text Output",
503 command=QView._onSaveText)
504 m.add_command(label="Toggle QSPY Binary Output",
505 command=QView._onSaveBin)
506 m.add_command(label="Toggle Matlab Output",
507 command=QView._onSaveMatlab)
508 m.add_command(label="Toggle Sequence Output",
509 command=QView._onSaveSequence)
510 m.add_separator()
511 m.add_command(label="Exit", command=QView._quit)
512 main_menu.add_cascade(label="File", menu=m)
513
514 # View menu...
515 m = Menu(main_menu, tearoff=0)
516 QView._view_canvas = IntVar()
517 QView._view_frame = IntVar()
518 m.add_checkbutton(label="Canvas", variable=QView._view_canvas,
519 command=QView._onCanvasView)
520 m.add_checkbutton(label="Frame", variable=QView._view_frame,
521 command=QView._onFrameView)
522 main_menu.add_cascade(label="View", menu=m)
523
524 # Global-Filters menu...
525 m = Menu(main_menu, tearoff=0)
526 m.add_command(label="SM Group...", accelerator="[NONE]",
527 command=QView._onGlbFilter_SM)
528 m.add_command(label="AO Group...", accelerator="[NONE]",
529 command=QView._onGlbFilter_AO)
530 m.add_command(label="QF Group...", accelerator="[NONE]",
531 command=QView._onGlbFilter_QF)
532 m.add_command(label="TE Group...", accelerator="[NONE]",
533 command=QView._onGlbFilter_TE)
534 m.add_command(label="MP Group...", accelerator="[NONE]",
535 command=QView._onGlbFilter_MP)
536 m.add_command(label="EQ Group...", accelerator="[NONE]",
537 command=QView._onGlbFilter_EQ)
538 m.add_command(label="SC Group...", accelerator="[NONE]",
539 command=QView._onGlbFilter_SC)
540 m.add_command(label="SEM Group...", accelerator="[NONE]",
541 command=QView._onGlbFilter_SEM)
542 m.add_command(label="MTX Group...", accelerator="[NONE]",
543 command=QView._onGlbFilter_MTX)
544 m.add_separator()
545 m.add_command(label="U0 Group...", accelerator="[NONE]",
546 command=QView._onGlbFilter_U0)
547 m.add_command(label="U1 Group...", accelerator="[NONE]",
548 command=QView._onGlbFilter_U1)
549 m.add_command(label="U2 Group...", accelerator="[NONE]",
550 command=QView._onGlbFilter_U2)
551 m.add_command(label="U3 Group...", accelerator="[NONE]",
552 command=QView._onGlbFilter_U3)
553 m.add_command(label="U4 Group...", accelerator="[NONE]",
554 command=QView._onGlbFilter_U4)
555 main_menu.add_cascade(label="Global-Filters", menu=m)
556 QView._menu_glb_filter = m
557
558 # Local-Filters menu...
559 m = Menu(main_menu, tearoff=0)
560 m.add_command(label="AO IDs...", accelerator="[NONE]",
561 command=QView._onLocFilter_AO)
562 m.add_command(label="EP IDs...", accelerator="[NONE]",
563 command=QView._onLocFilter_EP)
564 m.add_command(label="EQ IDs...", accelerator="[NONE]",
565 command=QView._onLocFilter_EQ)
566 m.add_command(label="AP IDs...", accelerator="[NONE]",
567 command=QView._onLocFilter_AP)
568 m.add_separator()
569 m.add_command(label="AO-OBJ...", command=QView._onLocFilter_AO_OBJ)
570 main_menu.add_cascade(label="Local-Filters", menu=m)
571 QView._menu_loc_filter = m
572
573 # Current-Obj menu...
574 m = Menu(main_menu, tearoff=0)
575 m.add_command(label="SM_OBJ", command=QView._onCurrObj_SM)
576 m.add_command(label="AO_OBJ", command=QView._onCurrObj_AO)
577 m.add_command(label="MP_OBJ", command=QView._onCurrObj_MP)
578 m.add_command(label="EQ_OBJ", command=QView._onCurrObj_EQ)
579 m.add_command(label="TE_OBJ", command=QView._onCurrObj_TE)
580 m.add_command(label="AP_OBJ", command=QView._onCurrObj_AP)
581 m.add_separator()
582 m1 = Menu(m, tearoff=0)
583 m1.add_command(label="SM_OBJ", command=QView._onQueryCurr_SM)
584 m1.add_command(label="AO_OBJ", command=QView._onQueryCurr_AO)
585 m1.add_command(label="MP_OBJ", command=QView._onQueryCurr_MP)
586 m1.add_command(label="EQ_OBJ", command=QView._onQueryCurr_EQ)
587 m1.add_command(label="TE_OBJ", command=QView._onQueryCurr_TE)
588 m1.add_command(label="AP_OBJ", command=QView._onQueryCurr_AP)
589 m.add_cascade(label="Query Current", menu=m1)
590 main_menu.add_cascade(label="Current-Obj", menu=m)
591 QView._menu_curr_obj = m
592
593 # Commands menu...
594 m = Menu(main_menu, tearoff=0)
595 m.add_command(label="Reset Target", command=QView.reset_target)
596 m.add_command(label="Query Target Info", command=QView._onTargetInfo)
597 m.add_command(label="Tick[0]", command=QView._onTick0)
598 m.add_command(label="Tick[1]", command=QView._onTick1)
599 m.add_command(label="Command...", command=QView._CommandDialog)
600 m.add_command(label="Show Note...", command=QView._NoteDialog)
601 m.add_command(label="Clear QSPY Screen", command=QView._onClearQspy)
602 m.add_separator()
603 m.add_command(label="Peek...", command=QView._PeekDialog)
604 m.add_command(label="Poke...", command=QView._PokeDialog)
605 main_menu.add_cascade(label="Commands", menu=m)
606 QView._menu_commands = m
607
608 # Events menu...
609 m = Menu(main_menu, tearoff=0)
610 m.add_command(label="Publish...", command=QView._onEvt_PUBLISH)
611 m.add_command(label="Post...", command=QView._onEvt_POST)
612 m.add_command(label="Init SM", command=QView._onEvt_INIT)
613 m.add_command(label="Dispatch...", command=QView._onEvt_DISPATCH)
614 main_menu.add_cascade(label="Events", menu=m)
615 QView._menu_events = m
616
617 # Custom menu...
618 m = Menu(main_menu, tearoff=0)
619 m.add_separator()
620 main_menu.add_cascade(label="Custom", menu=m)
621 QView.custom_menu = m
622
623 # Help menu...
624 m = Menu(main_menu, tearoff=0)
625 m.add_command(label="Online Help", command=QView._onHelp)
626 m.add_separator()
627 m.add_command(label="About...", command=QView._onAbout)
628 main_menu.add_cascade(label="Help", menu=m)
629
630 # statusbar (pack before text-area) ..................................
631 QView._scroll_text = IntVar()
632 QView._scroll_text.set(1) # text scrolling enabled
633 QView._echo_text = IntVar()
634 QView._echo_text.set(0) # text echo disabled
635 frame = Frame(root, borderwidth=1, relief="raised")
636 QView._target = Label(frame, height=2,
637 text="Target: " + QSpy._fmt_target)
638 QView._target.pack(side="left")
639 c = Checkbutton(frame, text="Scroll", variable=QView._scroll_text)
640 c.pack(side="right")
641 c = Checkbutton(frame, text="Echo", variable=QView._echo_text,
642 command=QSpy._reattach)
643 c.pack(side="right")
644 QView._tx = Label(frame, width=6, anchor=E,
645 borderwidth=1, relief="sunken")
646 QView._tx.pack(side="right")
647 Label(frame, text="Tx ").pack(side="right")
648 QView._rx = Label(frame, width=8, anchor=E,
649 borderwidth=1, relief="sunken")
650 QView._rx.pack(side="right")
651 Label(frame, text="Rx ").pack(side="right")
652 frame.pack(side="bottom", fill="x", pady=0)
653
654 # text-area with scrollbar............................................
655 frame = Frame(root, borderwidth=1, relief="sunken")
656 scrollbar = Scrollbar(frame)
657 QView._text = Text(frame, width=100, height=30,
658 wrap="word", yscrollcommand=scrollbar.set)
659 QView._text.bind("<Key>", lambda e: "break") # read-only text
660 scrollbar.config(command=QView._text.yview)
661 scrollbar.pack(side="right", fill="y")
662 QView._text.pack(side="left", fill="both", expand=True)
663 frame.pack(side="left", fill="both", expand=True)
664
665 # canvas..............................................................
666 QView._canvas_toplevel = Toplevel()
667 QView._canvas_toplevel.withdraw() # start not showing
668 QView._canvas_toplevel.protocol("WM_DELETE_WINDOW",
669 QView._onCanvasClose)
670 QView._canvas_toplevel.title("QView -- Canvas")
671 QView.canvas = Canvas(QView._canvas_toplevel)
672 QView.canvas.pack()
673
674 # frame..............................................................
675 QView._frame_toplevel = Toplevel()
676 QView._frame_toplevel.withdraw() # start not showing
677 QView._frame_toplevel.protocol("WM_DELETE_WINDOW",
678 QView._onFrameClose)
679 QView._frame_toplevel.title("QView -- Frame")
680 QView.frame = Frame(QView._frame_toplevel)
681 QView.frame.pack()
682
683 # tkinter variables for dialog boxes .................................
684 QView._locAO_OBJ = StringVar()
685 QView._currObj = (StringVar(), StringVar(), StringVar(),
686 StringVar(), StringVar(), StringVar())
687 QView._command = StringVar()
688 QView._command_p1 = StringVar()
689 QView._command_p2 = StringVar()
690 QView._command_p3 = StringVar()
691 QView._note = StringVar()
692 QView._note_kind = StringVar(value=0)
693 QView._peek_offs = StringVar()
694 QView._peek_dtype = StringVar(value=QView._dtypes[2])
695 QView._peek_len = StringVar()
696 QView._poke_offs = StringVar()
697 QView._poke_dtype = StringVar(value=QView._dtypes[2])
698 QView._poke_data = StringVar()
699 QView._evt_act = StringVar()
700 QView._evt_sig = StringVar()
701 QView._evt_par = (StringVar(), StringVar(), StringVar(),
702 StringVar(), StringVar(), StringVar(),
703 StringVar(), StringVar(), StringVar())
704 QView._evt_dtype = (StringVar(), StringVar(), StringVar(),
705 StringVar(), StringVar(), StringVar(),
706 StringVar(), StringVar(), StringVar())
707 for i in range(len(QView._evt_par)):
708 QView._evt_dtype[i].set(QView._dtypes[2])
709
710 QView._updateMenus()
711
712
713 # public static functions...
714
715 ## Set QView customization.
716 # @param cust the customization class instance
717 @staticmethod
718 def customize(cust):
719 print("This QView version no longer supports QView.customize()\n",
720 " use QView.main(<cust()>) instead")
721 sys.exit(-1)
722
723 ## Print a string to the Text area
724 @staticmethod
725 def print_text(string):
726 QView._text.delete(1.0, QView._text_lines)
727 QView._text.insert(END, "\n")
728 QView._text.insert(END, string)
729 if QView._scroll_text.get():
730 QView._text.yview_moveto(1) # scroll to the bottom
731
732 ## Make the canvas visible
733 # (to be used in the constructor of the customization class)
734 @staticmethod
735 def show_canvas(view=1):
736 QView._view_canvas.set(view)
737
738 ## Make the frame visible
739 # (to be used in the constructor of the customization class)
740 @staticmethod
741 def show_frame(view=1):
742 QView._view_frame.set(view)
743
744 # private static functions...
745 @staticmethod
746 def _quit(err=0):
747 QView._err = err
748 QView._gui.quit()
749
750 @staticmethod
751 def _onExit(*args):
752 QView._quit()
753
754 @staticmethod
755 def _onReset():
756 QView._glb_filter = 0
757 QView._loc_filter = QSpy._LOC_FLT_MASK_ALL
758 QView._locAO_OBJ.set("")
759 for i in range(len(QView._currObj)):
760 QView._currObj[i].set("")
761 QView._updateMenus()
762
763 @staticmethod
765
766 # internal helper function
767 def _update_glb_filter_menu(label, mask):
768 x = (QView._glb_filter & mask)
769 if x == 0:
770 status = "[ - ]"
771 elif x == mask:
772 status = "[ + ]"
773 else:
774 status = "[+-]"
775 QView._menu_glb_filter.entryconfig(label,
776 accelerator=status)
777
778 # internal helper function
779 def _update_loc_filter_menu(label, mask):
780 x = (QView._loc_filter & mask)
781 if x == 0:
782 status = "[ - ]"
783 elif x == mask:
784 status = "[ + ]"
785 else:
786 status = "[+-]"
787 QView._menu_loc_filter.entryconfig(label,
788 accelerator=status)
789
790 for i in range(len(QView._currObj)):
791 QView._menu_curr_obj.entryconfig(i,
792 accelerator=QView._currObj[i].get())
793 QView._menu_events.entryconfig(0,
794 accelerator=QView._currObj[QView.OBJ_AO].get())
795 QView._menu_events.entryconfig(1,
796 accelerator=QView._currObj[QView.OBJ_AO].get())
797 QView._menu_events.entryconfig(2,
798 accelerator=QView._currObj[QView.OBJ_SM].get())
799 QView._menu_events.entryconfig(3,
800 accelerator=QView._currObj[QView.OBJ_SM].get())
801 QView._menu_commands.entryconfig(8,
802 accelerator=QView._currObj[QView.OBJ_AP].get())
803 QView._menu_commands.entryconfig(9,
804 accelerator=QView._currObj[QView.OBJ_AP].get())
805 state_SM = "normal"
806 state_AO = "normal"
807 state_AP = "normal"
808 if QView._currObj[QView.OBJ_SM].get() == "":
809 state_SM = "disabled"
810 if QView._currObj[QView.OBJ_AO].get() == "":
811 state_AO = "disabled"
812 if QView._currObj[QView.OBJ_AP].get() == "":
813 state_AP ="disabled"
814 QView._menu_events.entryconfig(0, state=state_AO)
815 QView._menu_events.entryconfig(1, state=state_AO)
816 QView._menu_events.entryconfig(2, state=state_SM)
817 QView._menu_events.entryconfig(3, state=state_SM)
818 QView._menu_commands.entryconfig(8, state=state_AP)
819 QView._menu_commands.entryconfig(9, state=state_AP)
820
821 _update_glb_filter_menu("SM Group...", QSpy._GLB_FLT_MASK_SM)
822 _update_glb_filter_menu("AO Group...", QSpy._GLB_FLT_MASK_AO)
823 _update_glb_filter_menu("QF Group...", QSpy._GLB_FLT_MASK_QF)
824 _update_glb_filter_menu("TE Group...", QSpy._GLB_FLT_MASK_TE)
825 _update_glb_filter_menu("MP Group...", QSpy._GLB_FLT_MASK_MP)
826 _update_glb_filter_menu("EQ Group...", QSpy._GLB_FLT_MASK_EQ)
827 _update_glb_filter_menu("SC Group...", QSpy._GLB_FLT_MASK_SC)
828 _update_glb_filter_menu("SEM Group...", QSpy._GLB_FLT_MASK_SEM)
829 _update_glb_filter_menu("MTX Group...", QSpy._GLB_FLT_MASK_MTX)
830 _update_glb_filter_menu("U0 Group...", QSpy._GLB_FLT_MASK_U0)
831 _update_glb_filter_menu("U1 Group...", QSpy._GLB_FLT_MASK_U1)
832 _update_glb_filter_menu("U2 Group...", QSpy._GLB_FLT_MASK_U2)
833 _update_glb_filter_menu("U3 Group...", QSpy._GLB_FLT_MASK_U3)
834 _update_glb_filter_menu("U4 Group...", QSpy._GLB_FLT_MASK_U4)
835
836 _update_loc_filter_menu("AO IDs...", QSpy._LOC_FLT_MASK_AO)
837 _update_loc_filter_menu("EP IDs...", QSpy._LOC_FLT_MASK_EP)
838 _update_loc_filter_menu("EQ IDs...", QSpy._LOC_FLT_MASK_EQ)
839 _update_loc_filter_menu("AP IDs...", QSpy._LOC_FLT_MASK_AP)
840 QView._menu_loc_filter.entryconfig("AO-OBJ...",
841 accelerator=QView._locAO_OBJ.get())
842
843 @staticmethod
844 def _trap_error(*args):
845 QView._showerror("Runtime Error",
846 traceback.format_exc(3))
847 QView._quit(-3)
848
849 @staticmethod
850 def _assert(cond, message):
851 if not cond:
852 QView._showerror("Assertion",
853 message)
854 QView._quit(-3)
855
856 @staticmethod
857 def _onSaveDict(*args):
858 QSpy._sendTo(pack("<B", QSpy._QSPY_SAVE_DICT))
859
860 @staticmethod
861 def _onSaveText(*args):
862 QSpy._sendTo(pack("<B", QSpy._QSPY_TEXT_OUT))
863
864 @staticmethod
865 def _onSaveBin(*args):
866 QSpy._sendTo(pack("<B", QSpy._QSPY_BIN_OUT))
867
868 @staticmethod
869 def _onSaveMatlab(*args):
870 QSpy._sendTo(pack("<B", QSpy._QSPY_MATLAB_OUT))
871
872 @staticmethod
873 def _onSaveSequence(*args):
874 QSpy._sendTo(pack("<B", QSpy._QSPY_SEQUENCE_OUT))
875
876 @staticmethod
877 def _onCanvasView(*args):
878 if QView._view_canvas.get():
879 QView._canvas_toplevel.state("normal")
880 # make the canvas jump to the front
881 QView._canvas_toplevel.attributes("-topmost", 1)
882 QView._canvas_toplevel.attributes("-topmost", 0)
883 else:
884 QView._canvas_toplevel.withdraw()
885
886 @staticmethod
888 QView._view_canvas.set(0)
889 QView._canvas_toplevel.withdraw()
890
891 @staticmethod
892 def _onFrameView(*args):
893 if QView._view_frame.get():
894 QView._frame_toplevel.state("normal")
895 # make the frame jump to the front
896 QView._frame_toplevel.attributes("-topmost", 1)
897 QView._frame_toplevel.attributes("-topmost", 0)
898 else:
899 QView._frame_toplevel.withdraw()
900
901 @staticmethod
903 QView._view_frame.set(0)
904 QView._frame_toplevel.withdraw()
905
906 @staticmethod
907 def _onGlbFilter_SM(*args):
908 QView._GlbFilterDialog("SM Group", QSpy._GLB_FLT_MASK_SM)
909
910 @staticmethod
911 def _onGlbFilter_AO(*args):
912 QView._GlbFilterDialog("AO Group", QSpy._GLB_FLT_MASK_AO)
913
914 @staticmethod
915 def _onGlbFilter_QF(*args):
916 QView._GlbFilterDialog("QF Group", QSpy._GLB_FLT_MASK_QF)
917
918 @staticmethod
919 def _onGlbFilter_TE(*args):
920 QView._GlbFilterDialog("TE Group", QSpy._GLB_FLT_MASK_TE)
921
922 @staticmethod
923 def _onGlbFilter_EQ(*args):
924 QView._GlbFilterDialog("EQ Group", QSpy._GLB_FLT_MASK_EQ)
925
926 @staticmethod
927 def _onGlbFilter_MP(*args):
928 QView._GlbFilterDialog("MP Group", QSpy._GLB_FLT_MASK_MP)
929
930 @staticmethod
931 def _onGlbFilter_SC(*args):
932 QView._GlbFilterDialog("SC Group", QSpy._GLB_FLT_MASK_SC)
933
934 @staticmethod
936 QView._GlbFilterDialog("SEM Group", QSpy._GLB_FLT_MASK_SEM)
937
938 @staticmethod
940 QView._GlbFilterDialog("MTX Group", QSpy._GLB_FLT_MASK_MTX)
941
942 @staticmethod
943 def _onGlbFilter_U0(*args):
944 QView._GlbFilterDialog("U0 Group", QSpy._GLB_FLT_MASK_U0)
945
946 @staticmethod
947 def _onGlbFilter_U1(*args):
948 QView._GlbFilterDialog("U1 Group", QSpy._GLB_FLT_MASK_U1)
949
950 @staticmethod
951 def _onGlbFilter_U2(*args):
952 QView._GlbFilterDialog("U2 Group", QSpy._GLB_FLT_MASK_U2)
953
954 @staticmethod
955 def _onGlbFilter_U3(*args):
956 QView._GlbFilterDialog("U3 Group", QSpy._GLB_FLT_MASK_U3)
957
958 @staticmethod
959 def _onGlbFilter_U4(*args):
960 QView._GlbFilterDialog("U4 Group", QSpy._GLB_FLT_MASK_U4)
961
962 @staticmethod
963 def _onLocFilter_AO(*args):
964 QView._LocFilterDialog("AO IDs", QSpy._LOC_FLT_MASK_AO)
965
966 @staticmethod
967 def _onLocFilter_EP(*args):
968 QView._LocFilterDialog("EP IDs", QSpy._LOC_FLT_MASK_EP)
969
970 @staticmethod
971 def _onLocFilter_EQ(*args):
972 QView._LocFilterDialog("EQ IDs", QSpy._LOC_FLT_MASK_EQ)
973
974 @staticmethod
975 def _onLocFilter_AP(*args):
976 QView._LocFilterDialog("AP IDs", QSpy._LOC_FLT_MASK_AP)
977
978 @staticmethod
982 @staticmethod
983 def _onCurrObj_SM(*args):
984 QView._CurrObjDialog(QView.OBJ_SM, "SM_OBJ")
985 QView._updateMenus()
986
987 @staticmethod
988 def _onCurrObj_AO(*args):
989 QView._CurrObjDialog(QView.OBJ_AO, "AO_OBJ")
990 QView._updateMenus()
991
992 @staticmethod
993 def _onCurrObj_MP(*args):
994 QView._CurrObjDialog(QView.OBJ_MP, "MP_OBJ")
995
996 @staticmethod
997 def _onCurrObj_EQ(*args):
998 QView._CurrObjDialog(QView.OBJ_EQ, "EQ_OBJ")
999
1000 @staticmethod
1001 def _onCurrObj_TE(*args):
1002 QView._CurrObjDialog(QView.BJ_TE, "TE_OBJ")
1003
1004 @staticmethod
1005 def _onCurrObj_AP(*args):
1006 QView._CurrObjDialog(QView.OBJ_AP, "AP_OBJ")
1007 QView._updateMenus()
1008
1009 @staticmethod
1011 QView.query_curr(QView.OBJ_SM)
1012
1013 @staticmethod
1015 QView.query_curr(QView.OBJ_AO)
1016
1017 @staticmethod
1019 QView.query_curr(QView.OBJ_MP)
1020
1021 @staticmethod
1023 QView.query_curr(QView.OBJ_EQ)
1024
1025 @staticmethod
1027 QView.query_curr(QView.OBJ_TE)
1028
1029 @staticmethod
1031 QView.query_curr(QView.OBJ_AP)
1032
1033 @staticmethod
1034 def _onTargetInfo(*args):
1035 QSpy._sendTo(pack("<B", QSpy._TRGT_INFO))
1036
1037 @staticmethod
1038 def _onClearQspy(*args):
1039 QSpy._sendTo(pack("<B", QSpy._QSPY_CLEAR_SCREEN))
1040
1041 @staticmethod
1042 def _onTick0(*args):
1043 QView.tick(0)
1044
1045 @staticmethod
1046 def _onTick1(*args):
1047 QView.tick(1)
1048
1049 @staticmethod
1050 def _onEvt_PUBLISH(*args):
1051 QView._EvtDialog("Publish Event", publish)
1052
1053 @staticmethod
1054 def _onEvt_POST(*args):
1055 QView._EvtDialog("Post Event", post)
1056
1057 @staticmethod
1058 def _onEvt_INIT(*args):
1059 QView._EvtDialog("Init Event", init)
1060
1061 @staticmethod
1063 QView._EvtDialog("Dispatch Event", dispatch)
1064
1065 @staticmethod
1066 def _onHelp(*args):
1067 webbrowser.open("https://www.state-machine.com/qtools/qview.html",
1068 new=2)
1069
1070 @staticmethod
1071 def _onAbout(*args):
1072 QView._MessageDialog("About QView",
1073 "QView version " + \
1074 "%d.%d.%d"%(QView.VERSION//100, \
1075 (QView.VERSION//10) % 10, \
1076 QView.VERSION % 10) + \
1077 "\n\nFor more information see:\n"
1078 "https://www.state-machine.com/qtools/qview.html")
1079
1080 @staticmethod
1081 def _showerror(title, message):
1082 QView._gui.after_cancel(QSpy._after_id)
1083 QView._MessageDialog(title, message)
1084
1085 @staticmethod
1086 def _strVar_value(strVar, base=0):
1087 str = strVar.get().replace(" ", "") # cleanup spaces
1088 strVar.set(str)
1089 try:
1090 value = int(str, base=base)
1091 return value # integer
1092 except Exception:
1093 return str # string
1094
1095
1096 #-------------------------------------------------------------------------
1097 # private dialog boxes...
1098 #
1099 class _AttachDialog(Dialog):
1100 def __init__(self):
1101 QView._attach_dialog = self
1102 super().__init__(QView._gui, "Attach to QSpy")
1103
1104 def body(self, master):
1105 self.resizable(height=False, width=False)
1106 Label(master,
1107 text="Make sure that QSPY back-end is running and\n"
1108 "not already used by other front-end.\n\n"
1109 "Press Attach to re-try to attach or\n"
1110 "Close to quit.").pack()
1111
1112 def buttonbox(self):
1113 box = Frame(self)
1114 w = Button(box, text="Attach", width=10, command=self.ok,
1115 default=ACTIVE)
1116 w.pack(side=LEFT, padx=5, pady=5)
1117 w = Button(box, text="Close", width=10, command=self.cancelcancel)
1118 w.pack(side=LEFT, padx=5, pady=5)
1119 self.bind("<Return>", self.ok)
1120 self.bind("<Escape>", self.cancelcancel)
1121 box.pack()
1122
1123 def close(self):
1124 super().cancel()
1125 QView._attach_dialog = None
1126
1127 def validate(self):
1128 QSpy._attach()
1129 return 0
1130
1131 def apply(self):
1132 QView._attach_dialog = None
1133
1134 def cancel(self, event=None):
1135 super().cancel()
1136 QView._quit()
1137
1138
1139 #.........................................................................
1140 # helper dialog box for message boxes, @sa QView._showerror()
1141 class _MessageDialog(Dialog):
1142 def __init__(self, title, message):
1143 self.message = message
1144 super().__init__(QView._gui, title)
1145
1146 def body(self, master):
1147 self.resizable(height=False, width=False)
1148 Label(master, text=self.message, justify=LEFT).pack()
1149
1150 def buttonbox(self):
1151 box = Frame(self)
1152 Button(box, text="OK", width=10, command=self.ok,
1153 default=ACTIVE).pack(side=LEFT, padx=5, pady=5)
1154 self.bind("<Return>", self.ok)
1155 box.pack()
1156
1157 #.........................................................................
1158 class _GlbFilterDialog(Dialog):
1159 def __init__(self, title, mask):
1160 self._title = title
1161 self._mask = mask
1162 super().__init__(QView._gui, title)
1163
1164 def body(self, master):
1165 N_ROW = 3
1166 Button(master, text="Select ALL", command=self._sel_all)\
1167 .grid(row=0,column=0, padx=2, pady=2, sticky=W+E)
1168 Button(master, text="Clear ALL", command=self._clr_all)\
1169 .grid(row=0,column=N_ROW-1, padx=2, pady=2, sticky=W+E)
1170 n = 0
1171 self._filter_var = []
1172 for i in range(QSpy._GLB_FLT_RANGE):
1173 if self._mask & (1 << i) != 0:
1174 self._filter_var.append(IntVar())
1175 if QView._glb_filter & (1 << i):
1176 self._filter_var[n].set(1)
1177 Checkbutton(master, text=QSpy._QS[i], anchor=W,
1178 variable=self._filter_var[n])\
1179 .grid(row=(n + N_ROW)//N_ROW,column=(n+N_ROW)%N_ROW,
1180 padx=2,pady=2,sticky=W)
1181 n += 1
1182
1183 def _sel_all(self):
1184 n = 0
1185 for i in range(QSpy._GLB_FLT_RANGE):
1186 if self._mask & (1 << i) != 0:
1187 self._filter_var[n].set(1)
1188 n += 1
1189
1190 def _clr_all(self):
1191 n = 0
1192 for i in range(QSpy._GLB_FLT_RANGE):
1193 if self._mask & (1 << i) != 0:
1194 self._filter_var[n].set(0)
1195 n += 1
1196
1197 def apply(self):
1198 n = 0
1199 for i in range(QSpy._GLB_FLT_RANGE):
1200 if self._mask & (1 << i) != 0:
1201 if self._filter_var[n].get():
1202 QView._glb_filter |= (1 << i)
1203 else:
1204 QView._glb_filter &= ~(1 << i)
1205 n += 1
1206 QSpy._sendTo(pack("<BBQQ", QSpy._TRGT_GLB_FILTER, 16,
1207 QView._glb_filter & 0xFFFFFFFFFFFFFFFF,
1208 QView._glb_filter >> 64))
1209 QView._updateMenus()
1210
1211 #.........................................................................
1212 class _LocFilterDialog(Dialog):
1213 def __init__(self, title, mask):
1214 self._title = title
1215 self._mask = mask
1216 super().__init__(QView._gui, title)
1217
1218 def body(self, master):
1219 N_ROW = 8
1220 Button(master, text="Select ALL", command=self._sel_all)\
1221 .grid(row=0,column=0, padx=2, pady=2, sticky=W+E)
1222 Button(master, text="Clear ALL", command=self._clr_all)\
1223 .grid(row=0,column=N_ROW-1, padx=2, pady=2, sticky=W+E)
1224 n = 0
1225 self._filter_var = []
1226 if self._mask == QSpy._LOC_FLT_MASK_AO:
1227 QS_id = "AO-prio=%d"
1228 else:
1229 QS_id = "QS-ID=%d"
1230 for i in range(QSpy._LOC_FLT_RANGE):
1231 if self._mask & (1 << i) != 0:
1232 self._filter_var.append(IntVar())
1233 if QView._loc_filter & (1 << i):
1234 self._filter_var[n].set(1)
1235 Checkbutton(master, text=QS_id%(i), anchor=W,
1236 variable=self._filter_var[n])\
1237 .grid(row=(n + N_ROW)//N_ROW,column=(n+N_ROW)%N_ROW,
1238 padx=2,pady=2,sticky=W)
1239 n += 1
1240
1241 def _sel_all(self):
1242 n = 0
1243 for i in range(QSpy._LOC_FLT_RANGE):
1244 if self._mask & (1 << i) != 0:
1245 self._filter_var[n].set(1)
1246 n += 1
1247
1248 def _clr_all(self):
1249 n = 0
1250 for i in range(QSpy._LOC_FLT_RANGE):
1251 if self._mask & (1 << i) != 0:
1252 self._filter_var[n].set(0)
1253 n += 1
1254
1255 def apply(self):
1256 n = 0
1257 for i in range(QSpy._LOC_FLT_RANGE):
1258 if self._mask & (1 << i) != 0:
1259 if self._filter_var[n].get():
1260 QView._loc_filter |= (1 << i)
1261 else:
1262 QView._loc_filter &= ~(1 << i)
1263 n += 1
1264 QSpy._sendTo(pack("<BBQQ", QSpy._TRGT_LOC_FILTER, 16,
1265 QView._loc_filter & 0xFFFFFFFFFFFFFFFF,
1266 QView._loc_filter >> 64))
1267 QView._updateMenus()
1268
1269 #.........................................................................
1270 # deprecated
1272 def __init__(self):
1273 super().__init__(QView._gui, "Local AO-OBJ Filter")
1274
1275 def body(self, master):
1276 Label(master, text="AO-OBJ").grid(row=0,column=0,
1277 sticky=E,padx=2)
1278 Entry(master, relief=SUNKEN, width=25,
1279 textvariable=QView._locAO_OBJ).grid(row=0,column=1)
1280
1281 def validate(self):
1282 self._obj = QView._strVar_value(QView._locAO_OBJ)
1283 return 1
1284
1285 def apply(self):
1286 ao_filter(self._obj)
1287
1288 #.........................................................................
1289 class _CurrObjDialog(Dialog):
1290 def __init__(self, obj_kind, label):
1291 self._obj_kind = obj_kind
1292 self._label = label
1293 super().__init__(QView._gui, "Current Object")
1294
1295 def body(self, master):
1296 Label(master, text=self._label).grid(row=0,column=0,
1297 sticky=E,padx=2)
1298 Entry(master, relief=SUNKEN, width=25,
1299 textvariable=QView._currObj[self._obj_kind])\
1300 .grid(row=0,column=1)
1301
1302 def validate(self):
1303 self._obj = QView._strVar_value(QView._currObj[self._obj_kind])
1304 if self._obj == "":
1305 self._obj = 0
1306 return 1
1307
1308 def apply(self):
1309 current_obj(self._obj_kind, self._obj)
1310
1311 #.........................................................................
1312 class _CommandDialog(Dialog):
1313 def __init__(self):
1314 super().__init__(QView._gui, "Command")
1315 def body(self, master):
1316 Label(master, text="command").grid(row=0,column=0,sticky=E,padx=2)
1317 Entry(master, relief=SUNKEN, width=25,
1318 textvariable=QView._command).grid(row=0,column=1,pady=2)
1319 Label(master, text="param1").grid(row=1,column=0,sticky=E,padx=2)
1320 Entry(master, relief=SUNKEN, width=25,
1321 textvariable=QView._command_p1).grid(row=1,column=1,padx=2)
1322 Label(master, text="param2").grid(row=2,column=0,sticky=E,padx=2)
1323 Entry(master, relief=SUNKEN, width=25,
1324 textvariable=QView._command_p2).grid(row=2,column=1,padx=2)
1325 Label(master, text="param3").grid(row=3,column=0,sticky=E,padx=2)
1326 Entry(master, relief=SUNKEN, width=25,
1327 textvariable=QView._command_p3).grid(row=3,column=1,padx=2)
1328
1329 def validate(self):
1330 self._cmdId = QView._strVar_value(QView._command)
1331 if self._cmdId == "":
1332 QView._MessageDialog("Command Error", "empty command")
1333 return 0
1334 self._param1 = QView._strVar_value(QView._command_p1)
1335 if self._param1 == "":
1336 self._param1 = 0
1337 elif not isinstance(self._param1, int):
1338 QView._MessageDialog("Command Error", "param1 not integer")
1339 return 0
1340 self._param2 = QView._strVar_value(QView._command_p2)
1341 if self._param2 == "":
1342 self._param2 = 0
1343 elif not isinstance(self._param2, int):
1344 QView._MessageDialog("Command Error", "param2 not integer")
1345 return 0
1346 self._param3 = QView._strVar_value(QView._command_p3)
1347 if self._param3 == "":
1348 self._param3 = 0
1349 elif not isinstance(self._param3, int):
1350 QView._MessageDialog("Command Error", "param3 not integer")
1351 return 0
1352 return 1
1353
1354 def apply(self):
1355 command(self._cmdId, self._param1, self._param2, self._param3)
1356
1357 #.........................................................................
1358 class _NoteDialog(Dialog):
1359 def __init__(self):
1360 super().__init__(QView._gui, "Show Note")
1361 def body(self, master):
1362 Label(master, text="message").grid(row=0,column=0,sticky=E,padx=2)
1363 Entry(master, relief=SUNKEN, width=65,
1364 textvariable=QView._note).grid(row=0,column=1,sticky=W,pady=2)
1365 Label(master, text="kind").grid(row=1,column=0,sticky=E,padx=2)
1366 Entry(master, relief=SUNKEN, width=5,
1367 textvariable=QView._note_kind).grid(row=1,column=1,sticky=W,padx=2)
1368 def validate(self):
1369 self._note = QView._note.get()
1370 self._note_kind = QView._strVar_value(QView._note_kind)
1371 return 1
1372 def apply(self):
1373 QSpy._sendTo(struct.pack("<BB", QSpy._QSPY_SHOW_NOTE, self._note_kind),
1374 self._note)
1375
1376 #.........................................................................
1377 class _PeekDialog(Dialog):
1378 def __init__(self):
1379 super().__init__(QView._gui, "Peek")
1380
1381 def body(self, master):
1382 Label(master, text="obj/addr").grid(row=0,column=0,
1383 sticky=E,padx=2)
1384 Label(master, text=QView._currObj[OBJ_AP].get(),anchor=W,
1385 relief=SUNKEN).grid(row=0,column=1, columnspan=2,sticky=E+W)
1386 Label(master, text="offset").grid(row=1,column=0,sticky=E,padx=2)
1387 Entry(master, relief=SUNKEN, width=25,
1388 textvariable=QView._peek_offs).grid(row=1,column=1,
1389 columnspan=2)
1390 Label(master, text="n-units").grid(row=2,column=0,
1391 sticky=E,padx=2)
1392 Entry(master, relief=SUNKEN, width=12,
1393 textvariable=QView._peek_len).grid(row=2,column=1,
1394 sticky=E+W,padx=2)
1395 OptionMenu(master, QView._peek_dtype, *QView._dtypes).grid(row=2,
1396 column=2,sticky=E,padx=2)
1397
1398 def validate(self):
1399 if QView._currObj[OBJ_AP].get() == "":
1400 QView._MessageDialog("Peek Error", "Current AP_OBJ not set")
1401 return 0
1402 self._offs = QView._strVar_value(QView._peek_offs)
1403 if not isinstance(self._offs, int):
1404 self._offs = 0
1405 i = QView._dtypes.index(QView._peek_dtype.get())
1406 self._size = QView._dsizes[i]
1407 self._len = QView._strVar_value(QView._peek_len)
1408 if not isinstance(self._len, int):
1409 self._len = 1
1410 return 1
1411
1412 def apply(self):
1413 peek(self._offs, self._size, self._len)
1414
1415 #.........................................................................
1416 class _PokeDialog(Dialog):
1417 def __init__(self):
1418 super().__init__(QView._gui, "Poke")
1419
1420 def body(self, master):
1421 Label(master, text="obj/addr").grid(row=0,column=0,sticky=E,padx=2)
1422 Label(master, text=QView._currObj[OBJ_AP].get(), anchor=W,
1423 relief=SUNKEN).grid(row=0,column=1,sticky=E+W)
1424 Label(master, text="offset").grid(row=1,column=0,sticky=E,padx=2)
1425 Entry(master, relief=SUNKEN, width=25,
1426 textvariable=QView._poke_offs).grid(row=1,column=1)
1427 OptionMenu(master, QView._poke_dtype,
1428 *QView._dtypes).grid(row=2,column=0,sticky=E,padx=2)
1429 Entry(master, relief=SUNKEN, width=25,
1430 textvariable=QView._poke_data).grid(row=2,column=1)
1431
1432 def validate(self):
1433 if QView._currObj[OBJ_AP].get() == "":
1434 QView._MessageDialog("Poke Error", "Current AP_OBJ not set")
1435 return 0
1436 self._offs = QView._strVar_value(QView._poke_offs)
1437 if not isinstance(self._offs, int):
1438 self._offs = 0
1439
1440 self._data = QView._strVar_value(QView._poke_data)
1441 if not isinstance(self._data, int):
1442 QView._MessageDialog("Poke Error", "data not integer")
1443 return 0
1444 dtype = QView._poke_dtype.get()
1445 self._size = QView._dsizes[QView._dtypes.index(dtype)]
1446 if self._size == 1 and self._data > 0xFF:
1447 QView._MessageDialog("Poke Error", "8-bit data out of range")
1448 return 0
1449 if self._size == 2 and self._data > 0xFFFF:
1450 QView._MessageDialog("Poke Error", "16-bit data out of range")
1451 return 0
1452 if self._size == 4 and self._data > 0xFFFFFFFF:
1453 QView._MessageDialog("Poke Error", "32-bit data out of range")
1454 return 0
1455 return 1
1456
1457 def apply(self):
1458 poke(self._offs, self._size, self._data)
1459
1460 #.........................................................................
1461 class _EvtDialog(Dialog):
1462 def __init__(self, title, action):
1463 self._action = action
1464 if action == dispatch:
1465 self._obj = QView._currObj[OBJ_SM].get()
1466 else:
1467 self._obj = QView._currObj[OBJ_AO].get()
1468 super().__init__(QView._gui, title)
1469
1470 def body(self, master):
1471 Label(master, text="obj/addr").grid(row=0,column=0,
1472 sticky=E,padx=2)
1473 Label(master, text=self._obj, anchor=W,
1474 relief=SUNKEN).grid(row=0,column=1,columnspan=2,sticky=E+W)
1475 Frame(master,height=2,borderwidth=1,relief=SUNKEN).grid(row=1,
1476 column=0,columnspan=3,sticky=E+W+N+S,pady=4)
1477 Label(master, text="sig").grid(row=2,column=0,sticky=E,
1478 padx=2,pady=4)
1479 Entry(master, relief=SUNKEN,
1480 textvariable=QView._evt_sig).grid(row=2,column=1,
1481 columnspan=2,sticky=E+W)
1482 for i in range(len(QView._evt_par)):
1483 Label(master, text="par%d"%(i+1)).grid(row=3+i,column=0,
1484 sticky=E,padx=2)
1485 OptionMenu(master, QView._evt_dtype[i], *QView._dtypes).grid(
1486 row=3+i,column=1,sticky=E,padx=2)
1487 Entry(master, relief=SUNKEN, width=18,
1488 textvariable=QView._evt_par[i]).grid(row=3+i,column=2,
1489 sticky=E+W)
1490
1491 def validate(self):
1492 self._sig = QView._strVar_value(QView._evt_sig)
1493 if self._sig == "":
1494 QView._MessageDialog("Event error", "empty event sig")
1495 return 0
1496 self._params = bytearray()
1497 for i in range(len(QView._evt_par)):
1498 par = QView._strVar_value(QView._evt_par[i])
1499 if par == "":
1500 break
1501 if not isinstance(par, int):
1502 QView._MessageDialog("Event Error: par%d"%(i),
1503 "data not integer")
1504 return 0
1505 idx = QView._dtypes.index(QView._evt_dtype[i].get())
1506 size = QView._dsizes[idx]
1507 if size == 1 and par > 0xFF:
1508 QView._MessageDialog("Event Error: par%d"%(i),
1509 "8-bit data out of range")
1510 return 0
1511 if size == 2 and par > 0xFFFF:
1512 QView._MessageDialog("Event Error: par%d"%(i),
1513 "16-bit data out of range")
1514 return 0
1515 if size == 4 and par > 0xFFFFFFFF:
1516 QView._MessageDialog("Event Error: par%d"%(i),
1517 "32-bit data out of range")
1518 return 0
1519
1520 fmt = QSpy._fmt_endian + ("B", "H", "I")[idx]
1521 self._params.extend(pack(fmt, par))
1522 return 1
1523
1524 def apply(self):
1525 self._action(self._sig, self._params)
1526
1527
1528#=============================================================================
1529## Helper class for UDP-communication with the QSpy front-end
1530# (non-blocking UDP-socket version for QView)
1531#
1532class QSpy:
1533 # private class variables...
1534 _sock = None
1535 _is_attached = False
1536 _tx_seq = 0
1537 _rx_seq = 0
1538 _host_addr = ["localhost", 7701] # list, to be converted to a tuple
1539 _local_port = 0 # let the OS decide the best local port
1540 _after_id = None
1541
1542 # formats of various packet elements from the Target
1543 _fmt_target = "UNKNOWN"
1544 _fmt_endian = "<"
1545 _size_objPtr = 4
1546 _size_funPtr = 4
1547 _size_tstamp = 4
1548 _size_sig = 2
1549 _size_evtSize = 2
1550 _size_evtSize = 2
1551 _size_queueCtr = 1
1552 _size_poolCtr = 2
1553 _size_poolBlk = 2
1554 _size_tevtCtr = 2
1555 _fmt = "xBHxLxxxQ"
1556
1557 # QSPY UDP socket poll interval [ms]
1558 # NOTE: the chosen value actually sleeps for one system clock tick,
1559 # which is typically 10ms
1560 _POLLI = 10
1561
1562 # tuple of QS records from the Target.
1563 # !!! NOTE: Must match qpc/include/qs.h !!!
1564 _QS = ("QS_EMPTY",
1565 # [1] SM records
1566 "QS_QEP_STATE_ENTRY", "QS_QEP_STATE_EXIT",
1567 "QS_QEP_STATE_INIT", "QS_QEP_INIT_TRAN",
1568 "QS_QEP_INTERN_TRAN", "QS_QEP_TRAN",
1569 "QS_QEP_IGNORED", "QS_QEP_DISPATCH",
1570 "QS_QEP_UNHANDLED",
1571
1572 # [10] Active Object (AO) records
1573 "QS_QF_ACTIVE_DEFER", "QS_QF_ACTIVE_RECALL",
1574 "QS_QF_ACTIVE_SUBSCRIBE", "QS_QF_ACTIVE_UNSUBSCRIBE",
1575 "QS_QF_ACTIVE_POST", "QS_QF_ACTIVE_POST_LIFO",
1576 "QS_QF_ACTIVE_GET", "QS_QF_ACTIVE_GET_LAST",
1577 "QS_QF_ACTIVE_RECALL_ATTEMPT",
1578
1579 # [19] Event Queue (EQ) records
1580 "QS_QF_EQUEUE_POST", "QS_QF_EQUEUE_POST_LIFO",
1581 "QS_QF_EQUEUE_GET", "QS_QF_EQUEUE_GET_LAST",
1582
1583 # [23] Framework (QF) records
1584 "QS_QF_NEW_ATTEMPT",
1585
1586 # [24] Memory Pool (MP) records
1587 "QS_QF_MPOOL_GET", "QS_QF_MPOOL_PUT",
1588
1589 # [26] Additional Framework (QF) records
1590 "QS_QF_PUBLISH", "QS_QF_NEW_REF",
1591 "QS_QF_NEW", "QS_QF_GC_ATTEMPT",
1592 "QS_QF_GC", "QS_QF_TICK",
1593
1594 # [32] Time Event (TE) records
1595 "QS_QF_TIMEEVT_ARM", "QS_QF_TIMEEVT_AUTO_DISARM",
1596 "QS_QF_TIMEEVT_DISARM_ATTEMPT", "QS_QF_TIMEEVT_DISARM",
1597 "QS_QF_TIMEEVT_REARM", "QS_QF_TIMEEVT_POST",
1598
1599 # [38] Additional (QF) records
1600 "QS_QF_DELETE_REF", "QS_QF_CRIT_ENTRY",
1601 "QS_QF_CRIT_EXIT", "QS_QF_ISR_ENTRY",
1602 "QS_QF_ISR_EXIT", "QS_QF_INT_DISABLE",
1603 "QS_QF_INT_ENABLE",
1604
1605 # [45] Additional Active Object (AO) records
1606 "QS_QF_ACTIVE_POST_ATTEMPT",
1607
1608 # [46] Additional Event Queue (EQ) records
1609 "QS_QF_EQUEUE_POST_ATTEMPT",
1610
1611 # [47] Additional Memory Pool (MP) records
1612 "QS_QF_MPOOL_GET_ATTEMPT",
1613
1614 # [48] Scheduler (SC) records
1615 "QS_SCHED_PREEMPT", "QS_SCHED_RESTORE",
1616 "QS_SCHED_LOCK", "QS_SCHED_UNLOCK",
1617 "QS_SCHED_NEXT", "QS_SCHED_IDLE",
1618
1619 # [54] Miscellaneous QS records (not maskable)
1620 "QS_ENUM_DICT",
1621
1622 # [55] Additional QEP records
1623 "QS_QEP_TRAN_HIST", "QS_QEP_TRAN_EP",
1624 "QS_QEP_TRAN_XP",
1625
1626 # [58] Miscellaneous QS records (not maskable)
1627 "QS_TEST_PAUSED", "QS_TEST_PROBE_GET",
1628 "QS_SIG_DICT", "QS_OBJ_DICT",
1629 "QS_FUN_DICT", "QS_USR_DICT",
1630 "QS_TARGET_INFO", "QS_TARGET_DONE",
1631 "QS_RX_STATUS", "QS_QUERY_DATA",
1632 "QS_PEEK_DATA", "QS_ASSERT_FAIL",
1633 "QS_QF_RUN",
1634
1635 # [71] Semaphore (SEM) records
1636 "QS_SEM_TAKE", "QS_SEM_BLOCK",
1637 "QS_SEM_SIGNAL", "QS_SEM_BLOCK_ATTEMPT",
1638
1639 # [75] Mutex (MTX) records
1640 "QS_MTX_LOCK", "QS_MTX_BLOCK",
1641 "QS_MTX_UNLOCK", "QS_MTX_LOCK_ATTEMPT",
1642 "QS_MTX_BLOCK_ATTEMPT", "QS_MTX_UNLOCK_ATTEMPT",
1643
1644 # [81] Reserved QS records
1645 "QS_RESERVED_81",
1646 "QS_RESERVED_82", "QS_RESERVED_83",
1647 "QS_RESERVED_84", "QS_RESERVED_85",
1648 "QS_RESERVED_86", "QS_RESERVED_87",
1649 "QS_RESERVED_88", "QS_RESERVED_89",
1650 "QS_RESERVED_90", "QS_RESERVED_91",
1651 "QS_RESERVED_92", "QS_RESERVED_93",
1652 "QS_RESERVED_94", "QS_RESERVED_95",
1653 "QS_RESERVED_96", "QS_RESERVED_97",
1654 "QS_RESERVED_98", "QS_RESERVED_99",
1655
1656 # [100] Application-specific (User) QS records
1657 "QS_USER_00", "QS_USER_01",
1658 "QS_USER_02", "QS_USER_03",
1659 "QS_USER_04", "QS_USER_05",
1660 "QS_USER_06", "QS_USER_07",
1661 "QS_USER_08", "QS_USER_09",
1662 "QS_USER_10", "QS_USER_11",
1663 "QS_USER_12", "QS_USER_13",
1664 "QS_USER_14", "QS_USER_15",
1665 "QS_USER_16", "QS_USER_17",
1666 "QS_USER_18", "QS_USER_19",
1667 "QS_USER_20", "QS_USER_21",
1668 "QS_USER_22", "QS_USER_23",
1669 "QS_USER_24")
1670
1671 # global filter masks
1672 _GLB_FLT_MASK_ALL= 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
1673 _GLB_FLT_MASK_SM = 0x000000000000000003800000000003FE
1674 _GLB_FLT_MASK_AO = 0x0000000000000000000020000007FC00
1675 _GLB_FLT_MASK_QF = 0x000000000000000000001FC0FC800000
1676 _GLB_FLT_MASK_TE = 0x00000000000000000000003F00000000
1677 _GLB_FLT_MASK_EQ = 0x00000000000000000000400000780000
1678 _GLB_FLT_MASK_MP = 0x00000000000000000000800003000000
1679 _GLB_FLT_MASK_SC = 0x0000000000000000003F000000000000
1680 _GLB_FLT_MASK_SEM= 0x00000000000007800000000000000000
1681 _GLB_FLT_MASK_MTX= 0x000000000001F8000000000000000000
1682 _GLB_FLT_MASK_U0 = 0x000001F0000000000000000000000000
1683 _GLB_FLT_MASK_U1 = 0x00003E00000000000000000000000000
1684 _GLB_FLT_MASK_U2 = 0x0007C000000000000000000000000000
1685 _GLB_FLT_MASK_U3 = 0x00F80000000000000000000000000000
1686 _GLB_FLT_MASK_U4 = 0x1F000000000000000000000000000000
1687 _GLB_FLT_MASK_UA = 0x1FFFFFF0000000000000000000000000
1688 _GLB_FLT_RANGE = 125
1689
1690 # local filter masks
1691 _LOC_FLT_MASK_ALL= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
1692 _LOC_FLT_MASK_AO = 0x0000000000000001FFFFFFFFFFFFFFFE
1693 _LOC_FLT_MASK_EP = 0x000000000000FFFE0000000000000000
1694 _LOC_FLT_MASK_EQ = 0x00000000FFFF00000000000000000000
1695 _LOC_FLT_MASK_AP = 0xFFFFFFFF000000000000000000000000
1696 _LOC_FLT_RANGE = 128
1697
1698 # interesting packets from QSPY/Target...
1699 _PKT_TEXT_ECHO = 0
1700 _PKT_TARGET_INFO = 64
1701 _PKT_ASSERTION = 69
1702 _PKT_QF_RUN = 70
1703 _PKT_ATTACH_CONF = 128
1704 _PKT_DETACH = 129
1705
1706 # records to the Target...
1707 _TRGT_INFO = 0
1708 _TRGT_COMMAND = 1
1709 _TRGT_RESET = 2
1710 _TRGT_TICK = 3
1711 _TRGT_PEEK = 4
1712 _TRGT_POKE = 5
1713 _TRGT_FILL = 6
1714 _TRGT_TEST_SETUP = 7
1715 _TRGT_TEST_TEARDOWN = 8
1716 _TRGT_TEST_PROBE = 9
1717 _TRGT_GLB_FILTER = 10
1718 _TRGT_LOC_FILTER = 11
1719 _TRGT_AO_FILTER = 12
1720 _TRGT_CURR_OBJ = 13
1721 _TRGT_CONTINUE = 14
1722 _TRGT_QUERY_CURR = 15
1723 _TRGT_EVENT = 16
1724
1725 # packets to QSpy only...
1726 _QSPY_ATTACH = 128
1727 _QSPY_DETACH = 129
1728 _QSPY_SAVE_DICT = 130
1729 _QSPY_TEXT_OUT = 131
1730 _QSPY_BIN_OUT = 132
1731 _QSPY_MATLAB_OUT = 133
1732 _QSPY_SEQUENCE_OUT = 134
1733 _QSPY_CLEAR_SCREEN = 140
1734 _QSPY_SHOW_NOTE = 141
1735
1736 # packets to QSpy to be "massaged" and forwarded to the Target...
1737 _QSPY_SEND_EVENT = 135
1738 _QSPY_SEND_AO_FILTER = 136
1739 _QSPY_SEND_CURR_OBJ = 137
1740 _QSPY_SEND_COMMAND = 138
1741 _QSPY_SEND_TEST_PROBE = 139
1742
1743 # special event sub-commands for QSPY_SEND_EVENT
1744 _EVT_PUBLISH = 0
1745 _EVT_POST = 253
1746 _EVT_INIT = 254
1747 _EVT_DISPATCH = 255
1748
1749 @staticmethod
1750 def _init():
1751 # Create socket
1752 QSpy._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
1753 QSpy._sock.setblocking(0) # NON-BLOCKING socket
1754 try:
1755 QSpy._sock.bind(("0.0.0.0", QSpy._local_port))
1756 #print("bind: ", ("0.0.0.0", QSpy._local_port))
1757 except Exception:
1758 QView._showerror("UDP Socket Error",
1759 "Can't bind the UDP socket\n"
1760 "to the specified local_host.\n"
1761 "Check if other instances of qspyview\n"
1762 "or qutest are running...")
1763 QView._quit(-1)
1764 return -1
1765 return 0
1766
1767 @staticmethod
1768 def _attach():
1769 QSpy._is_attached = False
1770 QView._have_info = False
1771 if QView._echo_text.get():
1772 channels = 0x3
1773 else:
1774 channels = 0x1
1775 QSpy._sendTo(pack("<BB", QSpy._QSPY_ATTACH, channels))
1776 QSpy._attach_ctr = 50
1777 QSpy._after_id = QView._gui.after(1, QSpy._poll0) # start poll0
1778
1779 @staticmethod
1780 def _detach():
1781 if QSpy._sock is None:
1782 return
1783 QSpy._sendTo(pack("<B", QSpy._QSPY_DETACH))
1784 time.sleep(0.25) # let the socket finish sending the packet
1785 #QSpy._sock.shutdown(socket.SHUT_RDWR)
1786 QSpy._sock.close()
1787 QSpy._sock = None
1788
1789 @staticmethod
1791 # channels: 0x1-binary, 0x2-text, 0x3-both
1792 if QView._echo_text.get():
1793 channels = 0x3
1794 else:
1795 channels = 0x1
1796 QSpy._sendTo(pack("<BB", QSpy._QSPY_ATTACH, channels))
1797
1798 # poll the UDP socket until the QSpy confirms ATTACH
1799 @staticmethod
1800 def _poll0():
1801 #print("poll0 ", QSpy._attach_ctr)
1802 QSpy._attach_ctr -= 1
1803 if QSpy._attach_ctr == 0:
1804 if QView._attach_dialog is None:
1805 QView._AttachDialog() # launch the AttachDialog
1806 return
1807
1808 try:
1809 packet = QSpy._sock.recv(4096)
1810 if not packet:
1811 QView._showerror("UDP Socket Error",
1812 "Connection closed by QSpy")
1813 QView._quit(-1)
1814 return
1815 except OSError: # non-blocking socket...
1816 QSpy._after_id = QView._gui.after(QSpy._POLLI, QSpy._poll0)
1817 return # <======== most frequent return (no packet)
1818 except Exception:
1819 QView._showerror("UDP Socket Error",
1820 "Uknown UDP socket error")
1821 QView._quit(-1)
1822 return
1823
1824 # parse the packet...
1825 dlen = len(packet)
1826 if dlen < 2:
1827 QView._showerror("Communication Error",
1828 "UDP packet from QSpy too short")
1829 QView._quit(-2)
1830 return
1831
1832 recID = packet[1]
1833 if recID == QSpy._PKT_ATTACH_CONF:
1834 QSpy._is_attached = True
1835 if QView._attach_dialog is not None:
1836 QView._attach_dialog.close()
1837
1838 # send either reset or target-info request
1839 # (keep the poll0 loop running)
1840 if QView._reset_request:
1841 QView._reset_request = False
1842 QSpy._sendTo(pack("<B", QSpy._TRGT_RESET))
1843 else:
1844 QSpy._sendTo(pack("<B", QSpy._TRGT_INFO))
1845
1846 # switch to the regular polling...
1847 QSpy._after_id = QView._gui.after(QSpy._POLLI, QSpy._poll)
1848
1849 # only show the canvas, if visible
1850 QView._onCanvasView()
1851
1852 # only show the frame, if visible
1853 QView._onFrameView()
1854
1855 return
1856
1857 elif recID == QSpy._PKT_DETACH:
1858 QView._quit()
1859 return
1860
1861
1862 # regullar poll of the UDP socket after it has attached.
1863 @staticmethod
1864 def _poll():
1865 while True:
1866 try:
1867 packet = QSpy._sock.recv(4096)
1868 if not packet:
1869 QView._showerror("UDP Socket Error",
1870 "Connection closed by QSpy")
1871 QView._quit(-1)
1872 return
1873 except OSError: # non-blocking socket...
1874 QSpy._after_id = QView._gui.after(QSpy._POLLI, QSpy._poll)
1875 return # <============= no packet at this time
1876 except Exception:
1877 QView._showerror("UDP Socket Error",
1878 "Uknown UDP socket error")
1879 QView._quit(-1)
1880 return
1881
1882 # parse the packet...
1883 dlen = len(packet)
1884 if dlen < 2:
1885 QView._showerror("UDP Socket Data Error",
1886 "UDP packet from QSpy too short")
1887 QView._quit(-2)
1888 return
1889
1890 recID = packet[1]
1891 if recID == QSpy._PKT_TEXT_ECHO:
1892 # no need to check QView._echo_text.get()
1893 # because the text channel is closed
1894 QView.print_text(packet[3:])
1895
1896 elif recID == QSpy._PKT_TARGET_INFO:
1897 if dlen != 18:
1898 QView._showerror("UDP Socket Data Error",
1899 "Corrupted Target-info")
1900 QView._quit(-2)
1901 return
1902
1903 if packet[4] & 0x80 != 0: # big endian?
1904 QSpy._fmt_endian = ">"
1905
1906 tstamp = packet[5:18]
1907 QSpy._size_objPtr = tstamp[3] & 0x0F
1908 QSpy._size_funPtr = tstamp[3] >> 4
1909 QSpy._size_tstamp = tstamp[4] & 0x0F
1910 QSpy._size_sig = tstamp[0] & 0x0F
1911 QSpy._size_evtSize = tstamp[0] >> 4
1912 QSpy._size_queueCtr= tstamp[1] & 0x0F
1913 QSpy._size_poolCtr = tstamp[2] >> 4
1914 QSpy._size_poolBlk = tstamp[2] & 0x0F
1915 QSpy._size_tevtCtr = tstamp[1] >> 4
1916 QSpy._fmt_target = "%02d%02d%02d_%02d%02d%02d"\
1917 %(tstamp[12], tstamp[11], tstamp[10],
1918 tstamp[9], tstamp[8], tstamp[7])
1919 #print("******* Target:", QSpy._fmt_target)
1920 QView._target.configure(text="Target: " + QSpy._fmt_target)
1921 QView._have_info = True
1922
1923 # is this also target reset?
1924 if packet[2] != 0:
1925 QView._onReset()
1926 try:
1927 QView._inst.on_reset()
1928 except Exception:
1929 QView._showerror("Runtime Error",
1930 traceback.format_exc(3))
1931 QView._quit(-3)
1932 return
1933
1934 elif recID == QSpy._PKT_QF_RUN:
1935 try:
1936 QView._inst.on_run()
1937 except Exception:
1938 QView._showerror("Runtime Error",
1939 traceback.format_exc(3))
1940 QView._quit(-3)
1941 return
1942
1943 elif recID == QSpy._PKT_DETACH:
1944 QView._quit()
1945 return
1946
1947 elif recID <= 124: # other binary data
1948 # find the (global) handler for the packet
1949 handler = getattr(QView._inst,
1950 QSpy._QS[recID], None)
1951 if handler is not None:
1952 try:
1953 handler(packet) # call the packet handler
1954 except Exception:
1955 QView._showerror("Runtime Error",
1956 traceback.format_exc(3))
1957 QView._quit(-3)
1958 return
1959 QSpy._rx_seq += 1
1960 QView._rx.configure(text="%d"%(QSpy._rx_seq))
1961
1962
1963 @staticmethod
1964 def _sendTo(packet, str=None):
1965 tx_packet = bytearray([QSpy._tx_seq & 0xFF])
1966 tx_packet.extend(packet)
1967 if str is not None:
1968 tx_packet.extend(bytes(str, "utf-8"))
1969 tx_packet.extend(b"\0") # zero-terminate
1970 try:
1971 QSpy._sock.sendto(tx_packet, QSpy._host_addr)
1972 except Exception:
1973 QView._showerror("UDP Socket Error",
1974 traceback.format_exc(3))
1975 QView._quit(-1)
1976 QSpy._tx_seq += 1
1977 if not QView._gui is None:
1978 QView._tx.configure(text="%d"%(QSpy._tx_seq))
1979
1980 @staticmethod
1981 def _sendEvt(ao_prio, signal, params = None):
1982 #print("evt:", signal, params)
1983 fmt = "<BB" + QSpy._fmt[QSpy._size_sig] + "H"
1984 if params is not None:
1985 length = len(params)
1986 else:
1987 length = 0
1988
1989 if isinstance(signal, int):
1990 packet = bytearray(pack(
1991 fmt, QSpy._TRGT_EVENT, ao_prio, signal, length))
1992 if params is not None:
1993 packet.extend(params)
1994 QSpy._sendTo(packet)
1995 else:
1996 packet = bytearray(pack(
1997 fmt, QSpy._QSPY_SEND_EVENT, ao_prio, 0, length))
1998 if params is not None:
1999 packet.extend(params)
2000 QSpy._sendTo(packet, signal)
2001
2002#=============================================================================
2003# main entry point to QView
2004def main():
2005 QView.main(QView()) # standalone QView
2006
2007#=============================================================================
2008if __name__ == "__main__":
2009 main()
Helper class for UDP-communication with the QSpy front-end (non-blocking UDP-socket version for QView...
Definition qview.py:1532
_sendTo(packet, str=None)
Definition qview.py:1964
_sendEvt(ao_prio, signal, params=None)
Definition qview.py:1981
_reattach()
Definition qview.py:1790
body(self, master)
Definition qview.py:1104
cancel(self, event=None)
Definition qview.py:1134
__init__(self, obj_kind, label)
Definition qview.py:1290
body(self, master)
Definition qview.py:1470
__init__(self, title, action)
Definition qview.py:1462
__init__(self, title, mask)
Definition qview.py:1159
__init__(self, title, mask)
Definition qview.py:1213
__init__(self, title, message)
Definition qview.py:1142
body(self, master)
Definition qview.py:1361
body(self, master)
Definition qview.py:1381
body(self, master)
Definition qview.py:1420
_onQueryCurr_AO(*args)
Definition qview.py:1014
on_init(self)
Definition qview.py:172
_onSaveDict(*args)
Definition qview.py:857
_onQueryCurr_MP(*args)
Definition qview.py:1018
_onAbout(*args)
Definition qview.py:1071
_onHelp(*args)
Definition qview.py:1066
_onLocFilter_AO(*args)
Definition qview.py:963
_onCurrObj_EQ(*args)
Definition qview.py:997
_onQueryCurr_SM(*args)
Definition qview.py:1010
_onCanvasView(*args)
Definition qview.py:877
_onQueryCurr_AP(*args)
Definition qview.py:1030
customize(cust)
Set QView customization.
Definition qview.py:718
dispatch(signal, params=None)
dispatch a given event in the current SM object in the Target
Definition qview.py:403
_onFrameClose()
Definition qview.py:902
_onGlbFilter_U4(*args)
Definition qview.py:959
_onClearQspy(*args)
Definition qview.py:1038
current_obj(obj_kind, obj_id)
Set the Current-Object in the Target.
Definition qview.py:360
_onLocFilter_AO_OBJ(*args)
Definition qview.py:979
show_canvas(view=1)
Make the canvas visible (to be used in the constructor of the customization class)
Definition qview.py:735
_onSaveSequence(*args)
Definition qview.py:873
_onGlbFilter_MTX(*args)
Definition qview.py:939
_onGlbFilter_AO(*args)
Definition qview.py:911
_onSaveText(*args)
Definition qview.py:861
_onEvt_INIT(*args)
Definition qview.py:1058
_onQueryCurr_EQ(*args)
Definition qview.py:1022
_onGlbFilter_U0(*args)
Definition qview.py:943
peek(offset, size, num)
peeks data in the Target
Definition qview.py:212
_onGlbFilter_EQ(*args)
Definition qview.py:923
_trap_error(*args)
Definition qview.py:844
post(signal, params=None)
post a given event to the current AO object in the Target
Definition qview.py:390
qunpack(fmt, bstr)
Unpack a QS trace record.
Definition qview.py:437
_onGlbFilter_MP(*args)
Definition qview.py:927
_quit(err=0)
Definition qview.py:746
_onGlbFilter_SM(*args)
Definition qview.py:907
_onCurrObj_AO(*args)
Definition qview.py:988
loc_filter(*args)
Set/clear the Local-Filter in the Target.
Definition qview.py:299
_strVar_value(strVar, base=0)
Definition qview.py:1086
_onEvt_DISPATCH(*args)
Definition qview.py:1062
_onCanvasClose()
Definition qview.py:887
on_run(self)
Definition qview.py:180
query_curr(obj_kind)
query the current object in the Target
Definition qview.py:378
_onCurrObj_MP(*args)
Definition qview.py:993
_init_gui(root)
Definition qview.py:491
_onCurrObj_AP(*args)
Definition qview.py:1005
_onTick0(*args)
Definition qview.py:1042
print_text(string)
Print a string to the Text area.
Definition qview.py:725
_onGlbFilter_U2(*args)
Definition qview.py:951
_onCurrObj_TE(*args)
Definition qview.py:1001
_onSaveMatlab(*args)
Definition qview.py:869
init(signal=0, params=None)
take the top-most initial transition in the current SM object in the Target
Definition qview.py:397
_onGlbFilter_SEM(*args)
Definition qview.py:935
poke(offset, size, data)
pokes data into the Target
Definition qview.py:218
glb_filter(*args)
Set/clear the Global-Filter in the Target.
Definition qview.py:225
_onFrameView(*args)
Definition qview.py:892
on_reset(self)
Definition qview.py:176
ao_filter(obj_id)
Set/clear the Active-Object Local-Filter in the Target.
Definition qview.py:336
_onCurrObj_SM(*args)
Definition qview.py:983
_onGlbFilter_U1(*args)
Definition qview.py:947
_onLocFilter_AP(*args)
Definition qview.py:975
_onExit(*args)
Definition qview.py:751
_onGlbFilter_QF(*args)
Definition qview.py:915
_onEvt_PUBLISH(*args)
Definition qview.py:1050
publish(signal, params=None)
publish a given event to subscribers in the Target
Definition qview.py:384
_onLocFilter_EP(*args)
Definition qview.py:967
_onLocFilter_EQ(*args)
Definition qview.py:971
_assert(cond, message)
Definition qview.py:850
tick(tick_rate=0)
trigger system clock tick in the Target
Definition qview.py:206
_onTick1(*args)
Definition qview.py:1046
_onGlbFilter_U3(*args)
Definition qview.py:955
reset_target(*args)
Send the RESET packet to the Target.
Definition qview.py:185
_onGlbFilter_TE(*args)
Definition qview.py:919
command(cmdId, param1=0, param2=0, param3=0)
executes a given command in the Target
Definition qview.py:194
_onGlbFilter_SC(*args)
Definition qview.py:931
_onQueryCurr_TE(*args)
Definition qview.py:1026
_onEvt_POST(*args)
Definition qview.py:1054
_showerror(title, message)
Definition qview.py:1081
show_frame(view=1)
Make the frame visible (to be used in the constructor of the customization class)
Definition qview.py:741
_onTargetInfo(*args)
Definition qview.py:1034
_updateMenus()
Definition qview.py:764
_onSaveBin(*args)
Definition qview.py:865
main()
Definition qview.py:2004