2359 lines
77 KiB
C
2359 lines
77 KiB
C
/*********************************************************************
|
|
* SEGGER Microcontroller GmbH *
|
|
* The Embedded Experts *
|
|
**********************************************************************
|
|
* *
|
|
* (c) 1995 - 2021 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. *
|
|
* *
|
|
**********************************************************************
|
|
* *
|
|
* RTT version: 7.22 *
|
|
* *
|
|
**********************************************************************
|
|
|
|
---------------------------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: 22333 $
|
|
|
|
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 <string.h> // for memcpy
|
|
|
|
/*
|
|
* For CMSIS pack RTE.
|
|
* CMSIS pack RTE generates "RTC_Components.h" which contains the statements
|
|
* of the related <RTE_Components_h> element for all selected software components.
|
|
*/
|
|
#ifdef _RTE_
|
|
#include "RTE_Components.h"
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Configuration, default values
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
#if SEGGER_RTT_CPU_CACHE_LINE_SIZE
|
|
#ifdef SEGGER_RTT_CB_ALIGN
|
|
#error "Custom SEGGER_RTT_CB_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
|
|
#endif
|
|
#ifdef SEGGER_RTT_BUFFER_ALIGN
|
|
#error "Custom SEGGER_RTT_BUFFER_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
|
|
#endif
|
|
#ifdef SEGGER_RTT_PUT_CB_SECTION
|
|
#error "Custom SEGGER_RTT_PUT_CB_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
|
|
#endif
|
|
#ifdef SEGGER_RTT_PUT_BUFFER_SECTION
|
|
#error "Custom SEGGER_RTT_PUT_BUFFER_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
|
|
#endif
|
|
#ifdef SEGGER_RTT_BUFFER_ALIGNMENT
|
|
#error "Custom SEGGER_RTT_BUFFER_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
|
|
#endif
|
|
#ifdef SEGGER_RTT_ALIGNMENT
|
|
#error "Custom SEGGER_RTT_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
|
|
#endif
|
|
#endif
|
|
|
|
#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 SEGGER_RTT_CPU_CACHE_LINE_SIZE
|
|
#endif
|
|
|
|
#ifndef SEGGER_RTT_BUFFER_ALIGNMENT
|
|
#define SEGGER_RTT_BUFFER_ALIGNMENT SEGGER_RTT_CPU_CACHE_LINE_SIZE
|
|
#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) 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[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)]));
|
|
SEGGER_RTT_PUT_BUFFER_SECTION(
|
|
SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(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() \
|
|
{ \
|
|
volatile SEGGER_RTT_CB *pRTTCBInit; \
|
|
pRTTCBInit = (volatile SEGGER_RTT_CB *)((char *)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); \
|
|
do \
|
|
{ \
|
|
if (pRTTCBInit->acID[0] == '\0') \
|
|
{ \
|
|
_DoInit(); \
|
|
} \
|
|
} while (0); \
|
|
}
|
|
|
|
static void _DoInit(void)
|
|
{
|
|
volatile SEGGER_RTT_CB
|
|
*p; // Volatile to make sure that compiler cannot change the order of accesses to the control block
|
|
//
|
|
// Initialize control block
|
|
//
|
|
p = (volatile SEGGER_RTT_CB
|
|
*)((char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access control block uncached so that nothing in the cache ever becomes
|
|
// dirty and all changes are visible in HW directly
|
|
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 = BUFFER_SIZE_UP;
|
|
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 = BUFFER_SIZE_DOWN;
|
|
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((char *)&p->acID[7], "RTT");
|
|
RTT__DMB(); // Force order of memory accessed inside core for cores that allow to change the order
|
|
STRCPY((char *)&p->acID[0], "SEGGER");
|
|
RTT__DMB(); // Force order of memory accessed inside core for cores that allow to change the order
|
|
p->acID[6] = ' ';
|
|
RTT__DMB(); // Force order of memory accessed inside core for cores that allow to change the order
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _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;
|
|
volatile char *pDst;
|
|
//
|
|
// 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);
|
|
pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
|
|
NumBytesWritten += NumBytesToWrite;
|
|
NumBytes -= NumBytesToWrite;
|
|
WrOff += NumBytesToWrite;
|
|
while (NumBytesToWrite--)
|
|
{
|
|
*pDst++ = *pBuffer++;
|
|
};
|
|
#else
|
|
SEGGER_RTT_MEMCPY((void *)pDst, pBuffer, NumBytesToWrite);
|
|
NumBytesWritten += NumBytesToWrite;
|
|
pBuffer += NumBytesToWrite;
|
|
NumBytes -= NumBytesToWrite;
|
|
WrOff += NumBytesToWrite;
|
|
#endif
|
|
if (WrOff == pRing->SizeOfBuffer)
|
|
{
|
|
WrOff = 0u;
|
|
}
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
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;
|
|
volatile char *pDst;
|
|
|
|
WrOff = pRing->WrOff;
|
|
Rem = pRing->SizeOfBuffer - WrOff;
|
|
if (Rem > NumBytes)
|
|
{
|
|
//
|
|
// All data fits before wrap around
|
|
//
|
|
pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
|
|
WrOff += NumBytes;
|
|
while (NumBytes--)
|
|
{
|
|
*pDst++ = *pData++;
|
|
};
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
pRing->WrOff = WrOff;
|
|
#else
|
|
SEGGER_RTT_MEMCPY((void *)pDst, pData, NumBytes);
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
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) + SEGGER_RTT_UNCACHED_OFF;
|
|
NumBytesAtOnce = Rem;
|
|
while (NumBytesAtOnce--)
|
|
{
|
|
*pDst++ = *pData++;
|
|
};
|
|
pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF;
|
|
NumBytesAtOnce = NumBytes - Rem;
|
|
while (NumBytesAtOnce--)
|
|
{
|
|
*pDst++ = *pData++;
|
|
};
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
pRing->WrOff = NumBytes - Rem;
|
|
#else
|
|
NumBytesAtOnce = Rem;
|
|
pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
SEGGER_RTT_MEMCPY((void *)pDst, pData, NumBytesAtOnce);
|
|
NumBytesAtOnce = NumBytes - Rem;
|
|
pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF;
|
|
SEGGER_RTT_MEMCPY((void *)pDst, pData + Rem, NumBytesAtOnce);
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
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;
|
|
volatile char *pSrc;
|
|
|
|
INIT();
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_UP *)((char *)&_SEGGER_RTT.aUp[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
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);
|
|
pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
|
|
NumBytesRead += NumBytesRem;
|
|
BufferSize -= NumBytesRem;
|
|
RdOff += NumBytesRem;
|
|
while (NumBytesRem--)
|
|
{
|
|
*pBuffer++ = *pSrc++;
|
|
};
|
|
#else
|
|
SEGGER_RTT_MEMCPY(pBuffer, (void *)pSrc, 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)
|
|
{
|
|
pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
|
|
NumBytesRead += NumBytesRem;
|
|
BufferSize -= NumBytesRem;
|
|
RdOff += NumBytesRem;
|
|
while (NumBytesRem--)
|
|
{
|
|
*pBuffer++ = *pSrc++;
|
|
};
|
|
#else
|
|
SEGGER_RTT_MEMCPY(pBuffer, (void *)pSrc, 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;
|
|
volatile char *pSrc;
|
|
//
|
|
INIT();
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_DOWN *)((char *)&_SEGGER_RTT.aDown[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
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);
|
|
pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
|
|
NumBytesRead += NumBytesRem;
|
|
BufferSize -= NumBytesRem;
|
|
RdOff += NumBytesRem;
|
|
while (NumBytesRem--)
|
|
{
|
|
*pBuffer++ = *pSrc++;
|
|
};
|
|
#else
|
|
SEGGER_RTT_MEMCPY(pBuffer, (void *)pSrc, 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)
|
|
{
|
|
pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
|
|
NumBytesRead += NumBytesRem;
|
|
BufferSize -= NumBytesRem;
|
|
RdOff += NumBytesRem;
|
|
while (NumBytesRem--)
|
|
{
|
|
*pBuffer++ = *pSrc++;
|
|
};
|
|
#else
|
|
SEGGER_RTT_MEMCPY(pBuffer, (void *)pSrc, 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;
|
|
volatile char *pDst;
|
|
//
|
|
// Get "to-host" ring buffer and copy some elements into local variables.
|
|
//
|
|
pData = (const char *)pBuffer;
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_UP *)((char *)&_SEGGER_RTT.aUp[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
//
|
|
// 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
|
|
//
|
|
pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
|
|
Avail = NumBytes;
|
|
while (NumBytes--)
|
|
{
|
|
*pDst++ = *pData++;
|
|
};
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change
|
|
// the order of memory accesses
|
|
pRing->WrOff += Avail;
|
|
#else
|
|
SEGGER_RTT_MEMCPY((void *)pDst, pData, NumBytes);
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change
|
|
// the order of memory accesses
|
|
pRing->WrOff += NumBytes;
|
|
#endif
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Wrap-around necessary, write until wrap-around and reset WrOff
|
|
//
|
|
pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
|
|
NumBytes -= Avail;
|
|
while (Avail--)
|
|
{
|
|
*pDst++ = *pData++;
|
|
};
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change
|
|
// the order of memory accesses
|
|
pRing->WrOff = 0;
|
|
#else
|
|
SEGGER_RTT_MEMCPY((void *)pDst, pData, Avail);
|
|
pData += Avail;
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change
|
|
// the order of memory accesses
|
|
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;
|
|
volatile char *pDst;
|
|
//
|
|
// 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_BUFFER_UP *)((char *)&_SEGGER_RTT.aUp[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
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:
|
|
pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
memcpy((void *)pDst, pData, NumBytes);
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change
|
|
// the order of memory accesses
|
|
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
|
|
pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
memcpy((void *)pDst, 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)
|
|
{
|
|
pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF;
|
|
memcpy((void *)pDst, pData + Rem, NumBytes);
|
|
}
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change
|
|
// the order of memory accesses
|
|
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 <Down> 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;
|
|
//
|
|
// 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.
|
|
//
|
|
pData = (const char *)pBuffer;
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_UP *)((char *)&_SEGGER_RTT.aDown[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
//
|
|
// 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;
|
|
//
|
|
// Get "to-host" ring buffer.
|
|
//
|
|
pData = (const char *)pBuffer;
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_UP *)((char *)&_SEGGER_RTT.aUp[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
//
|
|
// 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 <Down> 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();
|
|
Status = SEGGER_RTT_WriteDownBufferNoLock(BufferIndex, pBuffer, NumBytes); // Call the non-locking write function
|
|
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();
|
|
Status = SEGGER_RTT_WriteNoLock(BufferIndex, pBuffer, NumBytes); // Call the non-locking write function
|
|
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;
|
|
volatile char *pDst;
|
|
//
|
|
// Get "to-host" ring buffer.
|
|
//
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_UP *)((char *)&_SEGGER_RTT.aUp[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
//
|
|
// 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)
|
|
{
|
|
pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
*pDst = c;
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
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;
|
|
volatile char *pDst;
|
|
//
|
|
// Prepare
|
|
//
|
|
INIT();
|
|
SEGGER_RTT_LOCK();
|
|
//
|
|
// Get "to-host" ring buffer.
|
|
//
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_UP *)((char *)&_SEGGER_RTT.aUp[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
//
|
|
// 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)
|
|
{
|
|
pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
*pDst = c;
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
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;
|
|
volatile char *pDst;
|
|
//
|
|
// Prepare
|
|
//
|
|
INIT();
|
|
SEGGER_RTT_LOCK();
|
|
//
|
|
// Get "to-host" ring buffer.
|
|
//
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_UP *)((char *)&_SEGGER_RTT.aUp[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
//
|
|
// 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)
|
|
{
|
|
pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF;
|
|
*pDst = c;
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
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)
|
|
{
|
|
SEGGER_RTT_BUFFER_DOWN *pRing;
|
|
unsigned RdOff;
|
|
int r;
|
|
|
|
INIT();
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_DOWN *)((char *)&_SEGGER_RTT.aDown[0] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
RdOff = pRing->RdOff;
|
|
if (RdOff != pRing->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_BUFFER_DOWN *)((char *)&_SEGGER_RTT.aDown[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
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_BUFFER_UP *)((char *)&_SEGGER_RTT.aUp[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
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;
|
|
volatile SEGGER_RTT_CB *pRTTCB;
|
|
|
|
INIT();
|
|
SEGGER_RTT_LOCK();
|
|
pRTTCB = (volatile SEGGER_RTT_CB
|
|
*)((unsigned char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link
|
|
// side and all of our changes go into HW directly
|
|
BufferIndex = 0;
|
|
do
|
|
{
|
|
if (pRTTCB->aDown[BufferIndex].pBuffer == NULL)
|
|
{
|
|
break;
|
|
}
|
|
BufferIndex++;
|
|
} while (BufferIndex < pRTTCB->MaxNumDownBuffers);
|
|
if (BufferIndex < pRTTCB->MaxNumDownBuffers)
|
|
{
|
|
pRTTCB->aDown[BufferIndex].sName = sName;
|
|
pRTTCB->aDown[BufferIndex].pBuffer = (char *)pBuffer;
|
|
pRTTCB->aDown[BufferIndex].SizeOfBuffer = BufferSize;
|
|
pRTTCB->aDown[BufferIndex].RdOff = 0u;
|
|
pRTTCB->aDown[BufferIndex].WrOff = 0u;
|
|
pRTTCB->aDown[BufferIndex].Flags = Flags;
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
}
|
|
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;
|
|
volatile SEGGER_RTT_CB *pRTTCB;
|
|
|
|
INIT();
|
|
SEGGER_RTT_LOCK();
|
|
pRTTCB = (volatile SEGGER_RTT_CB
|
|
*)((unsigned char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link
|
|
// side and all of our changes go into HW directly
|
|
BufferIndex = 0;
|
|
do
|
|
{
|
|
if (pRTTCB->aUp[BufferIndex].pBuffer == NULL)
|
|
{
|
|
break;
|
|
}
|
|
BufferIndex++;
|
|
} while (BufferIndex < pRTTCB->MaxNumUpBuffers);
|
|
if (BufferIndex < pRTTCB->MaxNumUpBuffers)
|
|
{
|
|
pRTTCB->aUp[BufferIndex].sName = sName;
|
|
pRTTCB->aUp[BufferIndex].pBuffer = (char *)pBuffer;
|
|
pRTTCB->aUp[BufferIndex].SizeOfBuffer = BufferSize;
|
|
pRTTCB->aUp[BufferIndex].RdOff = 0u;
|
|
pRTTCB->aUp[BufferIndex].WrOff = 0u;
|
|
pRTTCB->aUp[BufferIndex].Flags = Flags;
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
}
|
|
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;
|
|
volatile SEGGER_RTT_CB *pRTTCB;
|
|
volatile SEGGER_RTT_BUFFER_UP *pUp;
|
|
|
|
INIT();
|
|
pRTTCB = (volatile SEGGER_RTT_CB
|
|
*)((unsigned char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link
|
|
// side and all of our changes go into HW directly
|
|
if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS)
|
|
{
|
|
SEGGER_RTT_LOCK();
|
|
pUp = &pRTTCB->aUp[BufferIndex];
|
|
if (BufferIndex)
|
|
{
|
|
pUp->sName = sName;
|
|
pUp->pBuffer = (char *)pBuffer;
|
|
pUp->SizeOfBuffer = BufferSize;
|
|
pUp->RdOff = 0u;
|
|
pUp->WrOff = 0u;
|
|
}
|
|
pUp->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;
|
|
volatile SEGGER_RTT_CB *pRTTCB;
|
|
volatile SEGGER_RTT_BUFFER_DOWN *pDown;
|
|
|
|
INIT();
|
|
pRTTCB = (volatile SEGGER_RTT_CB
|
|
*)((unsigned char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link
|
|
// side and all of our changes go into HW directly
|
|
if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS)
|
|
{
|
|
SEGGER_RTT_LOCK();
|
|
pDown = &pRTTCB->aDown[BufferIndex];
|
|
if (BufferIndex)
|
|
{
|
|
pDown->sName = sName;
|
|
pDown->pBuffer = (char *)pBuffer;
|
|
pDown->SizeOfBuffer = BufferSize;
|
|
pDown->RdOff = 0u;
|
|
pDown->WrOff = 0u;
|
|
}
|
|
pDown->Flags = Flags;
|
|
RTT__DMB(); // Force data write to be complete before writing the <WrOff>, in case CPU is allowed to change the
|
|
// order of memory accesses
|
|
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;
|
|
volatile SEGGER_RTT_CB *pRTTCB;
|
|
volatile SEGGER_RTT_BUFFER_UP *pUp;
|
|
|
|
INIT();
|
|
pRTTCB = (volatile SEGGER_RTT_CB
|
|
*)((unsigned char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link
|
|
// side and all of our changes go into HW directly
|
|
if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS)
|
|
{
|
|
SEGGER_RTT_LOCK();
|
|
pUp = &pRTTCB->aUp[BufferIndex];
|
|
pUp->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;
|
|
volatile SEGGER_RTT_CB *pRTTCB;
|
|
volatile SEGGER_RTT_BUFFER_DOWN *pDown;
|
|
|
|
INIT();
|
|
pRTTCB = (volatile SEGGER_RTT_CB
|
|
*)((unsigned char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link
|
|
// side and all of our changes go into HW directly
|
|
if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS)
|
|
{
|
|
SEGGER_RTT_LOCK();
|
|
pDown = &pRTTCB->aDown[BufferIndex];
|
|
pDown->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;
|
|
volatile SEGGER_RTT_CB *pRTTCB;
|
|
volatile SEGGER_RTT_BUFFER_UP *pUp;
|
|
|
|
INIT();
|
|
pRTTCB = (volatile SEGGER_RTT_CB
|
|
*)((unsigned char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link
|
|
// side and all of our changes go into HW directly
|
|
if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS)
|
|
{
|
|
SEGGER_RTT_LOCK();
|
|
pUp = &pRTTCB->aUp[BufferIndex];
|
|
pUp->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;
|
|
volatile SEGGER_RTT_CB *pRTTCB;
|
|
volatile SEGGER_RTT_BUFFER_DOWN *pDown;
|
|
|
|
INIT();
|
|
pRTTCB = (volatile SEGGER_RTT_CB
|
|
*)((unsigned char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link
|
|
// side and all of our changes go into HW directly
|
|
if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS)
|
|
{
|
|
SEGGER_RTT_LOCK();
|
|
pDown = &pRTTCB->aDown[BufferIndex];
|
|
pDown->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)
|
|
*
|
|
* Notes
|
|
* (1) Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed
|
|
*/
|
|
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_BUFFER_UP
|
|
*)((char *)&_SEGGER_RTT.aUp[0] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side
|
|
// and all of our changes go into HW directly
|
|
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_BUFFER_UP
|
|
*)((char *)&_SEGGER_RTT.aUp[0] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side
|
|
// and all of our changes go into HW directly
|
|
//
|
|
// 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)
|
|
{
|
|
SEGGER_RTT_BUFFER_UP *pRing;
|
|
|
|
pRing =
|
|
(SEGGER_RTT_BUFFER_UP *)((char *)&_SEGGER_RTT.aUp[BufferIndex] +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the
|
|
// J-Link side and all of our changes go into HW directly
|
|
return _GetAvailWriteSpace(pRing);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* 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;
|
|
volatile SEGGER_RTT_CB *pRTTCB;
|
|
//
|
|
// Avoid warnings regarding volatile access order. It's not a problem
|
|
// in this case, but dampen compiler enthusiasm.
|
|
//
|
|
pRTTCB = (volatile SEGGER_RTT_CB
|
|
*)((unsigned char *)&_SEGGER_RTT +
|
|
SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link
|
|
// side and all of our changes go into HW directly
|
|
RdOff = pRTTCB->aUp[BufferIndex].RdOff;
|
|
WrOff = pRTTCB->aUp[BufferIndex].WrOff;
|
|
if (RdOff <= WrOff)
|
|
{
|
|
r = WrOff - RdOff;
|
|
}
|
|
else
|
|
{
|
|
r = pRTTCB->aUp[BufferIndex].SizeOfBuffer - (WrOff - RdOff);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/*************************** End of file ****************************/
|