/********************************************************************* * SEGGER Microcontroller GmbH * * The Embedded Experts * ********************************************************************** * * * (c) 1995 - 2019 SEGGER Microcontroller GmbH * * * * www.segger.com Support: support@segger.com * * * ********************************************************************** * * * SEGGER RTT * Real Time Transfer for embedded targets * * * ********************************************************************** * * * All rights reserved. * * * * SEGGER strongly recommends to not make any changes * * to or modify the source code of this software in order to stay * * compatible with the RTT protocol and J-Link. * * * * Redistribution and use in source and binary forms, with or * * without modification, are permitted provided that the following * * condition is met: * * * * o Redistributions of source code must retain the above copyright * * notice, this condition and the following disclaimer. * * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * * DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * * DAMAGE. * * * ********************************************************************** ---------------------------END-OF-HEADER------------------------------ File : SEGGER_RTT.c Purpose : Implementation of SEGGER real-time transfer (RTT) which allows real-time communication on targets which support debugger memory accesses while the CPU is running. Revision: $Rev: 19464 $ Additional information: Type "int" is assumed to be 32-bits in size H->T Host to target communication T->H Target to host communication RTT channel 0 is always present and reserved for Terminal usage. Name is fixed to "Terminal" Effective buffer size: SizeOfBuffer - 1 WrOff == RdOff: Buffer is empty WrOff == (RdOff - 1): Buffer is full WrOff > RdOff: Free space includes wrap-around WrOff < RdOff: Used space includes wrap-around (WrOff == (SizeOfBuffer - 1)) && (RdOff == 0): Buffer full and wrap-around after next byte ---------------------------------------------------------------------- */ #include "SEGGER_RTT.h" #include // for memcpy /********************************************************************* * * Configuration, default values * ********************************************************************** */ #ifndef BUFFER_SIZE_UP #define BUFFER_SIZE_UP 1024 // Size of the buffer for terminal output of target, up to host #endif #ifndef BUFFER_SIZE_DOWN #define BUFFER_SIZE_DOWN 16 // Size of the buffer for terminal input to target from host (Usually keyboard input) #endif #ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS #define SEGGER_RTT_MAX_NUM_UP_BUFFERS 2 // Number of up-buffers (T->H) available on this target #endif #ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS 2 // Number of down-buffers (H->T) available on this target #endif #ifndef SEGGER_RTT_BUFFER_SECTION #if defined(SEGGER_RTT_SECTION) #define SEGGER_RTT_BUFFER_SECTION SEGGER_RTT_SECTION #endif #endif #ifndef SEGGER_RTT_ALIGNMENT #define SEGGER_RTT_ALIGNMENT 0 #endif #ifndef SEGGER_RTT_BUFFER_ALIGNMENT #define SEGGER_RTT_BUFFER_ALIGNMENT 0 #endif #ifndef SEGGER_RTT_MODE_DEFAULT #define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP #endif #ifndef SEGGER_RTT_LOCK #define SEGGER_RTT_LOCK() #endif #ifndef SEGGER_RTT_UNLOCK #define SEGGER_RTT_UNLOCK() #endif #ifndef STRLEN #define STRLEN(a) strlen((a)) #endif #ifndef STRCPY #define STRCPY(pDest, pSrc, NumBytes) strcpy((pDest), (pSrc)) #endif #ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP #define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 #endif #ifndef SEGGER_RTT_MEMCPY #ifdef MEMCPY #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) MEMCPY((pDest), (pSrc), (NumBytes)) #else #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) memcpy((pDest), (pSrc), (NumBytes)) #endif #endif #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif // // For some environments, NULL may not be defined until certain headers are included // #ifndef NULL #define NULL 0 #endif /********************************************************************* * * Defines, fixed * ********************************************************************** */ #if (defined __ICCARM__) || (defined __ICCRX__) #define RTT_PRAGMA(P) _Pragma(#P) #endif #if SEGGER_RTT_ALIGNMENT || SEGGER_RTT_BUFFER_ALIGNMENT #if (defined __GNUC__) #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__((aligned(Alignment))) #elif (defined __ICCARM__) || (defined __ICCRX__) #define PRAGMA(A) _Pragma(#A) #define SEGGER_RTT_ALIGN(Var, Alignment) \ RTT_PRAGMA(data_alignment = Alignment) \ Var #elif (defined __CC_ARM) #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__((aligned(Alignment))) #else #error "Alignment not supported for this compiler." #endif #else #define SEGGER_RTT_ALIGN(Var, Alignment) Var #endif #if defined(SEGGER_RTT_SECTION) || defined(SEGGER_RTT_BUFFER_SECTION) #if (defined __GNUC__) #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__((section(Section))) Var #elif (defined __ICCARM__) || (defined __ICCRX__) #define SEGGER_RTT_PUT_SECTION(Var, Section) \ RTT_PRAGMA(location = Section) \ Var #elif (defined __CC_ARM) #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__((section(Section), zero_init)) Var #else #error "Section placement not supported for this compiler." #endif #else #define SEGGER_RTT_PUT_SECTION(Var, Section) Var #endif #if SEGGER_RTT_ALIGNMENT #define SEGGER_RTT_CB_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_ALIGNMENT) #else #define SEGGER_RTT_CB_ALIGN(Var) Var #endif #if SEGGER_RTT_BUFFER_ALIGNMENT #define SEGGER_RTT_BUFFER_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_BUFFER_ALIGNMENT) #else #define SEGGER_RTT_BUFFER_ALIGN(Var) Var #endif #if defined(SEGGER_RTT_SECTION) #define SEGGER_RTT_PUT_CB_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_SECTION) #else #define SEGGER_RTT_PUT_CB_SECTION(Var) Var #endif #if defined(SEGGER_RTT_BUFFER_SECTION) #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_BUFFER_SECTION) #else #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) Var #endif /********************************************************************* * * Static const data * ********************************************************************** */ static unsigned char _aTerminalId[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /********************************************************************* * * Static data * ********************************************************************** */ // // RTT Control Block and allocate buffers for channel 0 // SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT)); SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBuffer[BUFFER_SIZE_UP])); SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[BUFFER_SIZE_DOWN])); static unsigned char _ActiveTerminal; /********************************************************************* * * Static functions * ********************************************************************** */ /********************************************************************* * * _DoInit() * * Function description * Initializes the control block an buffers. * May only be called via INIT() to avoid overriding settings. * */ #define INIT() \ do \ { \ if (_SEGGER_RTT.acID[0] == '\0') \ { \ _DoInit(); \ } \ } while (0) static void _DoInit(void) { SEGGER_RTT_CB * p; // // Initialize control block // p = &_SEGGER_RTT; p->MaxNumUpBuffers = SEGGER_RTT_MAX_NUM_UP_BUFFERS; p->MaxNumDownBuffers = SEGGER_RTT_MAX_NUM_DOWN_BUFFERS; // // Initialize up buffer 0 // p->aUp[0].sName = "Terminal"; p->aUp[0].pBuffer = _acUpBuffer; p->aUp[0].SizeOfBuffer = sizeof(_acUpBuffer); p->aUp[0].RdOff = 0u; p->aUp[0].WrOff = 0u; p->aUp[0].Flags = SEGGER_RTT_MODE_DEFAULT; // // Initialize down buffer 0 // p->aDown[0].sName = "Terminal"; p->aDown[0].pBuffer = _acDownBuffer; p->aDown[0].SizeOfBuffer = sizeof(_acDownBuffer); p->aDown[0].RdOff = 0u; p->aDown[0].WrOff = 0u; p->aDown[0].Flags = SEGGER_RTT_MODE_DEFAULT; // // Finish initialization of the control block. // Copy Id string in three steps to make sure "SEGGER RTT" is not found // in initializer memory (usually flash) by J-Link // STRCPY(&p->acID[7], "RTT", 9); RTT__DMB(); STRCPY(&p->acID[0], "SEGGER", 7); RTT__DMB(); p->acID[6] = ' '; RTT__DMB(); } /********************************************************************* * * _WriteBlocking() * * Function description * Stores a specified number of characters in SEGGER RTT ring buffer * and updates the associated write pointer which is periodically * read by the host. * The caller is responsible for managing the write chunk sizes as * _WriteBlocking() will block until all data has been posted successfully. * * Parameters * pRing Ring buffer to post to. * 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 * >= 0 - Number of bytes written into buffer. */ static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP * pRing, const char * pBuffer, unsigned NumBytes) { unsigned NumBytesToWrite; unsigned NumBytesWritten; unsigned RdOff; unsigned WrOff; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP char * pDst; #endif // // Write data to buffer and handle wrap-around if necessary // NumBytesWritten = 0u; WrOff = pRing->WrOff; do { RdOff = pRing->RdOff; // May be changed by host (debug probe) in the meantime if (RdOff > WrOff) { NumBytesToWrite = RdOff - WrOff - 1u; } else { NumBytesToWrite = pRing->SizeOfBuffer - (WrOff - RdOff + 1u); } NumBytesToWrite = MIN(NumBytesToWrite, (pRing->SizeOfBuffer - WrOff)); // Number of bytes that can be written until buffer wrap-around NumBytesToWrite = MIN(NumBytesToWrite, NumBytes); #if SEGGER_RTT_MEMCPY_USE_BYTELOOP pDst = pRing->pBuffer + WrOff; NumBytesWritten += NumBytesToWrite; NumBytes -= NumBytesToWrite; WrOff += NumBytesToWrite; while (NumBytesToWrite--) { *pDst++ = *pBuffer++; }; #else SEGGER_RTT_MEMCPY(pRing->pBuffer + WrOff, pBuffer, NumBytesToWrite); NumBytesWritten += NumBytesToWrite; pBuffer += NumBytesToWrite; NumBytes -= NumBytesToWrite; WrOff += NumBytesToWrite; #endif if (WrOff == pRing->SizeOfBuffer) { WrOff = 0u; } RTT__DMB(); pRing->WrOff = WrOff; } while (NumBytes); // return NumBytesWritten; } /********************************************************************* * * _WriteNoCheck() * * Function description * Stores a specified number of characters in SEGGER RTT ring buffer * and updates the associated write pointer which is periodically * read by the host. * It is callers responsibility to make sure data actually fits in buffer. * * Parameters * pRing Ring buffer to post to. * 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. * * Notes * (1) If there might not be enough space in the "Up"-buffer, call _WriteBlocking */ static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP * pRing, const char * pData, unsigned NumBytes) { unsigned NumBytesAtOnce; unsigned WrOff; unsigned Rem; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP char * pDst; #endif WrOff = pRing->WrOff; Rem = pRing->SizeOfBuffer - WrOff; if (Rem > NumBytes) { // // All data fits before wrap around // #if SEGGER_RTT_MEMCPY_USE_BYTELOOP pDst = pRing->pBuffer + WrOff; WrOff += NumBytes; while (NumBytes--) { *pDst++ = *pData++; }; RTT__DMB(); pRing->WrOff = WrOff; #else SEGGER_RTT_MEMCPY(pRing->pBuffer + WrOff, pData, NumBytes); RTT__DMB(); pRing->WrOff = WrOff + NumBytes; #endif } else { // // We reach the end of the buffer, so need to wrap around // #if SEGGER_RTT_MEMCPY_USE_BYTELOOP pDst = pRing->pBuffer + WrOff; NumBytesAtOnce = Rem; while (NumBytesAtOnce--) { *pDst++ = *pData++; }; pDst = pRing->pBuffer; NumBytesAtOnce = NumBytes - Rem; while (NumBytesAtOnce--) { *pDst++ = *pData++; }; RTT__DMB(); pRing->WrOff = NumBytes - Rem; #else NumBytesAtOnce = Rem; SEGGER_RTT_MEMCPY(pRing->pBuffer + WrOff, pData, NumBytesAtOnce); NumBytesAtOnce = NumBytes - Rem; SEGGER_RTT_MEMCPY(pRing->pBuffer, pData + Rem, NumBytesAtOnce); RTT__DMB(); pRing->WrOff = NumBytesAtOnce; #endif } } /********************************************************************* * * _PostTerminalSwitch() * * Function description * Switch terminal to the given terminal ID. It is the caller's * responsibility to ensure the terminal ID is correct and there is * enough space in the buffer for this to complete successfully. * * Parameters * pRing Ring buffer to post to. * TerminalId Terminal ID to switch to. */ static void _PostTerminalSwitch(SEGGER_RTT_BUFFER_UP * pRing, unsigned char TerminalId) { unsigned char ac[2]; ac[0] = 0xFFu; ac[1] = _aTerminalId[TerminalId]; // Caller made already sure that TerminalId does not exceed our terminal limit _WriteBlocking(pRing, (const char *) ac, 2u); } /********************************************************************* * * _GetAvailWriteSpace() * * Function description * Returns the number of bytes that can be written to the ring * buffer without blocking. * * Parameters * pRing Ring buffer to check. * * Return value * Number of bytes that are free in the buffer. */ static unsigned _GetAvailWriteSpace(SEGGER_RTT_BUFFER_UP * pRing) { unsigned RdOff; unsigned WrOff; unsigned r; // // Avoid warnings regarding volatile access order. It's not a problem // in this case, but dampen compiler enthusiasm. // RdOff = pRing->RdOff; WrOff = pRing->WrOff; if (RdOff <= WrOff) { r = pRing->SizeOfBuffer - 1u - WrOff + RdOff; } else { r = RdOff - WrOff - 1u; } return r; } /********************************************************************* * * Public code * ********************************************************************** */ /********************************************************************* * * SEGGER_RTT_ReadUpBufferNoLock() * * Function description * Reads characters from SEGGER real-time-terminal control block * which have been previously stored by the application. * Do not lock against interrupts and multiple access. * Used to do the same operation that J-Link does, to transfer * RTT data via other channels, such as TCP/IP or UART. * * Parameters * BufferIndex Index of Up-buffer to be used. * pBuffer Pointer to buffer provided by target application, to copy characters from RTT-up-buffer to. * BufferSize Size of the target application buffer. * * Return value * Number of bytes that have been read. * * Additional information * This function must not be called when J-Link might also do RTT. */ unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void * pData, unsigned BufferSize) { unsigned NumBytesRem; unsigned NumBytesRead; unsigned RdOff; unsigned WrOff; unsigned char * pBuffer; SEGGER_RTT_BUFFER_UP * pRing; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP const char * pSrc; #endif // INIT(); pRing = &_SEGGER_RTT.aUp[BufferIndex]; pBuffer = (unsigned char *) pData; RdOff = pRing->RdOff; WrOff = pRing->WrOff; NumBytesRead = 0u; // // Read from current read position to wrap-around of buffer, first // if (RdOff > WrOff) { NumBytesRem = pRing->SizeOfBuffer - RdOff; NumBytesRem = MIN(NumBytesRem, BufferSize); #if SEGGER_RTT_MEMCPY_USE_BYTELOOP pSrc = pRing->pBuffer + RdOff; NumBytesRead += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; while (NumBytesRem--) { *pBuffer++ = *pSrc++; }; #else SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); NumBytesRead += NumBytesRem; pBuffer += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; #endif // // Handle wrap-around of buffer // if (RdOff == pRing->SizeOfBuffer) { RdOff = 0u; } } // // Read remaining items of buffer // NumBytesRem = WrOff - RdOff; NumBytesRem = MIN(NumBytesRem, BufferSize); if (NumBytesRem > 0u) { #if SEGGER_RTT_MEMCPY_USE_BYTELOOP pSrc = pRing->pBuffer + RdOff; NumBytesRead += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; while (NumBytesRem--) { *pBuffer++ = *pSrc++; }; #else SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); NumBytesRead += NumBytesRem; pBuffer += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; #endif } // // Update read offset of buffer // if (NumBytesRead) { pRing->RdOff = RdOff; } // return NumBytesRead; } /********************************************************************* * * 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) { unsigned NumBytesRem; unsigned NumBytesRead; unsigned RdOff; unsigned WrOff; unsigned char * pBuffer; SEGGER_RTT_BUFFER_DOWN * pRing; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP const char * pSrc; #endif // INIT(); pRing = &_SEGGER_RTT.aDown[BufferIndex]; pBuffer = (unsigned char *) pData; RdOff = pRing->RdOff; WrOff = pRing->WrOff; NumBytesRead = 0u; // // Read from current read position to wrap-around of buffer, first // if (RdOff > WrOff) { NumBytesRem = pRing->SizeOfBuffer - RdOff; NumBytesRem = MIN(NumBytesRem, BufferSize); #if SEGGER_RTT_MEMCPY_USE_BYTELOOP pSrc = pRing->pBuffer + RdOff; NumBytesRead += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; while (NumBytesRem--) { *pBuffer++ = *pSrc++; }; #else SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); NumBytesRead += NumBytesRem; pBuffer += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; #endif // // Handle wrap-around of buffer // if (RdOff == pRing->SizeOfBuffer) { RdOff = 0u; } } // // Read remaining items of buffer // NumBytesRem = WrOff - RdOff; NumBytesRem = MIN(NumBytesRem, BufferSize); if (NumBytesRem > 0u) { #if SEGGER_RTT_MEMCPY_USE_BYTELOOP pSrc = pRing->pBuffer + RdOff; NumBytesRead += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; while (NumBytesRem--) { *pBuffer++ = *pSrc++; }; #else SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); NumBytesRead += NumBytesRem; pBuffer += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; #endif } if (NumBytesRead) { pRing->RdOff = RdOff; } // return NumBytesRead; } /********************************************************************* * * SEGGER_RTT_ReadUpBuffer * * Function description * Reads characters from SEGGER real-time-terminal control block * which have been previously stored by the application. * Used to do the same operation that J-Link does, to transfer * RTT data via other channels, such as TCP/IP or UART. * * Parameters * BufferIndex Index of Up-buffer to be used. * pBuffer Pointer to buffer provided by target application, to copy characters from RTT-up-buffer to. * BufferSize Size of the target application buffer. * * Return value * Number of bytes that have been read. * * Additional information * This function must not be called when J-Link might also do RTT. * This function locks against all other RTT operations. I.e. during * the read operation, writing is also locked. * If only one consumer reads from the up buffer, * call sEGGER_RTT_ReadUpBufferNoLock() instead. */ unsigned SEGGER_RTT_ReadUpBuffer(unsigned BufferIndex, void * pBuffer, unsigned BufferSize) { unsigned NumBytesRead; // SEGGER_RTT_LOCK(); // // Call the non-locking read function // NumBytesRead = SEGGER_RTT_ReadUpBufferNoLock(BufferIndex, pBuffer, BufferSize); // // Finish up. // SEGGER_RTT_UNLOCK(); // return NumBytesRead; } /********************************************************************* * * SEGGER_RTT_Read * * Function description * Reads characters from SEGGER real-time-terminal control block * which have been previously stored by the host. * * 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_Read(unsigned BufferIndex, void * pBuffer, unsigned BufferSize) { unsigned NumBytesRead; // SEGGER_RTT_LOCK(); // // Call the non-locking read function // NumBytesRead = SEGGER_RTT_ReadNoLock(BufferIndex, pBuffer, BufferSize); // // Finish up. // SEGGER_RTT_UNLOCK(); // return NumBytesRead; } /********************************************************************* * * SEGGER_RTT_WriteWithOverwriteNoLock * * Function description * Stores a specified number of characters in SEGGER RTT * control block. * SEGGER_RTT_WriteWithOverwriteNoLock does not lock the application * and overwrites 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. * * Notes * (1) If there is not enough space in the "Up"-buffer, data is overwritten. * (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. * (3) Do not use SEGGER_RTT_WriteWithOverwriteNoLock if a J-Link * connection reads RTT data. */ void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void * pBuffer, unsigned NumBytes) { const char * pData; SEGGER_RTT_BUFFER_UP * pRing; unsigned Avail; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP char * pDst; #endif pData = (const char *) pBuffer; // // Get "to-host" ring buffer and copy some elements into local variables. // pRing = &_SEGGER_RTT.aUp[BufferIndex]; // // Check if we will overwrite data and need to adjust the RdOff. // if (pRing->WrOff == pRing->RdOff) { Avail = pRing->SizeOfBuffer - 1u; } else if (pRing->WrOff < pRing->RdOff) { Avail = pRing->RdOff - pRing->WrOff - 1u; } else { Avail = pRing->RdOff - pRing->WrOff - 1u + pRing->SizeOfBuffer; } if (NumBytes > Avail) { pRing->RdOff += (NumBytes - Avail); while (pRing->RdOff >= pRing->SizeOfBuffer) { pRing->RdOff -= pRing->SizeOfBuffer; } } // // Write all data, no need to check the RdOff, but possibly handle multiple wrap-arounds // Avail = pRing->SizeOfBuffer - pRing->WrOff; do { if (Avail > NumBytes) { // // Last round // #if SEGGER_RTT_MEMCPY_USE_BYTELOOP pDst = pRing->pBuffer + pRing->WrOff; Avail = NumBytes; while (NumBytes--) { *pDst++ = *pData++; }; RTT__DMB(); pRing->WrOff += Avail; #else SEGGER_RTT_MEMCPY(pRing->pBuffer + pRing->WrOff, pData, NumBytes); RTT__DMB(); pRing->WrOff += NumBytes; #endif break; } else { // // Wrap-around necessary, write until wrap-around and reset WrOff // #if SEGGER_RTT_MEMCPY_USE_BYTELOOP pDst = pRing->pBuffer + pRing->WrOff; NumBytes -= Avail; while (Avail--) { *pDst++ = *pData++; }; RTT__DMB(); pRing->WrOff = 0; #else SEGGER_RTT_MEMCPY(pRing->pBuffer + pRing->WrOff, pData, Avail); pData += Avail; RTT__DMB(); pRing->WrOff = 0; NumBytes -= Avail; #endif Avail = (pRing->SizeOfBuffer - 1); } } while (NumBytes); } /********************************************************************* * * 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. * MUST be > 0!!! * This is done for performance reasons, so no initial check has do be done. * * Return value * 1: Data has been copied * 0: No space, data has not been copied * * 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. */ #if (RTT_USE_ASM == 0) unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void * pBuffer, unsigned NumBytes) { const char * pData; SEGGER_RTT_BUFFER_UP * pRing; unsigned Avail; unsigned RdOff; unsigned WrOff; unsigned Rem; // // Cases: // 1) RdOff <= WrOff => Space until wrap-around is sufficient // 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks) // 3) RdOff < WrOff => No space in buf // 4) RdOff > WrOff => Space is sufficient // 5) RdOff > WrOff => No space in buf // // 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough // pData = (const char *) pBuffer; pRing = &_SEGGER_RTT.aUp[BufferIndex]; RdOff = pRing->RdOff; WrOff = pRing->WrOff; if (RdOff <= WrOff) { // Case 1), 2) or 3) Avail = pRing->SizeOfBuffer - WrOff - 1u; // Space until wrap-around (assume 1 byte not usable for case that RdOff == 0) if (Avail >= NumBytes) { // Case 1)? CopyStraight: memcpy(pRing->pBuffer + WrOff, pData, NumBytes); RTT__DMB(); pRing->WrOff = WrOff + NumBytes; return 1; } Avail += RdOff; // Space incl. wrap-around if (Avail >= NumBytes) { // Case 2? => If not, we have case 3) (does not fit) Rem = pRing->SizeOfBuffer - WrOff; // Space until end of buffer memcpy(pRing->pBuffer + WrOff, pData, Rem); // Copy 1st chunk NumBytes -= Rem; // // Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used // But 2nd check (considering space until wrap-around and until RdOff) revealed that RdOff is not 0, so we can use the // last element In this case, we may use a copy straight until buffer end anyway without needing to copy 2 chunks // Therefore, check if 2nd memcpy is necessary at all // if (NumBytes) { memcpy(pRing->pBuffer, pData + Rem, NumBytes); } RTT__DMB(); pRing->WrOff = NumBytes; return 1; } } else { // Potential case 4) Avail = RdOff - WrOff - 1u; if (Avail >= NumBytes) { // Case 4)? => If not, we have case 5) (does not fit) goto CopyStraight; } } return 0; // No space in buffer } #endif /********************************************************************* * * SEGGER_RTT_WriteDownBufferNoLock * * Function description * Stores a specified number of characters in SEGGER RTT * control block inside a buffer. * SEGGER_RTT_WriteDownBufferNoLock does not lock the application. * Used to do the same operation that J-Link does, to transfer * RTT data from other channels, such as TCP/IP or UART. * * Parameters * BufferIndex Index of "Down"-buffer to be used. * 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 "Down"-buffer. * * Notes * (1) Data is stored according to buffer flags. * (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. * * Additional information * This function must not be called when J-Link might also do RTT. */ unsigned SEGGER_RTT_WriteDownBufferNoLock(unsigned BufferIndex, const void * pBuffer, unsigned NumBytes) { unsigned Status; unsigned Avail; const char * pData; SEGGER_RTT_BUFFER_UP * pRing; pData = (const char *) pBuffer; // // Get "to-target" ring buffer. // It is save to cast that to a "to-host" buffer. Up and Down buffer differ in volatility of offsets that might be modified by // J-Link. // pRing = (SEGGER_RTT_BUFFER_UP *) &_SEGGER_RTT.aDown[BufferIndex]; // // How we output depends upon the mode... // switch (pRing->Flags) { case SEGGER_RTT_MODE_NO_BLOCK_SKIP: // // If we are in skip mode and there is no space for the whole // of this output, don't bother. // Avail = _GetAvailWriteSpace(pRing); if (Avail < NumBytes) { Status = 0u; } else { Status = NumBytes; _WriteNoCheck(pRing, pData, NumBytes); } break; case SEGGER_RTT_MODE_NO_BLOCK_TRIM: // // If we are in trim mode, trim to what we can output without blocking. // Avail = _GetAvailWriteSpace(pRing); Status = Avail < NumBytes ? Avail : NumBytes; _WriteNoCheck(pRing, pData, Status); break; case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: // // If we are in blocking mode, output everything. // Status = _WriteBlocking(pRing, pData, NumBytes); break; default: Status = 0u; break; } // // Finish up. // return Status; } /********************************************************************* * * SEGGER_RTT_WriteNoLock * * Function description * Stores a specified number of characters in SEGGER RTT * control block which is then read by the host. * SEGGER_RTT_WriteNoLock does not lock the application. * * 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) Data is stored according to buffer flags. * (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_WriteNoLock(unsigned BufferIndex, const void * pBuffer, unsigned NumBytes) { unsigned Status; unsigned Avail; const char * pData; SEGGER_RTT_BUFFER_UP * pRing; pData = (const char *) pBuffer; // // Get "to-host" ring buffer. // pRing = &_SEGGER_RTT.aUp[BufferIndex]; // // How we output depends upon the mode... // switch (pRing->Flags) { case SEGGER_RTT_MODE_NO_BLOCK_SKIP: // // If we are in skip mode and there is no space for the whole // of this output, don't bother. // Avail = _GetAvailWriteSpace(pRing); if (Avail < NumBytes) { Status = 0u; } else { Status = NumBytes; _WriteNoCheck(pRing, pData, NumBytes); } break; case SEGGER_RTT_MODE_NO_BLOCK_TRIM: // // If we are in trim mode, trim to what we can output without blocking. // Avail = _GetAvailWriteSpace(pRing); Status = Avail < NumBytes ? Avail : NumBytes; _WriteNoCheck(pRing, pData, Status); break; case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: // // If we are in blocking mode, output everything. // Status = _WriteBlocking(pRing, pData, NumBytes); break; default: Status = 0u; break; } // // Finish up. // return Status; } /********************************************************************* * * SEGGER_RTT_WriteDownBuffer * * Function description * Stores a specified number of characters in SEGGER RTT control block in a 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 "Down"-buffer. * * Notes * (1) Data is stored according to buffer flags. * * Additional information * This function must not be called when J-Link might also do RTT. * This function locks against all other RTT operations. I.e. during * the write operation, writing from the application is also locked. * If only one consumer writes to the down buffer, * call SEGGER_RTT_WriteDownBufferNoLock() instead. */ unsigned SEGGER_RTT_WriteDownBuffer(unsigned BufferIndex, const void * pBuffer, unsigned NumBytes) { unsigned Status; // INIT(); SEGGER_RTT_LOCK(); // // Call the non-locking write function // Status = SEGGER_RTT_WriteDownBufferNoLock(BufferIndex, pBuffer, NumBytes); // // Finish up. // SEGGER_RTT_UNLOCK(); // return Status; } /********************************************************************* * * SEGGER_RTT_Write * * Function description * Stores a specified number of characters in SEGGER RTT * control block which is then read by the host. * * 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) Data is stored according to buffer flags. */ unsigned SEGGER_RTT_Write(unsigned BufferIndex, const void * pBuffer, unsigned NumBytes) { unsigned Status; // INIT(); SEGGER_RTT_LOCK(); // // Call the non-locking write function // Status = SEGGER_RTT_WriteNoLock(BufferIndex, pBuffer, NumBytes); // // Finish up. // SEGGER_RTT_UNLOCK(); // return Status; } /********************************************************************* * * SEGGER_RTT_WriteString * * Function description * Stores string in SEGGER RTT control block. * This data is read by the host. * * Parameters * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). * s Pointer to string. * * Return value * Number of bytes which have been stored in the "Up"-buffer. * * Notes * (1) Data is stored according to buffer flags. * (2) String passed to this function has to be \0 terminated * (3) \0 termination character is *not* stored in RTT buffer */ unsigned SEGGER_RTT_WriteString(unsigned BufferIndex, const char * s) { unsigned Len; Len = STRLEN(s); return SEGGER_RTT_Write(BufferIndex, s, Len); } /********************************************************************* * * SEGGER_RTT_PutCharSkipNoLock * * Function description * Stores a single character/byte in SEGGER RTT buffer. * SEGGER_RTT_PutCharSkipNoLock does not lock the application and * skips the byte, if it does not fit into the buffer. * * Parameters * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). * c Byte to be stored. * * 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, the character 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_PutCharSkipNoLock(unsigned BufferIndex, char c) { SEGGER_RTT_BUFFER_UP * pRing; unsigned WrOff; unsigned Status; // // Get "to-host" ring buffer. // pRing = &_SEGGER_RTT.aUp[BufferIndex]; // // Get write position and handle wrap-around if necessary // WrOff = pRing->WrOff + 1; if (WrOff == pRing->SizeOfBuffer) { WrOff = 0; } // // Output byte if free space is available // if (WrOff != pRing->RdOff) { pRing->pBuffer[pRing->WrOff] = c; RTT__DMB(); pRing->WrOff = WrOff; Status = 1; } else { Status = 0; } // return Status; } /********************************************************************* * * SEGGER_RTT_PutCharSkip * * Function description * Stores a single character/byte in SEGGER RTT buffer. * * Parameters * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). * c Byte to be stored. * * 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, the character is dropped. */ unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c) { SEGGER_RTT_BUFFER_UP * pRing; unsigned WrOff; unsigned Status; // // Prepare // INIT(); SEGGER_RTT_LOCK(); // // Get "to-host" ring buffer. // pRing = &_SEGGER_RTT.aUp[BufferIndex]; // // Get write position and handle wrap-around if necessary // WrOff = pRing->WrOff + 1; if (WrOff == pRing->SizeOfBuffer) { WrOff = 0; } // // Output byte if free space is available // if (WrOff != pRing->RdOff) { pRing->pBuffer[pRing->WrOff] = c; RTT__DMB(); pRing->WrOff = WrOff; Status = 1; } else { Status = 0; } // // Finish up. // SEGGER_RTT_UNLOCK(); // return Status; } /********************************************************************* * * SEGGER_RTT_PutChar * * Function description * Stores a single character/byte in SEGGER RTT buffer. * * Parameters * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). * c Byte to be stored. * * Return value * Number of bytes which have been stored in the "Up"-buffer. * * Notes * (1) Data is stored according to buffer flags. */ unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) { SEGGER_RTT_BUFFER_UP * pRing; unsigned WrOff; unsigned Status; // // Prepare // INIT(); SEGGER_RTT_LOCK(); // // Get "to-host" ring buffer. // pRing = &_SEGGER_RTT.aUp[BufferIndex]; // // Get write position and handle wrap-around if necessary // WrOff = pRing->WrOff + 1; if (WrOff == pRing->SizeOfBuffer) { WrOff = 0; } // // Wait for free space if mode is set to blocking // if (pRing->Flags == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { while (WrOff == pRing->RdOff) { ; } } // // Output byte if free space is available // if (WrOff != pRing->RdOff) { pRing->pBuffer[pRing->WrOff] = c; RTT__DMB(); pRing->WrOff = WrOff; Status = 1; } else { Status = 0; } // // Finish up. // SEGGER_RTT_UNLOCK(); // return Status; } /********************************************************************* * * SEGGER_RTT_GetKey * * Function description * Reads one character from the SEGGER RTT buffer. * Host has previously stored data there. * * Return value * < 0 - No character available (buffer empty). * >= 0 - Character which has been read. (Possible values: 0 - 255) * * Notes * (1) This function is only specified for accesses to RTT buffer 0. */ int SEGGER_RTT_GetKey(void) { char c; int r; r = (int) SEGGER_RTT_Read(0u, &c, 1u); if (r == 1) { r = (int) (unsigned char) c; } else { r = -1; } return r; } /********************************************************************* * * SEGGER_RTT_WaitKey * * Function description * Waits until at least one character is avaible in the SEGGER RTT buffer. * Once a character is available, it is read and this function returns. * * Return value * >=0 - Character which has been read. * * Notes * (1) This function is only specified for accesses to RTT buffer 0 * (2) This function is blocking if no character is present in RTT buffer */ int SEGGER_RTT_WaitKey(void) { int r; do { r = SEGGER_RTT_GetKey(); } while (r < 0); return r; } /********************************************************************* * * SEGGER_RTT_HasKey * * Function description * Checks if at least one character for reading is available in the SEGGER RTT buffer. * * Return value * == 0 - No characters are available to read. * == 1 - At least one character is available. * * Notes * (1) This function is only specified for accesses to RTT buffer 0 */ int SEGGER_RTT_HasKey(void) { unsigned RdOff; int r; INIT(); RdOff = _SEGGER_RTT.aDown[0].RdOff; if (RdOff != _SEGGER_RTT.aDown[0].WrOff) { r = 1; } else { r = 0; } return r; } /********************************************************************* * * SEGGER_RTT_HasData * * Function description * Check if there is data from the host in the given buffer. * * Return value: * ==0: No data * !=0: Data in buffer * */ unsigned SEGGER_RTT_HasData(unsigned BufferIndex) { SEGGER_RTT_BUFFER_DOWN * pRing; unsigned v; pRing = &_SEGGER_RTT.aDown[BufferIndex]; v = pRing->WrOff; return v - pRing->RdOff; } /********************************************************************* * * SEGGER_RTT_HasDataUp * * Function description * Check if there is data remaining to be sent in the given buffer. * * Return value: * ==0: No data * !=0: Data in buffer * */ unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex) { SEGGER_RTT_BUFFER_UP * pRing; unsigned v; pRing = &_SEGGER_RTT.aUp[BufferIndex]; v = pRing->RdOff; return pRing->WrOff - v; } /********************************************************************* * * SEGGER_RTT_AllocDownBuffer * * Function description * Run-time configuration of the next down-buffer (H->T). * The next buffer, which is not used yet is configured. * This includes: Buffer address, size, name, flags, ... * * Parameters * 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. Buffer Index * < 0 - Error */ int SEGGER_RTT_AllocDownBuffer(const char * sName, void * pBuffer, unsigned BufferSize, unsigned Flags) { int BufferIndex; INIT(); SEGGER_RTT_LOCK(); BufferIndex = 0; do { if (_SEGGER_RTT.aDown[BufferIndex].pBuffer == NULL) { break; } BufferIndex++; } while (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers); if (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers) { _SEGGER_RTT.aDown[BufferIndex].sName = sName; _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char *) pBuffer; _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; RTT__DMB(); } else { BufferIndex = -1; } SEGGER_RTT_UNLOCK(); return BufferIndex; } /********************************************************************* * * SEGGER_RTT_AllocUpBuffer * * Function description * Run-time configuration of the next up-buffer (T->H). * The next buffer, which is not used yet is configured. * This includes: Buffer address, size, name, flags, ... * * Parameters * 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. Buffer Index * < 0 - Error */ int SEGGER_RTT_AllocUpBuffer(const char * sName, void * pBuffer, unsigned BufferSize, unsigned Flags) { int BufferIndex; INIT(); SEGGER_RTT_LOCK(); BufferIndex = 0; do { if (_SEGGER_RTT.aUp[BufferIndex].pBuffer == NULL) { break; } BufferIndex++; } while (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers); if (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers) { _SEGGER_RTT.aUp[BufferIndex].sName = sName; _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char *) pBuffer; _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; RTT__DMB(); } else { BufferIndex = -1; } SEGGER_RTT_UNLOCK(); return BufferIndex; } /********************************************************************* * * 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) { int r; INIT(); if (BufferIndex < (unsigned) _SEGGER_RTT.MaxNumUpBuffers) { SEGGER_RTT_LOCK(); if (BufferIndex > 0u) { _SEGGER_RTT.aUp[BufferIndex].sName = sName; _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char *) pBuffer; _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; } _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } else { r = -1; } return r; } /********************************************************************* * * 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) { int r; INIT(); if (BufferIndex < (unsigned) _SEGGER_RTT.MaxNumDownBuffers) { SEGGER_RTT_LOCK(); if (BufferIndex > 0u) { _SEGGER_RTT.aDown[BufferIndex].sName = sName; _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char *) pBuffer; _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; } _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; RTT__DMB(); SEGGER_RTT_UNLOCK(); r = 0; } else { r = -1; } return r; } /********************************************************************* * * SEGGER_RTT_SetNameUpBuffer * * Function description * Run-time configuration of a specific up-buffer name (T->H). * Buffer to be configured is specified by index. * * Parameters * BufferIndex Index of the buffer to renamed. * sName Pointer to a constant name string. * * Return value * >= 0 O.K. * < 0 Error */ int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char * sName) { int r; INIT(); if (BufferIndex < (unsigned) _SEGGER_RTT.MaxNumUpBuffers) { SEGGER_RTT_LOCK(); _SEGGER_RTT.aUp[BufferIndex].sName = sName; SEGGER_RTT_UNLOCK(); r = 0; } else { r = -1; } return r; } /********************************************************************* * * SEGGER_RTT_SetNameDownBuffer * * Function description * Run-time configuration of a specific Down-buffer name (T->H). * Buffer to be configured is specified by index. * * Parameters * BufferIndex Index of the buffer to renamed. * sName Pointer to a constant name string. * * Return value * >= 0 O.K. * < 0 Error */ int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char * sName) { int r; INIT(); if (BufferIndex < (unsigned) _SEGGER_RTT.MaxNumDownBuffers) { SEGGER_RTT_LOCK(); _SEGGER_RTT.aDown[BufferIndex].sName = sName; SEGGER_RTT_UNLOCK(); r = 0; } else { r = -1; } return r; } /********************************************************************* * * SEGGER_RTT_SetFlagsUpBuffer * * Function description * Run-time configuration of specific up-buffer flags (T->H). * Buffer to be configured is specified by index. * * Parameters * BufferIndex Index of the buffer. * Flags Flags to set for the buffer. * * Return value * >= 0 O.K. * < 0 Error */ int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) { int r; INIT(); if (BufferIndex < (unsigned) _SEGGER_RTT.MaxNumUpBuffers) { SEGGER_RTT_LOCK(); _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } else { r = -1; } return r; } /********************************************************************* * * SEGGER_RTT_SetFlagsDownBuffer * * Function description * Run-time configuration of specific Down-buffer flags (T->H). * Buffer to be configured is specified by index. * * Parameters * BufferIndex Index of the buffer to renamed. * Flags Flags to set for the buffer. * * Return value * >= 0 O.K. * < 0 Error */ int SEGGER_RTT_SetFlagsDownBuffer(unsigned BufferIndex, unsigned Flags) { int r; INIT(); if (BufferIndex < (unsigned) _SEGGER_RTT.MaxNumDownBuffers) { SEGGER_RTT_LOCK(); _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } else { r = -1; } return r; } /********************************************************************* * * SEGGER_RTT_Init * * Function description * Initializes the RTT Control Block. * Should be used in RAM targets, at start of the application. * */ void SEGGER_RTT_Init(void) { _DoInit(); } /********************************************************************* * * SEGGER_RTT_SetTerminal * * Function description * Sets the terminal to be used for output on channel 0. * * Parameters * TerminalId Index of the terminal. * * Return value * >= 0 O.K. * < 0 Error (e.g. if RTT is configured for non-blocking mode and there was no space in the buffer to set the new terminal Id) */ int SEGGER_RTT_SetTerminal(unsigned char TerminalId) { unsigned char ac[2]; SEGGER_RTT_BUFFER_UP * pRing; unsigned Avail; int r; // INIT(); // r = 0; ac[0] = 0xFFu; if (TerminalId < sizeof(_aTerminalId)) { // We only support a certain number of channels ac[1] = _aTerminalId[TerminalId]; pRing = &_SEGGER_RTT.aUp[0]; // Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we are and number of free bytes in // buffer does not change downwards after checking and before writing if ((pRing->Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { _ActiveTerminal = TerminalId; _WriteBlocking(pRing, (const char *) ac, 2u); } else { // Skipping mode or trim mode? => We cannot trim this command so handling is the same for both modes Avail = _GetAvailWriteSpace(pRing); if (Avail >= 2) { _ActiveTerminal = TerminalId; // Only change active terminal in case of success _WriteNoCheck(pRing, (const char *) ac, 2u); } else { r = -1; } } SEGGER_RTT_UNLOCK(); } else { r = -1; } return r; } /********************************************************************* * * SEGGER_RTT_TerminalOut * * Function description * Writes a string to the given terminal * without changing the terminal for channel 0. * * Parameters * TerminalId Index of the terminal. * s String to be printed on the terminal. * * Return value * >= 0 - Number of bytes written. * < 0 - Error. * */ int SEGGER_RTT_TerminalOut(unsigned char TerminalId, const char * s) { int Status; unsigned FragLen; unsigned Avail; SEGGER_RTT_BUFFER_UP * pRing; // INIT(); // // Validate terminal ID. // if (TerminalId < (char) sizeof(_aTerminalId)) { // We only support a certain number of channels // // Get "to-host" ring buffer. // pRing = &_SEGGER_RTT.aUp[0]; // // Need to be able to change terminal, write data, change back. // Compute the fixed and variable sizes. // FragLen = STRLEN(s); // // How we output depends upon the mode... // SEGGER_RTT_LOCK(); Avail = _GetAvailWriteSpace(pRing); switch (pRing->Flags & SEGGER_RTT_MODE_MASK) { case SEGGER_RTT_MODE_NO_BLOCK_SKIP: // // If we are in skip mode and there is no space for the whole // of this output, don't bother switching terminals at all. // if (Avail < (FragLen + 4u)) { Status = 0; } else { _PostTerminalSwitch(pRing, TerminalId); Status = (int) _WriteBlocking(pRing, s, FragLen); _PostTerminalSwitch(pRing, _ActiveTerminal); } break; case SEGGER_RTT_MODE_NO_BLOCK_TRIM: // // If we are in trim mode and there is not enough space for everything, // trim the output but always include the terminal switch. If no room // for terminal switch, skip that totally. // if (Avail < 4u) { Status = -1; } else { _PostTerminalSwitch(pRing, TerminalId); Status = (int) _WriteBlocking(pRing, s, (FragLen < (Avail - 4u)) ? FragLen : (Avail - 4u)); _PostTerminalSwitch(pRing, _ActiveTerminal); } break; case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: // // If we are in blocking mode, output everything. // _PostTerminalSwitch(pRing, TerminalId); Status = (int) _WriteBlocking(pRing, s, FragLen); _PostTerminalSwitch(pRing, _ActiveTerminal); break; default: Status = -1; break; } // // Finish up. // SEGGER_RTT_UNLOCK(); } else { Status = -1; } return Status; } /********************************************************************* * * SEGGER_RTT_GetAvailWriteSpace * * Function description * Returns the number of bytes available in the ring buffer. * * Parameters * BufferIndex Index of the up buffer. * * Return value * Number of bytes that are free in the selected up buffer. */ unsigned SEGGER_RTT_GetAvailWriteSpace(unsigned BufferIndex) { return _GetAvailWriteSpace(&_SEGGER_RTT.aUp[BufferIndex]); } /********************************************************************* * * SEGGER_RTT_GetBytesInBuffer() * * Function description * Returns the number of bytes currently used in the up buffer. * * Parameters * BufferIndex Index of the up buffer. * * Return value * Number of bytes that are used in the buffer. */ unsigned SEGGER_RTT_GetBytesInBuffer(unsigned BufferIndex) { unsigned RdOff; unsigned WrOff; unsigned r; // // Avoid warnings regarding volatile access order. It's not a problem // in this case, but dampen compiler enthusiasm. // RdOff = _SEGGER_RTT.aUp[BufferIndex].RdOff; WrOff = _SEGGER_RTT.aUp[BufferIndex].WrOff; if (RdOff <= WrOff) { r = WrOff - RdOff; } else { r = _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer - (WrOff - RdOff); } return r; } /*************************** End of file ****************************/