rusefi-1/firmware/util/datalogging.cpp

196 lines
5.6 KiB
C++
Raw Normal View History

2015-07-10 06:01:56 -07:00
/**
* @file datalogging.cpp
* @brief Buffered console output stream code
*
2018-08-31 18:27:41 -07:00
* Here we have a memory buffer and methods related to
2015-07-10 06:01:56 -07:00
* printing messages into this buffer. The purpose of the
* buffer is to allow fast, non-blocking, thread-safe logging.
*
* The idea is that each interrupt handler would have it's own logging buffer. You can add
* stuff into this buffer without any locking since it's you own buffer, and once you get
* the whole message you invoke the scheduleLogging() method which appends your local content
* into the global logging buffer, from which it is later dispatched to the console by our
* main console thread.
*
* @date Feb 25, 2013
2020-01-13 18:57:43 -08:00
* @author Andrey Belomutskiy, (c) 2012-2020
2015-07-10 06:01:56 -07:00
*
* This file is part of rusEfi - see http://rusefi.com
*
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "globalaccess.h"
2015-07-10 06:01:56 -07:00
2019-04-12 19:10:57 -07:00
#if ! EFI_UNIT_TEST
#include "os_access.h"
2015-07-10 06:01:56 -07:00
#include "chmtx.h"
#include "memstreams.h"
#include "console_io.h"
2019-07-06 17:15:49 -07:00
#include "os_util.h"
#endif // EFI_UNIT_TEST
2015-07-10 06:01:56 -07:00
static uint8_t intermediateLoggingBufferData[INTERMEDIATE_LOGGING_BUFFER_SIZE] CCM_OPTIONAL;
class IntermediateLogging {
public:
/**
* Class constructors are a great way to have simple initialization sequence
*/
IntermediateLogging() {
#if ! EFI_UNIT_TEST
msObjectInit(&intermediateLoggingBuffer, intermediateLoggingBufferData, INTERMEDIATE_LOGGING_BUFFER_SIZE, 0);
#endif // EFI_UNIT_TEST
}
#if ! EFI_UNIT_TEST
MemoryStream intermediateLoggingBuffer;
#endif // EFI_UNIT_TEST
// todo: look into chsnprintf once on Chibios 3
void vappendPrintfI(Logging *logging, const char *fmt, va_list arg) {
#if ! EFI_UNIT_TEST
intermediateLoggingBuffer.eos = 0; // reset
efiAssertVoid(CUSTOM_ERR_6603, getCurrentRemainingStack() > 128, "lowstck#1b");
chvprintf((BaseSequentialStream *) &intermediateLoggingBuffer, fmt, arg);
intermediateLoggingBuffer.buffer[intermediateLoggingBuffer.eos] = 0; // need to terminate explicitly
logging->append((char *)intermediateLoggingBuffer.buffer);
#endif // EFI_UNIT_TEST
}
};
static IntermediateLogging intermediateLogging;
2015-07-10 06:01:56 -07:00
/**
* @returns true if data does not fit into this buffer
*/
bool Logging::validateBuffer(const char *text, uint32_t extraLen) {
if (remainingSize() < extraLen + 1) {
2015-07-10 06:01:56 -07:00
#if EFI_PROD_CODE
warning(CUSTOM_LOGGING_BUFFER_OVERFLOW, "output overflow %s %d", name, extraLen);
2017-06-03 18:09:04 -07:00
#endif /* EFI_PROD_CODE */
2015-07-10 06:01:56 -07:00
return true;
}
2015-07-10 06:01:56 -07:00
return false;
}
void Logging::append(const char *text) {
2018-09-10 19:10:55 -07:00
efiAssertVoid(CUSTOM_APPEND_NULL, text != NULL, "append NULL");
2015-07-10 06:01:56 -07:00
uint32_t extraLen = efiStrlen(text);
bool isCapacityProblem = validateBuffer(text, extraLen);
2017-06-03 18:09:04 -07:00
if (isCapacityProblem) {
2015-07-10 06:01:56 -07:00
return;
}
strcpy(linePointer, text);
2015-07-10 06:01:56 -07:00
/**
* And now we are pointing at the zero char at the end of the buffer again
*/
linePointer += extraLen;
}
2015-07-10 06:01:56 -07:00
/**
* @note This method if fast because it does not validate much, be sure what you are doing
*/
void Logging::appendFast(const char *text) {
char *s = linePointer;
2015-07-10 06:01:56 -07:00
while ((*s++ = *text++) != 0)
;
linePointer = s - 1;
2015-07-10 06:01:56 -07:00
}
/**
* this method acquires system lock to guard the shared intermediateLoggingBuffer memory stream
*/
2018-08-31 19:30:03 -07:00
void Logging::vappendPrintf(const char *fmt, va_list arg) {
#if ! EFI_UNIT_TEST
2020-09-06 20:17:13 -07:00
#if EFI_ENABLE_ASSERTS
// todo: Kinetis needs real getCurrentRemainingStack or mock
if (getCurrentRemainingStack() < 128) {
firmwareError(CUSTOM_ERR_6604, "lowstck#5b %s", chThdGetSelfX()->name);
}
2020-09-06 20:17:13 -07:00
#endif // EFI_ENABLE_ASSERTS
chibios_rt::CriticalSectionLocker csl;
intermediateLogging.vappendPrintfI(this, fmt, arg);
#endif // EFI_UNIT_TEST
2015-07-10 06:01:56 -07:00
}
2018-08-31 18:38:14 -07:00
void Logging::appendPrintf(const char *fmt, ...) {
#if EFI_UNIT_TEST
va_list ap;
va_start(ap, fmt);
vsprintf(buffer, fmt, ap);
va_end(ap);
#else
2019-02-23 09:33:49 -08:00
efiAssertVoid(CUSTOM_APPEND_STACK, getCurrentRemainingStack() > 128, "lowstck#4");
2018-08-31 18:38:14 -07:00
va_list ap;
va_start(ap, fmt);
2018-08-31 19:30:03 -07:00
vappendPrintf(fmt, ap);
2018-08-31 18:38:14 -07:00
va_end(ap);
#endif // EFI_UNIT_TEST
2018-08-31 18:38:14 -07:00
}
void Logging::appendFloat(float value, int precision) {
2015-07-10 06:01:56 -07:00
/**
* todo: #1 this implementation is less than perfect
* todo: #2 The only way to avoid double promotion would probably be using *float instead of float
* See also http://stackoverflow.com/questions/5522051/printing-a-float-in-c-while-avoiding-variadic-parameter-promotion-to-double
*/
switch (precision) {
case 1:
appendPrintf("%.1f", value);
2015-07-10 06:01:56 -07:00
break;
case 2:
appendPrintf("%.2f", value);
2015-07-10 06:01:56 -07:00
break;
case 3:
appendPrintf("%.3f", value);
2015-07-10 06:01:56 -07:00
break;
case 4:
appendPrintf("%.4f", value);
2015-07-10 06:01:56 -07:00
break;
case 5:
appendPrintf("%.5f", value);
2015-07-10 06:01:56 -07:00
break;
case 6:
appendPrintf("%.6f", value);
2015-07-10 06:01:56 -07:00
break;
default:
appendPrintf("%.2f", value);
2015-07-10 06:01:56 -07:00
}
}
void appendMsgPrefix(Logging *logging) {
logging->append(PROTOCOL_MSG DELIMETER);
2015-07-10 06:01:56 -07:00
}
void appendMsgPostfix(Logging *logging) {
logging->append(DELIMETER);
2015-07-10 06:01:56 -07:00
}
void Logging::reset() {
linePointer = buffer;
*linePointer = 0;
2015-07-10 06:01:56 -07:00
}
Logging::Logging(char const *name, char *buffer, int bufferSize)
: name(name)
, buffer(buffer)
, bufferSize(bufferSize)
{
reset();
2015-07-10 06:01:56 -07:00
}
LoggingWithStorage::LoggingWithStorage(const char *name) : Logging(name, DEFAULT_BUFFER, sizeof(DEFAULT_BUFFER)) {
}