/* * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "string.h" #include "freertos/FreeRTOS.h" #include "SEGGER_RTT.h" #include "SEGGER_SYSVIEW.h" #include "SEGGER_SYSVIEW_Conf.h" #include "esp_app_trace.h" #include "esp_log.h" #include "esp_cpu.h" #include "esp_private/startup_internal.h" const static char *TAG = "segger_rtt"; #define SYSVIEW_EVENTS_BUF_SZ 255U // size of down channel data buf #define SYSVIEW_DOWN_BUF_SIZE 32 #define SEGGER_STOP_WAIT_TMO 1000000 //us #if CONFIG_APPTRACE_SV_BUF_WAIT_TMO == -1 #define SEGGER_HOST_WAIT_TMO ESP_APPTRACE_TMO_INFINITE #else #define SEGGER_HOST_WAIT_TMO CONFIG_APPTRACE_SV_BUF_WAIT_TMO #endif static uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ]; static uint16_t s_events_buf_filled; static uint8_t s_down_buf[SYSVIEW_DOWN_BUF_SIZE]; #if CONFIG_APPTRACE_SV_DEST_UART #define ESP_APPTRACE_DEST_SYSVIEW ESP_APPTRACE_DEST_UART #if CONFIG_APPTRACE_SV_DEST_CPU_0 || CONFIG_FREERTOS_UNICORE #define APPTRACE_SV_DEST_CPU 0 #else #define APPTRACE_SV_DEST_CPU 1 #endif // CONFIG_APPTRACE_SV_DEST_CPU_0 #elif CONFIG_APPTRACE_SV_DEST_JTAG || (CONFIG_APPTRACE_ENABLE && CONFIG_APPTRACE_DEST_UART_NONE) #define ESP_APPTRACE_DEST_SYSVIEW ESP_APPTRACE_DEST_TRAX #endif /********************************************************************* * * Public code * ********************************************************************** */ /********************************************************************* * * SEGGER_RTT_ESP_FlushNoLock() * * Function description * Flushes buffered events. * * Parameters * min_sz Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only. * tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. * * Return value * None. */ void SEGGER_RTT_ESP_FlushNoLock(unsigned long min_sz, unsigned long tmo) { esp_err_t res; if (s_events_buf_filled > 0) { res = esp_apptrace_write(ESP_APPTRACE_DEST_SYSVIEW, s_events_buf, s_events_buf_filled, tmo); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to flush buffered events (%d)!\n", res); } } // flush even if we failed to write buffered events, because no new events will be sent after STOP res = esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_SYSVIEW, min_sz, tmo); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to flush apptrace data (%d)!\n", res); } s_events_buf_filled = 0; } /********************************************************************* * * SEGGER_RTT_ESP_Flush() * * Function description * Flushes buffered events. * * Parameters * min_sz Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only. * tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. * * Return value * None. */ void SEGGER_RTT_ESP_Flush(unsigned long min_sz, unsigned long tmo) { SEGGER_SYSVIEW_LOCK(); SEGGER_RTT_ESP_FlushNoLock(min_sz, tmo); SEGGER_SYSVIEW_UNLOCK(); } /********************************************************************* * * SEGGER_RTT_ReadNoLock() * * Function description * Reads characters from SEGGER real-time-terminal control block * which have been previously stored by the host. * Do not lock against interrupts and multiple access. * * Parameters * BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). * pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to. * BufferSize Size of the target application buffer. * * Return value * Number of bytes that have been read. */ unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) { uint32_t size = BufferSize; esp_err_t res = esp_apptrace_read(ESP_APPTRACE_DEST_SYSVIEW, pData, &size, 0); if (res != ESP_OK) { return 0; } return size; } /********************************************************************* * * SEGGER_RTT_WriteSkipNoLock * * Function description * Stores a specified number of characters in SEGGER RTT * control block which is then read by the host. * SEGGER_RTT_WriteSkipNoLock does not lock the application and * skips all data, if the data does not fit into the buffer. * * Parameters * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. * NumBytes Number of bytes to be stored in the SEGGER RTT control block. * * Return value * Number of bytes which have been stored in the "Up"-buffer. * * Notes * (1) If there is not enough space in the "Up"-buffer, all data is dropped. * (2) For performance reasons this function does not call Init() * and may only be called after RTT has been initialized. * Either by calling SEGGER_RTT_Init() or calling another RTT API function first. */ unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { uint8_t *pbuf = (uint8_t *)pBuffer; uint8_t event_id = *pbuf; #if CONFIG_APPTRACE_SV_DEST_UART if ( (APPTRACE_SV_DEST_CPU != esp_cpu_get_core_id()) && ( (event_id == SYSVIEW_EVTID_ISR_ENTER) || (event_id == SYSVIEW_EVTID_ISR_EXIT) || (event_id == SYSVIEW_EVTID_TASK_START_EXEC) || (event_id == SYSVIEW_EVTID_TASK_STOP_EXEC) || (event_id == SYSVIEW_EVTID_TASK_START_READY) || (event_id == SYSVIEW_EVTID_TASK_STOP_READY) || (event_id == SYSVIEW_EVTID_USER_START) || (event_id == SYSVIEW_EVTID_USER_STOP) || (event_id == SYSVIEW_EVTID_TIMER_ENTER) || (event_id == SYSVIEW_EVTID_TIMER_EXIT) || (event_id == SYSVIEW_EVTID_STACK_INFO) || (event_id == SYSVIEW_EVTID_MODULEDESC) ) ){ return NumBytes; } // This is workaround for SystemView! // Without this line SystemView will hangs on when heap tracing enabled. if(event_id == SYSVIEW_EVTID_MODULEDESC){ return NumBytes; } #endif // CONFIG_APPTRACE_SV_DEST_UART if (NumBytes > SYSVIEW_EVENTS_BUF_SZ) { ESP_LOGE(TAG, "Too large event %u bytes!", NumBytes); return 0; } #if CONFIG_APPTRACE_SV_DEST_JTAG if (esp_cpu_get_core_id()) { // dual core specific code // use the highest - 1 bit of event ID to indicate core ID // the highest bit can not be used due to event ID encoding method // this reduces supported ID range to [0..63] (for 1 byte IDs) plus [128..16383] (for 2 bytes IDs) if (*pbuf & 0x80) { // 2 bytes ID *(pbuf + 1) |= (1 << 6); } else if (NumBytes != 10 || *pbuf != 0) { // ignore sync sequence *pbuf |= (1 << 6); } } #endif // CONFIG_APPTRACE_SV_DEST_JTAG #if CONFIG_APPTRACE_SV_DEST_JTAG if (s_events_buf_filled + NumBytes > SYSVIEW_EVENTS_BUF_SZ) { esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_SYSVIEW, s_events_buf, s_events_buf_filled, SEGGER_HOST_WAIT_TMO); if (res != ESP_OK) { return 0; // skip current data buffer only, accumulated events are kept } s_events_buf_filled = 0; } #endif memcpy(&s_events_buf[s_events_buf_filled], pBuffer, NumBytes); s_events_buf_filled += NumBytes; #if CONFIG_APPTRACE_SV_DEST_UART esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_SYSVIEW, pBuffer, NumBytes, SEGGER_HOST_WAIT_TMO); if (res != ESP_OK) { return 0; // skip current data buffer only, accumulated events are kept } s_events_buf_filled = 0; #endif if (event_id == SYSVIEW_EVTID_TRACE_STOP) { SEGGER_RTT_ESP_FlushNoLock(0, SEGGER_STOP_WAIT_TMO); } return NumBytes; } /********************************************************************* * * SEGGER_RTT_ConfigUpBuffer * * Function description * Run-time configuration of a specific up-buffer (T->H). * Buffer to be configured is specified by index. * This includes: Buffer address, size, name, flags, ... * * Parameters * BufferIndex Index of the buffer to configure. * sName Pointer to a constant name string. * pBuffer Pointer to a buffer to be used. * BufferSize Size of the buffer. * Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). * * Return value * >= 0 - O.K. * < 0 - Error * * Additional information * Buffer 0 is configured on compile-time. * May only be called once per buffer. * Buffer name and flags can be reconfigured using the appropriate functions. */ int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { s_events_buf_filled = 0; return 0; } /********************************************************************* * * SEGGER_RTT_ConfigDownBuffer * * Function description * Run-time configuration of a specific down-buffer (H->T). * Buffer to be configured is specified by index. * This includes: Buffer address, size, name, flags, ... * * Parameters * BufferIndex Index of the buffer to configure. * sName Pointer to a constant name string. * pBuffer Pointer to a buffer to be used. * BufferSize Size of the buffer. * Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). * * Return value * >= 0 O.K. * < 0 Error * * Additional information * Buffer 0 is configured on compile-time. * May only be called once per buffer. * Buffer name and flags can be reconfigured using the appropriate functions. */ int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { esp_apptrace_down_buffer_config(s_down_buf, sizeof(s_down_buf)); return 0; } /*************************** Init hook **************************** * * This init function is placed here because this port file will be * linked whenever SystemView is used. */ ESP_SYSTEM_INIT_FN(sysview_init, BIT(0), 120) { SEGGER_SYSVIEW_Conf(); return ESP_OK; } /*************************** End of file ****************************/