| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | #pragma once | |||
| 2 | ||||
| 3 | #include <cstdint> | |||
| 4 | #include <cstring> | |||
| 5 | ||||
| 6 | #include <rusefi/scaled_channel.h> | |||
| 7 | ||||
| 8 | #include "writer.h" | |||
| 9 | #include "mlg_types.h" | |||
| 10 | ||||
| 11 | // For unit tests we are manipulating with storage in runtime so consteval is not possible. | |||
| 12 | // In prod builds we have engine and configs as global instances so all addresses to read data from | |||
| 13 | // must be known compile-time. If consteval fails then some runtime logic made its way into LogField and that moves | |||
| 14 | // LogField instance into RAM which is correct from code perspective but incorrect intent-wise and consume code and RAM | |||
| 15 | // for no real reason. | |||
| 16 | #if defined(EFI_UNIT_TEST) && EFI_UNIT_TEST | |||
| 17 | #define LOG_FIELD_CONSTNESS_SPECIFIER_METHODS constexpr | |||
| 18 | #define LOG_FIELD_CONSTNESS_SPECIFIER_STORAGE const | |||
| 19 | #else | |||
| 20 | #define LOG_FIELD_CONSTNESS_SPECIFIER_METHODS consteval | |||
| 21 | #define LOG_FIELD_CONSTNESS_SPECIFIER_STORAGE const constinit | |||
| 22 | #endif | |||
| 23 | ||||
| 24 | namespace MLG::Entries { | |||
| 25 | using namespace MLG; | |||
| 26 | ||||
| 27 | class Field { | |||
| 28 | public: | |||
| 29 | // Scaled channels, memcpys data directly and describes format in header | |||
| 30 | template <typename TValue, int TMult, int TDiv> | |||
| 31 | 234 | LOG_FIELD_CONSTNESS_SPECIFIER_METHODS Field(const scaled_channel<TValue, TMult, TDiv>& toRead, | ||
| 32 | const char* name, const char* units, int8_t digits, const char* category = "none") | |||
| 33 | 234 | : m_multiplier(float(TDiv) / TMult) | ||
| 34 | 234 | , m_addr(toRead.getFirstByteAddr()) | ||
| 35 | 234 | , m_type_id(static_cast<std::underlying_type_t<Types::Field::Scalar>>(Types::Field::resolveBuiltInNumberType<TValue>())) | ||
| 36 | 234 | , m_digits(digits) | ||
| 37 | 234 | , m_size(Types::Field::sizeForType<Types::Field::resolveBuiltInNumberType<TValue>()>()) | ||
| 38 | 234 | , m_name(name) | ||
| 39 | 234 | , m_units(units) | ||
| 40 | 234 | , m_category(category) | ||
| 41 | 234 | , m_isBitField(false) | ||
| 42 | 234 | , m_bitsBlockOffset(0) | ||
| 43 | 234 | , m_bitNumber(0) | ||
| 44 | { | |||
| 45 | 234 | } | ||
| 46 | ||||
| 47 | // Non-scaled channel, works for plain arithmetic types (int, float, uint8_t, etc) | |||
| 48 | template <typename TValue, typename = typename std::enable_if<std::is_arithmetic_v<TValue>>::type> | |||
| 49 | 359 | LOG_FIELD_CONSTNESS_SPECIFIER_METHODS Field(TValue& toRead, | ||
| 50 | const char* name, const char* units, int8_t digits, const char* category = "none") | |||
| 51 | 359 | : m_multiplier(1) | ||
| 52 | 359 | , m_addr(&toRead) | ||
| 53 | 359 | , m_type_id(static_cast<std::underlying_type_t<Types::Field::Scalar>>(Types::Field::resolveBuiltInNumberType<TValue>())) | ||
| 54 | 359 | , m_digits(digits) | ||
| 55 | 359 | , m_size(Types::Field::sizeForType<Types::Field::resolveBuiltInNumberType<TValue>()>()) | ||
| 56 | 359 | , m_name(name) | ||
| 57 | 359 | , m_units(units) | ||
| 58 | 359 | , m_category(category) | ||
| 59 | 359 | , m_isBitField(false) | ||
| 60 | 359 | , m_bitsBlockOffset(0) | ||
| 61 | 359 | , m_bitNumber(0) | ||
| 62 | { | |||
| 63 | 359 | } | ||
| 64 | ||||
| 65 | // Bit channel | |||
| 66 | template <typename TValue> | |||
| 67 | 138 | LOG_FIELD_CONSTNESS_SPECIFIER_METHODS Field( | ||
| 68 | TValue& toRead, | |||
| 69 | const uint32_t bitsBlockOffset, | |||
| 70 | const uint8_t bitNumber, | |||
| 71 | const char* name, | |||
| 72 | const char* units, | |||
| 73 | const char* category = "none" | |||
| 74 | 138 | ): m_multiplier(1) | ||
| 75 | 138 | , m_addr(&toRead) | ||
| 76 | 138 | , m_type_id(static_cast<std::underlying_type_t<Types::Field::Scalar>>(Types::Field::Scalar::U08)) | ||
| 77 | 138 | , m_digits(0) | ||
| 78 | 138 | , m_size(1) | ||
| 79 | 138 | , m_name(name) | ||
| 80 | 138 | , m_units(units) | ||
| 81 | 138 | , m_category(category) | ||
| 82 | 138 | , m_isBitField(true) | ||
| 83 | 138 | , m_bitsBlockOffset(bitsBlockOffset) | ||
| 84 | 138 | , m_bitNumber(bitNumber) | ||
| 85 | { | |||
| 86 | 138 | } | ||
| 87 | ||||
| 88 | 729 | constexpr size_t getSize() const { return m_size; } | ||
| 89 | 387155862 | constexpr const void* getAddr() const { return m_addr; } | ||
| 90 | ||||
| 91 | // Write the header data describing this field. | |||
| 92 | // Returns the number of bytes written. | |||
| 93 | 406783 | size_t writeHeader(Writer& outBuffer) const { | ||
| 94 | 406783 | char buffer[Types::Field::DescriptorSize]; | ||
| 95 | ||||
| 96 | // Offset 0, length 1 = type | |||
| 97 | 406783 | buffer[0] = static_cast<char>(m_type_id); | ||
| 98 | ||||
| 99 | // Offset 1, length 34 = name | |||
| 100 | 406783 | strncpy(&buffer[1], m_name, 34); | ||
| 101 | ||||
| 102 | // Offset 35, length 10 = units | |||
| 103 | 406783 | strncpy(&buffer[35], m_units, 10); | ||
| 104 | ||||
| 105 | // Offset 45, length 1 = Display style | |||
| 106 | // value 0 -> floating point number | |||
| 107 | 406783 | buffer[45] = 0; | ||
| 108 | ||||
| 109 | // Offset 46, length 4 = Scale | |||
| 110 | 406783 | copyFloat(buffer + 46, m_multiplier); | ||
| 111 | ||||
| 112 | // Offset 50, length 4 = shift before scaling (always 0) | |||
| 113 | 406783 | copyFloat(buffer + 50, 0); | ||
| 114 | ||||
| 115 | // Offset 54, size 1 = digits to display (signed int) | |||
| 116 | 406783 | buffer[54] = m_digits; | ||
| 117 | ||||
| 118 | // Offset 55, (optional) category string | |||
| 119 |
1/2✓ Branch 0 taken 406783 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 406783 times.
✗ Decision 'false' not taken.
|
406783 | if (m_category) { |
| 120 | 406783 | size_t categoryLength = strlen(m_category); | ||
| 121 | 406783 | size_t lengthAfterCategory = 34 - categoryLength; | ||
| 122 | 406783 | memcpy(&buffer[55], m_category, categoryLength); | ||
| 123 | 406783 | memset(&buffer[55] + categoryLength, 0, lengthAfterCategory); | ||
| 124 | } else { | |||
| 125 | ✗ | memset(&buffer[55], 0, 34); | ||
| 126 | } | |||
| 127 | ||||
| 128 | // Total size = 89 | |||
| 129 |
1/1✓ Branch 1 taken 406783 times.
|
406783 | outBuffer.write(buffer, Types::Field::DescriptorSize); | |
| 130 | ||||
| 131 | 406783 | return Types::Field::DescriptorSize; | ||
| 132 | } | |||
| 133 | ||||
| 134 | // Write the field's data to the buffer. | |||
| 135 | // Returns the number of bytes written. | |||
| 136 | 387155866 | size_t writeData(char* buffer, void *offset) const { | ||
| 137 |
2/2✓ Branch 0 taken 72757689 times.
✓ Branch 1 taken 314398177 times.
|
2/2✓ Decision 'true' taken 72757689 times.
✓ Decision 'false' taken 314398177 times.
|
387155866 | if (m_isBitField) { |
| 138 | 72757689 | const char* const bitsBlockAddr = static_cast<const char*>(m_addr) + m_bitsBlockOffset; | ||
| 139 | 72757689 | const char* const byteWithBitAddr = bitsBlockAddr + m_bitNumber / 8; | ||
| 140 | 72757689 | unsigned char byteWithBit = 0; | ||
| 141 | 72757689 | memcpy_swapend(&byteWithBit, byteWithBitAddr, m_size, offset); | ||
| 142 | 72757689 | const uint8_t bitNumberInByte = m_bitNumber % 8; | ||
| 143 | 72757689 | buffer[0] = static_cast<char>(static_cast<bool>(byteWithBit & (1 << bitNumberInByte))); | ||
| 144 | } else { | |||
| 145 | 314398177 | memcpy_swapend(buffer, m_addr, m_size, offset); | ||
| 146 | } | |||
| 147 | ||||
| 148 | 387155866 | return m_size; | ||
| 149 | } | |||
| 150 | ||||
| 151 | private: | |||
| 152 | ||||
| 153 | 387969432 | static void memcpy_swapend(void* dest, const void* src, size_t const size, void *offset) { | ||
| 154 | 387969432 | const char* src2 = reinterpret_cast<const char*>(src); | ||
| 155 | 387969432 | char* dest2 = reinterpret_cast<char*>(dest); | ||
| 156 |
2/2✓ Branch 0 taken 826956249 times.
✓ Branch 1 taken 387969432 times.
|
2/2✓ Decision 'true' taken 826956249 times.
✓ Decision 'false' taken 387969432 times.
|
1214925681 | for (size_t i = 0; i < size; i++) { |
| 157 | // Endian swap - copy the end to the beginning | |||
| 158 | 826956249 | dest2[i] = src2[size - 1 - i + (uint64_t)offset]; | ||
| 159 | } | |||
| 160 | 387969432 | } | ||
| 161 | ||||
| 162 | 813566 | static void copyFloat(char* buffer, float value) { | ||
| 163 | 813566 | memcpy_swapend(buffer, &value, sizeof(float), nullptr); | ||
| 164 | 813566 | } | ||
| 165 | ||||
| 166 | const float m_multiplier; | |||
| 167 | const void* const m_addr; | |||
| 168 | const uint8_t m_type_id; | |||
| 169 | const int8_t m_digits; | |||
| 170 | const uint8_t m_size; | |||
| 171 | ||||
| 172 | const char* const m_name; | |||
| 173 | const char* const m_units; | |||
| 174 | const char* const m_category; | |||
| 175 | ||||
| 176 | const bool m_isBitField; | |||
| 177 | const uint32_t m_bitsBlockOffset; // only for bit log fields | |||
| 178 | const uint8_t m_bitNumber; // only for bit log fields | |||
| 179 | }; | |||
| 180 | } | |||
| 181 |