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 | 357 | LOG_FIELD_CONSTNESS_SPECIFIER_METHODS Field(TValue& toRead, | ||
50 | const char* name, const char* units, int8_t digits, const char* category = "none") | |||
51 | 357 | : m_multiplier(1) | ||
52 | 357 | , m_addr(&toRead) | ||
53 | 357 | , m_type_id(static_cast<std::underlying_type_t<Types::Field::Scalar>>(Types::Field::resolveBuiltInNumberType<TValue>())) | ||
54 | 357 | , m_digits(digits) | ||
55 | 357 | , m_size(Types::Field::sizeForType<Types::Field::resolveBuiltInNumberType<TValue>()>()) | ||
56 | 357 | , m_name(name) | ||
57 | 357 | , m_units(units) | ||
58 | 357 | , m_category(category) | ||
59 | 357 | , m_isBitField(false) | ||
60 | 357 | , m_bitsBlockOffset(0) | ||
61 | 357 | , m_bitNumber(0) | ||
62 | { | |||
63 | 357 | } | ||
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 | 727 | constexpr size_t getSize() const { return m_size; } | ||
89 | 380187558 | 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 | 404940 | size_t writeHeader(Writer& outBuffer) const { | ||
94 | 404940 | char buffer[Types::Field::DescriptorSize]; | ||
95 | ||||
96 | // Offset 0, length 1 = type | |||
97 | 404940 | buffer[0] = static_cast<char>(m_type_id); | ||
98 | ||||
99 | // Offset 1, length 34 = name | |||
100 | 404940 | strncpy(&buffer[1], m_name, 34); | ||
101 | ||||
102 | // Offset 35, length 10 = units | |||
103 | 404940 | strncpy(&buffer[35], m_units, 10); | ||
104 | ||||
105 | // Offset 45, length 1 = Display style | |||
106 | // value 0 -> floating point number | |||
107 | 404940 | buffer[45] = 0; | ||
108 | ||||
109 | // Offset 46, length 4 = Scale | |||
110 | 404940 | copyFloat(buffer + 46, m_multiplier); | ||
111 | ||||
112 | // Offset 50, length 4 = shift before scaling (always 0) | |||
113 | 404940 | copyFloat(buffer + 50, 0); | ||
114 | ||||
115 | // Offset 54, size 1 = digits to display (signed int) | |||
116 | 404940 | buffer[54] = m_digits; | ||
117 | ||||
118 | // Offset 55, (optional) category string | |||
119 |
1/2✓ Branch 0 taken 404940 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 404940 times.
✗ Decision 'false' not taken.
|
404940 | if (m_category) { |
120 | 404940 | size_t categoryLength = strlen(m_category); | ||
121 | 404940 | size_t lengthAfterCategory = 34 - categoryLength; | ||
122 | 404940 | memcpy(&buffer[55], m_category, categoryLength); | ||
123 | 404940 | 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 404940 times.
|
404940 | outBuffer.write(buffer, Types::Field::DescriptorSize); | |
130 | ||||
131 | 404940 | return Types::Field::DescriptorSize; | ||
132 | } | |||
133 | ||||
134 | // Write the field's data to the buffer. | |||
135 | // Returns the number of bytes written. | |||
136 | 380187562 | size_t writeData(char* buffer, void *offset) const { | ||
137 |
2/2✓ Branch 0 taken 71644701 times.
✓ Branch 1 taken 308542861 times.
|
2/2✓ Decision 'true' taken 71644701 times.
✓ Decision 'false' taken 308542861 times.
|
380187562 | if (m_isBitField) { |
138 | 71644701 | const char* const bitsBlockAddr = static_cast<const char*>(m_addr) + m_bitsBlockOffset; | ||
139 | 71644701 | const char* const byteWithBitAddr = bitsBlockAddr + m_bitNumber / 8; | ||
140 | 71644701 | unsigned char byteWithBit = 0; | ||
141 | 71644701 | memcpy_swapend(&byteWithBit, byteWithBitAddr, m_size, offset); | ||
142 | 71644701 | const uint8_t bitNumberInByte = m_bitNumber % 8; | ||
143 | 71644701 | buffer[0] = static_cast<char>(static_cast<bool>(byteWithBit & (1 << bitNumberInByte))); | ||
144 | } else { | |||
145 | 308542861 | memcpy_swapend(buffer, m_addr, m_size, offset); | ||
146 | } | |||
147 | ||||
148 | 380187562 | return m_size; | ||
149 | } | |||
150 | ||||
151 | private: | |||
152 | ||||
153 | 380997442 | static void memcpy_swapend(void* dest, const void* src, size_t const size, void *offset) { | ||
154 | 380997442 | const char* src2 = reinterpret_cast<const char*>(src); | ||
155 | 380997442 | char* dest2 = reinterpret_cast<char*>(dest); | ||
156 |
2/2✓ Branch 0 taken 811726411 times.
✓ Branch 1 taken 380997442 times.
|
2/2✓ Decision 'true' taken 811726411 times.
✓ Decision 'false' taken 380997442 times.
|
1192723853 | for (size_t i = 0; i < size; i++) { |
157 | // Endian swap - copy the end to the beginning | |||
158 | 811726411 | dest2[i] = src2[size - 1 - i + (uint64_t)offset]; | ||
159 | } | |||
160 | 380997442 | } | ||
161 | ||||
162 | 809880 | static void copyFloat(char* buffer, float value) { | ||
163 | 809880 | memcpy_swapend(buffer, &value, sizeof(float), nullptr); | ||
164 | 809880 | } | ||
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 |