| /******************************************************************************* | |
| * Trace Recorder Library for Tracealyzer v3.0.2 | |
| * Percepio AB, www.percepio.com | |
| * | |
| * trcKernelPort.c | |
| * | |
| * The kernel-specific code for integration with FreeRTOS. | |
| * | |
| * Terms of Use | |
| * This software (the "Tracealyzer Recorder Library") is the intellectual | |
| * property of Percepio AB and may not be sold or in other ways commercially | |
| * redistributed without explicit written permission by Percepio AB. | |
| * | |
| * Separate conditions applies for the SEGGER branded source code included. | |
| * | |
| * The recorder library is free for use together with Percepio products. | |
| * You may distribute the recorder library in its original form, but public | |
| * distribution of modified versions require approval by Percepio AB. | |
| * | |
| * Disclaimer | |
| * The trace tool and recorder library is being delivered to you AS IS and | |
| * Percepio AB makes no warranty as to its use or performance. Percepio AB does | |
| * not and cannot warrant the performance or results you may obtain by using the | |
| * software or documentation. Percepio AB make no warranties, express or | |
| * implied, as to noninfringement of third party rights, merchantability, or | |
| * fitness for any particular purpose. In no event will Percepio AB, its | |
| * technology partners, or distributors be liable to you for any consequential, | |
| * incidental or special damages, including any lost profits or lost savings, | |
| * even if a representative of Percepio AB has been advised of the possibility | |
| * of such damages, or for any claim by any third party. Some jurisdictions do | |
| * not allow the exclusion or limitation of incidental, consequential or special | |
| * damages, or the exclusion of implied warranties or limitations on how long an | |
| * implied warranty may last, so the above limitations may not apply to you. | |
| * | |
| * Tabs are used for indent in this file (1 tab = 4 spaces) | |
| * | |
| * Copyright Percepio AB, 2015. | |
| * www.percepio.com | |
| ******************************************************************************/ | |
| #include "trcKernelPort.h" | |
| #if (USE_TRACEALYZER_RECORDER == 1) | |
| #include <stdint.h> | |
| #include "trcRecorder.h" | |
| #include "trcStreamPort.h" | |
| #include "task.h" | |
| /* TzCtrl task TCB */ | |
| static xTaskHandle HandleTzCtrl; | |
| /* Called by TzCtrl task periodically (every 100 ms) */ | |
| static void CheckRecorderStatus(void); | |
| /* The TzCtrl task - receives commands from Tracealyzer (start/stop) */ | |
| static portTASK_FUNCTION( TzCtrl, pvParameters ); | |
| /* Monitored by TzCtrl task, that give warnings as User Events */ | |
| extern volatile uint32_t NoRoomForSymbol; | |
| extern volatile uint32_t NoRoomForObjectData; | |
| extern volatile uint32_t LongestSymbolName; | |
| extern volatile uint32_t MaxBytesTruncated; | |
| #define TRC_PORT_MALLOC(size) pvPortMalloc(size) | |
| #if ((TRC_STREAM_PORT_BLOCKING_TRANSFER == 1) && (TRC_MEASURE_BLOCKING_TIME == 1)) | |
| /*** Used in blocking transfer mode, if enabled TRC_MEASURE_BLOCKING_TIME **************/ | |
| /* The highest number of cycles used by SEGGER_RTT_Write. */ | |
| static volatile int32_t blockingCyclesMax; | |
| /* The number of times SEGGER_RTT_Write has blocked due to a full buffer. */ | |
| static volatile uint32_t blockingCount; | |
| /* User Event Channel for giving warnings regarding blocking */ | |
| static char* trcDiagnosticsChannel; | |
| #endif /*((TRC_STREAM_PORT_BLOCKING_TRANSFER==1) && (TRC_MEASURE_BLOCKING_TIME))*/ | |
| TRC_STREAM_PORT_ALLOCATE_FIELDS() | |
| /* User Event Channel for giving warnings regarding NoRoomForSymbol etc. */ | |
| char* trcWarningChannel; | |
| /* Keeps track of previous values, to only react on changes. */ | |
| static uint32_t NoRoomForSymbol_last = 0; | |
| static uint32_t NoRoomForObjectData_last = 0; | |
| static uint32_t LongestSymbolName_last = 0; | |
| static uint32_t MaxBytesTruncated_last = 0; | |
| /******************************************************************************* | |
| * prvTraceGetCurrentTaskHandle | |
| * | |
| * Function that returns the handle to the currently executing task. | |
| * | |
| ******************************************************************************/ | |
| void* prvTraceGetCurrentTaskHandle(void) | |
| { | |
| return xTaskGetCurrentTaskHandle(); | |
| } | |
| /******************************************************************************* | |
| * prvIsNewTCB | |
| * | |
| * Function that returns the handle to the currently executing task. | |
| * | |
| ******************************************************************************/ | |
| static void* pCurrentTCB = NULL; | |
| uint32_t prvIsNewTCB(void* pNewTCB) | |
| { | |
| if (pCurrentTCB != pNewTCB) | |
| { | |
| pCurrentTCB = pNewTCB; | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| /******************************************************************************* | |
| * CheckRecorderStatus | |
| * | |
| * Called by TzCtrl task periodically (every 100 ms - seems reasonable). | |
| * Checks a number of diagnostic variables and give warnings as user events, | |
| * in most cases including a suggested solution. | |
| ******************************************************************************/ | |
| static void CheckRecorderStatus(void) | |
| { | |
| if (NoRoomForSymbol > NoRoomForSymbol_last) | |
| { | |
| vTracePrintF(trcWarningChannel, "TRC_SYMBOL_TABLE_SLOTS too small. Add %d slots.", | |
| NoRoomForSymbol); | |
| NoRoomForSymbol_last = NoRoomForSymbol; | |
| } | |
| if (NoRoomForObjectData > NoRoomForObjectData_last) | |
| { | |
| vTracePrintF(trcWarningChannel, "TRC_OBJECT_DATA_SLOTS too small. Add %d slots.", | |
| NoRoomForObjectData); | |
| NoRoomForObjectData_last = NoRoomForObjectData; | |
| } | |
| if (LongestSymbolName > LongestSymbolName_last) | |
| { | |
| if (LongestSymbolName > TRC_SYMBOL_MAX_LENGTH) | |
| { | |
| vTracePrintF(trcWarningChannel, "TRC_SYMBOL_MAX_LENGTH too small. Add %d chars.", | |
| LongestSymbolName); | |
| } | |
| LongestSymbolName_last = LongestSymbolName; | |
| } | |
| if (MaxBytesTruncated > MaxBytesTruncated_last) | |
| { | |
| /* Some string event generated a too long string that was truncated. | |
| This may happen for the following functions: | |
| - vTracePrintF | |
| - vTracePrintF | |
| - vTraceStoreKernelObjectName | |
| - vTraceStoreUserEventChannelName | |
| - vTraceSetISRProperties | |
| A PSF event may store maximum 60 bytes payload, including data arguments | |
| and string characters. For User Events, also the User Event Channel ptr | |
| must be squeezed in, if a channel is specified. */ | |
| vTracePrintF(trcWarningChannel, "String event too long, up to %d bytes truncated.", | |
| MaxBytesTruncated); | |
| MaxBytesTruncated_last = MaxBytesTruncated; | |
| } | |
| #if ((TRC_STREAM_PORT_BLOCKING_TRANSFER==1) && (TRC_MEASURE_BLOCKING_TIME)) | |
| if (blockingCount > 0) | |
| { | |
| /* At least one case of blocking since the last check and this is | |
| the longest case. */ | |
| vTracePrintF(trcDiagnosticsChannel, "Longest since last: %d us", | |
| (uint32_t)blockingCyclesMax/(TRACE_CPU_CLOCK_HZ/1000000)); | |
| blockingCyclesMax = 0; | |
| } | |
| #endif | |
| } | |
| /******************************************************************************* | |
| * vTraceOnTraceBegin | |
| * | |
| * Called on trace begin. | |
| ******************************************************************************/ | |
| void vTraceOnTraceBegin(void) | |
| { | |
| TRC_STREAM_PORT_ON_TRACE_BEGIN(); | |
| } | |
| /******************************************************************************* | |
| * vTraceOnTraceEnd | |
| * | |
| * Called on trace end. | |
| ******************************************************************************/ | |
| void vTraceOnTraceEnd(void) | |
| { | |
| TRC_STREAM_PORT_ON_TRACE_END(); | |
| } | |
| /******************************************************************************* | |
| * TzCtrl | |
| * | |
| * Task for receiving commands from Tracealyzer and for recorder diagnostics. | |
| * | |
| ******************************************************************************/ | |
| static portTASK_FUNCTION( TzCtrl, pvParameters ) | |
| { | |
| TracealyzerCommandType msg; | |
| int bytes = 0; | |
| while (1) | |
| { | |
| bytes = 0; | |
| TRC_STREAM_PORT_READ_DATA(&msg, sizeof(TracealyzerCommandType), &bytes); | |
| if (bytes != 0) | |
| { | |
| if (bytes == sizeof(TracealyzerCommandType)) | |
| { | |
| if (isValidCommand(&msg)) | |
| { | |
| processCommand(&msg); /* Start or Stop currently... */ | |
| } | |
| } | |
| } | |
| do | |
| { | |
| bytes = 0; | |
| TRC_STREAM_PORT_PERIODIC_SEND_DATA(&bytes); | |
| } | |
| while (bytes != 0); | |
| CheckRecorderStatus(); | |
| vTaskDelay(TRC_CTRL_TASK_DELAY); /* 10ms */ | |
| } | |
| } | |
| /******************************************************************************* | |
| * Trace_Init | |
| * | |
| * The main initialization routine for the trace recorder. Configures the stream | |
| * and activates the TzCtrl task. | |
| * Also sets up the diagnostic User Event channels used by TzCtrl task. | |
| * | |
| ******************************************************************************/ | |
| void Trace_Init(void) | |
| { | |
| TRC_STREAM_PORT_INIT(); | |
| trcWarningChannel = vTraceStoreUserEventChannelName("Warnings from Recorder"); | |
| #if ((TRC_STREAM_PORT_BLOCKING_TRANSFER==1) && (TRC_MEASURE_BLOCKING_TIME)) | |
| trcDiagnosticsChannel = vTraceStoreUserEventChannelName("Blocking on trace buffer"); | |
| #endif | |
| /* Creates the TzCtrl task - receives trace commands (start, stop, ...) */ | |
| xTaskCreate( TzCtrl, "TzCtrl", configMINIMAL_STACK_SIZE, NULL, TRC_CTRL_TASK_PRIORITY, &HandleTzCtrl ); | |
| } | |
| #endif |