winIDEA SDK
Loading...
Searching...
No Matches
data_recorder_with_daq.py
1# This script is licensed under BSD License, see file LICENSE.txt, or search for `License` in the SDK online help.
2# (c) TASKING Germany GmbH, 2023
3#
4# This script demonstrates recording of variables using fast data
5# acquisition (DAQ) approach. The recorded data is written to CSV
6# file. If the 'openpyxl' module is installed, the data is also
7# written to XLSX file. If 'pylab' module is installed, the acquired
8# data is also plotted.
9#
10# All the above functionality is grouped into functions, so you can
11# easily take out only part of the script. This script can also be
12# imported as a module to user's scripts, so it is easy to reuse
13# functions found here.
14
15import sys
16import csv
17import time
18import isystem.connect as ic
19
20winidea_id = ''
21
22
23try:
24 import openpyxl
25 isOpenPyXLInstalled = True
26except (ImportError) as ex:
27 isOpenPyXLInstalled = False
28
29try:
30 import pylab as plab
31 isPyLabInstalled = True
32except (ImportError) as ex:
33 isPyLabInstalled = False
34
35
36def printHelp():
37 print("Usage: dataRecorderWithDAQ.py <variableName1 samplingRateInSeconds1> ...")
38 print("")
39 print(" If 'samplingRateInSeconds' == 0, the smallest possible sampling")
40 print(" time is used. Supported values: 0.001, 0.01, 0.1, 1 second.")
41 print(" See CDAQController::EDAQSampligFlags for all possible")
42 print(" values.")
43 print("")
44 print("")
45 print("Example: dataRecorderWithDAQ.py main_loop_counter 0.1 g_baseStruct.i_base 0.01")
46 print(" records main_loop_counter each 100 ms, and g_baseStruct.i_base with 10 ms period.")
47
48
49def initTarget(cmgr):
50 """
51 This function initializes the target. Customize it according to
52 your needs.
53 """
54
55 debugCtrl = ic.CDebugFacade(cmgr)
56
57 debugCtrl.download()
58 debugCtrl.runUntilFunction("main")
59 debugCtrl.waitUntilStopped()
60
61 debugCtrl.run()
62
63 return debugCtrl
64
65
66def realTimeToDAQTimeFlags(samplTime):
67 """
68 Converts the given sampling time in seconds to EDAQSamplingFlags.
69 """
70 if samplTime < 0.001:
71 return ic.CDAQController.daqSampleMax
72 elif samplTime < 0.01:
73 return ic.CDAQController.daqSample1ms
74 elif samplTime < 0.1:
75 return ic.CDAQController.daqSample10ms
76 elif samplTime < 1:
77 return ic.CDAQController.daqSample100ms
78 else:
79 return ic.CDAQController.daqSample1s
80
81
82def recordVariables(cmgr,
83 debugCtrl,
84 variables,
85 recordingTimeInSeconds,
86 fileName,
87 isRecordToMemory,
88 isPrintToStdOut):
89 """
90 This function reads varibles and writes them to CSV file.
91 If isRecordToMemory == False, the amount of data that can be recorded is
92 limited by the free disk size.
93
94 Parameters:
95
96 debugCtrl - iSYSTEM's debugCtrl controller, which provides access to target
97
98 variables - array of two element arrays, where the first element contains
99 variable name and the second element contains sampling interval,
100 for example: [['main_loop_counter', 0.1], ['g_baseStruct.i_base', 0]].
101 Sampling interval set to 0 means the smallest interval possible.
102
103 recordingTimeInSeconds - how long to record the data, in seconds. Recording
104 can also be terminated by pressing the 'q' key
105
106 fileName - name of the output CSV file.
107
108 isRecordToMemory - if True, then data is also stored into memory
109 array and returned as function return value. Be
110 aware of memory usage in this case. If false,
111 an empty list is returned.
112
113 isPrintToStdOut - if True, each row is printed to stdout during recording
114
115 Returns:
116 List of rows, where each row is a list containing time stamp and recorded
117 values in the same order as variable names were specified. Example for
118 two samples of three variables::
119
120 [[0, 23, 45, 4.35],
121 [0.1, 24, -525, 1.78]
122 ]
123
124 """
125
126 daqCtrl = ic.CDAQController(cmgr)
127
128 # check if DAQ system is available
129 daqInfo = daqCtrl.info()
130 if daqInfo.getMaxItems() == 0:
131 raise Exception("Data Acquisition (DAQ) system is not available.")
132
133 print('MaxItems = ', daqInfo.getMaxItems())
134
135 daqVariables = ic.DAQConfigVector()
136 for varSamplData in variables:
137 varName = varSamplData[0]
138 samplTime = realTimeToDAQTimeFlags(varSamplData[1])
139
140 if varName.startswith('0x'):
141 # Direct memory address reading (32bit variable)
142 memAddr = int(varName)
143 daqVariables.append(ic.CDAQConfigItem(4, 0, memAddr, samplTime))
144 else:
145 # Reading a regular variable
146 daqVariables.append(ic.CDAQConfigItem(varName, samplTime))
147
148 # note the time of the DAQ system
149 daqTimeStart = daqCtrl.status().getTime()
150
151 daqCtrl.configure(daqVariables)
152
153 # enable DAQ on the entire SoC
154 daqCtrl.enableGlobal(True)
155
156 startTime = time.time()
157 endTime = startTime + recordingTimeInSeconds
158
159 numVars = len(variables)
160 recordedData = []
161
162 with open(fileName, 'w') as csvFile:
163
164 # add parameter dialect = 'excel' for Excel specific output
165 # See also http://docs.python.org/library/csv.html
166 # for configuring CSV output
167 csvWriter = csv.writer(csvFile)
168
169 varNames = []
170 for varData in variables:
171 varNames.append(varData[0])
172
173 csvWriter.writerow(['Time'] + varNames)
174
175 sampleCounter = 0
176
177 lastTime = 0
178 row = [''] * (1 + numVars)
179
180 while time.time() < endTime:
181
182 daqStatus = daqCtrl.status()
183 # if any sample is available, display the status and print the samples
184 if daqStatus.getNumSamplesAvailable() > 0:
185 # print 'Last DAQ acquisition time = ', daqStatus.getLastLoopTime()
186 if daqStatus.getOverflow():
187 print('SAMPLING OVERFLOW!')
188
189 # read available samples into daqSamples
190 daqSamples = ic.DAQSampleVector()
191 daqCtrl.read(daqSamples)
192
193 # print 'Number of samples = ', daqSamples.size()
194 for daqSample in daqSamples:
195
196 sampleTime = daqSample.getTime() - daqTimeStart
197 columnIndex = daqSample.getIndex()+1
198
199 var = daqCtrl.getDataValue(daqSample)
200
201 if var.isTypeUnsigned() or var.isTypeSigned():
202 value = var.getLong()
203 elif var.isTypeFloat():
204 value = var.getDouble()
205 elif var.isTypeAddress():
206 value = var.getAddress().m_aAddress
207 elif var.isTypeCompound():
208 value = 'Struct'
209
210 # new time found - writing
211 if (sampleTime != lastTime):
212
213 # Write the last row of data if this is not the first
214 # data received
215 if (lastTime != 0):
216 csvWriter.writerow(row)
217 if isPrintToStdOut:
218 print(row)
219 if isRecordToMemory:
220 recordedData.append(row)
221
222 #row[:] = ''
223 row = [''] * (numVars+1)
224 row[0] = sampleTime
225
226 # Remember what time was last used to fill rhe row of data
227 lastTime = sampleTime
228
229 row[columnIndex] = value
230
231 # And the last line of data
232 if (lastTime != 0):
233 csvWriter.writerow(row)
234 if isPrintToStdOut:
235 print(row)
236 if isRecordToMemory:
237 recordedData.append(row)
238
239 return recordedData
240
241
242def writeDataToXLSX(fileName, data, expressions):
243 book = openpyxl.Workbook()
244 sheet = book.create_sheet()
245 sheet.title = 'Variables'
246
247 # write header
248 sheet.append(['Time'] + expressions)
249
250 for row in data:
251 sheet.append(row)
252
253 book.save(fileName)
254
255
256def main():
257
258 if len(sys.argv) < 2:
259 printHelp()
260 return
261
262 samplingInfo = []
263 varNames = []
264
265 # create (varName, samplingTime) pairs from params in command line
266 # Example input parameters:
267 # a_my_signal 0.01 a_my_int 0 a_my_char 1 DigitalIn.DIN0 0.1 AnalogIn.AIN1 0.1 DigitalIn.DIN125
268 # For digital mask testing:
269 # DigitalIn.DIN 1 DigitalIn.DIN2 1 DigitalIn.DIN123 1 DigitalIn.DIN765 1 DigitalIn.DIN23456 1
270 for idx in range(1, len(sys.argv), 2):
271 varName = sys.argv[idx]
272 varNames.append(varName)
273 samplingInfo.append([varName, float(sys.argv[idx + 1])])
274
275 cmgr = ic.ConnectionMgr()
276 cmgr.initLogger('daq', 'daqExample.log', ic.CLogger.PYTHON)
277 cmgr.connect(ic.CConnectionConfig().instanceId(winidea_id))
278 if not cmgr.isAttached():
279 print("The connection to winIDEA has not been established - exiting script.")
280 sys.exit(-1)
281 else:
282 print("Established connection to winIDEA.")
283 debugCtrl = initTarget(cmgr)
284
285 # Here you can modify recording time and file name.
286 recordingTimeInSeconds = 3 # after this time the script will stop
287 filePrefix = 'daqData'
288 isRecordToMemory = True
289 isPrintToStdOut = True
290 print('Recording ...')
291
292 daqResults = recordVariables(cmgr,
293 debugCtrl,
294 samplingInfo,
295 recordingTimeInSeconds,
296 filePrefix + '.csv',
297 isRecordToMemory,
298 isPrintToStdOut)
299
300 if isOpenPyXLInstalled and daqResults:
301 writeDataToXLSX(filePrefix + '.xlsx', daqResults, varNames)
302
303 if isPyLabInstalled:
304 lineTypes = ['k', 'r', 'g', 'b', 'k:', 'r:', 'g:', 'b:']
305
306 # create array of strings, since empty values are stored as empty strings
307 data = plab.array(daqResults).astype('S12')
308
309 plotIdx = 1
310 for varName in varNames:
311 plab.subplot(len(varNames), 1, plotIdx)
312
313 # filters all lines, where data is not available - if we have
314 # different sampling times for variables, then the less frequently
315 # sampled variables have no values.
316 linesData = data[data[:, plotIdx] != b'']
317 times = linesData[:, 0] # the first column is time
318 plab.plot(times, linesData[:, plotIdx], lineTypes[(plotIdx - 1)% len(lineTypes)])
319 plab.ylabel(varName)
320 plotIdx += 1
321
322 plab.xlabel('t[s]')
323 plab.show()
324
325 print('Done!')
326
327if __name__ == '__main__':
328 main()