1 /* 2 * Trace Recorder for Tracealyzer v4.5.1 3 * Copyright 2021 Percepio AB 4 * www.percepio.com 5 * 6 * SPDX-License-Identifier: Apache-2.0 7 * 8 * The implementation of the internal buffer. 9 */ 10 11 #include "trcRecorder.h" 12 13 #if (TRC_USE_TRACEALYZER_RECORDER == 1) && (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) 14 15 #include <stdio.h> 16 #include <string.h> 17 #include <stdarg.h> 18 #include "trcInternalBuffer.h" 19 20 21 /* The status codes for the pages of the internal trace buffer. */ 22 #define PAGE_STATUS_FREE 0 23 #define PAGE_STATUS_WRITE 1 24 #define PAGE_STATUS_READ 2 25 26 27 typedef struct{ 28 uint16_t Status; /* 16 bit to avoid implicit padding (warnings) */ 29 uint16_t BytesRemaining; 30 char* WritePointer; 31 } PageType; 32 33 34 PageType PageInfo[TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT] TRC_CFG_RECORDER_DATA_ATTRIBUTE; 35 36 37 char* EventBuffer TRC_CFG_RECORDER_DATA_ATTRIBUTE; 38 uint32_t TotalBytesRemaining_LowWaterMark TRC_CFG_RECORDER_DATA_ATTRIBUTE; 39 uint32_t TotalBytesRemaining TRC_CFG_RECORDER_DATA_ATTRIBUTE; 40 41 42 /** 43 * @brief Retrieve a buffer page to write to. 44 * 45 * @param prevPage Index of previous page. 46 * @return int Index of available page or -1 if no page is currently available. 47 */ prvAllocateBufferPage(int prevPage)48static int prvAllocateBufferPage(int prevPage) 49 { 50 int index; 51 int count = 0; 52 53 index = (prevPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); 54 55 while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT))) 56 { 57 index = (index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); 58 } 59 60 if (PageInfo[index].Status == PAGE_STATUS_FREE) 61 { 62 return index; 63 } 64 65 return -1; 66 } 67 68 /** 69 * @brief Mark a page read as complete. 70 * 71 * @param pageIndex Index of page 72 */ prvPageReadComplete(int pageIndex)73static void prvPageReadComplete(int pageIndex) 74 { 75 TRACE_ALLOC_CRITICAL_SECTION(); 76 77 TRACE_ENTER_CRITICAL_SECTION(); 78 PageInfo[pageIndex].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); 79 PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; 80 PageInfo[pageIndex].Status = PAGE_STATUS_FREE; 81 82 TotalBytesRemaining += (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); 83 84 TRACE_EXIT_CRITICAL_SECTION(); 85 } 86 87 /** 88 * @brief Get the current buffer page index and remaining number of bytes. 89 * 90 * @param bytesUsed Pointer to int where bytes used will be written. 91 * @return int Index of page or -1 if there is no current page. 92 */ prvGetBufferPage(int32_t * bytesUsed)93static int prvGetBufferPage(int32_t* bytesUsed) 94 { 95 static int8_t lastPage = -1; 96 int count = 0; 97 int8_t index = (int8_t) ((lastPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)); 98 99 while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT))) 100 { 101 index = (int8_t)((index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)); 102 } 103 104 if (PageInfo[index].Status == PAGE_STATUS_READ) 105 { 106 *bytesUsed = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) - PageInfo[index].BytesRemaining; 107 lastPage = index; 108 return index; 109 } 110 111 *bytesUsed = 0; 112 113 return -1; 114 } 115 prvPagedEventBufferInit(char * buffer)116void prvPagedEventBufferInit(char* buffer) 117 { 118 TotalBytesRemaining_LowWaterMark = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)* (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); 119 TotalBytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)* (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); 120 121 int i; 122 TRACE_ALLOC_CRITICAL_SECTION(); 123 124 EventBuffer = buffer; 125 126 TRACE_ENTER_CRITICAL_SECTION(); 127 for (i = 0; i < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); i++) 128 { 129 PageInfo[i].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); 130 PageInfo[i].WritePointer = &EventBuffer[i * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; 131 PageInfo[i].Status = PAGE_STATUS_FREE; 132 } 133 TRACE_EXIT_CRITICAL_SECTION(); 134 } 135 prvPagedEventBufferGetWritePointer(int sizeOfEvent)136void* prvPagedEventBufferGetWritePointer(int sizeOfEvent) 137 { 138 void* ret; 139 static int currentWritePage = -1; 140 141 if (currentWritePage == -1) 142 { 143 currentWritePage = prvAllocateBufferPage(currentWritePage); 144 if (currentWritePage == -1) 145 { 146 //DroppedEventCounter++; 147 return NULL; 148 } 149 } 150 151 if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0) 152 { 153 PageInfo[currentWritePage].Status = PAGE_STATUS_READ; 154 155 TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes 156 157 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark) 158 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining; 159 160 currentWritePage = prvAllocateBufferPage(currentWritePage); 161 if (currentWritePage == -1) 162 { 163 //DroppedEventCounter++; 164 return NULL; 165 } 166 } 167 ret = PageInfo[currentWritePage].WritePointer; 168 PageInfo[currentWritePage].WritePointer += sizeOfEvent; 169 PageInfo[currentWritePage].BytesRemaining = (uint16_t)(PageInfo[currentWritePage].BytesRemaining -sizeOfEvent); 170 171 TotalBytesRemaining = (TotalBytesRemaining-(uint16_t)sizeOfEvent); 172 173 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark) 174 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining; 175 176 return ret; 177 } 178 prvPagedEventBufferTransfer(void)179uint32_t prvPagedEventBufferTransfer(void) 180 { 181 int8_t pageToTransfer = -1; 182 int32_t bytesTransferredTotal = 0; 183 int32_t bytesTransferredNow = 0; 184 int32_t bytesToTransfer; 185 186 pageToTransfer = (int8_t)prvGetBufferPage(&bytesToTransfer); 187 188 /* bytesToTransfer now contains the number of "valid" bytes in the buffer page, that should be transmitted. 189 There might be some unused junk bytes in the end, that must be ignored. */ 190 191 if (pageToTransfer > -1) 192 { 193 while (1) /* Keep going until we have transferred all that we intended to */ 194 { 195 if (TRC_STREAM_PORT_WRITE_DATA( 196 &EventBuffer[pageToTransfer * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) + bytesTransferredTotal], 197 (uint32_t)(bytesToTransfer - bytesTransferredTotal), 198 &bytesTransferredNow) == 0) 199 { 200 /* Write was successful. Update the number of transferred bytes. */ 201 bytesTransferredTotal += bytesTransferredNow; 202 203 if (bytesTransferredTotal == bytesToTransfer) 204 { 205 /* All bytes have been transferred. Mark the buffer page as "Read Complete" (so it can be written to) and return OK. */ 206 prvPageReadComplete(pageToTransfer); 207 return (uint32_t)bytesTransferredTotal; 208 } 209 } 210 else 211 { 212 /* Some error from the streaming interface... */ 213 vTraceStop(); 214 return 0; 215 } 216 } 217 } 218 return 0; 219 } 220 221 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1) && (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)*/ 222