GCC Code Coverage Report


Directory: ./
File: Svc/BufferAccumulator/BufferAccumulator.cpp
Date: 2026-09-03 21:13:48
Exec Total Coverage
Lines: 104 118 88.1%
Functions: 10 10 100.0%
Branches: 63 82 76.8%

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 7 BufferAccumulator ::BufferAccumulator(const char* const compName)
25 : BufferAccumulatorComponentBase(compName), //!< The component name
26
1/1
✓ Branch 3 taken 7 times.
7 m_mode(BufferAccumulator_OpState::ACCUMULATE),
27 7 m_bufferMemory(nullptr),
28
1/1
✓ Branch 5 taken 7 times.
7 m_bufferQueue(),
29 7 m_send(false),
30 7 m_waitForBuffer(false),
31 7 m_numWarnings(0u),
32 7 m_numDrained(0u),
33 7 m_numToDrain(0u),
34 7 m_opCode(),
35 7 m_cmdSeq(0u),
36 14 m_allocatorId(0) {}
37
38 14 BufferAccumulator ::~BufferAccumulator() {}
39
40 // ----------------------------------------------------------------------
41 // Public methods
42 // ----------------------------------------------------------------------
43
44 7 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 7 this->m_allocatorId = identifier;
51 // Overflow protection
52 7 FW_ASSERT(maxNumBuffers > 0);
53 7 FW_ASSERT((std::numeric_limits<FwSizeType>::max() / maxNumBuffers) >= sizeof(Fw::Buffer));
54 7 FwSizeType memSize = static_cast<FwSizeType>(sizeof(Fw::Buffer) * maxNumBuffers);
55 7 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 7 times.
7 this->m_bufferMemory = static_cast<Fw::Buffer*>(allocator.checkedAllocate(identifier, memSize, recoverable));
58
1/1
✓ Branch 8 taken 7 times.
7 m_bufferQueue.init(this->m_bufferMemory, maxNumBuffers);
59
1/1
✓ Branch 6 taken 7 times.
7 this->m_mode = initialMode;
60 7 this->m_send = this->m_mode == BufferAccumulator_OpState::DRAIN;
61 7 }
62
63 7 void BufferAccumulator ::deallocateQueue(Fw::MemAllocator& allocator) {
64 7 allocator.deallocate(static_cast<FwEnumStoreType>(this->m_allocatorId), this->m_bufferMemory);
65 7 }
66
67 // ----------------------------------------------------------------------
68 // Handler implementations for user-defined typed input ports
69 // ----------------------------------------------------------------------
70
71 66 void BufferAccumulator ::bufferSendInFill_handler(const FwIndexType portNum, Fw::Buffer& buffer) {
72 66 const bool status = this->m_bufferQueue.enqueue(buffer);
73
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 3 times.
66 if (status) {
74
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 62 times.
63 if (this->m_numWarnings > 0) {
75 1 this->log_ACTIVITY_HI_BA_BufferAccepted();
76 }
77 63 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 66 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 55 times.
66 if (this->m_send) {
87 11 this->sendStoredBuffer();
88 }
89
90
3/3
✓ Branch 6 taken 66 times.
✓ Branch 12 taken 66 times.
✓ Branch 15 taken 66 times.
66 this->tlmWrite_BA_NumQueuedBuffers(static_cast<U32>(this->m_bufferQueue.getSize()));
91 66 }
92
93 51 void BufferAccumulator ::bufferSendInReturn_handler(const FwIndexType portNum, Fw::Buffer& buffer) {
94 51 this->bufferSendOutReturn_out(0, buffer);
95 51 this->m_waitForBuffer = false;
96
4/4
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 21 times.
✓ Branch 8 taken 30 times.
✓ Branch 9 taken 21 times.
81 if ((this->m_mode == BufferAccumulator_OpState::DRAIN) || // we are draining ALL buffers
97
2/2
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 21 times.
30 (this->m_numDrained < this->m_numToDrain)) { // OR we aren't done draining some buffers
98 // in a partial drain
99 30 this->m_send = true;
100 30 this->sendStoredBuffer();
101 }
102 51 }
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 6 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 6 times.
6 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 6 this->m_mode = mode;
125
2/2
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
6 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 4 this->m_send = false;
132 }
133
2/2
✓ Branch 6 taken 6 times.
✓ Branch 9 taken 6 times.
6 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
134 6 }
135
136 24 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 23 times.
24 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 22 times.
23 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 22 times.
22 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 22 this->m_opCode = opCode;
160 22 this->m_cmdSeq = cmdSeq;
161 22 this->m_numDrained = 0;
162 22 this->m_numToDrain = static_cast<FwSizeType>(numToDrain);
163
164
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 22 times.
22 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
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
22 if (!this->m_waitForBuffer) {
184 22 this->m_send = true;
185 22 this->sendStoredBuffer(); // kick off the draining
186 }
187 }
188
189 // ----------------------------------------------------------------------
190 // Private helper methods
191 // ----------------------------------------------------------------------
192
193 65 void BufferAccumulator ::sendStoredBuffer() {
194 65 FW_ASSERT(this->m_send);
195
1/1
✓ Branch 2 taken 65 times.
65 Fw::Buffer buffer;
196
2/2
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 34 times.
65 if ((this->m_numToDrain == 0) || // we are draining ALL buffers
197
1/2
✓ Branch 8 taken 31 times.
✗ Branch 9 not taken.
31 (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 65 times.
65 const bool status = this->m_bufferQueue.dequeue(buffer);
200
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 12 times.
65 if (status) { // a buffer was dequeued
201 53 this->m_numDrained++;
202
1/1
✓ Branch 5 taken 53 times.
53 this->bufferSendOutDrain_out(0, buffer);
203 53 this->m_waitForBuffer = true;
204 53 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 31 times.
✓ Branch 5 taken 34 times.
65 if ((this->m_numToDrain > 0) && // we are doing a partial drain
216
2/2
✓ Branch 8 taken 21 times.
✓ Branch 9 taken 10 times.
31 (this->m_numDrained == this->m_numToDrain)) { // AND we just finished draining
217 //
218
1/1
✓ Branch 9 taken 21 times.
21 this->log_ACTIVITY_HI_BA_PartialDrainDone(static_cast<U32>(this->m_numDrained));
219 // reset counters for partial buffer drain
220 21 this->m_numToDrain = 0;
221 21 this->m_numDrained = 0;
222 21 this->m_send = false;
223
2/2
✓ Branch 6 taken 21 times.
✓ Branch 17 taken 21 times.
21 this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::OK);
224 }
225
226
3/3
✓ Branch 6 taken 65 times.
✓ Branch 12 taken 65 times.
✓ Branch 15 taken 65 times.
65 this->tlmWrite_BA_NumQueuedBuffers(static_cast<U32>(this->m_bufferQueue.getSize()));
227 130 }
228
229 } // namespace Svc
230