501 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			501 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*********************************************************************
							 | 
						||
| 
								 | 
							
								*                    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 ****************************/
							 |