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