winIDEA SDK
variables_chart.py
1# This script is licensed under BSD License, see file LICENSE.txt.
2#
3# (c) TASKING Germany GmbH, 2023
4
5"""
6This script plots several variables in one chart. The chart is
7automatically scaled so that all the data is visible.
8To use this script as a module, import it to your scripts and
9call function startRecorder() with the list of variable you want to
10observe.
11
12This script requires additional python modules: matplotlib ver 1.1,
13and numpy.
14"""
15
16import time
17import isystem.connect as ic
18
19import numpy as np
20import matplotlib.pyplot as plt
21import matplotlib.animation as animation
22
23
24winidea_id = ''
25
26
27def initTarget(cmgr):
28 """
29 This function initializes the target. Customize it according to
30 your needs.
31 """
32
33 debugCtrl = ic.CDebugFacade(cmgr)
34
35 debugCtrl.download()
36 debugCtrl.runUntilFunction("main")
37 debugCtrl.waitUntilStopped()
38 debugCtrl.run()
39
40 return debugCtrl
41
42
43def _read_data(watches):
44 """
45 This function reads variables from the target. It is called
46 periodically from updateChart()
47 """
48 global g_startTime
49
50 # read value of variables
51 row = []
52 for expression in watches:
53
54 value = g_debugCtrl.evaluate(ic.IConnectDebug.fRealTime, expression)
55 # CValueType contains also other methods, if you want to get
56 # value as integer, float, ... See
57 # http://isystem.com/files/isystem.connect/api/classisys_1_1_c_value_type.html
58 row.append(value.getInt())
59
60 current_time = time.time() - g_startTime
61 return current_time, row
62
63
64def updateChart(num, watches, xRange, isScale):
65 """
66 This function is periodically called by the animation loop.
67 """
68 global xdata, ydata
69
70 # read the data
71 t, y = _read_data(watches)
72
73 # append the data to the existing vectors of data
74 xdata = np.hstack((xdata, t))
75 ydata = np.row_stack((ydata, y))
76
77 # adjust axes
78 xmin, xmax = ax.get_xlim()
79 ymin, ymax = ax.get_ylim()
80
81 is_redraw = False
82 if t >= xmax:
83 if isScale:
84 ax.set_xlim(xmin, 2*xmax)
85 is_redraw = True
86 else:
87 ax.set_xlim(t - xRange, t)
88 is_redraw = True
89
90 delta_y_max = np.max(ydata)
91 delta_y_min = np.min(ydata)
92
93 delta_y = (delta_y_max - delta_y_min) / 10 # scale by 10% more if needed
94 if delta_y_max > ymax:
95 ax.set_ylim(ymin, delta_y_max + delta_y)
96 is_redraw = True
97
98 if delta_y_max < ymin:
99 ax.set_ylim(delta_y_min - delta_y, ymax)
100 is_redraw = True
101
102 if is_redraw:
103 ax.figure.canvas.draw()
104
105 # refresh lines
106 for i in range(len(g_lines)):
107 g_lines[i].set_data(xdata, ydata[:, i])
108
109 return g_lines,
110
111
112def startRecorder(isInitTarget, watches, samplingInterval, xRange, isScale):
113 """
114 This is the main function of this module.
115 Parameters:
116
117 isInitTarget - if true, function initTarget() is called, otherwise
118 the target must be initialized and running
119
120 watches - list of variables to plot, for example ['g_int', 'g_char']
121
122 samplingInterval - time in milliseconds between reading of samples
123
124 xRange - initiali range on x-axis
125
126 isScale if true, data is scale along x axis so that everything is visible,
127 otherwise x-axis is shifted.
128 """
129 global g_lines, ax, xdata, ydata, \
130 g_debugCtrl, g_startTime
131
132 cmgr = ic.ConnectionMgr()
133 cmgr.connect(ic.CConnectionConfig().instanceId(winidea_id))
134
135 if isInitTarget:
136 g_debugCtrl = initTarget(cmgr)
137 else:
138 g_debugCtrl = ic.CDebugFacade(cmgr)
139
140 g_startTime = time.time()
141 xdata = np.zeros(0)
142 ydata = np.zeros((0, len(watches)))
143
144 figure = plt.figure()
145 ax = figure.add_subplot(111)
146
147 g_lines = ax.plot([0], [[0]*len(watches)], lw=1)
148 ax.set_ylim(-1, 1)
149 ax.set_xlim(0, xRange)
150 ax.grid()
151
152 ani = animation.FuncAnimation(figure, updateChart, 40, blit=False,
153 interval=samplingInterval,
154 fargs=[watches, xRange, isScale])
155 plt.show()
156
157
158if __name__ == '__main__':
159 startRecorder(True, ['g_complexStruct.i_cplx', 'g_char'], 10, 10, False)