GCC Code Coverage Report


Directory: ./
File: Svc/FrameAccumulator/FrameDetector/CcsdsTcFrameDetector.cpp
Date: 2026-09-23 22:11:34
Exec Total Coverage
Lines: 38 44 86.4%
Functions: 1 1 100.0%
Branches: 25 30 83.3%

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 6398 FrameDetector::Status CcsdsTcFrameDetector::detect(const Types::CircularBuffer& data, FwSizeType& size_out) const {
20
3/3
✓ Branch 1 taken 6398 times.
✓ Branch 3 taken 481 times.
✓ Branch 4 taken 5917 times.
6398 if (data.get_allocated_size() < Ccsds::TCHeader::SERIALIZED_SIZE + Ccsds::TCTrailer::SERIALIZED_SIZE) {
21 481 size_out = Ccsds::TCHeader::SERIALIZED_SIZE + Ccsds::TCTrailer::SERIALIZED_SIZE;
22 481 return Status::MORE_DATA_NEEDED;
23 }
24
25 // ---------------- Frame Header ----------------
26 // Copy CircularBuffer data into linear buffer, for serialization into FrameHeader object
27 U8 header_data[Ccsds::TCHeader::SERIALIZED_SIZE];
28
1/1
✓ Branch 1 taken 5917 times.
5917 Fw::SerializeStatus status = data.peek(header_data, Ccsds::TCHeader::SERIALIZED_SIZE, 0);
29
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5917 times.
5917 if (status != Fw::FW_SERIALIZE_OK) {
30 ✗ return Status::NO_FRAME_DETECTED;
31 }
32
1/1
✓ Branch 1 taken 5917 times.
5917 Fw::ExternalSerializeBuffer header_ser_buffer(header_data, Ccsds::TCHeader::SERIALIZED_SIZE);
33
1/1
✓ Branch 1 taken 5917 times.
5917 status = header_ser_buffer.setBuffLen(Ccsds::TCHeader::SERIALIZED_SIZE);
34 5917 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status));
35 // Attempt to deserialize data into the FrameHeader object
36
1/1
✓ Branch 1 taken 5917 times.
5917 Ccsds::TCHeader header;
37
1/1
✓ Branch 1 taken 5917 times.
5917 status = header.deserializeFrom(header_ser_buffer);
38 5917 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
39
40
2/2
✓ Branch 1 taken 5766 times.
✓ Branch 2 taken 151 times.
5917 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 5766 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 151 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
2/3
✓ Branch 1 taken 151 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 151 times.
151 if (data.get_allocated_size() < expected_frame_length) {
50 ✗ size_out = expected_frame_length;
51 ✗ 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 if (expected_frame_length < Ccsds::TCHeader::SERIALIZED_SIZE + Ccsds::TCTrailer::SERIALIZED_SIZE) {
57 ✗ 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 151 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 151 Ccsds::Utils::CRC16 crc;
67
2/2
✓ Branch 0 taken 3125 times.
✓ Branch 1 taken 151 times.
3276 for (FwSizeType i = 0; i < data_to_crc_length; ++i) {
68 3125 U8 byte = 0;
69
1/1
✓ Branch 1 taken 3125 times.
3125 status = data.peek(byte, i);
70 3125 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
71
1/1
✓ Branch 1 taken 3125 times.
3125 crc.update(byte);
72 }
73 151 U16 computed_fecf = crc.finalize();
74 // Retrieve CRC field from the trailer
75 U8 trailer_data[Ccsds::TCTrailer::SERIALIZED_SIZE];
76
1/1
✓ Branch 1 taken 151 times.
151 status = data.peek(trailer_data, Ccsds::TCTrailer::SERIALIZED_SIZE, data_to_crc_length);
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 if (status != Fw::FW_SERIALIZE_OK) {
78 ✗ return Status::NO_FRAME_DETECTED;
79 }
80
1/1
✓ Branch 1 taken 151 times.
151 Fw::ExternalSerializeBuffer trailer_ser_buffer(trailer_data, Ccsds::TCTrailer::SERIALIZED_SIZE);
81
1/1
✓ Branch 1 taken 151 times.
151 status = trailer_ser_buffer.setBuffLen(Ccsds::TCTrailer::SERIALIZED_SIZE);
82 151 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status));
83 // Attempt to deserialize data into the FrameTrailer object
84
1/1
✓ Branch 1 taken 151 times.
151 Ccsds::TCTrailer trailer;
85
1/1
✓ Branch 1 taken 151 times.
151 status = trailer.deserializeFrom(trailer_ser_buffer);
86 151 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
87 151 U16 transmitted_fecf = trailer.get_fecf();
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 if (transmitted_fecf != computed_fecf) {
89 // If the computed CRC does not match the transmitted CRC, we don't have a valid frame
90 ✗ return Status::NO_FRAME_DETECTED;
91 }
92 // At this point, we have validated the header and CRC - we report a valid frame detected
93 151 size_out = expected_frame_length;
94 151 return Status::FRAME_DETECTED;
95 5917 }
96
97 } // namespace FrameDetectors
98 } // namespace Svc
99