GCC Code Coverage Report


Directory: lib/fprime-samd/fprime-samd/
File: Svc/TmFramer/TmFramer.cpp
Date: 2026-10-20 16:48:53
Exec Total Coverage
Lines: 160 163 98.2%
Functions: 11 11 100.0%
Branches: 128 222 57.7%

Line Branch Exec Source
1 // ======================================================================
2 // \title TmFramer.cpp
3 // \brief cpp file for CCSDS TM Transfer Frame downlink framer implementation class
4 // ======================================================================
5
6 #include "fprime-samd/Svc/TmFramer/TmFramer.hpp"
7 #include "Drv/ByteStreamDriverModel/ByteStreamStatusEnumAc.hpp"
8 #include "Fw/Com/ComBuffer.hpp"
9 #include "Fw/Types/Assert.hpp"
10 #include "Svc/Ccsds/Utils/CRC16.hpp"
11 #include "samd-config/FramerConfig.hpp"
12
13 namespace Samd21 {
14
15 // Out-of-class definition required pre-C++17 for any ODR-use of a static constexpr member
16 constexpr U8 TmFramer::IDLE_DATA_PATTERN;
17
18 static_assert(ComCfg::TmFrameFixedSize > Svc::Ccsds::TMHeader::SERIALIZED_SIZE + Svc::Ccsds::TMTrailer::SERIALIZED_SIZE,
19 "ComCfg::TmFrameFixedSize too small to hold TMHeader + TMTrailer");
20
21 static constexpr FwSizeType TM_DATA_FIELD_CAPACITY =
22 ComCfg::TmFrameFixedSize - (Svc::Ccsds::TMHeader::SERIALIZED_SIZE + Svc::Ccsds::TMTrailer::SERIALIZED_SIZE);
23
24 static constexpr FwSizeType IDLE_SPACE_PACKET_MIN_SIZE = Svc::Ccsds::SpacePacketHeader::SERIALIZED_SIZE + 1;
25 static constexpr FwSizeType MAX_SINGLE_SPACE_PACKET_SIZE =
26 Svc::Ccsds::SpacePacketHeader::SERIALIZED_SIZE + FW_COM_BUFFER_MAX_SIZE;
27 static_assert(TM_DATA_FIELD_CAPACITY < MAX_SINGLE_SPACE_PACKET_SIZE ||
28 (TM_DATA_FIELD_CAPACITY - MAX_SINGLE_SPACE_PACKET_SIZE) == 0 ||
29 (TM_DATA_FIELD_CAPACITY - MAX_SINGLE_SPACE_PACKET_SIZE) >= IDLE_SPACE_PACKET_MIN_SIZE,
30 "FW_COM_BUFFER_MAX_SIZE vs ComCfg::TmFrameFixedSize can leave an unfillable "
31 "single-packet remainder on an empty TM frame buffer");
32
33 // ----------------------------------------------------------------------
34 // Component construction and destruction
35 // ----------------------------------------------------------------------
36
37 11 TmFramer ::TmFramer(const char* const compName)
38 : TmFramerComponentBase(compName),
39 11 m_driverConnected(false),
40 11 m_activeBufferIdx(0),
41 11 m_droppedPackets(0),
42 11 m_apidOverflowCount(0),
43 11 m_numApidsTracked(0),
44 11 m_masterFrameCount(0),
45
3/8
✓ Branch 10 taken 44 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 44 times.
✓ Branch 14 taken 11 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
77 m_virtualFrameCount(0) {
46
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 11 times.
33 for (FwIndexType i = 0; i < 2; i++) {
47 22 m_buffers[i].dataFieldSize = 0;
48 22 m_buffers[i].state = IDLE;
49 }
50 11 }
51
52
3/4
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 44 times.
✓ Branch 12 taken 11 times.
110 TmFramer ::~TmFramer() {}
53
54 // ----------------------------------------------------------------------
55 // Handler implementations for typed input ports
56 // ----------------------------------------------------------------------
57
58 // Unlike stock Svc::Ccsds::TmFramer (one buffer per frame), this component accumulates
59 // multiple Space Packets per frame
60
61 304 void TmFramer ::comPacketQueueIn_handler(FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
62 304 TxBuffer* activeBuf = &m_buffers[m_activeBufferIdx];
63
64 // Space Packet header (6B) + payload, no idle padding included yet.
65 304 FwSizeType spaceNeeded = Svc::Ccsds::SpacePacketHeader::SERIALIZED_SIZE + data.getSize();
66
67 // If both buffers are in flight (backpressure), drop this packet
68
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 304 times.
304 if (activeBuf->state == TRANSMITTING) {
69 ✗ this->m_droppedPackets++;
70 ✗ return;
71 }
72
73 // Flush first if adding this Space Packet would overflow the data field, OR would fit but
74 // leave a remainder too small for closeFrame()'s idle pad (the dead zone described above).
75 304 FwSizeType afterAppend = activeBuf->dataFieldSize + spaceNeeded;
76 304 bool wouldOverflow = afterAppend > TM_DATA_FIELD_CAPACITY;
77 304 bool wouldLeaveDeadZone = false;
78
2/2
✓ Branch 0 taken 302 times.
✓ Branch 1 taken 2 times.
304 if (!wouldOverflow) {
79 302 FwSizeType remainderAfterAppend = TM_DATA_FIELD_CAPACITY - afterAppend;
80
4/4
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 299 times.
302 wouldLeaveDeadZone = remainderAfterAppend > 0 && remainderAfterAppend < IDLE_SPACE_PACKET_MIN_SIZE;
81 }
82
83
4/4
✓ Branch 0 taken 302 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 301 times.
304 if (wouldOverflow || wouldLeaveDeadZone) {
84 3 flushActiveBuffer();
85
86 // flushActiveBuffer() swapped the active buffer -- re-acquire it
87 3 activeBuf = &m_buffers[m_activeBufferIdx];
88
89 // If both buffers are in flight (backpressure), drop this packet
90
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
3 if (activeBuf->state == TRANSMITTING) {
91 1 this->m_droppedPackets++;
92 1 return;
93 }
94
95
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 FW_ASSERT(activeBuf->state == IDLE);
96
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 FW_ASSERT(activeBuf->dataFieldSize == 0);
97 }
98
99 // A single ComBuffer + Space Packet header must never exceed the entire data field
100 // capacity -- otherwise it could never fit in any frame regardless of flushing.
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 303 times.
303 FW_ASSERT(spaceNeeded <= TM_DATA_FIELD_CAPACITY, static_cast<FwAssertArgType>(spaceNeeded));
102
103
2/2
✓ Branch 2 taken 273 times.
✓ Branch 3 taken 30 times.
303 if (activeBuf->state == IDLE) {
104 273 activeBuf->state = ACTIVE;
105 }
106
107 // Data field starts after the (not-yet-written) TMHeader; append at that offset.
108 303 U8* dataFieldStart = activeBuf->data + Svc::Ccsds::TMHeader::SERIALIZED_SIZE;
109 606 FwSizeType written = appendSpacePacket(dataFieldStart + activeBuf->dataFieldSize,
110 303 TM_DATA_FIELD_CAPACITY - activeBuf->dataFieldSize, data);
111 303 activeBuf->dataFieldSize += written;
112
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 303 times.
303 FW_ASSERT(activeBuf->dataFieldSize <= TM_DATA_FIELD_CAPACITY,
113 static_cast<FwAssertArgType>(activeBuf->dataFieldSize));
114
115 // dataFieldSize must end up either exactly full or with room for a valid idle pad.
116 303 FwSizeType finalRemainder = TM_DATA_FIELD_CAPACITY - activeBuf->dataFieldSize;
117
3/4
✓ Branch 0 taken 301 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 301 times.
303 FW_ASSERT(finalRemainder == 0 || finalRemainder >= IDLE_SPACE_PACKET_MIN_SIZE,
118 static_cast<FwAssertArgType>(finalRemainder));
119 }
120
121 303 ComCfg::Apid TmFramer ::apidForComBuffer(const Fw::ComBuffer& data) const {
122 // Every ComBuffer from Fw::TlmPacket/Fw::LogPacket leads with a FwPacketDescriptorType
123 // (Fw::ComPacket::serializeBase()) that is bit-identical to the ComCfg::Apid value we
124 // want. Peek it via a temporary ExternalSerializeBuffer over the same memory so `data`'s
125 // own cursor is untouched -- setBuffLen() marks its bytes readable without copying.
126
2/4
✓ Branch 8 taken 303 times.
✗ Branch 9 not taken.
✓ Branch 18 taken 303 times.
✗ Branch 19 not taken.
303 Fw::ExternalSerializeBuffer peek(const_cast<U8*>(data.getBuffAddr()), data.getSize());
127
2/4
✓ Branch 8 taken 303 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 303 times.
✗ Branch 12 not taken.
303 Fw::SerializeStatus status = peek.setBuffLen(data.getSize());
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 303 times.
303 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
129 303 FwPacketDescriptorType descriptor = 0;
130
1/2
✓ Branch 2 taken 303 times.
✗ Branch 3 not taken.
303 status = peek.deserializeTo(descriptor);
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 303 times.
303 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
132
1/2
✓ Branch 1 taken 303 times.
✗ Branch 2 not taken.
606 return static_cast<ComCfg::Apid>(descriptor);
133 303 }
134
135 303 U16 TmFramer ::nextApidSequenceCount(ComCfg::Apid apid) {
136 303 FwIndexType slotIdx = -1;
137
2/2
✓ Branch 4 taken 300 times.
✓ Branch 5 taken 16 times.
316 for (FwIndexType i = 0; i < this->m_numApidsTracked; i++) {
138
2/2
✓ Branch 10 taken 287 times.
✓ Branch 11 taken 13 times.
300 if (this->m_apidSequenceCounts[i].apid == apid) {
139 287 slotIdx = i;
140 287 break;
141 }
142 }
143
144
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 287 times.
303 if (slotIdx == -1) {
145 // First time seeing this APID -- claim the next free slot if one is available. If
146 // every downlink packet source is accounted for in Samd21::FramerConfig::MAX_TRACKED_APIDS,
147 // This path must stay non-fatal because it can be reached while handling a
148 // fatal/assert packet, and a crash here would prevent that packet from ever being sent.
149
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 15 times.
16 if (this->m_numApidsTracked >= Samd21::FramerConfig::MAX_TRACKED_APIDS) {
150 1 this->m_apidOverflowCount++;
151 1 return 0;
152 }
153 15 slotIdx = this->m_numApidsTracked;
154 15 this->m_apidSequenceCounts[slotIdx].apid = apid;
155 15 this->m_apidSequenceCounts[slotIdx].count = 0;
156 15 this->m_numApidsTracked++;
157 }
158
159 302 U16 count = this->m_apidSequenceCounts[slotIdx].count;
160 // Sequence count is 14 bits, mod-16384 per APID (CCSDS 133.0-B-2 4.1.3.4).
161 604 this->m_apidSequenceCounts[slotIdx].count =
162 604 static_cast<U16>((count + 1) & Svc::Ccsds::SpacePacketSubfields::SeqCountMask);
163 302 return count;
164 }
165
166 303 FwSizeType TmFramer ::appendSpacePacket(U8* dest, FwSizeType destCapacity, Fw::ComBuffer& data) {
167
2/4
✓ Branch 5 taken 303 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 303 times.
303 FW_ASSERT(destCapacity >= Svc::Ccsds::SpacePacketHeader::SERIALIZED_SIZE + data.getSize());
168
169
1/2
✓ Branch 2 taken 303 times.
✗ Branch 3 not taken.
303 Fw::Buffer bufWrapper(dest, destCapacity);
170
3/6
✓ Branch 3 taken 303 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 303 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 303 times.
✗ Branch 11 not taken.
303 Fw::ExternalSerializeBuffer serializer(bufWrapper.getData(), bufWrapper.getSize());
171
172 // Space Packet primary header (CCSDS 133.0-B-2): Packet Type = 0 (TM), Secondary Header
173 // Flag = 0, Sequence Flags = 0b11 (unsegmented) for every packet this framer builds.
174
1/2
✓ Branch 3 taken 303 times.
✗ Branch 4 not taken.
303 ComCfg::Apid apid = apidForComBuffer(data);
175
176
1/2
✓ Branch 2 taken 303 times.
✗ Branch 3 not taken.
303 Svc::Ccsds::SpacePacketHeader header;
177 303 U16 packetIdentification = static_cast<U16>(apid) & Svc::Ccsds::SpacePacketSubfields::ApidMask;
178
1/2
✓ Branch 2 taken 303 times.
✗ Branch 3 not taken.
303 header.set_packetIdentification(packetIdentification);
179
180 303 U16 packetSequenceControl = static_cast<U16>(0x3 << Svc::Ccsds::SpacePacketSubfields::SeqFlagsOffset);
181
2/4
✓ Branch 5 taken 303 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 303 times.
✗ Branch 9 not taken.
303 packetSequenceControl |= (nextApidSequenceCount(apid) & Svc::Ccsds::SpacePacketSubfields::SeqCountMask);
182
1/2
✓ Branch 2 taken 303 times.
✗ Branch 3 not taken.
303 header.set_packetSequenceControl(packetSequenceControl);
183
184 // Packet Data Length = size of user data field minus one (CCSDS 133.0-B-2 4.1.3.5.3)
185
2/6
✓ Branch 5 taken 303 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 303 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
303 FW_ASSERT(data.getSize() > 0, static_cast<FwAssertArgType>(data.getSize()));
186
2/4
✓ Branch 6 taken 303 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 303 times.
✗ Branch 10 not taken.
303 header.set_packetDataLength(static_cast<U16>(data.getSize() - 1));
187
188
1/2
✓ Branch 2 taken 303 times.
✗ Branch 3 not taken.
303 Fw::SerializeStatus status = serializer.serializeFrom(header);
189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 303 times.
303 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
190
191
2/4
✓ Branch 6 taken 303 times.
✗ Branch 7 not taken.
✓ Branch 14 taken 303 times.
✗ Branch 15 not taken.
303 status = serializer.serializeFrom(data.getBuffAddr(), data.getSize(), Fw::Serialization::OMIT_LENGTH);
192
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 303 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
303 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status, data.getSize());
193
194
1/2
✓ Branch 2 taken 303 times.
✗ Branch 3 not taken.
606 return serializer.getSize();
195 303 }
196
197 11 void TmFramer ::drvConnected_handler(FwIndexType portNum) {
198 11 this->m_driverConnected = true;
199 11 }
200
201 263 void TmFramer ::drvReturnIn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer, const Drv::ByteStreamStatus& status) {
202
1/2
✓ Branch 0 taken 393 times.
✗ Branch 1 not taken.
393 for (FwIndexType i = 0; i < 2; i++) {
203
5/6
✓ Branch 5 taken 263 times.
✓ Branch 6 taken 130 times.
✓ Branch 14 taken 263 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 263 times.
✓ Branch 17 taken 130 times.
393 if (m_buffers[i].state == TRANSMITTING && fwBuffer.getData() == m_buffers[i].data) {
204 263 m_buffers[i].state = IDLE;
205 263 m_buffers[i].dataFieldSize = 0;
206 263 return;
207 }
208 }
209 ✗ FW_ASSERT(false); // Buffer returned that we didn't send
210 }
211
212 271 void TmFramer ::closeFrame(U8* frameData, FwSizeType dataFieldUsed) {
213 271 U8* dataField = frameData + Svc::Ccsds::TMHeader::SERIALIZED_SIZE;
214
215 // Pad the remainder of the data field with a CCSDS idle Space Packet
216 // (CCSDS 132.0-B-3 4.2.2.5).
217 271 FwSizeType remaining = TM_DATA_FIELD_CAPACITY - dataFieldUsed;
218
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 2 times.
271 if (remaining > 0) {
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 269 times.
269 FW_ASSERT(remaining >= Svc::Ccsds::SpacePacketHeader::SERIALIZED_SIZE + 1,
220 static_cast<FwAssertArgType>(remaining));
221
222
1/2
✓ Branch 3 taken 269 times.
✗ Branch 4 not taken.
269 Fw::Buffer idleWrapper(dataField + dataFieldUsed, remaining);
223
3/6
✓ Branch 3 taken 269 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 269 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 269 times.
✗ Branch 11 not taken.
269 Fw::ExternalSerializeBuffer idleSerializer(idleWrapper.getData(), idleWrapper.getSize());
224
225
1/2
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
269 Svc::Ccsds::SpacePacketHeader idleHeader;
226
1/2
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
269 idleHeader.set_packetIdentification(static_cast<U16>(ComCfg::Apid::SPP_IDLE_PACKET) &
227 Svc::Ccsds::SpacePacketSubfields::ApidMask);
228
1/2
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
269 idleHeader.set_packetSequenceControl(static_cast<U16>(0x3 << Svc::Ccsds::SpacePacketSubfields::SeqFlagsOffset));
229 269 FwSizeType idleDataLen = remaining - Svc::Ccsds::SpacePacketHeader::SERIALIZED_SIZE;
230
1/2
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
269 idleHeader.set_packetDataLength(static_cast<U16>(idleDataLen - 1));
231
232
1/2
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
269 Fw::SerializeStatus status = idleSerializer.serializeFrom(idleHeader);
233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 269 times.
269 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
234
2/2
✓ Branch 0 taken 266286 times.
✓ Branch 1 taken 269 times.
266555 for (FwSizeType i = 0; i < idleDataLen; i++) {
235
1/2
✓ Branch 2 taken 266286 times.
✗ Branch 3 not taken.
266286 status = idleSerializer.serializeFrom(IDLE_DATA_PATTERN);
236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266286 times.
266286 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
237 }
238 269 }
239
240 // -----------------------------------------------
241 // Header (TM Transfer Frame Primary Header, CCSDS 132.0-B-3 4.1.2)
242 // -----------------------------------------------
243
1/2
✓ Branch 2 taken 271 times.
✗ Branch 3 not taken.
271 Svc::Ccsds::TMHeader header;
244 271 U16 globalVcId = static_cast<U16>(
245 1 << Svc::Ccsds::TMSubfields::virtualChannelIdOffset); // VCID=1, this project's downlink virtual channel
246 271 globalVcId |= static_cast<U16>(ComCfg::SpacecraftId << Svc::Ccsds::TMSubfields::spacecraftIdOffset);
247 271 globalVcId |= 0x0; // Operational Control Field: Flag = 0 (no OCF present)
248
249 271 U16 dataFieldStatus = static_cast<U16>(0x3 << Svc::Ccsds::TMSubfields::segLengthOffset); // Seg Length Id = 0b11
250 // First Header Pointer = 0: the first Space Packet in every frame starts at data-field
251 // offset 0 (this framer never spans a packet across frames).
252
253
1/2
✓ Branch 2 taken 271 times.
✗ Branch 3 not taken.
271 header.set_globalVcId(globalVcId);
254
1/2
✓ Branch 6 taken 271 times.
✗ Branch 7 not taken.
271 header.set_masterFrameCount(this->m_masterFrameCount);
255
1/2
✓ Branch 6 taken 271 times.
✗ Branch 7 not taken.
271 header.set_virtualFrameCount(this->m_virtualFrameCount);
256
1/2
✓ Branch 2 taken 271 times.
✗ Branch 3 not taken.
271 header.set_dataFieldStatus(dataFieldStatus);
257
258 // Single Master Channel / Virtual Channel in this deployment, so both counters
259 // track together.
260 271 this->m_masterFrameCount++; // U8 wraps mod-256
261 271 this->m_virtualFrameCount++; // U8 wraps mod-256
262
263
1/2
✓ Branch 2 taken 271 times.
✗ Branch 3 not taken.
271 Fw::Buffer headerWrapper(frameData, Svc::Ccsds::TMHeader::SERIALIZED_SIZE);
264
3/6
✓ Branch 3 taken 271 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 271 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 271 times.
✗ Branch 11 not taken.
271 Fw::ExternalSerializeBuffer headerSerializer(headerWrapper.getData(), headerWrapper.getSize());
265
1/2
✓ Branch 2 taken 271 times.
✗ Branch 3 not taken.
271 Fw::SerializeStatus status = headerSerializer.serializeFrom(header);
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 271 times.
271 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
267
268 // -----------------------------------------------
269 // Trailer (FECF, CRC-16/CCITT-FALSE per CCSDS 132.0-B-3 4.1.6)
270 // -----------------------------------------------
271 U16 crc =
272
1/2
✓ Branch 1 taken 271 times.
✗ Branch 2 not taken.
271 Svc::Ccsds::Utils::CRC16::compute(frameData, ComCfg::TmFrameFixedSize - Svc::Ccsds::TMTrailer::SERIALIZED_SIZE);
273
1/2
✓ Branch 2 taken 271 times.
✗ Branch 3 not taken.
271 Svc::Ccsds::TMTrailer trailer;
274
1/2
✓ Branch 2 taken 271 times.
✗ Branch 3 not taken.
271 trailer.set_fecf(crc);
275
276 271 Fw::Buffer trailerWrapper(frameData + ComCfg::TmFrameFixedSize - Svc::Ccsds::TMTrailer::SERIALIZED_SIZE,
277
1/2
✓ Branch 2 taken 271 times.
✗ Branch 3 not taken.
271 Svc::Ccsds::TMTrailer::SERIALIZED_SIZE);
278
3/6
✓ Branch 3 taken 271 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 271 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 271 times.
✗ Branch 11 not taken.
271 Fw::ExternalSerializeBuffer trailerSerializer(trailerWrapper.getData(), trailerWrapper.getSize());
279
1/2
✓ Branch 2 taken 271 times.
✗ Branch 3 not taken.
271 status = trailerSerializer.serializeFrom(trailer);
280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 271 times.
271 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
281 542 }
282
283 273 void TmFramer ::flushActiveBuffer() {
284
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 273 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 273 times.
273 FW_ASSERT(this->m_driverConnected);
285
286 273 TxBuffer& activeBuf = m_buffers[m_activeBufferIdx];
287
288 // Nothing to flush if the buffer hasn't been touched since its last return.
289
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 271 times.
273 if (activeBuf.state == IDLE) {
290 2 return;
291 }
292
293
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 271 times.
271 FW_ASSERT(activeBuf.state == ACTIVE);
294
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 271 times.
271 FW_ASSERT(activeBuf.dataFieldSize > 0);
295
296
1/2
✓ Branch 7 taken 271 times.
✗ Branch 8 not taken.
271 closeFrame(activeBuf.data, activeBuf.dataFieldSize);
297
298 271 activeBuf.state = TRANSMITTING;
299 271 m_activeBufferIdx = (m_activeBufferIdx + 1) % 2;
300
301
1/2
✓ Branch 3 taken 271 times.
✗ Branch 4 not taken.
271 Fw::Buffer txBuffer(activeBuf.data, ComCfg::TmFrameFixedSize);
302
1/2
✓ Branch 5 taken 271 times.
✗ Branch 6 not taken.
271 drvSendOut_out(0, txBuffer);
303 271 }
304
305 275 void TmFramer ::schedIn_handler(FwIndexType portNum, U32 context) {
306
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 275 times.
✓ Branch 5 taken 275 times.
✗ Branch 6 not taken.
275 if (this->m_driverConnected) {
307 275 FwIndexType nextBufferIdx = (m_activeBufferIdx + 1) % 2;
308 275 TxBuffer& nextBuf = m_buffers[nextBufferIdx];
309
310
2/4
✓ Branch 6 taken 275 times.
✗ Branch 7 not taken.
✓ Branch 13 taken 275 times.
✗ Branch 14 not taken.
275 this->tlmWrite_DroppedPackets(this->m_droppedPackets);
311
2/4
✓ Branch 6 taken 275 times.
✗ Branch 7 not taken.
✓ Branch 13 taken 275 times.
✗ Branch 14 not taken.
275 this->tlmWrite_ApidOverflowCount(this->m_apidOverflowCount);
312
313
2/2
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 270 times.
275 if (nextBuf.state == TRANSMITTING) {
314 // Can't flush because both buffers would be in flight
315 5 return;
316 }
317
318 270 flushActiveBuffer();
319 }
320 }
321
322 } // namespace Samd21
323