INSTINCT Code Coverage Report


Directory: src/
File: util/Vendor/Litton/Ln200UartSensor.cpp
Date: 2025-11-25 23:34:18
Exec Total Coverage
Lines: 0 81 0.0%
Functions: 0 10 0.0%
Branches: 0 96 0.0%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "Ln200UartSensor.hpp"
10
11 #include "util/Logger.hpp"
12
13 NAV::vendor::ln::Ln200UartSensor::Ln200UartSensor(std::string name)
14 : _name(std::move(name)), _bitBuffer(uart::sensors::UartSensor::DefaultReadBufferSize), _flagWindow(8)
15 {}
16
17 std::unique_ptr<uart::protocol::Packet> NAV::vendor::ln::Ln200UartSensor::findPacket(uint8_t dataByte)
18 {
19 // If we receive a full idle byte (0xFF), mark the idle period.
20 if (dataByte == 0xFF)
21 {
22 _wasIdle = true;
23 }
24
25 // Define the lambda for byte-to-bits conversion.
26 auto byteToBits = [](uint8_t byte) -> std::vector<bool> {
27 std::vector<bool> bits(8);
28 for (uint8_t i = 0; i < 8; ++i)
29 {
30 bits[7 - i] = (byte >> i) & 0x1;
31 }
32 return bits;
33 };
34
35 // Lambda for checking the flag sequence.
36 auto isFlagSequence = [](const ScrollingBuffer<bool>& window) -> bool {
37 // The flag is 01111110.
38 constexpr std::bitset<8> flagPattern("01111110");
39
40 // Compare the available bits in the window with the corresponding bits in the flag pattern.
41 for (size_t i = 0; i < window.size(); ++i)
42 {
43 if (window.at(i) != flagPattern[i])
44 {
45 return false;
46 }
47 }
48 return true;
49 };
50
51 auto bitBufferToByteVector = [](const ScrollingBuffer<bool>& bitBuffer) -> std::vector<uint8_t> {
52 std::vector<uint8_t> byteVector((bitBuffer.size() + 7) / 8, 0); // Allocate enough bytes
53 for (size_t i = 0; i < bitBuffer.size(); ++i)
54 {
55 if (bitBuffer.at(i))
56 {
57 byteVector[i / 8] |= (1 << (7 - (i % 8))); // Set the corresponding bit in the byte
58 }
59 }
60 return byteVector;
61 };
62
63 // Convert the received byte to bits.
64 auto bits = byteToBits(dataByte);
65 for (auto bit : bits)
66 {
67 // Update the flag window (we use a sliding window of 8 bits).
68 _flagWindow.push_back(bit);
69 if (_flagWindow.size() > 8)
70 {
71 _flagWindow.pop_front();
72 }
73
74 // Check for flag sequence.
75 if (_flagWindow.size() == 8 && isFlagSequence(_flagWindow))
76 {
77 if (_state == State::Receiving)
78 {
79 // End of frame detected.
80 if (!_bitBuffer.empty())
81 {
82 // Remove the flag bits from the _bitBuffer (assume the last 7 bits are the flag).
83 if (_bitBuffer.size() >= 7)
84 {
85 for (int i = 0; i < 7; ++i)
86 {
87 _bitBuffer.pop_back();
88 }
89 }
90 std::vector<uint8_t> byteVector = bitBufferToByteVector(_bitBuffer);
91 LOG_DATA("{}: Valid binary packet: Length={}", _name, _bitBuffer.size());
92 auto p = std::make_unique<uart::protocol::Packet>(byteVector, &_sensor);
93 _bitBuffer.clear();
94 _state = State::Idle;
95 _consecutiveOnes = 0;
96 _wasIdle = false; // Clear the idle flag.
97 return p;
98 }
99 _state = State::Idle;
100 _wasIdle = false;
101 }
102 else // _state == Idle
103 {
104 // Only consider this flag as a start sequence if the bus was idle (0xFF) just before.
105 if (_wasIdle)
106 {
107 // Start of frame detected.
108 _state = State::Receiving;
109 _consecutiveOnes = 0;
110 _bitBuffer.clear(); // Clear any previous payload.
111 _wasIdle = false; // Reset the idle flag.
112 }
113 // If _wasIdle is false, then the flag might be an ending flag from a previous message.
114 }
115 continue;
116 }
117
118 if (_state == State::Receiving)
119 {
120 // If the current bit is false and it follows five consecutive ones,
121 // it's a stuffed zero which should be ignored.
122 if (!bit && _consecutiveOnes == 5)
123 {
124 _consecutiveOnes = 0;
125 continue;
126 }
127
128 // For a true bit, increment the counter; for a false bit, reset it.
129 _consecutiveOnes = bit ? (_consecutiveOnes + 1) : 0;
130
131 // Append the bit to the buffer.
132 _bitBuffer.push_back(bit);
133 }
134 }
135 return nullptr;
136 }
137
138 void NAV::vendor::ln::Ln200UartSensor::packetFinderFunction(const std::vector<uint8_t>& data, const uart::xplat::TimeStamp& timestamp, uart::sensors::UartSensor::ValidPacketFoundHandler dispatchPacket, void* dispatchPacketUserData, void* userData)
139 {
140 auto* sensor = static_cast<Ln200UartSensor*>(userData);
141
142 for (size_t i = 0; i < data.size(); ++i, sensor->_runningDataIndex++)
143 {
144 auto packetPointer = sensor->findPacket(data.at(i));
145
146 if (packetPointer != nullptr)
147 {
148 uart::protocol::Packet packet = *packetPointer;
149 dispatchPacket(dispatchPacketUserData, packet, sensor->_runningDataIndex, timestamp);
150 }
151 }
152 }
153
154 uart::protocol::Packet::Type NAV::vendor::ln::Ln200UartSensor::packetTypeFunction([[maybe_unused]] const uart::protocol::Packet& packet)
155 {
156 return uart::protocol::Packet::Type::TYPE_BINARY;
157 }
158
159 bool NAV::vendor::ln::Ln200UartSensor::checksumFunction(const uart::protocol::Packet& packet)
160 {
161 // TODO: Use 14th word of message as checksum
162 if (packet.type() == uart::protocol::Packet::Type::TYPE_BINARY)
163 {
164 return true;
165 }
166 LOG_CRITICAL("Can't calculate checksum of packet with unknown type");
167 return false;
168 }
169
170 bool NAV::vendor::ln::Ln200UartSensor::isErrorFunction([[maybe_unused]] const uart::protocol::Packet& packet)
171 {
172 return false;
173 }
174
175 bool NAV::vendor::ln::Ln200UartSensor::isResponseFunction([[maybe_unused]] const uart::protocol::Packet& packet)
176 {
177 return false;
178 }
179