RF24Log  0.1.3
Unified logging library
AbstractStream.cpp
Go to the documentation of this file.
1 
15 #include "../RF24LogLevel.h"
16 #include "LevelDescriptions.h"
17 #include "../RF24LogBaseHandler.h"
18 #include "AbstractStream.h"
19 
20 /****************************************************************************/
21 
23 {
24  if (!logLevel) { return; } // skip level description for level 0
25  #if !defined(RF24LOG_NO_TIMESTAMP)
27  #endif
28  appendLogLevel(logLevel);
29 }
30 
31 /****************************************************************************/
32 
34 {
35  uint8_t subLevel = logLevel & 0x07;
36  if (logLevel >= RF24LogLevel::ERROR && logLevel <= RF24LogLevel::DEBUG + 7)
37  {
38  uint8_t logIndex = ((logLevel & 0x38) >> 3) - 1;
39  appendStr(RF24LogDescLevels[logIndex]);
40 
41  if(subLevel == 0)
42  {
43  #if !defined(RF24LOG_TERSE_DESC) && !defined(RF24LOG_SHORT_DESC)
44  appendChar(' ', 2);
45  #else
46  appendChar(' ');
47  #endif
48  }
49  else
50  {
51  #if !defined(RF24LOG_TERSE_DESC) && !defined(RF24LOG_SHORT_DESC)
52  appendChar('+');
53  #endif
54  appendUInt(subLevel, 8);
55  }
56  }
57  else {
59  appendChar(' ', logLevel < 010 ? 2 : (logLevel < 0100));
60  appendUInt(logLevel, 8);
61  }
63 }
64 
65 /****************************************************************************/
66 
67 void RF24LogAbstractStream::appendFormat(FormatSpecifier* fmt_parser, va_list *args)
68 {
69  if (fmt_parser->specifier == 's')
70  {
71  // print text from RAM
72  #ifdef Arduino
73  // warning: ISO C++17 does not allow 'register' storage class specifier [-Wregister]
74  register char *str_p = (char *)va_arg(*args, int);
75  #else
76  const char *str_p = va_arg(*args, char *);
77  #endif
78  appendStr(str_p);
79  }
80 
81 #ifdef ARDUINO_ARCH_AVR
82  else if (fmt_parser->specifier == 'S')
83  {
84  // print text from FLASH
85  register __FlashStringHelper *s = (__FlashStringHelper *)va_arg(*args, int);
86  appendStr(s);
87  }
88 #endif
89 
90  else if (fmt_parser->specifier == 'c')
91  {
92  // print a char
93  if (fmt_parser->width)
94  {
95  appendChar(fmt_parser->fill, fmt_parser->width - 1);
96  }
97  appendChar((char)va_arg(*args, int));
98  }
99 
100  else if (fmt_parser->specifier == 'D' || fmt_parser->specifier == 'F' || fmt_parser->specifier == 'f')
101  {
102  // print as double
103  double temp = va_arg(*args, double);
104 
105  // printf() traditionally reserves a precision of 0 to avoid printing a value of 0
106  // so, if precision is 0 and value is 0.0, then don't print and just consume arg
107  if (fmt_parser->precis == 0 && temp == 0.0) { return; }
108 
109  if (fmt_parser->precis >= 0)
110  {
111  appendDouble(temp, fmt_parser->precis);
112  }
113  else
114  {
115  appendDouble(temp);
116  }
117  }
118 
119  else
120  {
121  // print as integer
122  uint8_t base = 3; // use 3 as a invalid sentinel
123  if (fmt_parser->specifier == 'd' || fmt_parser->specifier == 'i') { base = 10; }
124  else if (fmt_parser->specifier == 'x' || fmt_parser->specifier == 'X') { base = 16; }
125  else if (fmt_parser->specifier == 'o') { base = 8; }
126  else if (fmt_parser->specifier == 'b') { base = 2; }
127  if (base != 3) // if it was a supported char
128  {
129  int temp = va_arg(*args, int);
130  if (fmt_parser->width)
131  {
132  uint16_t w = numbCharsToPrint(temp, base);
133  appendChar(fmt_parser->fill, (fmt_parser->width > w ? fmt_parser->width - w : 0));
134  }
135  if (fmt_parser->length & 0x80) // if explicitly unsigned
136  {
137  if (fmt_parser->length == 16) { appendUInt((unsigned short)temp, base); }
138  else if (fmt_parser->length == 8) { appendUInt((unsigned char)temp, base); }
139  // *most* arduino platforms may not support 64-bit-length integers
140  else /* assumes a 32 bit length */ { appendUInt((unsigned long)temp, base); }
141  }
142  else
143  {
144  if (fmt_parser->length == 16) { appendInt((short)temp); }
145  else if (fmt_parser->length == 8) { appendInt((char)temp); }
146  // *most* arduino platforms may not support 64-bit-length integers
147  else /* assumes a 32 bit length */ { appendInt((long)temp); }
148  }
149  }
150  else
151  {
152  appendChar(fmt_parser->specifier);
153  }
154  }
155 }
abstract class that allows using different output stream APIs
uint16_t numbCharsToPrint(int64_t numb, uint8_t base)
how wide (in characters) does it take to display a number
Definition: Common.cpp:18
A collection of constants used to describe a particular logging level.
#define RF24LOG_DELIMITER
Change The Delimiter character used in the header prefix of log messages.
virtual void appendUInt(unsigned long data, uint8_t base=10)=0
append an ‘unsigned’ (only +) number
virtual void appendInt(long data)=0
append a signed (+/-) number
virtual void appendStr(const char *data)=0
append a c-string
void appendLogLevel(uint8_t logLevel)
output a description of the log level
virtual void appendChar(char data, uint16_t depth=1)=0
append a character a number of times
void appendFormat(FormatSpecifier *fmt_parser, va_list *args)
output a data according to the format specifier
virtual void appendTimestamp()=0
output a timestamp
void descTimeLevel(uint8_t logLevel)
Automate the output of the header' timestamp and level description.
virtual void appendDouble(double data, uint8_t precision=2)=0
append a floating point number
@ DEBUG
Definition: RF24LogLevel.h:49
@ ERROR
Definition: RF24LogLevel.h:43
const char RF24LogDescLevel[]
description of the DEBUG base level
const char *const RF24LogDescLevels[]
collection of the base level descriptions
Some data about a format specifier.
uint8_t length
bit-length of the data (only applies to integer numbers)
uint16_t width
The width of the padding.
char specifier
datatype specifier
int8_t precis
The number of decimal places. If negative, then default of 2 places is used.
char fill
The default character used as padding.