1 | /* |
2 | * Copyright (c) 2007-2015 Freescale Semiconductor, Inc. |
3 | * Copyright 2018-2020 NXP |
4 | * |
5 | * License: NXP LA_OPT_NXP_Software_License |
6 | * |
7 | * NXP Confidential. This software is owned or controlled by NXP and may |
8 | * only be used strictly in accordance with the applicable license terms. |
9 | * By expressly accepting such terms or by downloading, installing, |
10 | * activating and/or otherwise using the software, you are agreeing that |
11 | * you have read, and that you agree to comply with and are bound by, |
12 | * such license terms. If you do not agree to be bound by the applicable |
13 | * license terms, then you may not retain, install, activate or otherwise |
14 | * use the software. This code may only be used in a microprocessor, |
15 | * microcontroller, sensor or digital signal processor ("NXP Product") |
16 | * supplied directly or indirectly from NXP. See the full NXP Software |
17 | * License Agreement in license/LA_OPT_NXP_Software_License.pdf |
18 | * |
19 | * FreeMASTER Communication Driver - Recorder implementation |
20 | */ |
21 | |
22 | #include "freemaster.h" |
23 | #include "freemaster_private.h" |
24 | #include "freemaster_protocol.h" |
25 | #include "freemaster_utils.h" |
26 | |
27 | #if FMSTR_USE_RECORDER > 0 && FMSTR_DISABLE == 0 |
28 | |
29 | #include "freemaster_rec.h" |
30 | |
31 | /******************************************************** |
32 | * local macros definition |
33 | ********************************************************/ |
34 | |
35 | /* Define Protocol operations*/ |
36 | #define FMSTR_REC_PRTCLSET_OP_CFGMEM 0x01U /* Set number of recorder variables, points and post-trigger */ |
37 | #define FMSTR_REC_PRTCLSET_OP_CFGVAR 0x02U /* Setup address, size, and threshold detection of one recorder variable */ |
38 | #define FMSTR_REC_PRTCLSET_OP_START 0x03U /* Start recorder if not yet running */ |
39 | #define FMSTR_REC_PRTCLSET_OP_STOP 0x04U /* Stop recorder immediately */ |
40 | |
41 | #define FMSTR_REC_PRTCLGET_OP_DESCR 0x81U /* String description of recorder sampling point etc. */ |
42 | #define FMSTR_REC_PRTCLGET_OP_LIMITS 0x82U /* Get maximum number of recorder variables, and size of the recorder memory. */ |
43 | #define FMSTR_REC_PRTCLGET_OP_INFO 0x83U /* Get recorder base address, number of recorded variables, and other info. */ |
44 | #define FMSTR_REC_PRTCLGET_OP_STATUS 0x84U /* Get current recorder status (running/stopped etc.) */ |
45 | |
46 | /* recorder structures alignment */ |
47 | #ifndef FMSTR_REC_STRUCT_ALIGN |
48 | #define FMSTR_REC_STRUCT_ALIGN sizeof(void *) |
49 | #endif |
50 | |
51 | /******************************************************** |
52 | * local types definition |
53 | ********************************************************/ |
54 | |
55 | /* Forward declaration of needed structures */ |
56 | struct FMSTR_REC_VAR_DATA_S; |
57 | |
58 | /* trigger threshold level (1,2,4 or 8 bytes) */ |
59 | typedef union |
60 | { |
61 | FMSTR_U8 raw[8]; |
62 | FMSTR_U8 u8; |
63 | FMSTR_S8 s8; |
64 | FMSTR_U16 u16; |
65 | FMSTR_S16 s16; |
66 | FMSTR_U32 u32; |
67 | FMSTR_S32 s32; |
68 | FMSTR_U64 u64; |
69 | FMSTR_S64 s64; |
70 | #if FMSTR_REC_FLOAT_TRIG > 0 |
71 | FMSTR_FLOAT fp; |
72 | FMSTR_DOUBLE dbl; |
73 | #endif |
74 | } FMSTR_REC_THRESHOLD; |
75 | |
76 | /* recorder runtime flags */ |
77 | typedef volatile union |
78 | { |
79 | FMSTR_FLAGS all; /* all flags in one field */ |
80 | |
81 | struct |
82 | { |
83 | unsigned isConfigured : 1; /* recorder is configured */ |
84 | unsigned hasData : 1; /* cleared when configured, set when at least one point is sampled */ |
85 | unsigned isRunning : 1; /* recorder is running */ |
86 | unsigned isVirginCycle : 1; /* virgin cycle of the circular buffer in-progress */ |
87 | unsigned isStopping : 1; /* trigger activated, sample countdown */ |
88 | } flg; |
89 | |
90 | } FMSTR_REC_FLAGS; |
91 | |
92 | /* compare functions prototype */ |
93 | typedef FMSTR_BOOL (*FMSTR_PCOMPAREFUNC)(struct FMSTR_REC_VAR_DATA_S *varData); |
94 | |
95 | /* Recorder internal description of one variable */ |
96 | typedef struct FMSTR_REC_VAR_DATA_S |
97 | { |
98 | FMSTR_REC_VAR cfg; /* variable configuration */ |
99 | FMSTR_REC_THRESHOLD thresholdVal; /* trigger threshold value if used */ |
100 | FMSTR_PCOMPAREFUNC compareFunc; /* pointer to trigger compare function if used */ |
101 | FMSTR_BOOL trgLastState; /* last trigger comparison state for edge detection if used */ |
102 | } FMSTR_REC_VAR_DATA; |
103 | |
104 | /* runtime variables */ |
105 | typedef struct |
106 | { |
107 | FMSTR_REC_VAR_DATA *varDescr; /* table with recorder variables description. */ |
108 | FMSTR_ADDR buffAddr; /* Address of buffer for recorded variables. */ |
109 | FMSTR_SIZE buffSize; /* Size of buffer for recorded variables. */ |
110 | FMSTR_SIZE totalSmplsCnt; /* recorder total samples count */ |
111 | FMSTR_SIZE timeDivCtr; /* recorder "clock" divisor counter */ |
112 | FMSTR_SIZE postTrigger; /* post-trigger value computed from user's pre-trigger */ |
113 | FMSTR_SIZE stopRecCountDown; /* post-trigger countdown counter */ |
114 | FMSTR_ADDR writePtr; /* write pointer in recorder buffer */ |
115 | FMSTR_ADDR endBuffPtr; /* pointer to end of active recorder buffer */ |
116 | FMSTR_SIZE pointSize; /* size of one variable shot */ |
117 | FMSTR_SIZE pointVarCount; /* number of variables recorded (trigger-only vars excluded) */ |
118 | FMSTR_REC_FLAGS flags; /* recorder flags */ |
119 | FMSTR_REC_CFG config; /* original recorder configuration */ |
120 | } FMSTR_REC; |
121 | |
122 | /* Map of FreeMASTER recorder instance in memory */ |
123 | /*********************************************/ |
124 | /*********************************************/ |
125 | /** FMSTR_REC **/ |
126 | /** ************************************** **/ |
127 | /** * FMSTR_REC_CFG * **/ |
128 | /** * * **/ |
129 | /** * * **/ |
130 | /** ************************************** **/ |
131 | /** **/ |
132 | /*********************************************/ |
133 | /** **/ |
134 | /** FMSTR_REC_VAR_DATA - arrays **/ |
135 | /** **/ |
136 | /*********************************************/ |
137 | /** **/ |
138 | /** **/ |
139 | /** **/ |
140 | /** FreeMASTER recorder samples buffer **/ |
141 | /** **/ |
142 | /** **/ |
143 | /** **/ |
144 | /*********************************************/ |
145 | |
146 | /******************************************************** |
147 | * local static functions declarations |
148 | ********************************************************/ |
149 | |
150 | static FMSTR_REC_BUFF *_FMSTR_GetRecorderBufferByRecIx(FMSTR_INDEX recIndex); |
151 | static FMSTR_REC *_FMSTR_GetRecorderByRecIx(FMSTR_INDEX recIndex); |
152 | |
153 | static FMSTR_U8 _FMSTR_CheckConfiguration(FMSTR_REC *recorder); |
154 | static FMSTR_U8 _FMSTR_RecMemCfg(FMSTR_REC *recorder, FMSTR_INDEX recIndex, FMSTR_REC_CFG *recCfg); |
155 | static FMSTR_U8 _FMSTR_RecVarCfg(FMSTR_REC *recorder, FMSTR_INDEX recVarIx, FMSTR_REC_VAR *recVarCfg); |
156 | |
157 | static FMSTR_U8 _FMSTR_StartRec(FMSTR_REC *recorder); |
158 | static FMSTR_U8 _FMSTR_TriggerRec(FMSTR_REC *recorder); |
159 | static FMSTR_U8 _FMSTR_AbortRec(FMSTR_REC *recorder); |
160 | |
161 | static FMSTR_BPTR _FMSTR_SetRecCmd_CFGMEM( |
162 | FMSTR_BPTR msgBuffIO, FMSTR_SIZE opLen, FMSTR_REC *recorder, FMSTR_INDEX recIndex, FMSTR_U8 *retStatus); |
163 | static FMSTR_BPTR _FMSTR_SetRecCmd_CFGVAR(FMSTR_BPTR msgBuffIO, |
164 | FMSTR_SIZE opLen, |
165 | FMSTR_REC *recorder, |
166 | FMSTR_U8 *retStatus); |
167 | |
168 | static FMSTR_BOOL _FMSTR_RecIsValidVarSize(FMSTR_SIZE size); |
169 | static FMSTR_U8 _FMSTR_CalcRecStatus(FMSTR_REC_FLAGS recFlags); |
170 | |
171 | static FMSTR_BOOL _FMSTR_Compare8S(FMSTR_REC_VAR_DATA *varData); |
172 | static FMSTR_BOOL _FMSTR_Compare8U(FMSTR_REC_VAR_DATA *varData); |
173 | static FMSTR_BOOL _FMSTR_Compare16S(FMSTR_REC_VAR_DATA *varData); |
174 | static FMSTR_BOOL _FMSTR_Compare16U(FMSTR_REC_VAR_DATA *varData); |
175 | static FMSTR_BOOL _FMSTR_Compare32S(FMSTR_REC_VAR_DATA *varData); |
176 | static FMSTR_BOOL _FMSTR_Compare32U(FMSTR_REC_VAR_DATA *varData); |
177 | static FMSTR_BOOL _FMSTR_Compare64S(FMSTR_REC_VAR_DATA *varData); |
178 | static FMSTR_BOOL _FMSTR_Compare64U(FMSTR_REC_VAR_DATA *varData); |
179 | #if FMSTR_REC_FLOAT_TRIG > 0 |
180 | static FMSTR_BOOL _FMSTR_CompareFloat(FMSTR_REC_VAR_DATA *varData); |
181 | static FMSTR_BOOL _FMSTR_CompareDouble(FMSTR_REC_VAR_DATA *varData); |
182 | #endif |
183 | |
184 | static void _FMSTR_Recorder2(FMSTR_REC *recorder); |
185 | |
186 | /******************************************************** |
187 | * static variables |
188 | ********************************************************/ |
189 | |
190 | /* Recorder buffers */ |
191 | static FMSTR_REC_BUFF fmstr_recBuffs[FMSTR_USE_RECORDER]; |
192 | |
193 | #if FMSTR_REC_BUFF_SIZE > 0 |
194 | /* statically allocated recorder buffer */ |
195 | static FMSTR_U8 fmstr_pOwnRecBuffer[FMSTR_REC_BUFF_SIZE]; |
196 | #endif |
197 | |
198 | /****************************************************************************** |
199 | * |
200 | * @brief Recorder Initialization |
201 | * |
202 | ******************************************************************************/ |
203 | |
204 | FMSTR_BOOL FMSTR_InitRec(void) |
205 | { |
206 | FMSTR_BOOL ok = FMSTR_TRUE; |
207 | |
208 | #if FMSTR_REC_BUFF_SIZE > 0 |
209 | FMSTR_REC_BUFF recBuffCfg; |
210 | #endif |
211 | |
212 | /* Initialize array of recorder buffers descriptors */ |
213 | FMSTR_MemSet(fmstr_recBuffs, 0, sizeof(fmstr_recBuffs)); |
214 | |
215 | #if FMSTR_REC_BUFF_SIZE > 0 |
216 | /* When FMSTR_REC_BUFF_SIZE is defined, create the default buffer */ |
217 | recBuffCfg.addr = (FMSTR_ADDR)fmstr_pOwnRecBuffer; |
218 | recBuffCfg.size = FMSTR_REC_BUFF_SIZE; |
219 | recBuffCfg.name = "Default Recorder"; |
220 | recBuffCfg.basePeriod_ns = FMSTR_REC_TIMEBASE; |
221 | |
222 | /* and create the recorder #0 automatically */ |
223 | ok = FMSTR_RecorderCreate(0, &recBuffCfg); |
224 | #endif |
225 | |
226 | return ok; |
227 | } |
228 | |
229 | /****************************************************************************** |
230 | * |
231 | * @brief API: Set up the recorder buffer |
232 | * |
233 | * @param recIndex - index of recorder to set up |
234 | * @param recBuffer - user buffer pointer |
235 | * @param recBuffSize - buffer size |
236 | * |
237 | * |
238 | ******************************************************************************/ |
239 | |
240 | FMSTR_BOOL FMSTR_RecorderCreate(FMSTR_INDEX recIndex, FMSTR_REC_BUFF *buffCfg) |
241 | { |
242 | FMSTR_REC_BUFF *recBuff; |
243 | FMSTR_SIZE alignment; |
244 | |
245 | /* Check the input parameters */ |
246 | if (recIndex >= (FMSTR_INDEX)FMSTR_USE_RECORDER) |
247 | { |
248 | return FMSTR_FALSE; |
249 | } |
250 | |
251 | FMSTR_ASSERT_RETURN(buffCfg != NULL, FMSTR_FALSE); |
252 | |
253 | if (buffCfg->addr == NULL) |
254 | { |
255 | return FMSTR_FALSE; |
256 | } |
257 | |
258 | /* Check for some minimal value of buffer */ |
259 | if (buffCfg->size < (sizeof(FMSTR_REC) + 128U)) |
260 | { |
261 | return FMSTR_FALSE; |
262 | } |
263 | |
264 | /* Check that the name is already included */ |
265 | if (buffCfg->name == NULL) |
266 | { |
267 | return FMSTR_FALSE; |
268 | } |
269 | |
270 | if ((recBuff = _FMSTR_GetRecorderBufferByRecIx(recIndex)) == NULL) |
271 | { |
272 | return FMSTR_FALSE; |
273 | } |
274 | |
275 | /* The buffer should not yet be used */ |
276 | if (FMSTR_ADDR_VALID(recBuff->addr) != FMSTR_FALSE) |
277 | { |
278 | return FMSTR_FALSE; |
279 | } |
280 | |
281 | /* Set up the recorder buffer */ |
282 | *recBuff = *buffCfg; |
283 | |
284 | /* Clean up the buffer */ |
285 | FMSTR_MemSet(recBuff->addr, 0, recBuff->size); |
286 | |
287 | /* Align buffer base address */ |
288 | alignment = FMSTR_GetAlignmentCorrection(recBuff->addr, FMSTR_REC_STRUCT_ALIGN); |
289 | recBuff->addr += alignment; |
290 | recBuff->size -= alignment; |
291 | |
292 | return FMSTR_TRUE; |
293 | } |
294 | |
295 | /****************************************************************************** |
296 | * |
297 | * @brief API: Change the recorder time base information. |
298 | * |
299 | * @param recIndex - index of recorder |
300 | * @param timeBase_ns - new time base to be assigned to recorder, in nanoseconds |
301 | * |
302 | ******************************************************************************/ |
303 | |
304 | FMSTR_BOOL FMSTR_RecorderSetTimeBase(FMSTR_INDEX recIndex, FMSTR_U32 timeBase_ns) |
305 | { |
306 | FMSTR_REC_BUFF *recBuff; |
307 | |
308 | FMSTR_ASSERT_RETURN(recIndex < (FMSTR_INDEX)FMSTR_USE_RECORDER, FMSTR_FALSE); |
309 | |
310 | recBuff = _FMSTR_GetRecorderBufferByRecIx(recIndex); |
311 | FMSTR_ASSERT_RETURN(recBuff != NULL, FMSTR_FALSE); |
312 | |
313 | recBuff->basePeriod_ns = timeBase_ns; |
314 | return FMSTR_TRUE; |
315 | } |
316 | |
317 | /****************************************************************************** |
318 | * |
319 | * @brief API: Set up the recorder configuration |
320 | * |
321 | * @param recIndex - index of recorder |
322 | * @param recCfg - pointer to recorder configuration |
323 | * |
324 | ******************************************************************************/ |
325 | |
326 | FMSTR_BOOL FMSTR_RecorderConfigure(FMSTR_INDEX recIndex, FMSTR_REC_CFG *recCfg) |
327 | { |
328 | FMSTR_REC *recorder; |
329 | |
330 | FMSTR_ASSERT_RETURN(recIndex < (FMSTR_INDEX)FMSTR_USE_RECORDER, FMSTR_FALSE); |
331 | FMSTR_ASSERT_RETURN(recCfg != NULL, FMSTR_FALSE); |
332 | |
333 | if ((recorder = _FMSTR_GetRecorderByRecIx(recIndex)) == NULL) |
334 | { |
335 | return FMSTR_FALSE; |
336 | } |
337 | |
338 | return (FMSTR_BOOL)((_FMSTR_RecMemCfg(recorder, recIndex, recCfg) == FMSTR_STS_OK) ? FMSTR_TRUE : FMSTR_FALSE); |
339 | } |
340 | |
341 | /****************************************************************************** |
342 | * |
343 | * @brief Set up the recorder configuration (internal version) |
344 | * |
345 | * @param recorder - recorder structure |
346 | * @param recCfg - recorder configuration |
347 | * |
348 | * @return FMSTR_STC_xxx status code |
349 | * |
350 | ******************************************************************************/ |
351 | |
352 | static FMSTR_U8 _FMSTR_RecMemCfg(FMSTR_REC *recorder, FMSTR_INDEX recIndex, FMSTR_REC_CFG *recCfg) |
353 | { |
354 | FMSTR_REC_BUFF *recBuff = _FMSTR_GetRecorderBufferByRecIx(recIndex); |
355 | FMSTR_ADDR dynAddr; |
356 | FMSTR_INDEX spaceLeft; |
357 | |
358 | /* Assert that recBuff->addr==recorder and that recBuff->size is large enough for recCfg->varCount and recorder |
359 | * structure itself */ |
360 | FMSTR_ASSERT(recBuff != NULL); |
361 | FMSTR_ASSERT(recBuff->addr == FMSTR_CAST_PTR_TO_ADDR(recorder)); |
362 | FMSTR_ASSERT(recBuff->size >= (FMSTR_SIZE)(sizeof(FMSTR_REC) + sizeof(FMSTR_REC_VAR_DATA) * (FMSTR_SIZE)recCfg->varCount)); |
363 | |
364 | /* Make sure the recorder is stopped first before clearing the whole structure below |
365 | (in case the FMSTR_Recorder is called from ISR, it could be invoked in the middle of clearing) */ |
366 | recorder->flags.all = 0U; |
367 | |
368 | /* Reset the recorder context */ |
369 | FMSTR_MemSet(recorder, 0, sizeof(FMSTR_REC)); |
370 | |
371 | /* Copy the config structure */ |
372 | recorder->config = *recCfg; |
373 | |
374 | /* Initialize the variable configuration array (the array follows the recorder structure) */ |
375 | dynAddr = (FMSTR_ADDR)(recorder + 1); |
376 | dynAddr += FMSTR_GetAlignmentCorrection(dynAddr, FMSTR_REC_STRUCT_ALIGN); |
377 | recorder->varDescr = (FMSTR_REC_VAR_DATA *)dynAddr; |
378 | FMSTR_MemSet(recorder->varDescr, 0, sizeof(FMSTR_REC_VAR_DATA) * (FMSTR_SIZE)recCfg->varCount); |
379 | |
380 | /* Data sampling area follows the variable array */ |
381 | dynAddr = (FMSTR_ADDR)(recorder->varDescr + recCfg->varCount); |
382 | dynAddr += FMSTR_GetAlignmentCorrection(dynAddr, FMSTR_REC_STRUCT_ALIGN); |
383 | recorder->buffAddr = dynAddr; |
384 | |
385 | /*...and spans to the end of the recorder memory */ |
386 | spaceLeft = dynAddr - FMSTR_CAST_PTR_TO_ADDR(recorder); |
387 | recorder->buffSize = recBuff->size - (FMSTR_SIZE)spaceLeft; |
388 | |
389 | return FMSTR_STS_OK; |
390 | } |
391 | |
392 | /****************************************************************************** |
393 | * |
394 | * @brief Handling SETREC Memory configuration command (CFGMEM op_code) |
395 | * |
396 | * @param msgBuffIO - original command (in) and response buffer (out) |
397 | * @param opLen - data length |
398 | * @param recorder - recorder structure |
399 | * @param retStatus - pointer to return status variable |
400 | * |
401 | * @return As all command handlers, the return value should be the buffer |
402 | * pointer where the response output finished (except checksum) |
403 | * |
404 | ******************************************************************************/ |
405 | |
406 | static FMSTR_BPTR _FMSTR_SetRecCmd_CFGMEM( |
407 | FMSTR_BPTR msgBuffIO, FMSTR_SIZE opLen, FMSTR_REC *recorder, FMSTR_INDEX recIndex, FMSTR_U8 *retStatus) |
408 | { |
409 | FMSTR_REC_CFG recCfg; |
410 | FMSTR_BPTR tmpMsgBuffIO = msgBuffIO; |
411 | |
412 | FMSTR_MemSet(&recCfg, 0, sizeof(recCfg)); |
413 | |
414 | /* Get the configuration from input buffer */ |
415 | msgBuffIO = FMSTR_ValueFromBuffer8(&recCfg.varCount, msgBuffIO); |
416 | msgBuffIO = FMSTR_SizeFromBuffer(&recCfg.totalSmps, msgBuffIO); |
417 | msgBuffIO = FMSTR_SizeFromBuffer(&recCfg.preTrigger, msgBuffIO); |
418 | msgBuffIO = FMSTR_SizeFromBuffer(&recCfg.timeDiv, msgBuffIO); |
419 | |
420 | /* Check the size if it's valid */ |
421 | if (msgBuffIO != (tmpMsgBuffIO + opLen)) |
422 | { |
423 | *retStatus = FMSTR_STC_INVSIZE; |
424 | return msgBuffIO; |
425 | } |
426 | |
427 | /* Configure the Recorder */ |
428 | *retStatus = _FMSTR_RecMemCfg(recorder, recIndex, &recCfg); |
429 | |
430 | return msgBuffIO; |
431 | } |
432 | |
433 | /****************************************************************************** |
434 | * |
435 | * @brief API: Set up the recorder variable configuration |
436 | * |
437 | * @param recIndex - index of recorder |
438 | * @param recCfg - pointer to recorder configuration |
439 | * |
440 | * |
441 | ******************************************************************************/ |
442 | |
443 | FMSTR_BOOL FMSTR_RecorderAddVariable(FMSTR_INDEX recIndex, FMSTR_INDEX recVarIx, FMSTR_REC_VAR *recVarCfg) |
444 | { |
445 | FMSTR_REC *recorder; |
446 | |
447 | if ((recorder = _FMSTR_GetRecorderByRecIx(recIndex)) == NULL) |
448 | { |
449 | return FMSTR_FALSE; |
450 | } |
451 | |
452 | return (FMSTR_BOOL)((_FMSTR_RecVarCfg(recorder, recVarIx, recVarCfg) == FMSTR_STS_OK) ? FMSTR_TRUE : FMSTR_FALSE); |
453 | } |
454 | |
455 | /****************************************************************************** |
456 | * |
457 | * @brief Set up the recorder variable configuration (internal version) |
458 | * |
459 | * @param recIndex - index of recorder |
460 | * @param recVarIx - index of variable |
461 | * @param recVarCfg - variable configuration |
462 | * |
463 | * @return FMSTR_STC_xxx status code |
464 | * |
465 | ******************************************************************************/ |
466 | |
467 | static FMSTR_U8 _FMSTR_RecVarCfg(FMSTR_REC *recorder, FMSTR_INDEX recVarIx, FMSTR_REC_VAR *recVarCfg) |
468 | { |
469 | FMSTR_REC_VAR_DATA *varDescr; |
470 | FMSTR_PCOMPAREFUNC compareFunc = NULL; |
471 | |
472 | FMSTR_ASSERT_RETURN(((FMSTR_SIZE)recVarIx) < recorder->config.varCount, FMSTR_STC_INSTERR); |
473 | |
474 | /* Cannot change variable configuration when recorder is already configured (or even running) */ |
475 | if (recorder->flags.all != 0U) |
476 | { |
477 | return FMSTR_STC_SERVBUSY; |
478 | } |
479 | |
480 | /* valid numeric variable sizes only */ |
481 | if (_FMSTR_RecIsValidVarSize(recVarCfg->size) == FMSTR_FALSE) |
482 | { |
483 | return FMSTR_STC_INVSIZE; |
484 | } |
485 | |
486 | #if FMSTR_USE_TSA > 0 && FMSTR_USE_TSA_SAFETY > 0 |
487 | if (FMSTR_CheckTsaSpace(recVarCfg->addr, recVarCfg->size, FMSTR_FALSE) == FMSTR_FALSE) |
488 | { |
489 | return FMSTR_STC_EACCESS; |
490 | } |
491 | #endif /* FMSTR_USE_TSA && FMSTR_USE_TSA_SAFETY */ |
492 | |
493 | /* Is the variable set up for triggerring? */ |
494 | if ((recVarCfg->triggerMode & FMSTR_REC_TRG_TYPE_MASK) != 0U) |
495 | { |
496 | /* Is the threshold also variable? */ |
497 | #if FMSTR_USE_TSA > 0 && FMSTR_USE_TSA_SAFETY > 0 |
498 | if ((recVarCfg->triggerMode & FMSTR_REC_TRG_F_VARTHR) != 0U) |
499 | { |
500 | if (FMSTR_CheckTsaSpace(recVarCfg->trgAddr, recVarCfg->size, FMSTR_FALSE) == FMSTR_FALSE) |
501 | { |
502 | return FMSTR_STC_EACCESS; |
503 | } |
504 | } |
505 | #endif /* FMSTR_USE_TSA && FMSTR_USE_TSA_SAFETY */ |
506 | |
507 | /* get compare function */ |
508 | |
509 | if ((recVarCfg->triggerMode & FMSTR_REC_TRG_TYPE_MASK) == FMSTR_REC_TRG_TYPE_FLOAT) |
510 | { |
511 | #if FMSTR_REC_FLOAT_TRIG > 0 |
512 | switch (recVarCfg->size) |
513 | { |
514 | case 4: |
515 | compareFunc = _FMSTR_CompareFloat; |
516 | break; |
517 | case 8: |
518 | compareFunc = _FMSTR_CompareDouble; |
519 | break; |
520 | default: |
521 | return FMSTR_STC_INVSIZE; |
522 | } |
523 | #else |
524 | return FMSTR_STC_FLOATDISABLED; |
525 | #endif |
526 | } |
527 | else |
528 | { |
529 | FMSTR_BOOL sign = |
530 | (FMSTR_BOOL)((recVarCfg->triggerMode & FMSTR_REC_TRG_TYPE_MASK) == FMSTR_REC_TRG_TYPE_SINT); |
531 | |
532 | switch (recVarCfg->size) |
533 | { |
534 | case 1: |
535 | compareFunc = sign != FMSTR_FALSE ? _FMSTR_Compare8S : _FMSTR_Compare8U; |
536 | break; |
537 | case 2: |
538 | compareFunc = sign != FMSTR_FALSE ? _FMSTR_Compare16S : _FMSTR_Compare16U; |
539 | break; |
540 | case 4: |
541 | compareFunc = sign != FMSTR_FALSE ? _FMSTR_Compare32S : _FMSTR_Compare32U; |
542 | break; |
543 | case 8: |
544 | compareFunc = sign != FMSTR_FALSE ? _FMSTR_Compare64S : _FMSTR_Compare64U; |
545 | break; |
546 | /* invalid trigger variable size */ |
547 | default: |
548 | return FMSTR_STC_INVSIZE; |
549 | } |
550 | } |
551 | } |
552 | |
553 | varDescr = &recorder->varDescr[recVarIx]; |
554 | |
555 | /* Store the variable configuration */ |
556 | varDescr->cfg = *recVarCfg; |
557 | varDescr->compareFunc = compareFunc; |
558 | |
559 | return FMSTR_STS_OK; |
560 | } |
561 | |
562 | /****************************************************************************** |
563 | * |
564 | * @brief Handling SETREC Variable configuration command (CFGVAR op_code) |
565 | * |
566 | * @param msgBuffIO - original command (in) and response buffer (out) |
567 | * @param opLen - data length |
568 | * @param retStatus - pointer to return status variable |
569 | * |
570 | * @return As all command handlers, the return value should be the buffer |
571 | * pointer where the response output finished (except checksum) |
572 | * |
573 | ******************************************************************************/ |
574 | |
575 | static FMSTR_BPTR _FMSTR_SetRecCmd_CFGVAR(FMSTR_BPTR msgBuffIO, |
576 | FMSTR_SIZE opLen, |
577 | FMSTR_REC *recorder, |
578 | FMSTR_U8 *retStatus) |
579 | { |
580 | FMSTR_REC_VAR recVarCfg; |
581 | FMSTR_BPTR tmpMsgBuffIO = msgBuffIO; |
582 | FMSTR_U8 recVarIx = 0; |
583 | |
584 | FMSTR_MemSet(&recVarCfg, 0, sizeof(recVarCfg)); |
585 | |
586 | /* Get the recorder variable configuration from input buffer */ |
587 | msgBuffIO = FMSTR_ValueFromBuffer8(&recVarIx, msgBuffIO); |
588 | msgBuffIO = FMSTR_AddressFromBuffer(&recVarCfg.addr, msgBuffIO); |
589 | msgBuffIO = FMSTR_ValueFromBuffer8(&recVarCfg.size, msgBuffIO); |
590 | msgBuffIO = FMSTR_ValueFromBuffer8(&recVarCfg.triggerMode, msgBuffIO); |
591 | |
592 | /* Only valid variable can be configured */ |
593 | if (recVarIx >= recorder->config.varCount) |
594 | { |
595 | *retStatus = FMSTR_STC_INSTERR; |
596 | return msgBuffIO; |
597 | } |
598 | |
599 | /* Sanity check on variable size */ |
600 | if (recVarCfg.size > sizeof(FMSTR_REC_THRESHOLD)) |
601 | { |
602 | *retStatus = FMSTR_STC_INVSIZE; |
603 | return msgBuffIO; |
604 | } |
605 | |
606 | /* Variable threshold? */ |
607 | if ((recVarCfg.triggerMode & FMSTR_REC_TRG_F_VARTHR) != 0U) |
608 | { |
609 | /* Yes, get the pointer to variable threshold variable */ |
610 | msgBuffIO = FMSTR_AddressFromBuffer(&recVarCfg.trgAddr, msgBuffIO); |
611 | } |
612 | else |
613 | { |
614 | /* Constant threshold. Get its address. */ |
615 | FMSTR_U8 *constThresholdPtr = recorder->varDescr[recVarIx].thresholdVal.raw; |
616 | |
617 | switch (recVarCfg.triggerMode & FMSTR_REC_TRG_TYPE_MASK) |
618 | { |
619 | case FMSTR_REC_TRG_TYPE_FLOAT: |
620 | #if FMSTR_REC_FLOAT_TRIG > 0 |
621 | /* The Float is coded as a raw bytes in ULEB format */ |
622 | msgBuffIO = FMSTR_UlebDecode(msgBuffIO, constThresholdPtr, recVarCfg.size); |
623 | break; |
624 | #else |
625 | *retStatus = FMSTR_STC_FLOATDISABLED; |
626 | return msgBuffIO; |
627 | #endif |
628 | |
629 | case FMSTR_REC_TRG_TYPE_SINT: |
630 | msgBuffIO = FMSTR_SlebDecode(msgBuffIO, constThresholdPtr, recVarCfg.size); |
631 | break; |
632 | |
633 | case FMSTR_REC_TRG_TYPE_UINT: |
634 | default: |
635 | msgBuffIO = FMSTR_UlebDecode(msgBuffIO, constThresholdPtr, recVarCfg.size); |
636 | break; |
637 | } |
638 | |
639 | /* Pointer to constant threshold value */ |
640 | recVarCfg.trgAddr = (FMSTR_ADDR)constThresholdPtr; |
641 | } |
642 | |
643 | /* Secoded ULEBs should match the expected op_data length */ |
644 | if (msgBuffIO != (tmpMsgBuffIO + opLen)) |
645 | { |
646 | *retStatus = FMSTR_STC_INVSIZE; |
647 | } |
648 | else |
649 | { |
650 | /* Configure the Recorder variable */ |
651 | *retStatus = _FMSTR_RecVarCfg(recorder, (FMSTR_INDEX)recVarIx, &recVarCfg); |
652 | } |
653 | return msgBuffIO; |
654 | } |
655 | |
656 | /****************************************************************************** |
657 | * |
658 | * @brief Check recording variable size |
659 | * |
660 | ******************************************************************************/ |
661 | |
662 | static FMSTR_BOOL _FMSTR_RecIsValidVarSize(FMSTR_SIZE size) |
663 | { |
664 | return (FMSTR_BOOL)(size == 1U || size == 2U || size == 4U || size == 8U); |
665 | } |
666 | |
667 | /****************************************************************************** |
668 | * |
669 | * @brief Handling SETREC command |
670 | * |
671 | * @param session - transport session |
672 | * @param msgBuffIO - original command (in) and response buffer (out) |
673 | * @param inputLen - data length of input data |
674 | * @param retStatus - pointer to return status variable |
675 | * |
676 | * @return As all command handlers, the return value should be the buffer |
677 | * pointer where the response output finished (except checksum) |
678 | * |
679 | ******************************************************************************/ |
680 | |
681 | FMSTR_BPTR FMSTR_SetRecCmd(FMSTR_SESSION * session, FMSTR_BPTR msgBuffIO, FMSTR_SIZE inputLen, FMSTR_U8 *retStatus) |
682 | { |
683 | FMSTR_REC *recorder = NULL; |
684 | FMSTR_BPTR response = msgBuffIO; |
685 | FMSTR_U8 responseCode = FMSTR_STS_OK; |
686 | FMSTR_U8 recIndex = 0; |
687 | |
688 | /* Get recerder index */ |
689 | msgBuffIO = FMSTR_ValueFromBuffer8(&recIndex, msgBuffIO); |
690 | inputLen--; |
691 | |
692 | /* Valid recorder? */ |
693 | if ((recorder = _FMSTR_GetRecorderByRecIx((FMSTR_INDEX)recIndex)) == NULL) |
694 | { |
695 | *retStatus = FMSTR_STC_INSTERR; |
696 | return response; |
697 | } |
698 | |
699 | while (inputLen != 0U && (responseCode == FMSTR_STS_OK)) |
700 | { |
701 | FMSTR_U8 opCode, opLen; |
702 | |
703 | #if FMSTR_SESSION_COUNT > 1 |
704 | /* Is feature locked by me */ |
705 | if(FMSTR_IsFeatureOwned(session, FMSTR_FEATURE_REC, recIndex) == FMSTR_FALSE) |
706 | { |
707 | *retStatus = FMSTR_STC_SERVBUSY; |
708 | return response; |
709 | } |
710 | #endif |
711 | |
712 | /* Get Operation Code and data length */ |
713 | msgBuffIO = FMSTR_ValueFromBuffer8(&opCode, msgBuffIO); |
714 | msgBuffIO = FMSTR_ValueFromBuffer8(&opLen, msgBuffIO); |
715 | |
716 | /* data would span beyond the total frame size */ |
717 | if ((opLen + 2UL) > inputLen) |
718 | { |
719 | *retStatus = FMSTR_STC_INVSIZE; |
720 | return response; |
721 | } |
722 | |
723 | inputLen -= opLen + 2U; |
724 | |
725 | switch (opCode) |
726 | { |
727 | /* Set number of recorder variables, recorder points and post-trigger points. */ |
728 | case FMSTR_REC_PRTCLSET_OP_CFGMEM: |
729 | msgBuffIO = _FMSTR_SetRecCmd_CFGMEM(msgBuffIO, opLen, recorder, (FMSTR_INDEX)recIndex, &responseCode); |
730 | break; |
731 | |
732 | /* Configure variable */ |
733 | case FMSTR_REC_PRTCLSET_OP_CFGVAR: |
734 | msgBuffIO = _FMSTR_SetRecCmd_CFGVAR(msgBuffIO, opLen, recorder, &responseCode); |
735 | break; |
736 | |
737 | /* Start Recorder */ |
738 | case FMSTR_REC_PRTCLSET_OP_START: |
739 | responseCode = _FMSTR_StartRec(recorder); |
740 | break; |
741 | |
742 | /* Stop Recorder */ |
743 | case FMSTR_REC_PRTCLSET_OP_STOP: |
744 | responseCode = _FMSTR_AbortRec(recorder); |
745 | break; |
746 | |
747 | default: |
748 | responseCode = FMSTR_STC_INVOPCODE; |
749 | break; |
750 | } |
751 | } |
752 | |
753 | *retStatus = responseCode; |
754 | return response; |
755 | } |
756 | |
757 | /****************************************************************************** |
758 | * |
759 | * @brief Help function to crete recorder status byte |
760 | * |
761 | * @param recFlags - recorder flags |
762 | * |
763 | * @return Recorder status in specified protocol form. |
764 | * |
765 | ******************************************************************************/ |
766 | |
767 | static FMSTR_U8 _FMSTR_CalcRecStatus(FMSTR_REC_FLAGS recFlags) |
768 | { |
769 | /* Not Configured */ |
770 | if (recFlags.flg.isConfigured == 0U) |
771 | { |
772 | return 0x00; |
773 | } |
774 | |
775 | /* Running */ |
776 | if (recFlags.flg.isRunning != 0U) |
777 | { |
778 | return 0x02; |
779 | } |
780 | |
781 | /* Stopped, no data yet (was never running or was stopped before the first sample taken) */ |
782 | if (recFlags.flg.hasData == 0U) |
783 | { |
784 | return 0x01; |
785 | } |
786 | |
787 | /* Stopped, some data but not all (stopped during virgn cycle) */ |
788 | if (recFlags.flg.isVirginCycle != 0U) |
789 | { |
790 | return 0x03; |
791 | } |
792 | |
793 | /* Stopped, all data ready */ |
794 | return 0x04; |
795 | } |
796 | |
797 | /****************************************************************************** |
798 | * |
799 | * @brief Handling GETREC command |
800 | * |
801 | * @param session - transport session |
802 | * @param msgBuffIO - original command (in) and response buffer (out) |
803 | * @param retStatus - pointer to return status variable |
804 | * |
805 | * @return As all command handlers, the return value should be the buffer |
806 | * pointer where the response output finished (except checksum) |
807 | * |
808 | ******************************************************************************/ |
809 | |
810 | FMSTR_BPTR FMSTR_GetRecCmd(FMSTR_SESSION * session, FMSTR_BPTR msgBuffIO, FMSTR_U8 *retStatus) |
811 | { |
812 | FMSTR_U8 responseCode = (FMSTR_STS_OK | FMSTR_STSF_VARLEN); |
813 | FMSTR_BPTR response = msgBuffIO; |
814 | FMSTR_REC *recorder; |
815 | FMSTR_U8 recIndex; |
816 | FMSTR_U8 cfgCode; |
817 | |
818 | /* Get recorder index */ |
819 | msgBuffIO = FMSTR_ValueFromBuffer8(&recIndex, msgBuffIO); |
820 | |
821 | if ((recorder = _FMSTR_GetRecorderByRecIx((FMSTR_INDEX)recIndex)) == NULL) |
822 | { |
823 | *retStatus = FMSTR_STC_INSTERR; |
824 | return response; |
825 | } |
826 | else |
827 | { |
828 | /* Get the command configuration code */ |
829 | msgBuffIO = FMSTR_ValueFromBuffer8(&cfgCode, msgBuffIO); |
830 | |
831 | switch (cfgCode) |
832 | { |
833 | /* Get recorder description */ |
834 | case FMSTR_REC_PRTCLGET_OP_DESCR: |
835 | { |
836 | FMSTR_REC_BUFF *recorderBuff; |
837 | FMSTR_SIZE strLen; |
838 | |
839 | /* Get the recorder raw buffer where is also stored its name */ |
840 | if ((recorderBuff = _FMSTR_GetRecorderBufferByRecIx((FMSTR_INDEX)recIndex)) == NULL) |
841 | { |
842 | responseCode = FMSTR_STC_INVBUFF; |
843 | } |
844 | else |
845 | { |
846 | strLen = FMSTR_StrLen(recorderBuff->name); |
847 | response = FMSTR_CopyToBuffer(response, (FMSTR_ADDR)recorderBuff->name, strLen); |
848 | } |
849 | } |
850 | break; |
851 | |
852 | /* Get recorder limits */ |
853 | case FMSTR_REC_PRTCLGET_OP_LIMITS: |
854 | { |
855 | FMSTR_REC_BUFF *recorderBuff; |
856 | |
857 | /* Get the recorder */ |
858 | if ((recorderBuff = _FMSTR_GetRecorderBufferByRecIx((FMSTR_INDEX)recIndex)) == NULL) |
859 | { |
860 | responseCode = FMSTR_STC_INVBUFF; |
861 | } |
862 | else |
863 | { |
864 | /* Put Raw Size of recorder buffer */ |
865 | response = FMSTR_SizeToBuffer(response, recorderBuff->size); |
866 | /* Put Base period of the recorder */ |
867 | response = FMSTR_ULebToBuffer(response, recorderBuff->basePeriod_ns); |
868 | /* Put Size of recorder structure */ |
869 | response = FMSTR_SizeToBuffer(response, sizeof(FMSTR_REC)); |
870 | /* Put Size of recorder variable structure */ |
871 | response = FMSTR_SizeToBuffer(response, sizeof(FMSTR_REC_VAR_DATA)); |
872 | } |
873 | } |
874 | break; |
875 | |
876 | /* Get recorder info or status */ |
877 | case FMSTR_REC_PRTCLGET_OP_STATUS: |
878 | case FMSTR_REC_PRTCLGET_OP_INFO: |
879 | { |
880 | FMSTR_U8 recorderStatus; |
881 | |
882 | /* Make sure the status is up to date */ |
883 | recorderStatus = _FMSTR_CheckConfiguration(recorder); |
884 | FMSTR_UNUSED(recorderStatus); |
885 | |
886 | /* Add current status to buffer */ |
887 | recorderStatus = _FMSTR_CalcRecStatus(recorder->flags); |
888 | response = FMSTR_ValueToBuffer8(response, recorderStatus); |
889 | |
890 | /* full info response contains additional data */ |
891 | if (cfgCode == FMSTR_REC_PRTCLGET_OP_INFO) |
892 | { |
893 | if (recorderStatus == 0x00U) |
894 | { |
895 | /* count of recorded variables */ |
896 | response = FMSTR_ValueToBuffer8(response, 0U); |
897 | /* base address of recorder buffer */ |
898 | response = FMSTR_AddressToBuffer(response, FMSTR_CAST_PTR_TO_ADDR(NULL)); |
899 | /* size of the one set of the recorder point */ |
900 | response = FMSTR_SizeToBuffer(response, 0U); |
901 | /* count of currently stored points */ |
902 | response = FMSTR_SizeToBuffer(response, 0U); |
903 | /* index of the firt point in circular buffer */ |
904 | response = FMSTR_SizeToBuffer(response, 0U); |
905 | } |
906 | else |
907 | { |
908 | FMSTR_S32 byteIx = recorder->writePtr - recorder->buffAddr; |
909 | FMSTR_SIZE currIx = (FMSTR_SIZE)(((FMSTR_U32)byteIx) / recorder->pointSize); |
910 | FMSTR_SIZE recFirstPnt = recorder->flags.flg.isVirginCycle != 0U ? 0U : currIx; |
911 | FMSTR_SIZE recPntCnt = |
912 | recorder->flags.flg.isVirginCycle != 0U ? currIx : recorder->totalSmplsCnt; |
913 | |
914 | /* count of recorded variables */ |
915 | response = FMSTR_ValueToBuffer8(response, recorder->pointVarCount); |
916 | /* base address of recorder buffer */ |
917 | response = FMSTR_AddressToBuffer(response, recorder->buffAddr); |
918 | /* size of the one set of the recorder point */ |
919 | response = FMSTR_SizeToBuffer(response, recorder->pointSize); |
920 | /* count of currently stored points */ |
921 | response = FMSTR_SizeToBuffer(response, recPntCnt); |
922 | /* index of the first point in circular buffer */ |
923 | response = FMSTR_SizeToBuffer(response, recFirstPnt); |
924 | } |
925 | } |
926 | } |
927 | break; |
928 | |
929 | default: |
930 | responseCode = FMSTR_STC_INVOPCODE; |
931 | break; |
932 | } |
933 | } |
934 | |
935 | *retStatus = responseCode; |
936 | return response; |
937 | } |
938 | |
939 | /****************************************************************************** |
940 | * |
941 | * @brief API: Start recorder function |
942 | * |
943 | * @param recIndex - recorder index |
944 | * |
945 | * @return FMSTR_TRUE in case of successfuly start, FMSTR_FALSE otherwise. |
946 | * |
947 | * |
948 | ******************************************************************************/ |
949 | |
950 | FMSTR_BOOL FMSTR_RecorderStart(FMSTR_INDEX recIndex) |
951 | { |
952 | FMSTR_REC *recorder; |
953 | |
954 | /* Get the recorder */ |
955 | if ((recorder = _FMSTR_GetRecorderByRecIx(recIndex)) == NULL) |
956 | { |
957 | return FMSTR_FALSE; |
958 | } |
959 | |
960 | return (FMSTR_BOOL)((_FMSTR_StartRec(recorder) == FMSTR_STS_OK) ? FMSTR_TRUE : FMSTR_FALSE); |
961 | } |
962 | |
963 | /****************************************************************************** |
964 | * |
965 | * @brief API: Pull the trigger of the recorder |
966 | * |
967 | * This function starts the post-trigger stop countdown |
968 | * |
969 | ******************************************************************************/ |
970 | |
971 | FMSTR_BOOL FMSTR_RecorderTrigger(FMSTR_INDEX recIndex) |
972 | { |
973 | FMSTR_REC *recorder; |
974 | |
975 | /* Get the recorder */ |
976 | if ((recorder = _FMSTR_GetRecorderByRecIx(recIndex)) == NULL) |
977 | { |
978 | return FMSTR_FALSE; |
979 | } |
980 | |
981 | return (FMSTR_BOOL)((_FMSTR_TriggerRec(recorder) == FMSTR_STS_OK) ? FMSTR_TRUE : FMSTR_FALSE); |
982 | } |
983 | |
984 | /****************************************************************************** |
985 | * |
986 | * @brief API: Stop recorder immediatelly |
987 | * |
988 | * This function starts the post-trigger stop countdown |
989 | * |
990 | ******************************************************************************/ |
991 | |
992 | FMSTR_BOOL FMSTR_RecorderAbort(FMSTR_INDEX recIndex) |
993 | { |
994 | FMSTR_REC *recorder; |
995 | |
996 | /* Get the recorder */ |
997 | if ((recorder = _FMSTR_GetRecorderByRecIx(recIndex)) == NULL) |
998 | { |
999 | return FMSTR_FALSE; |
1000 | } |
1001 | |
1002 | return (FMSTR_BOOL)((_FMSTR_AbortRec(recorder) == FMSTR_STS_OK) ? FMSTR_TRUE : FMSTR_FALSE); |
1003 | } |
1004 | |
1005 | /****************************************************************************** |
1006 | * |
1007 | * @brief Internal start recorder function |
1008 | * |
1009 | * @param recIndex - recorder index |
1010 | * |
1011 | * @return Result status of start recorder operation, that could be used for communication |
1012 | * |
1013 | * This function starts recording (initializes internal recording variables and flags) |
1014 | * |
1015 | ******************************************************************************/ |
1016 | |
1017 | static FMSTR_U8 _FMSTR_StartRec(FMSTR_REC *recorder) |
1018 | { |
1019 | /* must be configured */ |
1020 | if (recorder->flags.flg.isConfigured == 0U) |
1021 | { |
1022 | FMSTR_U8 responseCode; |
1023 | |
1024 | if ((responseCode = _FMSTR_CheckConfiguration(recorder)) != FMSTR_STS_OK) |
1025 | { |
1026 | return responseCode; |
1027 | } |
1028 | } |
1029 | |
1030 | /* already running ? */ |
1031 | if (recorder->flags.flg.isRunning != 0U) |
1032 | { |
1033 | return FMSTR_STS_OK; |
1034 | } |
1035 | |
1036 | /* initialize write pointer */ |
1037 | recorder->writePtr = recorder->buffAddr; |
1038 | |
1039 | /* initialize time divisor */ |
1040 | recorder->timeDivCtr = 0U; |
1041 | |
1042 | /* run now in virgin cycle */ |
1043 | recorder->flags.flg.isRunning = 1U; |
1044 | recorder->flags.flg.hasData = 0U; |
1045 | recorder->flags.flg.isVirginCycle = 1U; |
1046 | recorder->flags.flg.isStopping = 0U; |
1047 | |
1048 | return FMSTR_STS_OK; |
1049 | } |
1050 | |
1051 | /****************************************************************************** |
1052 | * |
1053 | * @brief Internal Trigger recorder function |
1054 | * |
1055 | * @param recIndex - recorder index |
1056 | * |
1057 | * @return Result status of start recorder operation, taht could be used for communication |
1058 | * |
1059 | * This function stops recording (same as manual trigger) |
1060 | * |
1061 | ******************************************************************************/ |
1062 | |
1063 | static FMSTR_U8 _FMSTR_TriggerRec(FMSTR_REC *recorder) |
1064 | { |
1065 | /* must be configured */ |
1066 | if (recorder->flags.flg.isConfigured == 0U) |
1067 | { |
1068 | return FMSTR_STC_NOTINIT; |
1069 | } |
1070 | |
1071 | if ((recorder->flags.flg.isRunning != 0U) && (recorder->flags.flg.isStopping == 0U)) |
1072 | { |
1073 | recorder->flags.flg.isStopping = 1U; |
1074 | recorder->stopRecCountDown = recorder->postTrigger; |
1075 | } |
1076 | |
1077 | return FMSTR_STS_OK; |
1078 | } |
1079 | |
1080 | /****************************************************************************** |
1081 | * |
1082 | * @brief Internal Stop recorder function |
1083 | * |
1084 | * @return Result status of start recorder operation, taht could be used for communication |
1085 | * |
1086 | * This function stops recording immediatelly |
1087 | * |
1088 | ******************************************************************************/ |
1089 | |
1090 | static FMSTR_U8 _FMSTR_AbortRec(FMSTR_REC *recorder) |
1091 | { |
1092 | /* must be configured */ |
1093 | if (recorder->flags.flg.isConfigured == 0U) |
1094 | { |
1095 | return FMSTR_STC_NOTINIT; |
1096 | } |
1097 | |
1098 | if (recorder->flags.flg.isRunning != 0U) |
1099 | { |
1100 | recorder->flags.flg.isRunning = 0U; |
1101 | recorder->flags.flg.isStopping = 0U; |
1102 | } |
1103 | |
1104 | return FMSTR_STS_OK; |
1105 | } |
1106 | |
1107 | /****************************************************************************** |
1108 | * |
1109 | * @brief Check wether given memory region is inside any recorder buffer |
1110 | * |
1111 | * @param addr - address of the memory to be checked |
1112 | * @param size - size of the memory to be checked |
1113 | * |
1114 | * @return This function returns non-zero if user space is in recorder buffer |
1115 | * |
1116 | * This function is called as a part of TSA-checking process when the PC host |
1117 | * is requesting memory contents |
1118 | * |
1119 | ******************************************************************************/ |
1120 | |
1121 | FMSTR_BOOL FMSTR_IsInRecBuffer(FMSTR_ADDR addr, FMSTR_SIZE size) |
1122 | { |
1123 | FMSTR_REC *recorder; |
1124 | FMSTR_INDEX i; |
1125 | |
1126 | for (i = 0; i < (FMSTR_INDEX)FMSTR_USE_RECORDER; i++) |
1127 | { |
1128 | /* Get the recorder */ |
1129 | if ((recorder = _FMSTR_GetRecorderByRecIx(i)) != NULL) |
1130 | { |
1131 | if (addr >= recorder->buffAddr) |
1132 | { |
1133 | if ((addr + size) <= (recorder->buffAddr + recorder->buffSize)) |
1134 | { |
1135 | return FMSTR_TRUE; |
1136 | } |
1137 | } |
1138 | } |
1139 | } |
1140 | |
1141 | return FMSTR_FALSE; |
1142 | } |
1143 | |
1144 | /****************************************************************************** |
1145 | * |
1146 | * @brief Check the configuration of the recorder |
1147 | * |
1148 | * @return * @return Result status of start recorder operation, that could be used for communication |
1149 | * |
1150 | * |
1151 | ******************************************************************************/ |
1152 | |
1153 | static FMSTR_U8 _FMSTR_CheckConfiguration(FMSTR_REC *recorder) |
1154 | { |
1155 | FMSTR_SIZE pointSize = 0U; |
1156 | FMSTR_SIZE pointVarCount = 0U; |
1157 | FMSTR_SIZE blen = 0U; |
1158 | FMSTR_SIZE totalSmpls = 0; |
1159 | FMSTR_SIZE8 i; |
1160 | |
1161 | if (recorder->flags.flg.isConfigured == 0U) |
1162 | { |
1163 | /* calculate sum of sizes of all variables */ |
1164 | FMSTR_SIZE size; |
1165 | |
1166 | /* get all addresses and sizes */ |
1167 | for (i = 0; i < recorder->config.varCount; i++) |
1168 | { |
1169 | size = recorder->varDescr[i].cfg.size; |
1170 | |
1171 | /* variable size must be one of valid sizes */ |
1172 | if (size != 1U && size != 2U && size != 4U && size != 8U) |
1173 | { |
1174 | return FMSTR_STC_INVSIZE; |
1175 | } |
1176 | |
1177 | /* compute total size of one sample snapshot */ |
1178 | if ((recorder->varDescr[i].cfg.triggerMode & FMSTR_REC_TRG_F_TRGONLY) == 0U) |
1179 | { |
1180 | pointSize += size; |
1181 | pointVarCount++; |
1182 | } |
1183 | } |
1184 | |
1185 | /* no variable configured, or samples too big */ |
1186 | if (pointSize == 0U || pointSize > recorder->buffSize) |
1187 | { |
1188 | return FMSTR_STC_INVSIZE; |
1189 | } |
1190 | |
1191 | /* user wants to use less sample points than maximum available */ |
1192 | if (recorder->config.totalSmps != 0U) |
1193 | { |
1194 | /* total recorder buffer length in bytes */ |
1195 | blen = (FMSTR_SIZE)(recorder->config.totalSmps * pointSize); |
1196 | |
1197 | /* recorder memory available? */ |
1198 | if (blen > recorder->buffSize) |
1199 | { |
1200 | totalSmpls = 0; /* user wants more than maximu, use the maximum */ |
1201 | } |
1202 | else |
1203 | { |
1204 | totalSmpls = recorder->config.totalSmps; /* OK, accept user value */ |
1205 | } |
1206 | } |
1207 | |
1208 | /* use maximum available memory for samples */ |
1209 | if (totalSmpls == 0U) |
1210 | { |
1211 | totalSmpls = recorder->buffSize / pointSize; |
1212 | |
1213 | /* total recorder buffer length in bytes */ |
1214 | blen = (FMSTR_SIZE)(totalSmpls * pointSize); |
1215 | } |
1216 | |
1217 | /* Use pre-trigger value to calculate post-trigger count */ |
1218 | if (recorder->config.preTrigger < totalSmpls) |
1219 | { |
1220 | recorder->postTrigger = (FMSTR_SIZE)(totalSmpls - recorder->config.preTrigger - 1U); |
1221 | } |
1222 | else |
1223 | { |
1224 | recorder->postTrigger = (FMSTR_SIZE)(totalSmpls - 1U); /* pre-trigger too high, use maximum possible */ |
1225 | } |
1226 | |
1227 | /* Remember samples total count*/ |
1228 | recorder->totalSmplsCnt = totalSmpls; |
1229 | |
1230 | /* remember the effective end of circular buffer */ |
1231 | recorder->endBuffPtr = (FMSTR_ADDR)(recorder->buffAddr + (blen / FMSTR_CFG_BUS_WIDTH)); |
1232 | |
1233 | /* Store variable set size */ |
1234 | recorder->pointSize = pointSize; |
1235 | recorder->pointVarCount = pointVarCount; |
1236 | |
1237 | /* it was not configured before, now everything is okay */ |
1238 | recorder->flags.all = 0; |
1239 | recorder->flags.flg.isConfigured = 1U; |
1240 | } |
1241 | |
1242 | return FMSTR_STS_OK; |
1243 | } |
1244 | |
1245 | /****************************************************************************** |
1246 | * |
1247 | * @brief Compare macro used in trigger detection |
1248 | * |
1249 | * @param v - original command |
1250 | * @param t - response buffer |
1251 | * |
1252 | * @return zero when value is lower than threshold. |
1253 | * @return non-zero when value is greater than or equal as threshold |
1254 | * |
1255 | ******************************************************************************/ |
1256 | |
1257 | #define CMP(v, t) ((FMSTR_BOOL)(((v) < (t)) ? 0 : 1)) |
1258 | |
1259 | static FMSTR_BOOL _FMSTR_Compare8S(FMSTR_REC_VAR_DATA *varData) |
1260 | { |
1261 | return CMP(FMSTR_GetS8(varData->cfg.addr), FMSTR_GetS8(varData->cfg.trgAddr)); |
1262 | } |
1263 | |
1264 | static FMSTR_BOOL _FMSTR_Compare8U(FMSTR_REC_VAR_DATA *varData) |
1265 | { |
1266 | return CMP(FMSTR_GetU8(varData->cfg.addr), FMSTR_GetU8(varData->cfg.trgAddr)); |
1267 | } |
1268 | |
1269 | static FMSTR_BOOL _FMSTR_Compare16S(FMSTR_REC_VAR_DATA *varData) |
1270 | { |
1271 | return CMP(FMSTR_GetS16(varData->cfg.addr), FMSTR_GetS16(varData->cfg.trgAddr)); |
1272 | } |
1273 | |
1274 | static FMSTR_BOOL _FMSTR_Compare16U(FMSTR_REC_VAR_DATA *varData) |
1275 | { |
1276 | return CMP(FMSTR_GetU16(varData->cfg.addr), FMSTR_GetU16(varData->cfg.trgAddr)); |
1277 | } |
1278 | |
1279 | static FMSTR_BOOL _FMSTR_Compare32S(FMSTR_REC_VAR_DATA *varData) |
1280 | { |
1281 | return CMP(FMSTR_GetS32(varData->cfg.addr), FMSTR_GetS32(varData->cfg.trgAddr)); |
1282 | } |
1283 | |
1284 | static FMSTR_BOOL _FMSTR_Compare32U(FMSTR_REC_VAR_DATA *varData) |
1285 | { |
1286 | return CMP(FMSTR_GetU32(varData->cfg.addr), FMSTR_GetU32(varData->cfg.trgAddr)); |
1287 | } |
1288 | |
1289 | static FMSTR_BOOL _FMSTR_Compare64S(FMSTR_REC_VAR_DATA *varData) |
1290 | { |
1291 | return CMP(FMSTR_GetS64(varData->cfg.addr), FMSTR_GetS64(varData->cfg.trgAddr)); |
1292 | } |
1293 | |
1294 | static FMSTR_BOOL _FMSTR_Compare64U(FMSTR_REC_VAR_DATA *varData) |
1295 | { |
1296 | return CMP(FMSTR_GetU64(varData->cfg.addr), FMSTR_GetU64(varData->cfg.trgAddr)); |
1297 | } |
1298 | |
1299 | #if FMSTR_REC_FLOAT_TRIG > 0 |
1300 | static FMSTR_BOOL _FMSTR_CompareFloat(FMSTR_REC_VAR_DATA *varData) |
1301 | { |
1302 | return CMP(FMSTR_GetFloat(varData->cfg.addr), FMSTR_GetFloat(varData->cfg.trgAddr)); |
1303 | } |
1304 | |
1305 | static FMSTR_BOOL _FMSTR_CompareDouble(FMSTR_REC_VAR_DATA *varData) |
1306 | { |
1307 | return CMP(FMSTR_GetDouble(varData->cfg.addr), FMSTR_GetDouble(varData->cfg.trgAddr)); |
1308 | } |
1309 | #endif |
1310 | |
1311 | /****************************************************************************** |
1312 | * |
1313 | * @brief Gets the pointer pointing to recorder data buffer by Recorder Index |
1314 | * |
1315 | * @param recIndex - Index of Recorder |
1316 | * |
1317 | * @return NULL when the recorder doesn't exists, otherwise the pointer to recorder buffer |
1318 | * |
1319 | ******************************************************************************/ |
1320 | |
1321 | static FMSTR_REC_BUFF *_FMSTR_GetRecorderBufferByRecIx(FMSTR_INDEX recIndex) |
1322 | { |
1323 | if (recIndex < 0 || recIndex >= (FMSTR_INDEX)FMSTR_USE_RECORDER) |
1324 | { |
1325 | return NULL; |
1326 | } |
1327 | |
1328 | return &fmstr_recBuffs[recIndex]; |
1329 | } |
1330 | |
1331 | /****************************************************************************** |
1332 | * |
1333 | * @brief Gets the pointer pointing to recorder data by Recorder Index |
1334 | * |
1335 | * @param recIndex - Index of Recorder |
1336 | * |
1337 | * @return NULL when the recorder doesn't exists, otherwise the pointer to recorder structure |
1338 | * |
1339 | ******************************************************************************/ |
1340 | |
1341 | static FMSTR_REC *_FMSTR_GetRecorderByRecIx(FMSTR_INDEX recIndex) |
1342 | { |
1343 | if (recIndex < 0 || recIndex >= (FMSTR_INDEX)FMSTR_USE_RECORDER) |
1344 | { |
1345 | return NULL; |
1346 | } |
1347 | |
1348 | return (FMSTR_REC *)fmstr_recBuffs[recIndex].addr; |
1349 | } |
1350 | |
1351 | /****************************************************************************** |
1352 | * |
1353 | * @brief API: Recorder worker routine - can be called from application's timer ISR |
1354 | * |
1355 | * |
1356 | * This returns quickly if recorder is not running, otherwise it calls quite lengthy |
1357 | * recorder routine which does all the recorder work (sampling, triggering) |
1358 | * |
1359 | ******************************************************************************/ |
1360 | |
1361 | #if defined(FMSTR_PLATFORM_56F8xxx) || defined(FMSTR_PLATFORM_56F8xx) |
1362 | #pragma interrupt called |
1363 | #endif |
1364 | |
1365 | void FMSTR_Recorder(FMSTR_INDEX recIndex) |
1366 | { |
1367 | FMSTR_REC *recorder = _FMSTR_GetRecorderByRecIx(recIndex); |
1368 | |
1369 | /* recorder not active */ |
1370 | if (recorder == NULL || recorder->flags.flg.isRunning == 0U) |
1371 | { |
1372 | return; |
1373 | } |
1374 | |
1375 | /* do the hard work */ |
1376 | _FMSTR_Recorder2(recorder); |
1377 | } |
1378 | |
1379 | /****************************************************************************** |
1380 | * |
1381 | * @brief Recorder function called when recorder is active |
1382 | * |
1383 | ******************************************************************************/ |
1384 | |
1385 | #if defined(FMSTR_PLATFORM_56F8xxx) || defined(FMSTR_PLATFORM_56F8xx) |
1386 | #pragma interrupt called |
1387 | #endif |
1388 | |
1389 | static void _FMSTR_Recorder2(FMSTR_REC *recorder) |
1390 | { |
1391 | FMSTR_REC_VAR_DATA *recVarData; |
1392 | FMSTR_PCOMPAREFUNC compareFunc; |
1393 | FMSTR_U8 triggerMode; |
1394 | FMSTR_SIZE8 sz; |
1395 | FMSTR_SIZE i; |
1396 | FMSTR_BOOL cmp; |
1397 | FMSTR_U8 triggerResult; |
1398 | |
1399 | /* skip this call ? */ |
1400 | if (recorder->timeDivCtr > 0U) |
1401 | { |
1402 | /* maybe next time... */ |
1403 | recorder->timeDivCtr--; |
1404 | return; |
1405 | } |
1406 | |
1407 | /* re-initialize divider */ |
1408 | recorder->timeDivCtr = recorder->config.timeDiv; |
1409 | |
1410 | /* take snapshot of variable values */ |
1411 | for (i = 0U; i < recorder->config.varCount; i++) |
1412 | { |
1413 | recVarData = &recorder->varDescr[i]; |
1414 | triggerMode = recVarData->cfg.triggerMode; |
1415 | |
1416 | /* test trigger condition if still running */ |
1417 | if (recVarData->compareFunc != NULL && recorder->flags.flg.isStopping == 0U) |
1418 | { |
1419 | /* compare trigger threshold */ |
1420 | compareFunc = recVarData->compareFunc; |
1421 | cmp = compareFunc(recVarData); |
1422 | |
1423 | /* No trigger checking in virgin cycle */ |
1424 | if (recorder->flags.flg.isVirginCycle == 0U) |
1425 | { |
1426 | /* Check the Above trigger */ |
1427 | if (cmp != FMSTR_FALSE && (triggerMode & FMSTR_REC_TRG_F_ABOVE) != 0U) |
1428 | { |
1429 | /* Solve as Edge or Level trigger */ |
1430 | if ((triggerMode & FMSTR_REC_TRG_F_LEVEL) != 0U || (recVarData->trgLastState == FMSTR_FALSE)) |
1431 | { |
1432 | triggerResult = _FMSTR_TriggerRec(recorder); |
1433 | } |
1434 | } |
1435 | |
1436 | /* Check the Below trigger */ |
1437 | if (cmp == FMSTR_FALSE && (triggerMode & FMSTR_REC_TRG_F_BELOW) != 0U) |
1438 | { |
1439 | /* Solve as Edge or Level trigger */ |
1440 | if ((triggerMode & FMSTR_REC_TRG_F_LEVEL) != 0U || recVarData->trgLastState != FMSTR_FALSE) |
1441 | { |
1442 | triggerResult = _FMSTR_TriggerRec(recorder); |
1443 | } |
1444 | } |
1445 | } |
1446 | |
1447 | /* Store the last comparision */ |
1448 | recVarData->trgLastState = cmp; |
1449 | } |
1450 | |
1451 | /* Store the recorder variable to buffer */ |
1452 | if ((triggerMode & FMSTR_REC_TRG_F_TRGONLY) == 0U) |
1453 | { |
1454 | sz = recVarData->cfg.size; |
1455 | FMSTR_MemCpyFrom(recorder->writePtr, recVarData->cfg.addr, sz); |
1456 | sz /= FMSTR_CFG_BUS_WIDTH; |
1457 | recorder->writePtr += sz; |
1458 | } |
1459 | } |
1460 | |
1461 | /* We now have at least some data*/ |
1462 | recorder->flags.flg.hasData = 1U; |
1463 | |
1464 | /* wrap around (circular buffer) ? */ |
1465 | if (recorder->writePtr >= recorder->endBuffPtr) |
1466 | { |
1467 | recorder->writePtr = recorder->buffAddr; |
1468 | recorder->flags.flg.isVirginCycle = 0U; |
1469 | } |
1470 | |
1471 | /* in stopping mode ? (note that this bit might have been set just above!) */ |
1472 | if (recorder->flags.flg.isStopping != 0U) |
1473 | { |
1474 | /* count down post-trigger samples expired ? */ |
1475 | if (recorder->stopRecCountDown == 0U) |
1476 | { |
1477 | /* STOP RECORDER */ |
1478 | recorder->flags.flg.isRunning = 0U; |
1479 | return; |
1480 | } |
1481 | |
1482 | /* perhaps next time */ |
1483 | recorder->stopRecCountDown--; |
1484 | } |
1485 | |
1486 | FMSTR_UNUSED(triggerResult); |
1487 | } |
1488 | |
1489 | #else /* FMSTR_USE_RECORDER && (!FMSTR_DISABLE) */ |
1490 | |
1491 | FMSTR_BOOL FMSTR_RecorderCreate(FMSTR_INDEX recIndex, FMSTR_REC_BUFF *buffCfg) |
1492 | { |
1493 | FMSTR_UNUSED(recIndex); |
1494 | FMSTR_UNUSED(buffCfg); |
1495 | |
1496 | return FMSTR_TRUE; |
1497 | } |
1498 | |
1499 | FMSTR_BOOL FMSTR_RecorderSetTimeBase(FMSTR_INDEX recIndex, FMSTR_U32 timeBase_ns) |
1500 | { |
1501 | FMSTR_UNUSED(recIndex); |
1502 | FMSTR_UNUSED(timeBase_ns); |
1503 | |
1504 | return FMSTR_TRUE; |
1505 | } |
1506 | |
1507 | /* use void recorder API functions */ |
1508 | void FMSTR_Recorder(FMSTR_INDEX recIndex) |
1509 | { |
1510 | FMSTR_UNUSED(recIndex); |
1511 | } |
1512 | |
1513 | FMSTR_BOOL FMSTR_RecorderTrigger(FMSTR_INDEX recIndex) |
1514 | { |
1515 | FMSTR_UNUSED(recIndex); |
1516 | |
1517 | return FMSTR_TRUE; |
1518 | } |
1519 | |
1520 | FMSTR_BOOL FMSTR_RecorderAbort(FMSTR_INDEX recIndex) |
1521 | { |
1522 | FMSTR_UNUSED(recIndex); |
1523 | |
1524 | return FMSTR_TRUE; |
1525 | } |
1526 | |
1527 | FMSTR_BOOL FMSTR_RecorderConfigure(FMSTR_INDEX recIndex, FMSTR_REC_CFG *recCfg) |
1528 | { |
1529 | FMSTR_UNUSED(recIndex); |
1530 | FMSTR_UNUSED(recCfg); |
1531 | |
1532 | return FMSTR_TRUE; |
1533 | } |
1534 | |
1535 | FMSTR_BOOL FMSTR_RecorderAddVariable(FMSTR_INDEX recIndex, FMSTR_INDEX recVarIx, FMSTR_REC_VAR *recVarCfg) |
1536 | { |
1537 | FMSTR_UNUSED(recIndex); |
1538 | FMSTR_UNUSED(recVarIx); |
1539 | FMSTR_UNUSED(recVarCfg); |
1540 | |
1541 | return FMSTR_TRUE; |
1542 | } |
1543 | |
1544 | FMSTR_BOOL FMSTR_RecorderStart(FMSTR_INDEX recIndex) |
1545 | { |
1546 | FMSTR_UNUSED(recIndex); |
1547 | return FMSTR_TRUE; |
1548 | } |
1549 | |
1550 | #endif /* FMSTR_USE_RECORDER && (!FMSTR_DISABLE) */ |
1551 | |