123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- /*********************************************************************
- * SEGGER Microcontroller GmbH & Co. KG *
- * The Embedded Experts *
- **********************************************************************
- * *
- * (c) 2014 - 2017 SEGGER Microcontroller GmbH & Co. KG *
- * *
- * 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 *
- * conditions are met: *
- * *
- * o Redistributions of source code must retain the above copyright *
- * notice, this list of conditions and the following disclaimer. *
- * *
- * o Redistributions in binary form must reproduce the above *
- * copyright notice, this list of conditions and the following *
- * disclaimer in the documentation and/or other materials provided *
- * with the distribution. *
- * *
- * o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
- * nor the names of its contributors may be used to endorse or *
- * promote products derived from this software without specific *
- * prior written permission. *
- * *
- * 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: 6.18a *
- * *
- **********************************************************************
- ---------------------------END-OF-HEADER------------------------------
- File : SEGGER_RTT_printf.c
- Purpose : Replacement for printf to write formatted data via RTT
- Revision: $Rev: 4351 $
- ----------------------------------------------------------------------
- */
- #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
- *
- **********************************************************************
- */
- int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
- /*********************************************************************
- *
- * 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 ****************************/
|