rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
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 */
45bool 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
56void Logging::append(const char *text) {
57 efiAssertVoid(ObdCode::CUSTOM_APPEND_NULL, text != NULL, "append NULL");
58 size_t extraLen = std::strlen(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 */
73void Logging::appendFast(const char *text) {
74 char *s = linePointer;
75 while ((*s++ = *text++) != 0)
76 ;
77 linePointer = s - 1;
78}
79
80void 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
97void 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
133Logging::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
141LoggingWithStorage::LoggingWithStorage(const char *p_name) : Logging(p_name, DEFAULT_BUFFER, sizeof(DEFAULT_BUFFER)) {
142}
void appendFast(const char *text)
const char *const name
Definition datalogging.h:56
void void appendFloat(float value, int precision)
size_t remainingSize() const
Definition datalogging.h:49
void reset()
char * linePointer
Definition datalogging.h:70
char *const buffer
Definition datalogging.h:63
Logging()=delete
void appendPrintf(const char *fmt,...) __attribute__((format(printf
const int bufferSize
Definition datalogging.h:64
LoggingWithStorage(const char *name)
bool warning(ObdCode code, const char *fmt,...)
@ CUSTOM_LOGGING_BUFFER_OVERFLOW
@ CUSTOM_APPEND_STACK
@ CUSTOM_APPEND_NULL
static BigBufferHandle buffer