rusEFI
The most advanced open source ECU
datalogging.cpp
Go to the documentation of this file.
1 /**
2  * @file datalogging.cpp
3  * @brief Buffered console output stream code
4  *
5  * Here we have a memory buffer and methods related to
6  * printing messages into this buffer. The purpose of the
7  * buffer is to allow fast, non-blocking, thread-safe logging.
8  *
9  * The idea is that each interrupt handler would have it's own logging buffer. You can add
10  * stuff into this buffer without any locking since it's you own buffer, and once you get
11  * the whole message you invoke the scheduleLogging() method which appends your local content
12  * into the global logging buffer, from which it is later dispatched to the console by our
13  * main console thread.
14  *
15  * @date Feb 25, 2013
16  * @author Andrey Belomutskiy, (c) 2012-2020
17  *
18  * This file is part of rusEfi - see http://rusefi.com
19  *
20  * rusEfi is free software; you can redistribute it and/or modify it under the terms of
21  * the GNU General Public License as published by the Free Software Foundation; either
22  * version 3 of the License, or (at your option) any later version.
23  *
24  * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
25  * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License along with this program.
29  * If not, see <http://www.gnu.org/licenses/>.
30  *
31  */
32 
33 #include "pch.h"
34 
35 #if ! EFI_UNIT_TEST
36 
37 #include "chmtx.h"
38 #include "memstreams.h"
39 #include "console_io.h"
40 #endif // EFI_UNIT_TEST
41 
42 /**
43  * @returns true if data does not fit into this buffer
44  */
45 bool Logging::validateBuffer(uint32_t extraLen) {
46  if (remainingSize() < extraLen + 1) {
47 #if EFI_PROD_CODE
48  warning(ObdCode::CUSTOM_LOGGING_BUFFER_OVERFLOW, "output overflow %s %d", name, extraLen);
49 #endif /* EFI_PROD_CODE */
50  return true;
51  }
52 
53  return false;
54 }
55 
56 void Logging::append(const char *text) {
57  efiAssertVoid(ObdCode::CUSTOM_APPEND_NULL, text != NULL, "append NULL");
58  uint32_t extraLen = efiStrlen(text);
59  bool isCapacityProblem = validateBuffer(extraLen);
60  if (isCapacityProblem) {
61  return;
62  }
63  strcpy(linePointer, text);
64  /**
65  * And now we are pointing at the zero char at the end of the buffer again
66  */
67  linePointer += extraLen;
68 }
69 
70 /**
71  * @note This method if fast because it does not validate much, be sure what you are doing
72  */
73 void Logging::appendFast(const char *text) {
74  char *s = linePointer;
75  while ((*s++ = *text++) != 0)
76  ;
77  linePointer = s - 1;
78 }
79 
80 void Logging::appendPrintf(const char *fmt, ...) {
81  efiAssertVoid(ObdCode::CUSTOM_APPEND_STACK, hasLotsOfRemainingStack(), "lowstck#4");
82 
83  size_t available = remainingSize();
84 
85  va_list ap;
86  va_start(ap, fmt);
87  size_t written = chvsnprintf(linePointer, available, fmt, ap);
88  va_end(ap);
89 
90  // chvnsprintf returns how many bytes WOULD HAVE been written if it fit,
91  // so clip it to the available space if necessary
92  linePointer += (written > available) ? available : written;
93  // ensure buffer is always null terminated
94  buffer[bufferSize - 1] = '\0';
95 }
96 
97 void Logging::appendFloat(float value, int precision) {
98  /**
99  * todo: #1 this implementation is less than perfect
100  * todo: #2 The only way to avoid double promotion would probably be using *float instead of float
101  * See also http://stackoverflow.com/questions/5522051/printing-a-float-in-c-while-avoiding-variadic-parameter-promotion-to-double
102  */
103  switch (precision) {
104  case 1:
105  appendPrintf("%.1f", value);
106  break;
107  case 2:
108  appendPrintf("%.2f", value);
109  break;
110  case 3:
111  appendPrintf("%.3f", value);
112  break;
113  case 4:
114  appendPrintf("%.4f", value);
115  break;
116  case 5:
117  appendPrintf("%.5f", value);
118  break;
119  case 6:
120  appendPrintf("%.6f", value);
121  break;
122 
123  default:
124  appendPrintf("%.2f", value);
125  }
126 }
127 
130  *linePointer = 0;
131 }
132 
133 Logging::Logging(char const *p_name, char *p_buffer, int p_bufferSize)
134  : name(p_name)
135  , buffer(p_buffer)
136  , bufferSize(p_bufferSize)
137 {
138  reset();
139 }
140 
141 LoggingWithStorage::LoggingWithStorage(const char *p_name) : Logging(p_name, DEFAULT_BUFFER, sizeof(DEFAULT_BUFFER)) {
142 }
void appendFast(const char *text)
Definition: datalogging.cpp:73
const char *const name
Definition: datalogging.h:52
void appendFloat(float value, int precision)
Definition: datalogging.cpp:97
size_t remainingSize() const
Definition: datalogging.h:45
void appendPrintf(const char *fmt,...)
Definition: datalogging.cpp:80
void reset()
char * linePointer
Definition: datalogging.h:66
char *const buffer
Definition: datalogging.h:59
Logging()=delete
const int bufferSize
Definition: datalogging.h:60
LoggingWithStorage(const char *name)
bool warning(ObdCode code, const char *fmt,...)
@ CUSTOM_LOGGING_BUFFER_OVERFLOW
@ CUSTOM_APPEND_STACK
@ CUSTOM_APPEND_NULL
static BigBufferHandle buffer