mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-06 18:08:00 +00:00
on NRF52 use the Segger debug console for debug logging
This commit is contained in:
2005
lib/segger_rtt/src/SEGGER_RTT.c
Normal file
2005
lib/segger_rtt/src/SEGGER_RTT.c
Normal file
File diff suppressed because it is too large
Load Diff
235
lib/segger_rtt/src/SEGGER_RTT_ASM_ARMv7M.S
Normal file
235
lib/segger_rtt/src/SEGGER_RTT_ASM_ARMv7M.S
Normal file
@@ -0,0 +1,235 @@
|
||||
/*********************************************************************
|
||||
* (c) SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
* www.segger.com *
|
||||
**********************************************************************
|
||||
|
||||
-------------------------- END-OF-HEADER -----------------------------
|
||||
|
||||
File : SEGGER_RTT_ASM_ARMv7M.S
|
||||
Purpose : Assembler implementation of RTT functions for ARMv7M
|
||||
|
||||
Additional information:
|
||||
This module is written to be assembler-independent and works with
|
||||
GCC and clang (Embedded Studio) and IAR.
|
||||
*/
|
||||
|
||||
#define SEGGER_RTT_ASM // Used to control processed input from header file
|
||||
#include "SEGGER_RTT.h"
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, fixed
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#define _CCIAR 0
|
||||
#define _CCCLANG 1
|
||||
|
||||
#if (defined __SES_ARM) || (defined __GNUC__) || (defined __clang__)
|
||||
#define _CC_TYPE _CCCLANG
|
||||
#define _PUB_SYM .global
|
||||
#define _EXT_SYM .extern
|
||||
#define _END .end
|
||||
#define _WEAK .weak
|
||||
#define _THUMB_FUNC .thumb_func
|
||||
#define _THUMB_CODE .code 16
|
||||
#define _WORD .word
|
||||
#define _SECTION(Sect, Type, AlignExp) .section Sect ##, "ax"
|
||||
#define _ALIGN(Exp) .align Exp
|
||||
#define _PLACE_LITS .ltorg
|
||||
#define _DATA_SECT_START
|
||||
#define _C_STARTUP _start
|
||||
#define _STACK_END __stack_end__
|
||||
#define _RAMFUNC
|
||||
//
|
||||
// .text => Link to flash
|
||||
// .fast => Link to RAM
|
||||
// OtherSect => Usually link to RAM
|
||||
// Alignment is 2^x
|
||||
//
|
||||
#elif defined (__IASMARM__)
|
||||
#define _CC_TYPE _CCIAR
|
||||
#define _PUB_SYM PUBLIC
|
||||
#define _EXT_SYM EXTERN
|
||||
#define _END END
|
||||
#define _WEAK _WEAK
|
||||
#define _THUMB_FUNC
|
||||
#define _THUMB_CODE THUMB
|
||||
#define _WORD DCD
|
||||
#define _SECTION(Sect, Type, AlignExp) SECTION Sect ## : ## Type ## :REORDER:NOROOT ## (AlignExp)
|
||||
#define _ALIGN(Exp) alignrom Exp
|
||||
#define _PLACE_LITS
|
||||
#define _DATA_SECT_START DATA
|
||||
#define _C_STARTUP __iar_program_start
|
||||
#define _STACK_END sfe(CSTACK)
|
||||
#define _RAMFUNC SECTION_TYPE SHT_PROGBITS, SHF_WRITE | SHF_EXECINSTR
|
||||
//
|
||||
// .text => Link to flash
|
||||
// .textrw => Link to RAM
|
||||
// OtherSect => Usually link to RAM
|
||||
// NOROOT => Allows linker to throw away the function, if not referenced
|
||||
// Alignment is 2^x
|
||||
//
|
||||
#endif
|
||||
|
||||
#if (_CC_TYPE == _CCIAR)
|
||||
NAME SEGGER_RTT_ASM_ARMv7M
|
||||
#else
|
||||
.syntax unified
|
||||
#endif
|
||||
|
||||
#if defined (RTT_USE_ASM) && (RTT_USE_ASM == 1)
|
||||
#define SHT_PROGBITS 0x1
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Public / external symbols
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
_EXT_SYM __aeabi_memcpy
|
||||
_EXT_SYM __aeabi_memcpy4
|
||||
_EXT_SYM _SEGGER_RTT
|
||||
|
||||
_PUB_SYM SEGGER_RTT_ASM_WriteSkipNoLock
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
_SECTION(.text, CODE, 2)
|
||||
_ALIGN(2)
|
||||
_THUMB_FUNC
|
||||
SEGGER_RTT_ASM_WriteSkipNoLock: // unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pData, unsigned NumBytes) {
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// Register usage:
|
||||
// R0 Temporary needed as RdOff, <Tmp> register later on
|
||||
// R1 pData
|
||||
// R2 <NumBytes>
|
||||
// R3 <Tmp> register. Hold free for subroutine calls
|
||||
// R4 <Rem>
|
||||
// R5 pRing->pBuffer
|
||||
// R6 pRing (Points to active struct SEGGER_RTT_BUFFER_DOWN)
|
||||
// R7 WrOff
|
||||
//
|
||||
PUSH {R4-R7}
|
||||
ADD R3,R0,R0, LSL #+1
|
||||
LDR.W R0,=_SEGGER_RTT // pRing = &_SEGGER_RTT.aUp[BufferIndex];
|
||||
ADD R0,R0,R3, LSL #+3
|
||||
ADD R6,R0,#+24
|
||||
LDR R0,[R6, #+16] // RdOff = pRing->RdOff;
|
||||
LDR R7,[R6, #+12] // WrOff = pRing->WrOff;
|
||||
LDR R5,[R6, #+4] // pRing->pBuffer
|
||||
CMP R7,R0
|
||||
BCC.N _CheckCase4 // if (RdOff <= WrOff) { => Case 1), 2) or 3)
|
||||
//
|
||||
// Handling for case 1, later on identical to case 4
|
||||
//
|
||||
LDR R3,[R6, #+8] // Avail = pRing->SizeOfBuffer - WrOff - 1u; => Space until wrap-around (assume 1 byte not usable for case that RdOff == 0)
|
||||
SUBS R4,R3,R7 // <Rem> (Used in case we jump into case 2 afterwards)
|
||||
SUBS R3,R4,#+1 // <Avail>
|
||||
CMP R3,R2
|
||||
BCC.N _CheckCase2 // if (Avail >= NumBytes) { => Case 1)?
|
||||
_Case4:
|
||||
ADDS R5,R7,R5 // pBuffer += WrOff
|
||||
ADDS R0,R2,R7 // v = WrOff + NumBytes
|
||||
//
|
||||
// 2x unrolling for the copy loop that is used most of the time
|
||||
// This is a special optimization for small SystemView packets and makes them even faster
|
||||
//
|
||||
_ALIGN(2)
|
||||
_LoopCopyStraight: // memcpy(pRing->pBuffer + WrOff, pData, NumBytes);
|
||||
LDRB R3,[R1], #+1
|
||||
STRB R3,[R5], #+1 // *pDest++ = *pSrc++
|
||||
SUBS R2,R2,#+1
|
||||
BEQ _CSDone
|
||||
LDRB R3,[R1], #+1
|
||||
STRB R3,[R5], #+1 // *pDest++ = *pSrc++
|
||||
SUBS R2,R2,#+1
|
||||
BNE _LoopCopyStraight
|
||||
_CSDone:
|
||||
STR R0,[R6, #+12] // pRing->WrOff = WrOff + NumBytes;
|
||||
MOVS R0,#+1
|
||||
POP {R4-R7}
|
||||
BX LR // Return 1
|
||||
_CheckCase2:
|
||||
ADDS R0,R0,R3 // Avail += RdOff; => Space incl. wrap-around
|
||||
CMP R0,R2
|
||||
BCC.N _Case3 // if (Avail >= NumBytes) { => Case 2? => If not, we have case 3) (does not fit)
|
||||
//
|
||||
// Handling for case 2
|
||||
//
|
||||
ADDS R0,R7,R5 // v = pRing->pBuffer + WrOff => Do not change pRing->pBuffer here because 2nd chunk needs org. value
|
||||
SUBS R2,R2,R4 // NumBytes -= Rem; (Rem = pRing->SizeOfBuffer - WrOff; => Space until end of buffer)
|
||||
_LoopCopyBeforeWrapAround: // memcpy(pRing->pBuffer + WrOff, pData, Rem); => Copy 1st chunk
|
||||
LDRB R3,[R1], #+1
|
||||
STRB R3,[R0], #+1 // *pDest++ = *pSrc++
|
||||
SUBS R4,R4,#+1
|
||||
BNE _LoopCopyBeforeWrapAround
|
||||
//
|
||||
// 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
|
||||
//
|
||||
ADDS R4,R2,#+0 // Save <NumBytes> (needed as counter in loop but must be written to <WrOff> after the loop). Also use this inst to update the flags to skip 2nd loop if possible
|
||||
BEQ.N _No2ChunkNeeded // if (NumBytes) {
|
||||
_LoopCopyAfterWrapAround: // memcpy(pRing->pBuffer, pData + Rem, NumBytes);
|
||||
LDRB R3,[R1], #+1 // pData already points to the next src byte due to copy loop increment before this loop
|
||||
STRB R3,[R5], #+1 // *pDest++ = *pSrc++
|
||||
SUBS R2,R2,#+1
|
||||
BNE _LoopCopyAfterWrapAround
|
||||
_No2ChunkNeeded:
|
||||
STR R4,[R6, #+12] // pRing->WrOff = NumBytes; => Must be written after copying data because J-Link may read control block asynchronously while writing into buffer
|
||||
MOVS R0,#+1
|
||||
POP {R4-R7}
|
||||
BX LR // Return 1
|
||||
_CheckCase4:
|
||||
SUBS R0,R0,R7
|
||||
SUBS R0,R0,#+1 // Avail = RdOff - WrOff - 1u;
|
||||
CMP R0,R2
|
||||
BCS.N _Case4 // if (Avail >= NumBytes) { => Case 4) == 1) ? => If not, we have case 5) == 3) (does not fit)
|
||||
_Case3:
|
||||
MOVS R0,#+0
|
||||
POP {R4-R7}
|
||||
BX LR // Return 0
|
||||
_PLACE_LITS
|
||||
|
||||
#endif // defined (RTT_USE_ASM) && (RTT_USE_ASM == 1)
|
||||
_END
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
500
lib/segger_rtt/src/SEGGER_RTT_printf.c
Normal file
500
lib/segger_rtt/src/SEGGER_RTT_printf.c
Normal file
@@ -0,0 +1,500 @@
|
||||
/*********************************************************************
|
||||
* 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_printf.c
|
||||
Purpose : Replacement for printf to write formatted data via RTT
|
||||
Revision: $Rev: 17697 $
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#include "SEGGER_RTT.h"
|
||||
#include "SEGGER_RTT_Conf.h"
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, configurable
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
|
||||
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
|
||||
#define FORMAT_FLAG_PAD_ZERO (1u << 1)
|
||||
#define FORMAT_FLAG_PRINT_SIGN (1u << 2)
|
||||
#define FORMAT_FLAG_ALTERNATE (1u << 3)
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Types
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char* pBuffer;
|
||||
unsigned BufferSize;
|
||||
unsigned Cnt;
|
||||
|
||||
int ReturnValue;
|
||||
|
||||
unsigned RTTBufferIndex;
|
||||
} SEGGER_RTT_PRINTF_DESC;
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Function prototypes
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Static code
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
/*********************************************************************
|
||||
*
|
||||
* _StoreChar
|
||||
*/
|
||||
static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
|
||||
unsigned Cnt;
|
||||
|
||||
Cnt = p->Cnt;
|
||||
if ((Cnt + 1u) <= p->BufferSize) {
|
||||
*(p->pBuffer + Cnt) = c;
|
||||
p->Cnt = Cnt + 1u;
|
||||
p->ReturnValue++;
|
||||
}
|
||||
//
|
||||
// Write part of string, when the buffer is full
|
||||
//
|
||||
if (p->Cnt == p->BufferSize) {
|
||||
if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
|
||||
p->ReturnValue = -1;
|
||||
} else {
|
||||
p->Cnt = 0u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _PrintUnsigned
|
||||
*/
|
||||
static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
|
||||
static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
unsigned Div;
|
||||
unsigned Digit;
|
||||
unsigned Number;
|
||||
unsigned Width;
|
||||
char c;
|
||||
|
||||
Number = v;
|
||||
Digit = 1u;
|
||||
//
|
||||
// Get actual field width
|
||||
//
|
||||
Width = 1u;
|
||||
while (Number >= Base) {
|
||||
Number = (Number / Base);
|
||||
Width++;
|
||||
}
|
||||
if (NumDigits > Width) {
|
||||
Width = NumDigits;
|
||||
}
|
||||
//
|
||||
// Print leading chars if necessary
|
||||
//
|
||||
if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {
|
||||
if (FieldWidth != 0u) {
|
||||
if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {
|
||||
c = '0';
|
||||
} else {
|
||||
c = ' ';
|
||||
}
|
||||
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
|
||||
FieldWidth--;
|
||||
_StoreChar(pBufferDesc, c);
|
||||
if (pBufferDesc->ReturnValue < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pBufferDesc->ReturnValue >= 0) {
|
||||
//
|
||||
// Compute Digit.
|
||||
// Loop until Digit has the value of the highest digit required.
|
||||
// Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
|
||||
//
|
||||
while (1) {
|
||||
if (NumDigits > 1u) { // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned)
|
||||
NumDigits--;
|
||||
} else {
|
||||
Div = v / Digit;
|
||||
if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done
|
||||
break;
|
||||
}
|
||||
}
|
||||
Digit *= Base;
|
||||
}
|
||||
//
|
||||
// Output digits
|
||||
//
|
||||
do {
|
||||
Div = v / Digit;
|
||||
v -= Div * Digit;
|
||||
_StoreChar(pBufferDesc, _aV2C[Div]);
|
||||
if (pBufferDesc->ReturnValue < 0) {
|
||||
break;
|
||||
}
|
||||
Digit /= Base;
|
||||
} while (Digit);
|
||||
//
|
||||
// Print trailing spaces if necessary
|
||||
//
|
||||
if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
|
||||
if (FieldWidth != 0u) {
|
||||
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
|
||||
FieldWidth--;
|
||||
_StoreChar(pBufferDesc, ' ');
|
||||
if (pBufferDesc->ReturnValue < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _PrintInt
|
||||
*/
|
||||
static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
|
||||
unsigned Width;
|
||||
int Number;
|
||||
|
||||
Number = (v < 0) ? -v : v;
|
||||
|
||||
//
|
||||
// Get actual field width
|
||||
//
|
||||
Width = 1u;
|
||||
while (Number >= (int)Base) {
|
||||
Number = (Number / (int)Base);
|
||||
Width++;
|
||||
}
|
||||
if (NumDigits > Width) {
|
||||
Width = NumDigits;
|
||||
}
|
||||
if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
|
||||
FieldWidth--;
|
||||
}
|
||||
|
||||
//
|
||||
// Print leading spaces if necessary
|
||||
//
|
||||
if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {
|
||||
if (FieldWidth != 0u) {
|
||||
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
|
||||
FieldWidth--;
|
||||
_StoreChar(pBufferDesc, ' ');
|
||||
if (pBufferDesc->ReturnValue < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// Print sign if necessary
|
||||
//
|
||||
if (pBufferDesc->ReturnValue >= 0) {
|
||||
if (v < 0) {
|
||||
v = -v;
|
||||
_StoreChar(pBufferDesc, '-');
|
||||
} else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
|
||||
_StoreChar(pBufferDesc, '+');
|
||||
} else {
|
||||
|
||||
}
|
||||
if (pBufferDesc->ReturnValue >= 0) {
|
||||
//
|
||||
// Print leading zeros if necessary
|
||||
//
|
||||
if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {
|
||||
if (FieldWidth != 0u) {
|
||||
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
|
||||
FieldWidth--;
|
||||
_StoreChar(pBufferDesc, '0');
|
||||
if (pBufferDesc->ReturnValue < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pBufferDesc->ReturnValue >= 0) {
|
||||
//
|
||||
// Print number without sign
|
||||
//
|
||||
_PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Public code
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_RTT_vprintf
|
||||
*
|
||||
* Function description
|
||||
* Stores a formatted 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")
|
||||
* sFormat Pointer to format string
|
||||
* pParamList Pointer to the list of arguments for the format string
|
||||
*
|
||||
* Return values
|
||||
* >= 0: Number of bytes which have been stored in the "Up"-buffer.
|
||||
* < 0: Error
|
||||
*/
|
||||
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
|
||||
char c;
|
||||
SEGGER_RTT_PRINTF_DESC BufferDesc;
|
||||
int v;
|
||||
unsigned NumDigits;
|
||||
unsigned FormatFlags;
|
||||
unsigned FieldWidth;
|
||||
char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
|
||||
|
||||
BufferDesc.pBuffer = acBuffer;
|
||||
BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE;
|
||||
BufferDesc.Cnt = 0u;
|
||||
BufferDesc.RTTBufferIndex = BufferIndex;
|
||||
BufferDesc.ReturnValue = 0;
|
||||
|
||||
do {
|
||||
c = *sFormat;
|
||||
sFormat++;
|
||||
if (c == 0u) {
|
||||
break;
|
||||
}
|
||||
if (c == '%') {
|
||||
//
|
||||
// Filter out flags
|
||||
//
|
||||
FormatFlags = 0u;
|
||||
v = 1;
|
||||
do {
|
||||
c = *sFormat;
|
||||
switch (c) {
|
||||
case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
|
||||
case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break;
|
||||
case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break;
|
||||
case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break;
|
||||
default: v = 0; break;
|
||||
}
|
||||
} while (v);
|
||||
//
|
||||
// filter out field with
|
||||
//
|
||||
FieldWidth = 0u;
|
||||
do {
|
||||
c = *sFormat;
|
||||
if ((c < '0') || (c > '9')) {
|
||||
break;
|
||||
}
|
||||
sFormat++;
|
||||
FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
|
||||
} while (1);
|
||||
|
||||
//
|
||||
// Filter out precision (number of digits to display)
|
||||
//
|
||||
NumDigits = 0u;
|
||||
c = *sFormat;
|
||||
if (c == '.') {
|
||||
sFormat++;
|
||||
do {
|
||||
c = *sFormat;
|
||||
if ((c < '0') || (c > '9')) {
|
||||
break;
|
||||
}
|
||||
sFormat++;
|
||||
NumDigits = NumDigits * 10u + ((unsigned)c - '0');
|
||||
} while (1);
|
||||
}
|
||||
//
|
||||
// Filter out length modifier
|
||||
//
|
||||
c = *sFormat;
|
||||
do {
|
||||
if ((c == 'l') || (c == 'h')) {
|
||||
sFormat++;
|
||||
c = *sFormat;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
//
|
||||
// Handle specifiers
|
||||
//
|
||||
switch (c) {
|
||||
case 'c': {
|
||||
char c0;
|
||||
v = va_arg(*pParamList, int);
|
||||
c0 = (char)v;
|
||||
_StoreChar(&BufferDesc, c0);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
v = va_arg(*pParamList, int);
|
||||
_PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
|
||||
break;
|
||||
case 'u':
|
||||
v = va_arg(*pParamList, int);
|
||||
_PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
v = va_arg(*pParamList, int);
|
||||
_PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
|
||||
break;
|
||||
case 's':
|
||||
{
|
||||
const char * s = va_arg(*pParamList, const char *);
|
||||
do {
|
||||
c = *s;
|
||||
s++;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
_StoreChar(&BufferDesc, c);
|
||||
} while (BufferDesc.ReturnValue >= 0);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
v = va_arg(*pParamList, int);
|
||||
_PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
|
||||
break;
|
||||
case '%':
|
||||
_StoreChar(&BufferDesc, '%');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sFormat++;
|
||||
} else {
|
||||
_StoreChar(&BufferDesc, c);
|
||||
}
|
||||
} while (BufferDesc.ReturnValue >= 0);
|
||||
|
||||
if (BufferDesc.ReturnValue > 0) {
|
||||
//
|
||||
// Write remaining data, if any
|
||||
//
|
||||
if (BufferDesc.Cnt != 0u) {
|
||||
SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
|
||||
}
|
||||
BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
|
||||
}
|
||||
return BufferDesc.ReturnValue;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_RTT_printf
|
||||
*
|
||||
* Function description
|
||||
* Stores a formatted 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")
|
||||
* sFormat Pointer to format string, followed by the arguments for conversion
|
||||
*
|
||||
* Return values
|
||||
* >= 0: Number of bytes which have been stored in the "Up"-buffer.
|
||||
* < 0: Error
|
||||
*
|
||||
* Notes
|
||||
* (1) Conversion specifications have following syntax:
|
||||
* %[flags][FieldWidth][.Precision]ConversionSpecifier
|
||||
* (2) Supported flags:
|
||||
* -: Left justify within the field width
|
||||
* +: Always print sign extension for signed conversions
|
||||
* 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
|
||||
* Supported conversion specifiers:
|
||||
* c: Print the argument as one char
|
||||
* d: Print the argument as a signed integer
|
||||
* u: Print the argument as an unsigned integer
|
||||
* x: Print the argument as an hexadecimal integer
|
||||
* s: Print the string pointed to by the argument
|
||||
* p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
|
||||
*/
|
||||
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
|
||||
int r;
|
||||
va_list ParamList;
|
||||
|
||||
va_start(ParamList, sFormat);
|
||||
r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
|
||||
va_end(ParamList);
|
||||
return r;
|
||||
}
|
||||
/*************************** End of file ****************************/
|
||||
Reference in New Issue
Block a user