GCC Code Coverage Report


Directory: Svc/BufferAccumulator/
File: BufferAccumulator.cpp
Date: 2026-10-14 21:17:34
Exec Total Coverage
Lines: 112 118 94.9%
Functions: 10 10 100.0%
Branches: 69 82 84.1%

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 8 BufferAccumulator ::BufferAccumulator(const char* const compName)
25 : BufferAccumulatorComponentBase(compName), //!< The component name
26
1/1
✓ Branch 3 taken 8 times.
8 m_mode(BufferAccumulator_OpState::ACCUMULATE),
27 8 m_bufferMemory(nullptr),
28
1/1
✓ Branch 5 taken 8 times.
8 m_bufferQueue(),
29 8 m_send(false),
30 8 m_waitForBuffer(false),
31 8 m_numWarnings(0u),
32 8 m_numDrained(0u),
33 8 m_numToDrain(0u),
34 8 m_opCode(),
35 8 m_cmdSeq(0u),
36 16 m_allocatorId(0) {}
37
38 16 BufferAccumulator ::~BufferAccumulator() {}
39
40 // ----------------------------------------------------------------------
41 // Public methods
42 // ----------------------------------------------------------------------
43
44 8 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 8 this->m_allocatorId = identifier;
51 // Overflow protection
52 8 FW_ASSERT(maxNumBuffers > 0);
53 8 FW_ASSERT((std::numeric_limits<FwSizeType>::max() / maxNumBuffers) >= sizeof(Fw::Buffer));
54 8 FwSizeType memSize = static_cast<FwSizeType>(sizeof(Fw::Buffer) * maxNumBuffers);
55 8 bool recoverable = false;
56 // A null or short allocation would be placement-new'd through by the queue below
57
1/1
✓ Branch 6 taken 8 times.
8 this->m_bufferMemory = static_cast<Fw::Buffer*>(allocator.checkedAllocate(identifier, memSize, recoverable));
58
1/1
✓ Branch 8 taken 8 times.
8 m_bufferQueue.init(this->m_bufferMemory, maxNumBuffers);
59
1/1
✓ Branch 6 taken 8 times.
8 this->m_mode = initialMode;
60 8 this->m_send = this->m_mode == BufferAccumulator_OpState::DRAIN;
61 8 }
62
63 8 void BufferAccumulator ::deallocateQueue(Fw::MemAllocator& allocator) {
64 8 allocator.deallocate(static_cast<FwEnumStoreType>(this->m_allocatorId), this->m_bufferMemory);
65 8 }
66
67 // ----------------------------------------------------------------------
68 // Handler implementations for user-defined typed input ports
69 // ----------------------------------------------------------------------
70
71 68 void BufferAccumulator ::bufferSendInFill_handler(const FwIndexType portNum, Fw::Buffer& buffer) {
72 68 const bool status = this->m_bufferQueue.enqueue(buffer);
73
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 3 times.
68 if (status) {
74
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 64 times.
65 if (this->m_numWarnings > 0) {
75 1 this->log_ACTIVITY_HI_BA_BufferAccepted();
76 }
77 65 this->m_numWarnings = 0;
78 } else {
79
2/2
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
3 if (this->m_numWarnings == 0) {
80 2 this->log_WARNING_HI_BA_QueueFull();
81 }
82 3 m_numWarnings++;
83 // The buffer is dropped; ownership must go back to its sender or the pool is depleted
84 3 this->bufferSendOutReturn_out(0, buffer);
85 }
86
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 68 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 57 times.
68 if (this->m_send) {
87 11 this->sendStoredBuffer();
88 }
89
90
3/3
✓ Branch 6 taken 68 times.
✓ Branch 12 taken 68 times.
✓ Branch 15 taken 68 times.
68 this->tlmWrite_BA_NumQueuedBuffers(static_cast<U32>(this->m_bufferQueue.getSize()));
91 68 }
92
93 53 void BufferAccumulator ::bufferSendInReturn_handler(const FwIndexType portNum, Fw::Buffer& buffer) {
94 53 this->bufferSendOutReturn_out(0, buffer);
95 53 this->m_waitForBuffer = false;
96
4/4
✓ Branch 6 taken 32 times.
✓ Branch 7 taken 21 times.
✓ Branch 8 taken 31 times.
✓ Branch 9 taken 22 times.
85 if ((this->m_mode == BufferAccumulator_OpState::DRAIN) || // we are draining ALL buffers
97
2/2
✓ Branch 8 taken 10 times.
✓ Branch 9 taken 22 times.
32 (this->m_numDrained < this->m_numToDrain)) { // OR we aren't done draining some buffers
98 // in a partial drain
99 31 this->m_send = true;
100 31 this->sendStoredBuffer();
101 }
102 53 }
103
104 1 void BufferAccumulator ::pingIn_handler(const FwIndexType portNum, U32 key) {
105 1 this->pingOut_out(0, key);
106 1 }
107
108 // ----------------------------------------------------------------------
109 // Command handler implementations
110 // ----------------------------------------------------------------------
111
112 7 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
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
7 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 7 this->m_mode = mode;
125
2/2
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 5 times.
7 if (mode == BufferAccumulator_OpState::DRAIN) {
126
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 if (!this->m_waitForBuffer) {
127 2 this->m_send = true;
128 2 this->sendStoredBuffer();
129 }
130 } else {
131 5 this->m_send = false;
132 }
133
2/2
✓ Branch 6 taken 7 times.
✓ Branch 9 taken 7 times.
7 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
134 7 }
135
136 26 void BufferAccumulator ::BA_DrainBuffers_cmdHandler(const FwOpcodeType opCode,
137 const U32 cmdSeq,
138 U32 numToDrain,
139 const BufferAccumulator_BlockMode& blockMode) {
140
2/2
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 25 times.
26 if (this->m_numDrained < this->m_numToDrain) {
141 2 this->log_WARNING_HI_BA_StillDraining(static_cast<U32>(this->m_numDrained),
142 1 static_cast<U32>(this->m_numToDrain));
143
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::BUSY);
144 1 return;
145 }
146
147
2/2
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 24 times.
25 if (this->m_mode == BufferAccumulator_OpState::DRAIN) {
148 1 this->log_WARNING_HI_BA_AlreadyDraining();
149
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
150 1 return;
151 }
152
153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 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 24 this->m_opCode = opCode;
160 24 this->m_cmdSeq = cmdSeq;
161 24 this->m_numDrained = 0;
162 24 this->m_numToDrain = static_cast<FwSizeType>(numToDrain);
163
164
2/2
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 22 times.
24 if (blockMode == BufferAccumulator_BlockMode::NOBLOCK) {
165 2 FwSizeType numBuffers = this->m_bufferQueue.getSize();
166
167
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (numBuffers < static_cast<FwSizeType>(numToDrain)) {
168 2 this->m_numToDrain = numBuffers;
169 2 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
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
2 if (0 == this->m_numToDrain) {
176 1 this->log_ACTIVITY_HI_BA_PartialDrainDone(0);
177
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
178 1 return;
179 }
180 }
181
182 // We are still waiting for a buffer from last time
183
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 23 times.
✗ Branch 6 not taken.
23 if (!this->m_waitForBuffer) {
184 23 this->m_send = true;
185 23 this->sendStoredBuffer(); // kick off the draining
186 }
187 }
188
189 // ----------------------------------------------------------------------
190 // Private helper methods
191 // ----------------------------------------------------------------------
192
193 67 void BufferAccumulator ::sendStoredBuffer() {
194 67 FW_ASSERT(this->m_send);
195
1/1
✓ Branch 2 taken 67 times.
67 Fw::Buffer buffer;
196
2/2
✓ Branch 4 taken 33 times.
✓ Branch 5 taken 34 times.
67 if ((this->m_numToDrain == 0) || // we are draining ALL buffers
197
1/2
✓ Branch 8 taken 33 times.
✗ Branch 9 not taken.
33 (this->m_numDrained < this->m_numToDrain)) { // OR we aren't done draining some buffers in a
198 // partial drain
199
1/1
✓ Branch 4 taken 67 times.
67 const bool status = this->m_bufferQueue.dequeue(buffer);
200
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12 times.
67 if (status) { // a buffer was dequeued
201 55 this->m_numDrained++;
202
1/1
✓ Branch 5 taken 55 times.
55 this->bufferSendOutDrain_out(0, buffer);
203 55 this->m_waitForBuffer = true;
204 55 this->m_send = false;
205
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 11 times.
12 } else if (this->m_numToDrain > 0) {
206
1/1
✓ Branch 8 taken 1 times.
2 this->log_WARNING_HI_BA_DrainStalled(static_cast<U32>(this->m_numDrained),
207 1 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
2/2
✓ Branch 4 taken 33 times.
✓ Branch 5 taken 34 times.
67 if ((this->m_numToDrain > 0) && // we are doing a partial drain
216
2/2
✓ Branch 8 taken 22 times.
✓ Branch 9 taken 11 times.
33 (this->m_numDrained == this->m_numToDrain)) { // AND we just finished draining
217 //
218
1/1
✓ Branch 9 taken 22 times.
22 this->log_ACTIVITY_HI_BA_PartialDrainDone(static_cast<U32>(this->m_numDrained));
219 // reset counters for partial buffer drain
220 22 this->m_numToDrain = 0;
221 22 this->m_numDrained = 0;
222 22 this->m_send = false;
223
2/2
✓ Branch 6 taken 22 times.
✓ Branch 17 taken 22 times.
22 this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::OK);
224 }
225
226
3/3
✓ Branch 6 taken 67 times.
✓ Branch 12 taken 67 times.
✓ Branch 15 taken 67 times.
67 this->tlmWrite_BA_NumQueuedBuffers(static_cast<U32>(this->m_bufferQueue.getSize()));
227 134 }
228
229 } // namespace Svc
230