GCC Code Coverage Report


Directory: ./
File: BufferAccumulator.cpp
Date: 2026-09-03 22:13:16
Exec Total Coverage
Lines: 60 118 50.8%
Functions: 8 10 80.0%
Branches: 24 76 31.6%

Line Branch Exec Source
1 // ======================================================================
2 // \title BufferAccumulator.cpp
3 // \author bocchino
4 // \brief BufferAccumulator implementation
5 //
6 // \copyright
7 // Copyright (C) 2017 California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12
13 #include "Svc/BufferAccumulator/BufferAccumulator.hpp"
14
15 #include <limits>
16 #include "Fw/Types/BasicTypes.hpp"
17
18 namespace Svc {
19
20 // ----------------------------------------------------------------------
21 // Construction, initialization, and destruction
22 // ----------------------------------------------------------------------
23
24 1 BufferAccumulator ::BufferAccumulator(const char* const compName)
25 : BufferAccumulatorComponentBase(compName), //!< The component name
26 1 m_mode(BufferAccumulator_OpState::ACCUMULATE),
27 1 m_bufferMemory(nullptr),
28
1/1
✓ Branch 1 taken 1 times.
1 m_bufferQueue(),
29 1 m_send(false),
30 1 m_waitForBuffer(false),
31 1 m_numWarnings(0u),
32 1 m_numDrained(0u),
33 1 m_numToDrain(0u),
34 1 m_opCode(),
35 1 m_cmdSeq(0u),
36
1/1
✓ Branch 2 taken 1 times.
2 m_allocatorId(0) {}
37
38 2 BufferAccumulator ::~BufferAccumulator() {}
39
40 // ----------------------------------------------------------------------
41 // Public methods
42 // ----------------------------------------------------------------------
43
44 1 void BufferAccumulator ::allocateQueue(FwEnumStoreType identifier,
45 Fw::MemAllocator& allocator,
46 FwSizeType maxNumBuffers, //!< The maximum number of buffers
47 BufferAccumulator_OpState initialMode
48 //!< The initial operating mode
49 ) {
50 1 this->m_allocatorId = identifier;
51 // Overflow protection
52 1 FW_ASSERT(maxNumBuffers > 0);
53 1 FW_ASSERT((std::numeric_limits<FwSizeType>::max() / maxNumBuffers) >= sizeof(Fw::Buffer));
54 1 FwSizeType memSize = static_cast<FwSizeType>(sizeof(Fw::Buffer) * maxNumBuffers);
55 1 bool recoverable = false;
56 // A null or short allocation would be placement-new'd through by the queue below
57
1/1
✓ Branch 1 taken 1 times.
1 this->m_bufferMemory = static_cast<Fw::Buffer*>(allocator.checkedAllocate(identifier, memSize, recoverable));
58
1/1
✓ Branch 1 taken 1 times.
1 m_bufferQueue.init(this->m_bufferMemory, maxNumBuffers);
59
1/1
✓ Branch 1 taken 1 times.
1 this->m_mode = initialMode;
60 1 this->m_send = this->m_mode == BufferAccumulator_OpState::DRAIN;
61 1 }
62
63 1 void BufferAccumulator ::deallocateQueue(Fw::MemAllocator& allocator) {
64 1 allocator.deallocate(static_cast<FwEnumStoreType>(this->m_allocatorId), this->m_bufferMemory);
65 1 }
66
67 // ----------------------------------------------------------------------
68 // Handler implementations for user-defined typed input ports
69 // ----------------------------------------------------------------------
70
71 2 void BufferAccumulator ::bufferSendInFill_handler(const FwIndexType portNum, Fw::Buffer& buffer) {
72 2 const bool status = this->m_bufferQueue.enqueue(buffer);
73
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (status) {
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (this->m_numWarnings > 0) {
75 this->log_ACTIVITY_HI_BA_BufferAccepted();
76 }
77 2 this->m_numWarnings = 0;
78 } else {
79 if (this->m_numWarnings == 0) {
80 this->log_WARNING_HI_BA_QueueFull();
81 }
82 m_numWarnings++;
83 // The buffer is dropped; ownership must go back to its sender or the pool is depleted
84 this->bufferSendOutReturn_out(0, buffer);
85 }
86
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (this->m_send) {
87 2 this->sendStoredBuffer();
88 }
89
90
3/3
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
2 this->tlmWrite_BA_NumQueuedBuffers(static_cast<U32>(this->m_bufferQueue.getSize()));
91 2 }
92
93 2 void BufferAccumulator ::bufferSendInReturn_handler(const FwIndexType portNum, Fw::Buffer& buffer) {
94 2 this->bufferSendOutReturn_out(0, buffer);
95 2 this->m_waitForBuffer = false;
96
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 if ((this->m_mode == BufferAccumulator_OpState::DRAIN) || // we are draining ALL buffers
97 (this->m_numDrained < this->m_numToDrain)) { // OR we aren't done draining some buffers
98 // in a partial drain
99 2 this->m_send = true;
100 2 this->sendStoredBuffer();
101 }
102 2 }
103
104 59 void BufferAccumulator ::pingIn_handler(const FwIndexType portNum, U32 key) {
105 59 this->pingOut_out(0, key);
106 59 }
107
108 // ----------------------------------------------------------------------
109 // Command handler implementations
110 // ----------------------------------------------------------------------
111
112 void BufferAccumulator ::BA_SetMode_cmdHandler(const FwOpcodeType opCode,
113 const U32 cmdSeq,
114 const BufferAccumulator_OpState& mode) {
115 // cancel an in-progress partial drain
116 if (this->m_numToDrain > 0) {
117 // reset counters for partial buffer drain
118 this->m_numToDrain = 0;
119 this->m_numDrained = 0;
120 // respond to the original command
121 this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::OK);
122 }
123
124 this->m_mode = mode;
125 if (mode == BufferAccumulator_OpState::DRAIN) {
126 if (!this->m_waitForBuffer) {
127 this->m_send = true;
128 this->sendStoredBuffer();
129 }
130 } else {
131 this->m_send = false;
132 }
133 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
134 }
135
136 void BufferAccumulator ::BA_DrainBuffers_cmdHandler(const FwOpcodeType opCode,
137 const U32 cmdSeq,
138 U32 numToDrain,
139 const BufferAccumulator_BlockMode& blockMode) {
140 if (this->m_numDrained < this->m_numToDrain) {
141 this->log_WARNING_HI_BA_StillDraining(static_cast<U32>(this->m_numDrained),
142 static_cast<U32>(this->m_numToDrain));
143 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::BUSY);
144 return;
145 }
146
147 if (this->m_mode == BufferAccumulator_OpState::DRAIN) {
148 this->log_WARNING_HI_BA_AlreadyDraining();
149 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
150 return;
151 }
152
153 if (numToDrain == 0) {
154 this->log_ACTIVITY_HI_BA_PartialDrainDone(0);
155 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
156 return;
157 }
158
159 this->m_opCode = opCode;
160 this->m_cmdSeq = cmdSeq;
161 this->m_numDrained = 0;
162 this->m_numToDrain = static_cast<FwSizeType>(numToDrain);
163
164 if (blockMode == BufferAccumulator_BlockMode::NOBLOCK) {
165 FwSizeType numBuffers = this->m_bufferQueue.getSize();
166
167 if (numBuffers < static_cast<FwSizeType>(numToDrain)) {
168 this->m_numToDrain = numBuffers;
169 this->log_WARNING_LO_BA_NonBlockDrain(static_cast<U32>(this->m_numToDrain), numToDrain);
170 }
171
172 /* OK if there were 0 buffers queued, and we
173 * end up setting numToDrain to 0
174 */
175 if (0 == this->m_numToDrain) {
176 this->log_ACTIVITY_HI_BA_PartialDrainDone(0);
177 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
178 return;
179 }
180 }
181
182 // We are still waiting for a buffer from last time
183 if (!this->m_waitForBuffer) {
184 this->m_send = true;
185 this->sendStoredBuffer(); // kick off the draining
186 }
187 }
188
189 // ----------------------------------------------------------------------
190 // Private helper methods
191 // ----------------------------------------------------------------------
192
193 4 void BufferAccumulator ::sendStoredBuffer() {
194 4 FW_ASSERT(this->m_send);
195
1/1
✓ Branch 1 taken 4 times.
4 Fw::Buffer buffer;
196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if ((this->m_numToDrain == 0) || // we are draining ALL buffers
197 (this->m_numDrained < this->m_numToDrain)) { // OR we aren't done draining some buffers in a
198 // partial drain
199
1/1
✓ Branch 1 taken 4 times.
4 const bool status = this->m_bufferQueue.dequeue(buffer);
200
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (status) { // a buffer was dequeued
201 2 this->m_numDrained++;
202
1/1
✓ Branch 1 taken 2 times.
2 this->bufferSendOutDrain_out(0, buffer);
203 2 this->m_waitForBuffer = true;
204 2 this->m_send = false;
205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (this->m_numToDrain > 0) {
206 this->log_WARNING_HI_BA_DrainStalled(static_cast<U32>(this->m_numDrained),
207 static_cast<U32>(this->m_numToDrain));
208 }
209 }
210
211 /* This used to be "else if", but then you wait for all
212 * drained buffers in a partial drain to be RETURNED before returning OK.
213 * Correct thing is to return OK once they are SENT
214 */
215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if ((this->m_numToDrain > 0) && // we are doing a partial drain
216 (this->m_numDrained == this->m_numToDrain)) { // AND we just finished draining
217 //
218 this->log_ACTIVITY_HI_BA_PartialDrainDone(static_cast<U32>(this->m_numDrained));
219 // reset counters for partial buffer drain
220 this->m_numToDrain = 0;
221 this->m_numDrained = 0;
222 this->m_send = false;
223 this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::OK);
224 }
225
226
3/3
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
4 this->tlmWrite_BA_NumQueuedBuffers(static_cast<U32>(this->m_bufferQueue.getSize()));
227 4 }
228
229 } // namespace Svc
230