GCC Code Coverage Report


Directory: ./
File: Svc/Ccsds/TmFramer/TmFramer.cpp
Date: 2026-09-23 22:11:34
Exec Total Coverage
Lines: 58 58 100.0%
Functions: 6 6 100.0%
Branches: 23 25 92.0%

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 "Svc/Ccsds/Utils/IdlePacket.hpp"
10 #include "config/FppConstantsAc.hpp"
11
12 namespace Svc {
13
14 namespace Ccsds {
15
16 // ----------------------------------------------------------------------
17 // Component construction and destruction
18 // ----------------------------------------------------------------------
19
20 1 TmFramer ::TmFramer(const char* const compName)
21 1 : TmFramerComponentBase(compName), m_masterFrameCount(0), m_virtualFrameCount(0) {}
22
23 2 TmFramer ::~TmFramer() {}
24
25 // ----------------------------------------------------------------------
26 // Handler implementations for typed input ports
27 // ----------------------------------------------------------------------
28
29 239 void TmFramer ::dataIn_handler(FwIndexType portNum, Fw::Buffer& data, const ComCfg::FrameContext& context) {
30 239 FW_ASSERT(data.getSize() <= TmPayloadCapacity, static_cast<FwAssertArgType>(data.getSize()));
31 // The data must either fill the data field exactly or leave room for a minimum idle packet (4.2.2.5)
32
1/1
✓ Branch 1 taken 239 times.
239 const FwSizeType residual = TmPayloadCapacity - data.getSize();
33 239 FW_ASSERT(residual == 0 || residual >= Utils::IdlePacket::MIN_SIZE, static_cast<FwAssertArgType>(residual));
34 239 FW_ASSERT(context.get_firstHeaderPointer() <= TMSubfields::fhpMask,
35 static_cast<FwAssertArgType>(context.get_firstHeaderPointer()));
36 239 FW_ASSERT(this->m_bufferState == BufferOwnershipState::OWNED, static_cast<FwAssertArgType>(this->m_bufferState));
37
38 // -----------------------------------------------
39 // Header
40 // -----------------------------------------------
41
1/1
✓ Branch 1 taken 239 times.
239 TMHeader header;
42
43 // GVCID (Global Virtual Channel ID) (Standard 4.1.2.2 and 4.1.2.3)
44 239 U16 globalVcId = static_cast<U16>(context.get_vcId() << TMSubfields::virtualChannelIdOffset);
45 239 globalVcId |= static_cast<U16>(ComCfg::SpacecraftId << TMSubfields::spacecraftIdOffset);
46 239 globalVcId |= 0x0; // Operational Control Field: Flag set to 0 (Standard 4.1.2.4)
47
48 // Data Field Status (Standard 4.1.2.7):
49 // - all flags to 0 except Segment Length Id 0b11 (Standard 4.1.2.7.5)
50 // - First Header Pointer from context (Standard 4.1.2.7.6): set by an upstream aggregator when packets
51 // span frames; the default of 0 indicates a packet header at offset 0 of the data field
52 const U16 dataFieldStatus =
53 239 static_cast<U16>((0x3 << TMSubfields::segLengthOffset) | context.get_firstHeaderPointer());
54
55
1/1
✓ Branch 1 taken 239 times.
239 header.set_globalVcId(globalVcId);
56
1/1
✓ Branch 1 taken 239 times.
239 header.set_masterFrameCount(this->m_masterFrameCount);
57
1/1
✓ Branch 1 taken 239 times.
239 header.set_virtualFrameCount(this->m_virtualFrameCount);
58
1/1
✓ Branch 1 taken 239 times.
239 header.set_dataFieldStatus(dataFieldStatus);
59
60 // We use only a single Virtual Channel for now, so master and virtual frame counts are the same
61 239 this->m_masterFrameCount++; // U8 intended to wrap around (modulo 256)
62 239 this->m_virtualFrameCount++; // U8 intended to wrap around (modulo 256)
63
64 // -------------------------------------------------
65 // Data field
66 // -------------------------------------------------
67 // Payload packet
68 Fw::SerializeStatus status;
69 // Create frame Fw::Buffer using member data field
70
1/1
✓ Branch 1 taken 239 times.
239 Fw::Buffer frameBuffer = Fw::Buffer(this->m_frameBuffer, sizeof(this->m_frameBuffer));
71
1/1
✓ Branch 1 taken 239 times.
239 auto frameSerializer = frameBuffer.getSerializer();
72
1/1
✓ Branch 1 taken 239 times.
239 status = frameSerializer.serializeFrom(header);
73 239 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
74
3/3
✓ Branch 1 taken 239 times.
✓ Branch 4 taken 239 times.
✓ Branch 7 taken 239 times.
239 status = frameSerializer.serializeFrom(data.getData(), data.getSize(), Fw::Serialization::OMIT_LENGTH);
75 239 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
76
77 // As per TM Standard 4.2.2.5, fill the rest of the data field with an Idle Packet.
78 // A full data field (e.g. delivered by a spanning aggregator) requires no fill.
79
1/2
✓ Branch 0 taken 239 times.
✗ Branch 1 not taken.
239 if (residual > 0) {
80
1/1
✓ Branch 1 taken 239 times.
239 this->fill_with_idle_packet(frameSerializer);
81 }
82
83 // -------------------------------------------------
84 // Trailer (CRC)
85 // -------------------------------------------------
86
1/1
✓ Branch 1 taken 239 times.
239 TMTrailer trailer;
87 // Compute CRC over the entire frame buffer minus the FECF trailer (Standard 4.1.6)
88 U16 crc =
89
2/2
✓ Branch 1 taken 239 times.
✓ Branch 4 taken 239 times.
239 Ccsds::Utils::CRC16::compute(frameBuffer.getData(), sizeof(this->m_frameBuffer) - TMTrailer::SERIALIZED_SIZE);
90 // Set the Frame Error Control Field (FECF)
91
1/1
✓ Branch 1 taken 239 times.
239 trailer.set_fecf(crc);
92 // Move the serializer pointer to the end of the location where the trailer will be serialized
93
1/1
✓ Branch 1 taken 239 times.
239 status = frameSerializer.moveSerToOffset(ComCfg::TmFrameFixedSize - TMTrailer::SERIALIZED_SIZE);
94 239 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
95
1/1
✓ Branch 1 taken 239 times.
239 status = frameSerializer.serializeFrom(trailer);
96 239 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
97
98 239 this->m_bufferState = BufferOwnershipState::NOT_OWNED;
99
1/1
✓ Branch 1 taken 239 times.
239 this->dataOut_out(0, frameBuffer, context);
100
1/1
✓ Branch 1 taken 239 times.
239 this->dataReturnOut_out(0, data, context); // return ownership of the original data buffer
101 239 }
102
103 240 void TmFramer ::comStatusIn_handler(FwIndexType portNum, Fw::Success& condition) {
104
1/2
✓ Branch 1 taken 240 times.
✗ Branch 2 not taken.
240 if (this->isConnected_comStatusOut_OutputPort(portNum)) {
105 240 this->comStatusOut_out(portNum, condition);
106 }
107 240 }
108
109 239 void TmFramer ::dataReturnIn_handler(FwIndexType portNum,
110 Fw::Buffer& frameBuffer,
111 const ComCfg::FrameContext& context) {
112 // Assert that the returned buffer is the member, and set ownership state
113 239 FW_ASSERT(frameBuffer.getData() >= &this->m_frameBuffer[0]);
114 239 FW_ASSERT(frameBuffer.getData() < &this->m_frameBuffer[0] + sizeof(this->m_frameBuffer));
115 239 this->m_bufferState = BufferOwnershipState::OWNED;
116 239 }
117
118 239 void TmFramer ::fill_with_idle_packet(Fw::SerialBufferBase& serializer) {
119 239 constexpr FwSizeType endIndex = ComCfg::TmFrameFixedSize - TMTrailer::SERIALIZED_SIZE;
120 239 const FwSizeType startIndex = serializer.getSize();
121 239 FW_ASSERT(startIndex <= endIndex, static_cast<FwAssertArgType>(startIndex));
122 239 const FwSizeType idlePacketSize = endIndex - startIndex;
123
124 239 FW_ASSERT(idlePacketSize >= Utils::IdlePacket::MIN_SIZE, static_cast<FwAssertArgType>(idlePacketSize));
125 239 FW_ASSERT(idlePacketSize <= ComCfg::TmFrameFixedSize, static_cast<FwAssertArgType>(idlePacketSize));
126
127 239 const Fw::SerializeStatus status = Utils::IdlePacket::serialize(serializer, idlePacketSize);
128 239 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
129 239 }
130 } // namespace Ccsds
131 } // namespace Svc
132