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