-/*********************************************************************\r
-* SEGGER MICROCONTROLLER GmbH & Co. KG *\r
-* Solutions for real time microcontroller applications *\r
-**********************************************************************\r
-* *\r
-* (c) 2014 - 2016 SEGGER Microcontroller GmbH & Co. KG *\r
-* *\r
-* www.segger.com Support: support@segger.com *\r
-* *\r
-**********************************************************************\r
-* *\r
-* SEGGER RTT * Real Time Transfer for embedded targets *\r
-* *\r
-**********************************************************************\r
-* *\r
-* All rights reserved. *\r
-* *\r
-* * This software may in its unmodified form be freely redistributed *\r
-* in source, linkable, or executable form. *\r
-* * The source code may be modified, provided the source code *\r
-* retains the above copyright notice, this list of conditions and *\r
-* the following disclaimer. *\r
-* * Modified versions of this software in source, executable, or *\r
-* linkable form may not be distributed without prior consent of *\r
-* SEGGER. *\r
-* * This software may only be used for communication with SEGGER *\r
-* J-Link debug probes. *\r
-* *\r
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *\r
-* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *\r
-* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *\r
-* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *\r
-* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\r
-* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *\r
-* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *\r
-* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *\r
-* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *\r
-* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *\r
-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *\r
-* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *\r
-* DAMAGE. *\r
-* *\r
-**********************************************************************\r
-* *\r
-* RTT version: 6.00e *\r
-* *\r
-**********************************************************************\r
----------------------------END-OF-HEADER------------------------------\r
-File : SEGGER_RTT_printf.c\r
-Purpose : Replacement for printf to write formatted data via RTT\r
-Revision: $Rev: 3667 $\r
-----------------------------------------------------------------------\r
-*/\r
-#include "SEGGER_RTT.h"\r
-#include "SEGGER_RTT_Conf.h"\r
-\r
-/*********************************************************************\r
-*\r
-* Defines, configurable\r
-*\r
-**********************************************************************\r
-*/\r
-\r
-#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE\r
- #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)\r
-#endif\r
-\r
-#include <stdlib.h>\r
-#include <stdarg.h>\r
-\r
-\r
-#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)\r
-#define FORMAT_FLAG_PAD_ZERO (1u << 1)\r
-#define FORMAT_FLAG_PRINT_SIGN (1u << 2)\r
-#define FORMAT_FLAG_ALTERNATE (1u << 3)\r
-\r
-/*********************************************************************\r
-*\r
-* Types\r
-*\r
-**********************************************************************\r
-*/\r
-\r
-typedef struct {\r
- char* pBuffer;\r
- unsigned BufferSize;\r
- unsigned Cnt;\r
-\r
- int ReturnValue;\r
-\r
- unsigned RTTBufferIndex;\r
-} SEGGER_RTT_PRINTF_DESC;\r
-\r
-/*********************************************************************\r
-*\r
-* Function prototypes\r
-*\r
-**********************************************************************\r
-*/\r
-int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);\r
-\r
-/*********************************************************************\r
-*\r
-* Static code\r
-*\r
-**********************************************************************\r
-*/\r
-/*********************************************************************\r
-*\r
-* _StoreChar\r
-*/\r
-static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {\r
- unsigned Cnt;\r
-\r
- Cnt = p->Cnt;\r
- if ((Cnt + 1u) <= p->BufferSize) {\r
- *(p->pBuffer + Cnt) = c;\r
- p->Cnt = Cnt + 1u;\r
- p->ReturnValue++;\r
- }\r
- //\r
- // Write part of string, when the buffer is full\r
- //\r
- if (p->Cnt == p->BufferSize) {\r
- if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {\r
- p->ReturnValue = -1;\r
- } else {\r
- p->Cnt = 0u;\r
- }\r
- }\r
-}\r
-\r
-/*********************************************************************\r
-*\r
-* _PrintUnsigned\r
-*/\r
-static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {\r
- static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\r
- unsigned Div;\r
- unsigned Digit;\r
- unsigned Number;\r
- unsigned Width;\r
- char c;\r
-\r
- Number = v;\r
- Digit = 1u;\r
- //\r
- // Get actual field width\r
- //\r
- Width = 1u;\r
- while (Number >= Base) {\r
- Number = (Number / Base);\r
- Width++;\r
- }\r
- if (NumDigits > Width) {\r
- Width = NumDigits;\r
- }\r
- //\r
- // Print leading chars if necessary\r
- //\r
- if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {\r
- if (FieldWidth != 0u) {\r
- if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {\r
- c = '0';\r
- } else {\r
- c = ' ';\r
- }\r
- while ((FieldWidth != 0u) && (Width < FieldWidth)) {\r
- FieldWidth--;\r
- _StoreChar(pBufferDesc, c);\r
- if (pBufferDesc->ReturnValue < 0) {\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- if (pBufferDesc->ReturnValue >= 0) {\r
- //\r
- // Compute Digit.\r
- // Loop until Digit has the value of the highest digit required.\r
- // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.\r
- //\r
- while (1) {\r
- 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)\r
- NumDigits--;\r
- } else {\r
- Div = v / Digit;\r
- if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done\r
- break;\r
- }\r
- }\r
- Digit *= Base;\r
- }\r
- //\r
- // Output digits\r
- //\r
- do {\r
- Div = v / Digit;\r
- v -= Div * Digit;\r
- _StoreChar(pBufferDesc, _aV2C[Div]);\r
- if (pBufferDesc->ReturnValue < 0) {\r
- break;\r
- }\r
- Digit /= Base;\r
- } while (Digit);\r
- //\r
- // Print trailing spaces if necessary\r
- //\r
- if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {\r
- if (FieldWidth != 0u) {\r
- while ((FieldWidth != 0u) && (Width < FieldWidth)) {\r
- FieldWidth--;\r
- _StoreChar(pBufferDesc, ' ');\r
- if (pBufferDesc->ReturnValue < 0) {\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-/*********************************************************************\r
-*\r
-* _PrintInt\r
-*/\r
-static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {\r
- unsigned Width;\r
- int Number;\r
-\r
- Number = (v < 0) ? -v : v;\r
-\r
- //\r
- // Get actual field width\r
- //\r
- Width = 1u;\r
- while (Number >= (int)Base) {\r
- Number = (Number / (int)Base);\r
- Width++;\r
- }\r
- if (NumDigits > Width) {\r
- Width = NumDigits;\r
- }\r
- if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {\r
- FieldWidth--;\r
- }\r
-\r
- //\r
- // Print leading spaces if necessary\r
- //\r
- if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {\r
- if (FieldWidth != 0u) {\r
- while ((FieldWidth != 0u) && (Width < FieldWidth)) {\r
- FieldWidth--;\r
- _StoreChar(pBufferDesc, ' ');\r
- if (pBufferDesc->ReturnValue < 0) {\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- //\r
- // Print sign if necessary\r
- //\r
- if (pBufferDesc->ReturnValue >= 0) {\r
- if (v < 0) {\r
- v = -v;\r
- _StoreChar(pBufferDesc, '-');\r
- } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {\r
- _StoreChar(pBufferDesc, '+');\r
- } else {\r
-\r
- }\r
- if (pBufferDesc->ReturnValue >= 0) {\r
- //\r
- // Print leading zeros if necessary\r
- //\r
- if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {\r
- if (FieldWidth != 0u) {\r
- while ((FieldWidth != 0u) && (Width < FieldWidth)) {\r
- FieldWidth--;\r
- _StoreChar(pBufferDesc, '0');\r
- if (pBufferDesc->ReturnValue < 0) {\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- if (pBufferDesc->ReturnValue >= 0) {\r
- //\r
- // Print number without sign\r
- //\r
- _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);\r
- }\r
- }\r
- }\r
-}\r
-\r
-/*********************************************************************\r
-*\r
-* Public code\r
-*\r
-**********************************************************************\r
-*/\r
-/*********************************************************************\r
-*\r
-* SEGGER_RTT_vprintf\r
-*\r
-* Function description\r
-* Stores a formatted string in SEGGER RTT control block.\r
-* This data is read by the host.\r
-*\r
-* Parameters\r
-* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")\r
-* sFormat Pointer to format string\r
-* pParamList Pointer to the list of arguments for the format string\r
-*\r
-* Return values\r
-* >= 0: Number of bytes which have been stored in the "Up"-buffer.\r
-* < 0: Error\r
-*/\r
-int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {\r
- char c;\r
- SEGGER_RTT_PRINTF_DESC BufferDesc;\r
- int v;\r
- unsigned NumDigits;\r
- unsigned FormatFlags;\r
- unsigned FieldWidth;\r
- char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];\r
-\r
- BufferDesc.pBuffer = acBuffer;\r
- BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE;\r
- BufferDesc.Cnt = 0u;\r
- BufferDesc.RTTBufferIndex = BufferIndex;\r
- BufferDesc.ReturnValue = 0;\r
-\r
- do {\r
- c = *sFormat;\r
- sFormat++;\r
- if (c == 0u) {\r
- break;\r
- }\r
- if (c == '%') {\r
- //\r
- // Filter out flags\r
- //\r
- FormatFlags = 0u;\r
- v = 1;\r
- do {\r
- c = *sFormat;\r
- switch (c) {\r
- case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;\r
- case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break;\r
- case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break;\r
- case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break;\r
- default: v = 0; break;\r
- }\r
- } while (v);\r
- //\r
- // filter out field with\r
- //\r
- FieldWidth = 0u;\r
- do {\r
- c = *sFormat;\r
- if ((c < '0') || (c > '9')) {\r
- break;\r
- }\r
- sFormat++;\r
- FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');\r
- } while (1);\r
-\r
- //\r
- // Filter out precision (number of digits to display)\r
- //\r
- NumDigits = 0u;\r
- c = *sFormat;\r
- if (c == '.') {\r
- sFormat++;\r
- do {\r
- c = *sFormat;\r
- if ((c < '0') || (c > '9')) {\r
- break;\r
- }\r
- sFormat++;\r
- NumDigits = NumDigits * 10u + ((unsigned)c - '0');\r
- } while (1);\r
- }\r
- //\r
- // Filter out length modifier\r
- //\r
- c = *sFormat;\r
- do {\r
- if ((c == 'l') || (c == 'h')) {\r
- sFormat++;\r
- c = *sFormat;\r
- } else {\r
- break;\r
- }\r
- } while (1);\r
- //\r
- // Handle specifiers\r
- //\r
- switch (c) {\r
- case 'c': {\r
- char c0;\r
- v = va_arg(*pParamList, int);\r
- c0 = (char)v;\r
- _StoreChar(&BufferDesc, c0);\r
- break;\r
- }\r
- case 'd':\r
- v = va_arg(*pParamList, int);\r
- _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);\r
- break;\r
- case 'u':\r
- v = va_arg(*pParamList, int);\r
- _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);\r
- break;\r
- case 'x':\r
- case 'X':\r
- v = va_arg(*pParamList, int);\r
- _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);\r
- break;\r
- case 's':\r
- {\r
- const char * s = va_arg(*pParamList, const char *);\r
- do {\r
- c = *s;\r
- s++;\r
- if (c == '\0') {\r
- break;\r
- }\r
- _StoreChar(&BufferDesc, c);\r
- } while (BufferDesc.ReturnValue >= 0);\r
- }\r
- break;\r
- case 'p':\r
- v = va_arg(*pParamList, int);\r
- _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);\r
- break;\r
- case '%':\r
- _StoreChar(&BufferDesc, '%');\r
- break;\r
- default:\r
- break;\r
- }\r
- sFormat++;\r
- } else {\r
- _StoreChar(&BufferDesc, c);\r
- }\r
- } while (BufferDesc.ReturnValue >= 0);\r
-\r
- if (BufferDesc.ReturnValue > 0) {\r
- //\r
- // Write remaining data, if any\r
- //\r
- if (BufferDesc.Cnt != 0u) {\r
- SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);\r
- }\r
- BufferDesc.ReturnValue += (int)BufferDesc.Cnt;\r
- }\r
- return BufferDesc.ReturnValue;\r
-}\r
-\r
-/*********************************************************************\r
-*\r
-* SEGGER_RTT_printf\r
-*\r
-* Function description\r
-* Stores a formatted string in SEGGER RTT control block.\r
-* This data is read by the host.\r
-*\r
-* Parameters\r
-* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")\r
-* sFormat Pointer to format string, followed by the arguments for conversion\r
-*\r
-* Return values\r
-* >= 0: Number of bytes which have been stored in the "Up"-buffer.\r
-* < 0: Error\r
-*\r
-* Notes\r
-* (1) Conversion specifications have following syntax:\r
-* %[flags][FieldWidth][.Precision]ConversionSpecifier\r
-* (2) Supported flags:\r
-* -: Left justify within the field width\r
-* +: Always print sign extension for signed conversions\r
-* 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision\r
-* Supported conversion specifiers:\r
-* c: Print the argument as one char\r
-* d: Print the argument as a signed integer\r
-* u: Print the argument as an unsigned integer\r
-* x: Print the argument as an hexadecimal integer\r
-* s: Print the string pointed to by the argument\r
-* p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)\r
-*/\r
-int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {\r
- int r;\r
- va_list ParamList;\r
-\r
- va_start(ParamList, sFormat);\r
- r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);\r
- va_end(ParamList);\r
- return r;\r
-}\r
-/*************************** End of file ****************************/\r