GCC Code Coverage Report


Directory: /home/runner/work/fprime/fprime/Svc/Ccsds/TmFramer/
File: TmFramer.cpp
Date: 2026-09-03 22:13:28
Exec Total Coverage
Lines: 63 63 100.0%
Functions: 6 6 100.0%
Branches: 30 31 96.8%

Line Branch Exec Source
1 // ======================================================================
2 // \title TmFramer.cpp
3 // \author thomas-bc
4 // \brief cpp file for TmFramer component implementation class
5 // ======================================================================
6
7 #include "Svc/Ccsds/TmFramer/TmFramer.hpp"
8 #include "Svc/Ccsds/Utils/CRC16.hpp"
9 #include "config/FppConstantsAc.hpp"
10
11 namespace Svc {
12
13 namespace Ccsds {
14
15 // ----------------------------------------------------------------------
16 // Component construction and destruction
17 // ----------------------------------------------------------------------
18
19 1 TmFramer ::TmFramer(const char* const compName)
20 1 : TmFramerComponentBase(compName), m_masterFrameCount(0), m_virtualFrameCount(0) {}
21
22 2 TmFramer ::~TmFramer() {}
23
24 // ----------------------------------------------------------------------
25 // Handler implementations for typed input ports
26 // ----------------------------------------------------------------------
27
28 229 void TmFramer ::dataIn_handler(FwIndexType portNum, Fw::Buffer& data, const ComCfg::FrameContext& context) {
29 229 FW_ASSERT(data.getSize() <= ComCfg::TmFrameFixedSize - TMHeader::SERIALIZED_SIZE - TMTrailer::SERIALIZED_SIZE,
30 static_cast<FwAssertArgType>(data.getSize()));
31 229 FW_ASSERT(this->m_bufferState == BufferOwnershipState::OWNED, static_cast<FwAssertArgType>(this->m_bufferState));
32
33 // -----------------------------------------------
34 // Header
35 // -----------------------------------------------
36
1/1
✓ Branch 1 taken 229 times.
229 TMHeader header;
37
38 // GVCID (Global Virtual Channel ID) (Standard 4.1.2.2 and 4.1.2.3)
39 229 U16 globalVcId = static_cast<U16>(context.get_vcId() << TMSubfields::virtualChannelIdOffset);
40 229 globalVcId |= static_cast<U16>(ComCfg::SpacecraftId << TMSubfields::spacecraftIdOffset);
41 229 globalVcId |= 0x0; // Operational Control Field: Flag set to 0 (Standard 4.1.2.4)
42
43 // Data Field Status (Standard 4.1.2.7):
44 // - all flags to 0 except segment length id 0b11 per standard (4.1.2.7)
45 // - First Header Pointer is always 0 since we are always wrapping a single entire packet at offset 0
46 229 U16 dataFieldStatus = 0;
47 229 dataFieldStatus |= 0x3 << TMSubfields::segLengthOffset; // Seg Length Id '11' (0x3) per Standard (4.1.2.7.5)
48
49
1/1
✓ Branch 1 taken 229 times.
229 header.set_globalVcId(globalVcId);
50
1/1
✓ Branch 1 taken 229 times.
229 header.set_masterFrameCount(this->m_masterFrameCount);
51
1/1
✓ Branch 1 taken 229 times.
229 header.set_virtualFrameCount(this->m_virtualFrameCount);
52
1/1
✓ Branch 1 taken 229 times.
229 header.set_dataFieldStatus(dataFieldStatus);
53
54 // We use only a single Virtual Channel for now, so master and virtual frame counts are the same
55 229 this->m_masterFrameCount++; // U8 intended to wrap around (modulo 256)
56 229 this->m_virtualFrameCount++; // U8 intended to wrap around (modulo 256)
57
58 // -------------------------------------------------
59 // Data field
60 // -------------------------------------------------
61 // Payload packet
62 Fw::SerializeStatus status;
63 // Create frame Fw::Buffer using member data field
64
1/1
✓ Branch 1 taken 229 times.
229 Fw::Buffer frameBuffer = Fw::Buffer(this->m_frameBuffer, sizeof(this->m_frameBuffer));
65
1/1
✓ Branch 1 taken 229 times.
229 auto frameSerializer = frameBuffer.getSerializer();
66
1/1
✓ Branch 1 taken 229 times.
229 status = frameSerializer.serializeFrom(header);
67 229 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
68
3/3
✓ Branch 1 taken 229 times.
✓ Branch 4 taken 229 times.
✓ Branch 7 taken 229 times.
229 status = frameSerializer.serializeFrom(data.getData(), data.getSize(), Fw::Serialization::OMIT_LENGTH);
69 229 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
70
71 // As per TM Standard 4.2.2.5, fill the rest of the data field with an Idle Packet
72
1/1
✓ Branch 1 taken 229 times.
229 this->fill_with_idle_packet(frameSerializer);
73
74 // -------------------------------------------------
75 // Trailer (CRC)
76 // -------------------------------------------------
77
1/1
✓ Branch 1 taken 229 times.
229 TMTrailer trailer;
78 // Compute CRC over the entire frame buffer minus the FECF trailer (Standard 4.1.6)
79 U16 crc =
80
2/2
✓ Branch 1 taken 229 times.
✓ Branch 4 taken 229 times.
229 Ccsds::Utils::CRC16::compute(frameBuffer.getData(), sizeof(this->m_frameBuffer) - TMTrailer::SERIALIZED_SIZE);
81 // Set the Frame Error Control Field (FECF)
82
1/1
✓ Branch 1 taken 229 times.
229 trailer.set_fecf(crc);
83 // Move the serializer pointer to the end of the location where the trailer will be serialized
84
1/1
✓ Branch 1 taken 229 times.
229 status = frameSerializer.moveSerToOffset(ComCfg::TmFrameFixedSize - TMTrailer::SERIALIZED_SIZE);
85 229 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
86
1/1
✓ Branch 1 taken 229 times.
229 status = frameSerializer.serializeFrom(trailer);
87 229 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
88
89 229 this->m_bufferState = BufferOwnershipState::NOT_OWNED;
90
1/1
✓ Branch 1 taken 229 times.
229 this->dataOut_out(0, frameBuffer, context);
91
1/1
✓ Branch 1 taken 229 times.
229 this->dataReturnOut_out(0, data, context); // return ownership of the original data buffer
92 229 }
93
94 230 void TmFramer ::comStatusIn_handler(FwIndexType portNum, Fw::Success& condition) {
95
1/2
✓ Branch 1 taken 230 times.
✗ Branch 2 not taken.
230 if (this->isConnected_comStatusOut_OutputPort(portNum)) {
96 230 this->comStatusOut_out(portNum, condition);
97 }
98 230 }
99
100 229 void TmFramer ::dataReturnIn_handler(FwIndexType portNum,
101 Fw::Buffer& frameBuffer,
102 const ComCfg::FrameContext& context) {
103 // Assert that the returned buffer is the member, and set ownership state
104 229 FW_ASSERT(frameBuffer.getData() >= &this->m_frameBuffer[0]);
105 229 FW_ASSERT(frameBuffer.getData() < &this->m_frameBuffer[0] + sizeof(this->m_frameBuffer));
106 229 this->m_bufferState = BufferOwnershipState::OWNED;
107 229 }
108
109 229 void TmFramer ::fill_with_idle_packet(Fw::SerialBufferBase& serializer) {
110 229 constexpr U16 endIndex = ComCfg::TmFrameFixedSize - TMTrailer::SERIALIZED_SIZE;
111 229 constexpr U16 idleApid = static_cast<U16>(ComCfg::Apid::SPP_IDLE_PACKET);
112
1/1
✓ Branch 1 taken 229 times.
229 const U16 startIndex = static_cast<U16>(serializer.getSize());
113 229 const U16 idlePacketSize = static_cast<U16>(endIndex - startIndex);
114 // Length token is defined as the number of bytes of payload data minus 1
115 229 const U16 lengthToken = static_cast<U16>(idlePacketSize - SpacePacketHeader::SERIALIZED_SIZE - 1);
116
117 229 FW_ASSERT(idlePacketSize >= 7, static_cast<FwAssertArgType>(idlePacketSize)); // 7 bytes minimum for idle packet
118 229 FW_ASSERT(idlePacketSize <= ComCfg::TmFrameFixedSize, static_cast<FwAssertArgType>(idlePacketSize));
119
120
1/1
✓ Branch 1 taken 229 times.
229 SpacePacketHeader header;
121
1/1
✓ Branch 1 taken 229 times.
229 header.set_packetIdentification(idleApid);
122
1/1
✓ Branch 1 taken 229 times.
229 header.set_packetSequenceControl(
123 0x3 << SpacePacketSubfields::SeqFlagsOffset); // Sequence Flags = 0b11 (unsegmented) & unused Seq count
124
1/1
✓ Branch 1 taken 229 times.
229 header.set_packetDataLength(lengthToken);
125 // Serialize header and idle data into the frame
126
1/1
✓ Branch 1 taken 229 times.
229 Fw::SerializeStatus status = serializer.serializeFrom(header);
127 229 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
128
2/2
✓ Branch 0 taken 157587 times.
✓ Branch 1 taken 229 times.
157816 for (U16 i = static_cast<U16>(startIndex + SpacePacketHeader::SERIALIZED_SIZE); i < endIndex; i++) {
129
1/1
✓ Branch 1 taken 157587 times.
157587 status = serializer.serializeFrom(IDLE_DATA_PATTERN); // Idle data
130 157587 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
131 }
132 229 }
133 } // namespace Ccsds
134 } // namespace Svc
135