| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title CcsdsTcFrameDetector.hpp | ||
| 3 | // \author thomas-bc | ||
| 4 | // \brief hpp file for fprime frame detector definitions | ||
| 5 | // ====================================================================== | ||
| 6 | |||
| 7 | #include "Svc/FrameAccumulator/FrameDetector/CcsdsTcFrameDetector.hpp" | ||
| 8 | #include <cstdio> | ||
| 9 | #include "Svc/Ccsds/Types/FppConstantsAc.hpp" | ||
| 10 | #include "Svc/Ccsds/Types/TCHeaderSerializableAc.hpp" | ||
| 11 | #include "Svc/Ccsds/Types/TCTrailerSerializableAc.hpp" | ||
| 12 | #include "Svc/Ccsds/Utils/CRC16.hpp" | ||
| 13 | #include "Utils/Hash/Hash.hpp" | ||
| 14 | #include "config/FppConstantsAc.hpp" | ||
| 15 | |||
| 16 | namespace Svc { | ||
| 17 | namespace FrameDetectors { | ||
| 18 | |||
| 19 | 1008 | FrameDetector::Status CcsdsTcFrameDetector::detect(const Types::CircularBuffer& data, FwSizeType& size_out) const { | |
| 20 |
3/3✓ Branch 2 taken 1008 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1007 times.
|
1008 | if (data.get_allocated_size() < Ccsds::TCHeader::SERIALIZED_SIZE + Ccsds::TCTrailer::SERIALIZED_SIZE) { |
| 21 | 1 | size_out = Ccsds::TCHeader::SERIALIZED_SIZE + Ccsds::TCTrailer::SERIALIZED_SIZE; | |
| 22 | 1 | return Status::MORE_DATA_NEEDED; | |
| 23 | } | ||
| 24 | |||
| 25 | // ---------------- Frame Header ---------------- | ||
| 26 | // Copy CircularBuffer data into linear buffer, for serialization into FrameHeader object | ||
| 27 | 1007 | U8 header_data[Ccsds::TCHeader::SERIALIZED_SIZE]; | |
| 28 |
1/1✓ Branch 2 taken 1007 times.
|
1007 | Fw::SerializeStatus status = data.peek(header_data, Ccsds::TCHeader::SERIALIZED_SIZE, 0); |
| 29 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1007 times.
|
1007 | if (status != Fw::FW_SERIALIZE_OK) { |
| 30 | ✗ | return Status::NO_FRAME_DETECTED; | |
| 31 | } | ||
| 32 |
1/1✓ Branch 2 taken 1007 times.
|
1007 | Fw::ExternalSerializeBuffer header_ser_buffer(header_data, Ccsds::TCHeader::SERIALIZED_SIZE); |
| 33 |
1/1✓ Branch 2 taken 1007 times.
|
1007 | status = header_ser_buffer.setBuffLen(Ccsds::TCHeader::SERIALIZED_SIZE); |
| 34 | 1007 | FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status)); | |
| 35 | // Attempt to deserialize data into the FrameHeader object | ||
| 36 |
1/1✓ Branch 2 taken 1007 times.
|
1007 | Ccsds::TCHeader header; |
| 37 |
1/1✓ Branch 2 taken 1007 times.
|
1007 | status = header.deserializeFrom(header_ser_buffer); |
| 38 | 1007 | FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); | |
| 39 | |||
| 40 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1006 times.
|
1007 | if (header.get_flagsAndScId() != this->m_expectedFlagsAndScIdToken) { |
| 41 | // If the flags and SC ID do not match the expected token, we don't have a valid frame | ||
| 42 | 1 | return Status::NO_FRAME_DETECTED; | |
| 43 | } | ||
| 44 | // TC protocol defines the Frame Length as number of bytes minus 1, so we add 1 back to get length in bytes | ||
| 45 | const FwSizeType expected_frame_length = | ||
| 46 | 1006 | static_cast<FwSizeType>((header.get_vcIdAndLength() & Ccsds::TCSubfields::FrameLengthMask) + 1); | |
| 47 | |||
| 48 | // If the full frame is not yet available, report that more data is needed | ||
| 49 |
3/3✓ Branch 2 taken 1006 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1005 times.
|
1006 | if (data.get_allocated_size() < expected_frame_length) { |
| 50 | 1 | size_out = expected_frame_length; | |
| 51 | 1 | return Status::MORE_DATA_NEEDED; | |
| 52 | } | ||
| 53 | // Validate minimum frame size BEFORE computing data_to_crc_length. | ||
| 54 | // If expected_frame_length < TRAILER_SIZE the subtraction below would underflow to a | ||
| 55 | // near-maximum value, causing the CRC loop to read far beyond the valid frame data. | ||
| 56 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1003 times.
|
1005 | if (expected_frame_length < Ccsds::TCHeader::SERIALIZED_SIZE + Ccsds::TCTrailer::SERIALIZED_SIZE) { |
| 57 | 2 | return Status::NO_FRAME_DETECTED; | |
| 58 | } | ||
| 59 | // Safe: the guard above guarantees expected_frame_length >= TRAILER_SIZE, so this | ||
| 60 | // subtraction cannot underflow. Type is FwSizeType (not U16) to avoid silent truncation | ||
| 61 | // if expected_frame_length ever exceeds 65535. | ||
| 62 | 1003 | const FwSizeType data_to_crc_length = expected_frame_length - Ccsds::TCTrailer::SERIALIZED_SIZE; | |
| 63 | |||
| 64 | // ---------------- Frame Trailer ---------------- | ||
| 65 | // Compute CRC on the received data | ||
| 66 | 1003 | Ccsds::Utils::CRC16 crc; | |
| 67 |
2/2✓ Branch 0 taken 15035 times.
✓ Branch 1 taken 1003 times.
|
16038 | for (FwSizeType i = 0; i < data_to_crc_length; ++i) { |
| 68 | 15035 | U8 byte = 0; | |
| 69 |
1/1✓ Branch 2 taken 15035 times.
|
15035 | status = data.peek(byte, i); |
| 70 | 15035 | FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); | |
| 71 |
1/1✓ Branch 1 taken 15035 times.
|
15035 | crc.update(byte); |
| 72 | } | ||
| 73 | 1003 | U16 computed_fecf = crc.finalize(); | |
| 74 | // Retrieve CRC field from the trailer | ||
| 75 | 1003 | U8 trailer_data[Ccsds::TCTrailer::SERIALIZED_SIZE]; | |
| 76 |
1/1✓ Branch 2 taken 1003 times.
|
1003 | status = data.peek(trailer_data, Ccsds::TCTrailer::SERIALIZED_SIZE, data_to_crc_length); |
| 77 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1003 times.
|
1003 | if (status != Fw::FW_SERIALIZE_OK) { |
| 78 | ✗ | return Status::NO_FRAME_DETECTED; | |
| 79 | } | ||
| 80 |
1/1✓ Branch 2 taken 1003 times.
|
1003 | Fw::ExternalSerializeBuffer trailer_ser_buffer(trailer_data, Ccsds::TCTrailer::SERIALIZED_SIZE); |
| 81 |
1/1✓ Branch 2 taken 1003 times.
|
1003 | status = trailer_ser_buffer.setBuffLen(Ccsds::TCTrailer::SERIALIZED_SIZE); |
| 82 | 1003 | FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status)); | |
| 83 | // Attempt to deserialize data into the FrameTrailer object | ||
| 84 |
1/1✓ Branch 2 taken 1003 times.
|
1003 | Ccsds::TCTrailer trailer; |
| 85 |
1/1✓ Branch 2 taken 1003 times.
|
1003 | status = trailer.deserializeFrom(trailer_ser_buffer); |
| 86 | 1003 | FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); | |
| 87 | 1003 | U16 transmitted_fecf = trailer.get_fecf(); | |
| 88 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1002 times.
|
1003 | if (transmitted_fecf != computed_fecf) { |
| 89 | // If the computed CRC does not match the transmitted CRC, we don't have a valid frame | ||
| 90 | 1 | return Status::NO_FRAME_DETECTED; | |
| 91 | } | ||
| 92 | // At this point, we have validated the header and CRC - we report a valid frame detected | ||
| 93 | 1002 | size_out = expected_frame_length; | |
| 94 | 1002 | return Status::FRAME_DETECTED; | |
| 95 | 1007 | } | |
| 96 | |||
| 97 | } // namespace FrameDetectors | ||
| 98 | } // namespace Svc | ||
| 99 |