GCC Code Coverage Report


Directory: ./
File: unit_tests/test-framework/mlg_reader.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 0.0% 0 0 134
Functions: 0.0% 0 0 11
Branches: 0.0% 0 0 93
Decisions: 0.0% 0 - 40

Line Branch Decision Exec Source
1 /*
2 * mlg_reader.cpp
3 *
4 */
5
6 #include <iostream>
7 #include <fstream>
8 #include <cstdint> // For fixed-width integer types like int32_t
9 #include <stdexcept> // For std::runtime_error
10 #include <chrono> // For time-related operations
11 #include <ctime> // For std::put_time and std::localtime
12 #include "mlg_reader.h"
13 #define FIXED_HEADER_SIZE 24
14
15 int readSwappedInt(std::ifstream *ifs) {
16 int32_t value;
17 if (!ifs->read(reinterpret_cast<char*>(&value), sizeof(value))) {
18 throw std::runtime_error("Error reading value");
19 }
20 uint32_t swapped_value = ((value & 0x000000FF) << 24)
21 | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8)
22 | ((value & 0xFF000000) >> 24);
23 return static_cast<int32_t>(swapped_value);
24 }
25
26 float readSwappedFloat(std::ifstream *ifs) {
27 int value;
28 if (!ifs->read(reinterpret_cast<char*>(&value), sizeof(value))) {
29 throw std::runtime_error("Error reading value");
30 }
31 union {
32 float f;
33 uint32_t i;
34 } converter;
35 uint32_t swapped_bytes = ((value & 0x000000FF) << 24)
36 | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8)
37 | ((value & 0xFF000000) >> 24);
38
39 converter.i = swapped_bytes;
40 return converter.f;
41 }
42
43 int16_t readSwappedShort(std::ifstream *ifs) {
44 int16_t value;
45 if (!ifs->read(reinterpret_cast<char*>(&value), sizeof(value))) {
46 throw std::runtime_error("Error reading value");
47 }
48 uint16_t swapped_value = ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8);
49 return static_cast<int16_t>(swapped_value);
50 }
51
52 int8_t readByte(std::ifstream *ifs) {
53 int8_t value;
54 if (!ifs->read(reinterpret_cast<char*>(&value), sizeof(value))) {
55 throw std::runtime_error("Error reading value");
56 }
57 return value;
58 }
59
60 static std::string readFixedSizeString(std::ifstream &ifs, int size) {
61 std::string s;
62 s.reserve(size); // Pre-allocate memory
63 bool terminated = false;
64 for (int i = 0; i < size; ++i) {
65 char c;
66 if (!ifs.read(&c, 1)) {
67 throw std::runtime_error(
68 "Error reading fixed size string byte "
69 + std::to_string(i));
70 }
71 if (c == 0) {
72 terminated = true;
73 }
74 if (!terminated) {
75 s += c;
76 }
77 }
78 return s;
79 }
80
81 int BinarySensorReader::readRecordsMetadata(std::ifstream &ifs,
82 int numberOfFields) {
83 int lineTotalSize = 0;
84 for (int i = 0; i < numberOfFields; ++i) {
85 int8_t typeCode = readByte(&ifs);
86 std::string fieldName = readFixedSizeString(ifs, 34);
87 std::string units = readFixedSizeString(ifs, 10);
88
89 // std::cout << "fieldName [" << fieldName << "]" << std::endl;
90 // std::cout << "units [" << units << "]" << std::endl;
91
92 /*int8_t style = */readByte(&ifs);
93 float scale = readSwappedFloat(&ifs);
94 float transform = readSwappedFloat(&ifs);
95 int8_t digits = readByte(&ifs);
96 /*category*/readFixedSizeString(ifs, 34);
97
98 MlgDataType type = findByOrdinal(typeCode);
99 lineTotalSize += getRecordSize(type);
100
101 Record *record = new Record(fieldName, type, scale);
102 recordByName[fieldName] = record;
103 records.emplace_back(record);
104 }
105
106 if (afterHeaderCallback) {
107 afterHeaderCallback();
108 }
109
110 return lineTotalSize;
111 }
112
113 void BinarySensorReader::readLoggerFieldData() {
114 /*uint16_t timestamp =*/static_cast<uint16_t>(readSwappedShort(&ifs));
115
116 // std::cout << "Reading for record " << recordCounter << std::endl;
117
118 for (Record *record : records) {
119 float value = record->read(ifs);
120 currentSnapshot[record->getFieldName()] = value;
121 }
122
123 /*uint8_t crc = */static_cast<uint8_t>(readByte(&ifs)); // Use the new helper
124
125 recordCounter++;
126 //logContent.emplace_back(currentSnapshot);
127 }
128
129 std::map<const std::string, float>& BinarySensorReader::readBlock() {
130 uint8_t blockType = static_cast<uint8_t>(readByte(&ifs)); // Use the new helper
131 uint8_t counter = static_cast<uint8_t>(readByte(&ifs)); // Use the new helper
132
133 if (blockType == 0) {
134 readLoggerFieldData();
135 } else if (blockType == 1) {
136 throw std::runtime_error("todo support markers");
137 } else {
138 throw std::runtime_error(
139 "Unexpected block type " + std::to_string(blockType));
140 }
141
142 return currentSnapshot;
143 }
144
145 void BinarySensorReader::openMlg(const std::string fileName) {
146 ifs.open(fileName, std::ios::binary);
147
148 if (!ifs.is_open()) {
149 throw std::runtime_error("Error opening file: " + fileName);
150 }
151
152 int header = readSwappedInt(&ifs);
153
154 std::cout << "header " << std::hex << header << std::dec << std::endl;
155 if (header != 0x4d4c564c) {
156 throw std::runtime_error("header " + std::to_string(header));
157 }
158
159 int32_t version = readSwappedInt(&ifs);
160 std::cout << "version " << std::hex << version << std::dec << std::endl;
161 if (version != 0x47000002) {
162 throw std::runtime_error("version " + std::to_string(version));
163 }
164
165 int32_t timeStamp = readSwappedInt(&ifs);
166 std::cout << "timeStamp " << timeStamp;
167
168 {
169 std::time_t ts_seconds = static_cast<std::time_t>(timeStamp);
170 std::tm *ptm = std::localtime(&ts_seconds);
171 char buffer[32];
172 std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", ptm);
173 std::cout << " " << buffer << std::endl;
174 }
175
176 int32_t infoDataState = readSwappedInt(&ifs);
177 std::cout << "infoDataState " << std::hex << infoDataState << "/"
178 << std::dec << infoDataState << std::endl;
179
180 int32_t dataBeginIndex = readSwappedInt(&ifs);
181 std::cout << "dataBeginIndex " << std::hex << dataBeginIndex << "/"
182 << std::dec << dataBeginIndex << std::endl;
183
184 uint16_t recordLength = readSwappedShort(&ifs);
185 uint16_t numberOfFields = readSwappedShort(&ifs);
186 std::cout << "numberOfFields=" << numberOfFields << std::endl;
187
188 int fieldsHeaderAreaSize = 89 * numberOfFields;
189 std::cout << "fields area size " << fieldsHeaderAreaSize
190 << ", recordLength=" << recordLength << std::endl;
191
192 int infoBlockExpectedSize = dataBeginIndex - FIXED_HEADER_SIZE
193 - fieldsHeaderAreaSize;
194 bool isInfoBlockExpected = infoBlockExpectedSize > 0;
195 if (isInfoBlockExpected) {
196 std::cout << "Expecting infoBlock " << infoBlockExpectedSize
197 << std::endl;
198 }
199
200 int lineTotalSize = readRecordsMetadata(ifs, numberOfFields);
201
202 if (isInfoBlockExpected) {
203
204 std::string infoBlock = readFixedSizeString(ifs, infoBlockExpectedSize);
205 std::cout << "Skipping infoBlock length=" << infoBlock.length()
206 << std::endl;
207 int sizeValidation = dataBeginIndex - infoBlock.length()
208 - fieldsHeaderAreaSize - FIXED_HEADER_SIZE - 1;
209
210 if (sizeValidation != 0)
211 throw std::runtime_error(
212 "Size validation failed by "
213 + std::to_string(sizeValidation));
214 }
215 }
216
217 void BinarySensorReader::readMlg(mlg_logline_callback_t callback) {
218 while (!eof()) {
219 callback(readBlock());
220 }
221
222 std::cout << "Got " << recordCounter << " record(s)" << std::endl;
223
224 ifs.close();
225 }
226
227 bool BinarySensorReader::eof() {
228 return (ifs.peek() == EOF);
229 }
230