1 /*
2  * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "string.h"
8 #include "freertos/FreeRTOS.h"
9 #include "SEGGER_RTT.h"
10 #include "SEGGER_SYSVIEW.h"
11 #include "SEGGER_SYSVIEW_Conf.h"
12 
13 #include "esp_app_trace.h"
14 #include "esp_log.h"
15 
16 const static char *TAG = "segger_rtt";
17 
18 #define SYSVIEW_EVENTS_BUF_SZ         255U
19 
20 // size of down channel data buf
21 #define SYSVIEW_DOWN_BUF_SIZE   32
22 #define SEGGER_STOP_WAIT_TMO    1000000 //us
23 #if CONFIG_APPTRACE_SV_BUF_WAIT_TMO == -1
24 #define SEGGER_HOST_WAIT_TMO    ESP_APPTRACE_TMO_INFINITE
25 #else
26 #define SEGGER_HOST_WAIT_TMO    CONFIG_APPTRACE_SV_BUF_WAIT_TMO
27 #endif
28 
29 static uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ];
30 static uint16_t s_events_buf_filled;
31 static uint8_t s_down_buf[SYSVIEW_DOWN_BUF_SIZE];
32 
33 /*********************************************************************
34 *
35 *       Public code
36 *
37 **********************************************************************
38 */
39 
40 /*********************************************************************
41 *
42 *       SEGGER_RTT_ESP_FlushNoLock()
43 *
44 *  Function description
45 *    Flushes buffered events.
46 *
47 *  Parameters
48 *    min_sz  Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only.
49 *    tmo     Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
50 *
51 *  Return value
52 *    None.
53 */
SEGGER_RTT_ESP_FlushNoLock(unsigned long min_sz,unsigned long tmo)54 void SEGGER_RTT_ESP_FlushNoLock(unsigned long min_sz, unsigned long tmo)
55 {
56     esp_err_t res;
57     if (s_events_buf_filled > 0) {
58       res = esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, s_events_buf, s_events_buf_filled, tmo);
59       if (res != ESP_OK) {
60         ESP_LOGE(TAG, "Failed to flush buffered events (%d)!\n", res);
61       }
62     }
63     // flush even if we failed to write buffered events, because no new events will be sent after STOP
64     res = esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, min_sz, tmo);
65     if (res != ESP_OK) {
66       ESP_LOGE(TAG, "Failed to flush apptrace data (%d)!\n", res);
67     }
68     s_events_buf_filled = 0;
69 }
70 
71 /*********************************************************************
72 *
73 *       SEGGER_RTT_ESP_Flush()
74 *
75 *  Function description
76 *    Flushes buffered events.
77 *
78 *  Parameters
79 *    min_sz  Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only.
80 *    tmo     Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
81 *
82 *  Return value
83 *    None.
84 */
SEGGER_RTT_ESP_Flush(unsigned long min_sz,unsigned long tmo)85 void SEGGER_RTT_ESP_Flush(unsigned long min_sz, unsigned long tmo)
86 {
87     SEGGER_SYSVIEW_LOCK();
88     SEGGER_RTT_ESP_FlushNoLock(min_sz, tmo);
89     SEGGER_SYSVIEW_UNLOCK();
90 }
91 
92 /*********************************************************************
93 *
94 *       SEGGER_RTT_ReadNoLock()
95 *
96 *  Function description
97 *    Reads characters from SEGGER real-time-terminal control block
98 *    which have been previously stored by the host.
99 *    Do not lock against interrupts and multiple access.
100 *
101 *  Parameters
102 *    BufferIndex  Index of Down-buffer to be used (e.g. 0 for "Terminal").
103 *    pBuffer      Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to.
104 *    BufferSize   Size of the target application buffer.
105 *
106 *  Return value
107 *    Number of bytes that have been read.
108 */
SEGGER_RTT_ReadNoLock(unsigned BufferIndex,void * pData,unsigned BufferSize)109 unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) {
110   uint32_t size = BufferSize;
111   esp_err_t res = esp_apptrace_read(ESP_APPTRACE_DEST_TRAX, pData, &size, 0);
112   if (res != ESP_OK) {
113     return 0;
114   }
115   return size;
116 }
117 
118 /*********************************************************************
119 *
120 *       SEGGER_RTT_WriteSkipNoLock
121 *
122 *  Function description
123 *    Stores a specified number of characters in SEGGER RTT
124 *    control block which is then read by the host.
125 *    SEGGER_RTT_WriteSkipNoLock does not lock the application and
126 *    skips all data, if the data does not fit into the buffer.
127 *
128 *  Parameters
129 *    BufferIndex  Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
130 *    pBuffer      Pointer to character array. Does not need to point to a \0 terminated string.
131 *    NumBytes     Number of bytes to be stored in the SEGGER RTT control block.
132 *
133 *  Return value
134 *    Number of bytes which have been stored in the "Up"-buffer.
135 *
136 *  Notes
137 *    (1) If there is not enough space in the "Up"-buffer, all data is dropped.
138 *    (2) For performance reasons this function does not call Init()
139 *        and may only be called after RTT has been initialized.
140 *        Either by calling SEGGER_RTT_Init() or calling another RTT API function first.
141 */
SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex,const void * pBuffer,unsigned NumBytes)142 unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) {
143   uint8_t *pbuf = (uint8_t *)pBuffer;
144   uint8_t event_id = *pbuf;
145 
146   if (NumBytes > SYSVIEW_EVENTS_BUF_SZ) {
147       ESP_LOGE(TAG, "Too large event %u bytes!", NumBytes);
148       return 0;
149   }
150   if (cpu_hal_get_core_id()) { // dual core specific code
151     // use the highest - 1 bit of event ID to indicate core ID
152     // the highest bit can not be used due to event ID encoding method
153     // this reduces supported ID range to [0..63] (for 1 byte IDs) plus [128..16383] (for 2 bytes IDs)
154     if (*pbuf & 0x80) { // 2 bytes ID
155       *(pbuf + 1) |= (1 << 6);
156     } else if (NumBytes != 10 || *pbuf != 0) { // ignore sync sequence
157       *pbuf |= (1 << 6);
158     }
159   }
160   if (s_events_buf_filled + NumBytes > SYSVIEW_EVENTS_BUF_SZ) {
161     esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, s_events_buf, s_events_buf_filled, SEGGER_HOST_WAIT_TMO);
162     if (res != ESP_OK) {
163       return 0; // skip current data buffer only, accumulated events are kept
164     }
165     s_events_buf_filled = 0;
166   }
167   memcpy(&s_events_buf[s_events_buf_filled], pBuffer, NumBytes);
168   s_events_buf_filled += NumBytes;
169   if (event_id == SYSVIEW_EVTID_TRACE_STOP) {
170     SEGGER_RTT_ESP_FlushNoLock(0, SEGGER_STOP_WAIT_TMO);
171   }
172   return NumBytes;
173 }
174 
175 /*********************************************************************
176 *
177 *       SEGGER_RTT_ConfigUpBuffer
178 *
179 *  Function description
180 *    Run-time configuration of a specific up-buffer (T->H).
181 *    Buffer to be configured is specified by index.
182 *    This includes: Buffer address, size, name, flags, ...
183 *
184 *  Parameters
185 *    BufferIndex  Index of the buffer to configure.
186 *    sName        Pointer to a constant name string.
187 *    pBuffer      Pointer to a buffer to be used.
188 *    BufferSize   Size of the buffer.
189 *    Flags        Operating modes. Define behavior if buffer is full (not enough space for entire message).
190 *
191 *  Return value
192 *    >= 0 - O.K.
193 *     < 0 - Error
194 *
195 *  Additional information
196 *    Buffer 0 is configured on compile-time.
197 *    May only be called once per buffer.
198 *    Buffer name and flags can be reconfigured using the appropriate functions.
199 */
SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex,const char * sName,void * pBuffer,unsigned BufferSize,unsigned Flags)200 int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) {
201   s_events_buf_filled = 0;
202   return 0;
203 }
204 
205 /*********************************************************************
206 *
207 *       SEGGER_RTT_ConfigDownBuffer
208 *
209 *  Function description
210 *    Run-time configuration of a specific down-buffer (H->T).
211 *    Buffer to be configured is specified by index.
212 *    This includes: Buffer address, size, name, flags, ...
213 *
214 *  Parameters
215 *    BufferIndex  Index of the buffer to configure.
216 *    sName        Pointer to a constant name string.
217 *    pBuffer      Pointer to a buffer to be used.
218 *    BufferSize   Size of the buffer.
219 *    Flags        Operating modes. Define behavior if buffer is full (not enough space for entire message).
220 *
221 *  Return value
222 *    >= 0  O.K.
223 *     < 0  Error
224 *
225 *  Additional information
226 *    Buffer 0 is configured on compile-time.
227 *    May only be called once per buffer.
228 *    Buffer name and flags can be reconfigured using the appropriate functions.
229 */
SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex,const char * sName,void * pBuffer,unsigned BufferSize,unsigned Flags)230 int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) {
231   esp_apptrace_down_buffer_config(s_down_buf, sizeof(s_down_buf));
232   return 0;
233 }
234 
235 /*************************** End of file ****************************/
236