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 */
56struct FMSTR_REC_VAR_DATA_S;
57
58/* trigger threshold level (1,2,4 or 8 bytes) */
59typedef 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 */
77typedef 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 */
93typedef FMSTR_BOOL (*FMSTR_PCOMPAREFUNC)(struct FMSTR_REC_VAR_DATA_S *varData);
94
95/* Recorder internal description of one variable */
96typedef 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 */
105typedef 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
150static FMSTR_REC_BUFF *_FMSTR_GetRecorderBufferByRecIx(FMSTR_INDEX recIndex);
151static FMSTR_REC *_FMSTR_GetRecorderByRecIx(FMSTR_INDEX recIndex);
152
153static FMSTR_U8 _FMSTR_CheckConfiguration(FMSTR_REC *recorder);
154static FMSTR_U8 _FMSTR_RecMemCfg(FMSTR_REC *recorder, FMSTR_INDEX recIndex, FMSTR_REC_CFG *recCfg);
155static FMSTR_U8 _FMSTR_RecVarCfg(FMSTR_REC *recorder, FMSTR_INDEX recVarIx, FMSTR_REC_VAR *recVarCfg);
156
157static FMSTR_U8 _FMSTR_StartRec(FMSTR_REC *recorder);
158static FMSTR_U8 _FMSTR_TriggerRec(FMSTR_REC *recorder);
159static FMSTR_U8 _FMSTR_AbortRec(FMSTR_REC *recorder);
160
161static FMSTR_BPTR _FMSTR_SetRecCmd_CFGMEM(
162 FMSTR_BPTR msgBuffIO, FMSTR_SIZE opLen, FMSTR_REC *recorder, FMSTR_INDEX recIndex, FMSTR_U8 *retStatus);
163static FMSTR_BPTR _FMSTR_SetRecCmd_CFGVAR(FMSTR_BPTR msgBuffIO,
164 FMSTR_SIZE opLen,
165 FMSTR_REC *recorder,
166 FMSTR_U8 *retStatus);
167
168static FMSTR_BOOL _FMSTR_RecIsValidVarSize(FMSTR_SIZE size);
169static FMSTR_U8 _FMSTR_CalcRecStatus(FMSTR_REC_FLAGS recFlags);
170
171static FMSTR_BOOL _FMSTR_Compare8S(FMSTR_REC_VAR_DATA *varData);
172static FMSTR_BOOL _FMSTR_Compare8U(FMSTR_REC_VAR_DATA *varData);
173static FMSTR_BOOL _FMSTR_Compare16S(FMSTR_REC_VAR_DATA *varData);
174static FMSTR_BOOL _FMSTR_Compare16U(FMSTR_REC_VAR_DATA *varData);
175static FMSTR_BOOL _FMSTR_Compare32S(FMSTR_REC_VAR_DATA *varData);
176static FMSTR_BOOL _FMSTR_Compare32U(FMSTR_REC_VAR_DATA *varData);
177static FMSTR_BOOL _FMSTR_Compare64S(FMSTR_REC_VAR_DATA *varData);
178static FMSTR_BOOL _FMSTR_Compare64U(FMSTR_REC_VAR_DATA *varData);
179#if FMSTR_REC_FLOAT_TRIG > 0
180static FMSTR_BOOL _FMSTR_CompareFloat(FMSTR_REC_VAR_DATA *varData);
181static FMSTR_BOOL _FMSTR_CompareDouble(FMSTR_REC_VAR_DATA *varData);
182#endif
183
184static void _FMSTR_Recorder2(FMSTR_REC *recorder);
185
186/********************************************************
187 * static variables
188 ********************************************************/
189
190/* Recorder buffers */
191static FMSTR_REC_BUFF fmstr_recBuffs[FMSTR_USE_RECORDER];
192
193#if FMSTR_REC_BUFF_SIZE > 0
194/* statically allocated recorder buffer */
195static FMSTR_U8 fmstr_pOwnRecBuffer[FMSTR_REC_BUFF_SIZE];
196#endif
197
198/******************************************************************************
199 *
200 * @brief Recorder Initialization
201 *
202 ******************************************************************************/
203
204FMSTR_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
240FMSTR_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
304FMSTR_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
326FMSTR_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
352static 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
406static 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
443FMSTR_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
467static 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
575static 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
662static 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
681FMSTR_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
767static 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
810FMSTR_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
950FMSTR_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
971FMSTR_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
992FMSTR_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
1017static 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
1063static 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
1090static 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
1121FMSTR_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
1153static 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
1259static 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
1264static 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
1269static 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
1274static 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
1279static 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
1284static 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
1289static 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
1294static 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
1300static 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
1305static 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
1321static 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
1341static 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
1365void 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
1389static 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
1491FMSTR_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
1499FMSTR_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 */
1508void FMSTR_Recorder(FMSTR_INDEX recIndex)
1509{
1510 FMSTR_UNUSED(recIndex);
1511}
1512
1513FMSTR_BOOL FMSTR_RecorderTrigger(FMSTR_INDEX recIndex)
1514{
1515 FMSTR_UNUSED(recIndex);
1516
1517 return FMSTR_TRUE;
1518}
1519
1520FMSTR_BOOL FMSTR_RecorderAbort(FMSTR_INDEX recIndex)
1521{
1522 FMSTR_UNUSED(recIndex);
1523
1524 return FMSTR_TRUE;
1525}
1526
1527FMSTR_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
1535FMSTR_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
1544FMSTR_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