| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 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 | ✗ | 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 | */ | |||
| 73 | 80916 | void Logging::appendFast(const char *text) { | ||
| 74 | 80916 | char *s = linePointer; | ||
| 75 |
2/2✓ Branch 0 taken 232051 times.
✓ Branch 1 taken 80916 times.
|
2/2✓ Decision 'true' taken 232051 times.
✓ Decision 'false' taken 80916 times.
|
312967 | while ((*s++ = *text++) != 0) |
| 76 | ; | |||
| 77 | 80916 | linePointer = s - 1; | ||
| 78 | 80916 | } | ||
| 79 | ||||
| 80 | 584 | void Logging::appendPrintf(const char *fmt, ...) { | ||
| 81 | efiAssertVoid(ObdCode::CUSTOM_APPEND_STACK, hasLotsOfRemainingStack(), "lowstck#4"); | |||
| 82 | ||||
| 83 | 584 | size_t available = remainingSize(); | ||
| 84 | ||||
| 85 | 584 | va_list ap; | ||
| 86 | 584 | va_start(ap, fmt); | ||
| 87 | 584 | size_t written = chvsnprintf(linePointer, available, fmt, ap); | ||
| 88 | 584 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 584 times.
|
584 | linePointer += (written > available) ? available : written; | |
| 93 | // ensure buffer is always null terminated | |||
| 94 | 584 | 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 | ||||
| 128 | 585 | void Logging::reset() { | ||
| 129 | 585 | linePointer = buffer; | ||
| 130 | 585 | *linePointer = 0; | ||
| 131 | 585 | } | ||
| 132 | ||||
| 133 | 1 | Logging::Logging(char const *p_name, char *p_buffer, int p_bufferSize) | ||
| 134 | 1 | : name(p_name) | ||
| 135 | 1 | , buffer(p_buffer) | ||
| 136 | 1 | , bufferSize(p_bufferSize) | ||
| 137 | { | |||
| 138 | 1 | reset(); | ||
| 139 | 1 | } | ||
| 140 | ||||
| 141 | ✗ | LoggingWithStorage::LoggingWithStorage(const char *p_name) : Logging(p_name, DEFAULT_BUFFER, sizeof(DEFAULT_BUFFER)) { | ||
| 142 | ✗ | } | ||
| 143 |