#include "SEGGER_RTT.h"
#include "SEGGER_RTT_Conf.h"
#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)
typedef struct {
char* pBuffer;
unsigned BufferSize;
unsigned Cnt;
int ReturnValue;
unsigned RTTBufferIndex;
} SEGGER_RTT_PRINTF_DESC;
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++;
}
if (p->Cnt == p->BufferSize) {
if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
p->ReturnValue = -1;
} else {
p->Cnt = 0u;
}
}
}
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;
Width = 1u;
while (Number >= Base) {
Number = (Number / Base);
Width++;
}
if (NumDigits > Width) {
Width = NumDigits;
}
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) {
while (1) {
if (NumDigits > 1u) { NumDigits--;
} else {
Div = v / Digit;
if (Div < Base) { break;
}
}
Digit *= Base;
}
do {
Div = v / Digit;
v -= Div * Digit;
_StoreChar(pBufferDesc, _aV2C[Div]);
if (pBufferDesc->ReturnValue < 0) {
break;
}
Digit /= Base;
} while (Digit);
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;
}
}
}
}
}
}
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;
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--;
}
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;
}
}
}
}
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) {
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) {
_PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
}
}
}
}
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
char c;
SEGGER_RTT_PRINTF_DESC BufferDesc;
int v;
unsigned char PrecisionSet;
unsigned Precision;
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 == '%') {
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);
FieldWidth = 0u;
do {
c = *sFormat;
if ((c < '0') || (c > '9')) {
break;
}
sFormat++;
FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
} while (1);
PrecisionSet = 0;
Precision = 0u;
c = *sFormat;
if (c == '.') {
sFormat++;
if (*sFormat == '*') {
sFormat++;
PrecisionSet = 1;
Precision = va_arg(*pParamList, int);
} else {
do {
c = *sFormat;
if ((c < '0') || (c > '9')) {
break;
}
PrecisionSet = 1;
sFormat++;
Precision = Precision * 10u + ((unsigned)c - '0');
} while (1);
}
}
c = *sFormat;
do {
if ((c == 'l') || (c == 'h')) {
sFormat++;
c = *sFormat;
} else {
break;
}
} while (1);
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, Precision, FieldWidth, FormatFlags);
break;
case 'u':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 10u, Precision, FieldWidth, FormatFlags);
break;
case 'x':
case 'X':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 16u, Precision, FieldWidth, FormatFlags);
break;
case 's':
{
const char * s = va_arg(*pParamList, const char *);
if (s == NULL) {
s = "(NULL)"; PrecisionSet = 0; }
do {
c = *s;
s++;
if (c == '\0') {
break;
}
if ((PrecisionSet != 0) && (Precision == 0)) {
break;
}
_StoreChar(&BufferDesc, c);
Precision--;
} 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) {
if (BufferDesc.Cnt != 0u) {
SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
}
BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
}
return BufferDesc.ReturnValue;
}
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;
}