GCC Code Coverage Report


Directory: ./
File: Svc/WasmSequencer/WasmSequencer.cpp
Date: 2026-11-03 21:15:54
Exec Total Coverage
Lines: 302 313 96.5%
Functions: 24 25 96.0%
Branches: 209 225 92.9%

Line Branch Exec Source
1 // ======================================================================
2 // \title WasmSequencer.cpp
3 // \author tumbar
4 // \brief cpp file for WasmSequencer component implementation class
5 // ======================================================================
6
7 #include "Svc/WasmSequencer/WasmSequencer.hpp"
8
9 #include "Fw/Cmd/CmdResponseEnumAc.hpp"
10 #include "Fw/Types/Assert.hpp"
11 #include "Fw/Types/LinearBufferTemplate.hpp"
12 #include "Fw/Types/Serializable.hpp"
13 #include "Fw/Types/SuccessEnumAc.hpp"
14 #include "Os/Mutex.hpp"
15 #include "Svc/Seq/BlockStateEnumAc.hpp"
16 #include "Svc/Seq/SeqArgsSerializableAc.hpp"
17 #include "Svc/WasmSequencer/WasmSequencer_CommandRequestSerializableAc.hpp"
18 #include "Svc/WasmSequencer/WasmSequencer_ControllerStateMachine_StateEnumAc.hpp"
19 #include "Svc/WasmSequencer/WasmSequencer_HostFunctionEnumAc.hpp"
20 #include "Svc/WasmSequencer/WasmSequencer_InvokeRequestSerializableAc.hpp"
21 #include "Svc/WasmSequencer/WasmSequencer_LoadRequestSerializableAc.hpp"
22 #include "Svc/WasmSequencer/WasmSequencer_SignalSourceEnumAc.hpp"
23 #include "Svc/WasmSequencer/fprime_spacewasm/include/fprime_spacewasm.h"
24 #include "Svc/WasmSequencer/spacewasm_include/spacewasm.h"
25 #include "config/CommandDispatcherImplCfg.hpp"
26 #include "config/FwAssertArgTypeAliasAc.h"
27 #include "config/FwIndexTypeAliasAc.h"
28 #include "config/FwSizeTypeAliasAc.h"
29
30 namespace Svc {
31
32 329 U8* WasmSequencer ::globalAllocCallback(void* userdata, size_t size, size_t align) {
33
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 329 times.
329 if (userdata == nullptr) {
34 ✗ return nullptr;
35 }
36 329 return static_cast<WasmSequencer*>(userdata)->globalAlloc(static_cast<U32>(size), static_cast<U32>(align));
37 }
38
39 329 void WasmSequencer ::globalDeallocCallback(void* userdata, U8* ptr, size_t size, size_t align) {
40 (void)size;
41 (void)align;
42
1/2
✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
329 if (userdata != nullptr) {
43 329 static_cast<WasmSequencer*>(userdata)->globalDealloc(ptr);
44 }
45 329 }
46
47 // ----------------------------------------------------------------------
48 // Component construction and destruction
49 // ----------------------------------------------------------------------
50
51 218 WasmSequencer ::WasmSequencer(const char* const compName)
52 : WasmSequencerComponentBase(compName),
53 218 m_heapPages(nullptr),
54 218 m_heapPagesUsed(0),
55 218 m_heapPoisoned(false),
56 218 m_guestPool(nullptr),
57 218 m_guestPoolOffset(0),
58 218 m_wasm(nullptr),
59 218 m_hasExecutingContext(false),
60
1/1
✓ Branch 5 taken 218 times.
218 m_pendingTimer(),
61 218 m_hasPendingTimer(false),
62
1/1
✓ Branch 5 taken 218 times.
218 m_hostFunctionStart(),
63 218 m_hasHostFunctionStart(false),
64 218 m_dequeueSucceeded(false),
65 218 m_invokeStatus(SPACEWASM_OK),
66 218 m_pendingPause(false),
67 218 m_cancelRequested(false),
68 218 m_writeTelemetryQueued(false),
69
11/11
✓ Branch 17 taken 218 times.
✓ Branch 23 taken 218 times.
✓ Branch 29 taken 218 times.
✓ Branch 35 taken 218 times.
✓ Branch 45 taken 218 times.
✓ Branch 51 taken 218 times.
✓ Branch 57 taken 1090 times.
✓ Branch 60 taken 1090 times.
✓ Branch 61 taken 218 times.
✓ Branch 67 taken 218 times.
✓ Branch 73 taken 218 times.
1962 m_sequencesStarted(0) {}
70
71 216 void WasmSequencer ::configure(const Config& cfg, Fw::MemAllocator& mallocator) {
72 216 FW_ASSERT(this->m_wasm == nullptr);
73 216 FW_ASSERT(this->m_allocator == nullptr);
74
75 216 getGlobalAllocatorLock()->lock();
76 216 const auto status = spacewasm_fprime_register_global_allocator(&globalAllocCallback, &globalDeallocCallback, this);
77 216 getGlobalAllocatorLock()->unlock();
78
79 216 FW_ASSERT(status == SPACEWASM_OK, status);
80
81 216 this->m_config = cfg;
82
83 // Allocate the heap memory pool
84 {
85 216 FW_ASSERT(
86 this->m_config.heapPages > 0 && this->m_config.heapPages <= Svc::WasmSequencerConfig::SPACEWASM_MAX_PAGES,
87 static_cast<FwAssertArgType>(this->m_config.heapPages), Svc::WasmSequencerConfig::SPACEWASM_MAX_PAGES);
88
89 // Allocate the heap page list
90 {
91 216 FwSizeType actualSize = sizeof(U8*) * this->m_config.heapPages;
92
1/1
✓ Branch 4 taken 216 times.
216 auto ptr = mallocator.checkedAllocate(0, actualSize);
93 216 this->m_heapPages = reinterpret_cast<U8**>(ptr);
94 }
95
96 // Allocate each heap page
97
2/2
✓ Branch 4 taken 864 times.
✓ Branch 5 taken 216 times.
1080 for (FwSizeType i = 0; i < this->m_config.heapPages; i++) {
98 864 auto actualSize = Svc::WasmSequencerConfig::SPACEWASM_PAGE_SIZE;
99 auto ptr =
100
1/1
✓ Branch 4 taken 864 times.
864 mallocator.checkedAllocate(static_cast<FwIndexType>(i) + 1, actualSize, SPACEWASM_MEMORY_ALIGNMENT);
101 864 this->m_heapPages[i] = reinterpret_cast<U8*>(ptr);
102 }
103 216 this->m_heapPagesUsed = 0;
104 }
105
106 // Allocate the guest memory pool
107 {
108 216 auto actualSize = this->m_config.guestMemorySize;
109
1/1
✓ Branch 8 taken 216 times.
216 auto ptr = mallocator.checkedAllocate(static_cast<FwIndexType>(this->m_config.heapPages) + 1, actualSize,
110 SPACEWASM_MEMORY_ALIGNMENT);
111 216 this->m_guestPoolOffset = 0;
112 216 this->m_guestPool = reinterpret_cast<U8*>(ptr);
113 }
114
115 // Allocate the serialOut buffer
116
2/2
✓ Branch 4 taken 215 times.
✓ Branch 5 taken 1 times.
216 if (this->m_config.serialOutMax > 0) {
117 215 auto actualSize = this->m_config.serialOutMax;
118
1/1
✓ Branch 8 taken 215 times.
215 auto ptr = mallocator.checkedAllocate(static_cast<FwIndexType>(this->m_config.heapPages) + 2, actualSize);
119
1/1
✓ Branch 6 taken 215 times.
215 this->m_serialOutBuffer.setExtBuffer(reinterpret_cast<U8*>(ptr), actualSize);
120 }
121
122 // Allocate the serialIn queues
123 {
124
1/1
✓ Branch 5 taken 216 times.
216 Os::ScopeLock scopeLock(this->m_serialInMutex);
125
2/2
✓ Branch 0 taken 1080 times.
✓ Branch 1 taken 216 times.
1296 for (FwIndexType i = 0; i < NUM_SERIALIN_INPUT_PORTS; i++) {
126
2/2
✓ Branch 5 taken 1079 times.
✓ Branch 6 taken 1 times.
1080 if (this->m_config.serialIn[i].size > 0) {
127 1079 auto actualSize = this->m_config.serialIn[i].size;
128 auto ptr =
129
1/1
✓ Branch 8 taken 1079 times.
1079 mallocator.checkedAllocate(static_cast<FwIndexType>(this->m_config.heapPages) + 3 + i, actualSize);
130
1/1
✓ Branch 5 taken 1079 times.
1079 this->m_serialInQueue[i].setup(reinterpret_cast<U8*>(ptr), actualSize);
131 }
132 }
133 216 }
134
135 // Allocate the initial store
136 216 this->m_allocator = &mallocator;
137 216 this->createStore();
138 216 }
139
140 218 void WasmSequencer ::deinit() {
141
2/2
✓ Branch 4 taken 216 times.
✓ Branch 5 taken 2 times.
218 if (this->m_wasm != nullptr) {
142 216 this->destroyStore();
143 }
144
145
2/2
✓ Branch 4 taken 216 times.
✓ Branch 5 taken 2 times.
218 if (this->m_allocator != nullptr) {
146 // Deallocate each heap page
147
2/2
✓ Branch 4 taken 864 times.
✓ Branch 5 taken 216 times.
1080 for (FwSizeType i = 0; i < this->m_config.heapPages; i++) {
148 864 this->m_allocator->deallocate(static_cast<FwIndexType>(i) + 1, this->m_heapPages[i]);
149 864 this->m_heapPages[i] = nullptr;
150 }
151
152 // Deallocate the heap page pool
153 216 this->m_allocator->deallocate(0, this->m_heapPages);
154
155 // Deallocate the guest memory pool
156
1/2
✓ Branch 4 taken 216 times.
✗ Branch 5 not taken.
216 if (this->m_guestPool != nullptr) {
157 216 this->m_allocator->deallocate(static_cast<FwIndexType>(this->m_config.heapPages) + 1, this->m_guestPool);
158 }
159
160 // Deallocate the serialOut buffer
161
2/2
✓ Branch 6 taken 215 times.
✓ Branch 7 taken 1 times.
216 if (this->m_serialOutBuffer.getBuffAddr() != nullptr) {
162 430 this->m_allocator->deallocate(static_cast<FwIndexType>(this->m_config.heapPages) + 2,
163 215 this->m_serialOutBuffer.getBuffAddr());
164 }
165
166 // Deallocate the serialIn queues
167
2/2
✓ Branch 0 taken 1080 times.
✓ Branch 1 taken 216 times.
1296 for (FwIndexType i = 0; i < NUM_SERIALIN_INPUT_PORTS; i++) {
168
2/2
✓ Branch 5 taken 1078 times.
✓ Branch 6 taken 2 times.
1080 if (this->m_serialInQueue[i].get_capacity() > 0) {
169 2156 this->m_allocator->deallocate(static_cast<FwIndexType>(this->m_config.heapPages) + 3 + i,
170 1078 this->m_serialInQueue[i].get_buffer());
171 }
172 }
173 }
174
175 // Release our slot in the process-wide global-allocator registry so it can
176 // be reused by a later sequencer instance.
177 218 getGlobalAllocatorLock()->lock();
178 218 (void)spacewasm_fprime_deregister_global_allocator(this);
179 218 getGlobalAllocatorLock()->unlock();
180
181 // Clean up dangling pointers
182 218 this->m_allocator = nullptr;
183 218 this->m_wasm = nullptr;
184
185 218 WasmSequencerComponentBase::deinit();
186 218 }
187
188 // ----------------------------------------------------------------------
189 // Handler implementations for typed input ports
190 // ----------------------------------------------------------------------
191
192 11 void WasmSequencer ::checkTimers_handler(FwIndexType portNum, U32 context) {
193 // Drive the sleep-wake / host-function-timeout checks in the state machine.
194 11 this->interpreter_sendSignal_checkTimers();
195 11 }
196
197 18 void WasmSequencer ::cmdResponseIn_handler(FwIndexType portNum,
198 FwOpcodeType opCode,
199 U32 cmdSeq,
200 const Fw::CmdResponse& response) {
201 18 FW_ASSERT(this->m_wasm != nullptr);
202
203 // The CmdDisp echoes back the context we sent, not a real cmdSeq. We packed
204 // our cmdUid into that context (see makeCmdUid); rename for clarity.
205 18 const U32 cmdUid = cmdSeq;
206 18 const U16 sequenceIndex = static_cast<U16>((cmdUid & 0xFFFF0000) >> 16);
207 18 const U16 cmdIndex = static_cast<U16>(cmdUid & 0xFFFF);
208 18 const U16 currentSequenceIndex = static_cast<U16>(this->m_sequencesStarted & 0xFFFF);
209 18 const U16 currentCmdIndex = static_cast<U16>(this->m_tlm.commandsDispatched & 0xFFFF);
210
211 // If the response is from a previous execution window, treat it as a nominal
212 // late reply (e.g. a command that returned after a CANCEL) and just report it
213 // without failing the current sequence.
214
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (sequenceIndex != currentSequenceIndex) {
215 2 this->log_WARNING_LO_CmdResponseFromOldSequence(CmdDispatcherCfg::getEventOpcode(opCode), response,
216 sequenceIndex, currentSequenceIndex);
217 2 return;
218 }
219
220 // From here on the response claims to be from the current sequence, so any
221 // inconsistency is a genuine error that should fail the sequence.
222
4/9
✓ Branch 2 taken 16 times.
✓ Branch 10 taken 16 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 5 times.
✓ Branch 14 taken 11 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
32 if (this->interpreter_getState() !=
223
4/6
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
43 WasmSequencer_InterpreterStateMachine_State::RUNNING_AWAITING_RESPONSE_WAITING ||
224 11 this->m_pendingHostFunction.kind != WasmSequencer_HostFunction::COMMAND) {
225
2/2
✓ Branch 6 taken 5 times.
✓ Branch 10 taken 5 times.
5 this->interpreter_sendSignal_hostResponseUnexpected(WasmSequencer_HostFunction::COMMAND);
226 5 return;
227 }
228
229 // Awaiting a command response, but was it for this exact dispatch instance, or
230 // an earlier one in this sequence with the same opcode?
231
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (cmdIndex != currentCmdIndex) {
232 1 this->log_WARNING_HI_WrongCmdResponseIndex(CmdDispatcherCfg::getEventOpcode(opCode), response, cmdIndex,
233 currentCmdIndex);
234
2/2
✓ Branch 6 taken 1 times.
✓ Branch 10 taken 1 times.
1 this->interpreter_sendSignal_hostResponseUnexpected(WasmSequencer_HostFunction::COMMAND);
235 1 return;
236 }
237
238 10 this->m_pendingHostFunction.clear();
239
240 // Track commands that came back with a non-OK response.
241
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 9 times.
10 if (response != Fw::CmdResponse::OK) {
242 1 this->m_tlm.commandsFailed++;
243 }
244
245
1/2
✗ Branch 7 not taken.
✓ Branch 8 taken 10 times.
10 this->interpreter_sendSignal_hostResumeI32(static_cast<I32>(response.e));
246 }
247
248 28 void WasmSequencer ::writeTelemetry_handler(FwIndexType portNum, U32 context) {
249 28 bool expected = false;
250
1/2
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
28 if (this->m_writeTelemetryQueued.compare_exchange_strong(expected, true)) {
251
1/1
✓ Branch 5 taken 28 times.
28 this->writeTelemetryInternal_internalInterfaceInvoke();
252 }
253 28 }
254
255 ✗ void WasmSequencer ::writeTelemetryInternal_overflowHook() {
256 ✗ this->m_writeTelemetryQueued = false;
257 ✗ }
258
259 28 void WasmSequencer ::writeTelemetryInternal_internalInterfaceHandler() {
260 28 this->m_writeTelemetryQueued = false;
261 28 FW_ASSERT(this->m_wasm != nullptr);
262
263
1/1
✓ Branch 3 taken 28 times.
28 auto now = this->getTime();
264
265
3/3
✓ Branch 6 taken 28 times.
✓ Branch 11 taken 28 times.
✓ Branch 15 taken 28 times.
28 this->tlmWrite_ControllerState(this->controller_getState(), now);
266
3/3
✓ Branch 6 taken 28 times.
✓ Branch 11 taken 28 times.
✓ Branch 15 taken 28 times.
28 this->tlmWrite_InterpreterState(this->interpreter_getState(), now);
267
2/2
✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
28 this->tlmWrite_SequencesSucceeded(this->m_tlm.sequencesSucceeded, now);
268
2/2
✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
28 this->tlmWrite_SequencesFailed(this->m_tlm.sequencesFailed, now);
269
2/2
✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
28 this->tlmWrite_SequencesCancelled(this->m_tlm.sequencesCancelled, now);
270
2/2
✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
28 this->tlmWrite_CommandsDispatched(this->m_tlm.commandsDispatched, now);
271
2/2
✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
28 this->tlmWrite_CommandsFailed(this->m_tlm.commandsFailed, now);
272
2/2
✓ Branch 6 taken 28 times.
✓ Branch 12 taken 28 times.
28 this->tlmWrite_LastTrapReason(this->m_exit.lastTrapReason, now);
273
2/2
✓ Branch 6 taken 28 times.
✓ Branch 12 taken 28 times.
28 this->tlmWrite_SeqName(this->m_tlm.sequenceName, now);
274 56 }
275
276 12 void WasmSequencer ::seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& filename, const Svc::SeqArgs& args) {
277 12 FW_ASSERT(this->m_wasm != nullptr);
278
279
1/1
✓ Branch 2 taken 12 times.
12 Fw::String runModuleName = "";
280
281
2/2
✓ Branch 6 taken 12 times.
✓ Branch 10 taken 12 times.
36 this->controller_sendSignal_run(Svc::WasmSequencer_LoadRequest(
282 filename, runModuleName,
283
2/2
✓ Branch 3 taken 12 times.
✓ Branch 7 taken 12 times.
24 Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::PORT_RUN, WasmSequencer_CommandRequest(0, 0),
284 BlockState::NO_BLOCK,
285 /* moduleIdx */ 0 // placeholder, gets filled in after load
286 )));
287 24 }
288
289 2 void WasmSequencer ::seqCancelIn_handler(FwIndexType portNum) {
290 2 this->controller_sendSignal_cancel();
291 2 this->interpreter_sendSignal_cancel();
292 2 }
293
294 // ----------------------------------------------------------------------
295 // Handler implementations for serial input ports
296 // ----------------------------------------------------------------------
297
298 32 void WasmSequencer ::serialIn_handler(FwIndexType portNum, Fw::LinearBufferBase& buffer) {
299 32 FW_ASSERT(portNum < NUM_SERIALIN_INPUT_PORTS, portNum, NUM_SERIALIN_INPUT_PORTS);
300
1/1
✓ Branch 5 taken 32 times.
32 Os::ScopeLock scopeLock(this->m_serialInMutex);
301 32 auto& queue = this->m_serialInQueue[portNum];
302 32 auto fullFullBehavior = this->m_config.serialIn[portNum].fullBehavior;
303
304 // Each message is framed on the queue as [U32 length][payload]
305 32 const FwSizeType headerSize = sizeof(U32);
306
1/1
✓ Branch 7 taken 32 times.
32 const FwSizeType payloadSize = buffer.getSize();
307
1/1
✓ Branch 2 taken 32 times.
32 const FwSizeType capacity = queue.get_capacity();
308
309 // Make sure the queue is sized to hold this framed message at all. This does
310 // not check free space, only that the queue's capacity is large enough.
311
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 29 times.
32 if (headerSize + payloadSize > capacity) {
312 // The largest payload this queue could ever hold is capacity - headerSize. A queue smaller
313 // than the header (including a port left un-configured with capacity 0) can hold nothing.
314 3 const FwSizeType maxPayload = (capacity > headerSize) ? (capacity - headerSize) : 0;
315
1/1
✓ Branch 5 taken 3 times.
3 this->log_WARNING_HI_SerialInFrameTooLarge(static_cast<U32>(portNum), static_cast<U32>(payloadSize),
316 static_cast<U32>(maxPayload));
317 3 return;
318 }
319
320 // Total framed size; <= capacity by the assertions above, so it cannot overflow.
321 29 const FwSizeType frameSize = headerSize + payloadSize;
322
323 // Check if we _can_ push the data to the queue
324
3/3
✓ Branch 2 taken 29 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 25 times.
29 if (frameSize > queue.get_free_size()) {
325 // The queue is full and cannot push this data
326
2/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 switch (fullFullBehavior) {
327 2 case SerialInQueueFullBehavior::DROP_OLDEST:
328 // Drop oldest messages until this one fits.
329
3/3
✓ Branch 2 taken 4 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
4 while (frameSize > queue.get_free_size()) {
330 2 U32 nextMsgSize;
331
1/1
✓ Branch 2 taken 2 times.
2 auto status = queue.peek(nextMsgSize);
332 2 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, portNum, status);
333
334
1/1
✓ Branch 2 taken 2 times.
2 const FwSizeType allocated = queue.get_allocated_size();
335 2 FW_ASSERT(allocated >= headerSize, portNum, static_cast<FwAssertArgType>(allocated));
336 2 FW_ASSERT(static_cast<FwSizeType>(nextMsgSize) <= allocated - headerSize, portNum,
337 static_cast<FwAssertArgType>(nextMsgSize), static_cast<FwAssertArgType>(allocated));
338
339
1/1
✓ Branch 2 taken 2 times.
2 status = queue.rotate(headerSize + nextMsgSize);
340
341 2 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, portNum, status);
342 }
343
344 // Now it fits, fall through to push the data to the queue
345 2 break;
346 2 case SerialInQueueFullBehavior::DROP_NEWEST:
347 // Drop this message
348 2 return;
349
350 ✗ case SerialInQueueFullBehavior::ASSERT:
351 ✗ FW_ASSERT(false, portNum, static_cast<FwAssertArgType>(frameSize),
352 static_cast<FwAssertArgType>(queue.get_free_size()), static_cast<FwAssertArgType>(capacity));
353 ✗ break;
354 }
355 }
356
357 // The message should be able to be put into the queue.
358 // Enqueue it as a raw [U32 size][payload] frame. We use the raw (const U8*, size)
359
1/1
✓ Branch 2 taken 27 times.
54 Fw::LinearBufferTemplate<sizeof(U32)> sizeSer;
360
1/1
✓ Branch 2 taken 27 times.
27 auto status = sizeSer.serializeFrom(static_cast<U32>(payloadSize));
361 27 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
362
363
1/1
✓ Branch 4 taken 27 times.
27 status = queue.serialize(sizeSer.getBuffAddr(), headerSize);
364 27 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
365
366
1/1
✓ Branch 6 taken 27 times.
27 status = queue.serialize(buffer.getBuffAddr(), payloadSize);
367 27 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
368
369 // Wake up any blocking recv calls
370
1/1
✓ Branch 5 taken 27 times.
27 this->interpreter_sendSignal_serialInMessage(portNum);
371 32 }
372
373 // ----------------------------------------------------------------------
374 // Handler implementations for commands
375 // ----------------------------------------------------------------------
376
377 137 void WasmSequencer ::RUN_cmdHandler(FwOpcodeType opCode,
378 U32 cmdSeq,
379 const Fw::CmdStringArg& fileName,
380 const Svc::BlockState& block) {
381 137 FW_ASSERT(this->m_wasm != nullptr);
382
383
1/1
✓ Branch 2 taken 137 times.
137 Fw::String runModuleName = "";
384
2/2
✓ Branch 9 taken 137 times.
✓ Branch 13 taken 137 times.
411 this->controller_sendSignal_run(Svc::WasmSequencer_LoadRequest(
385 fileName, runModuleName,
386
1/1
✓ Branch 3 taken 137 times.
685 Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::COMMAND_RUN,
387
1/1
✓ Branch 2 taken 137 times.
274 WasmSequencer_CommandRequest(opCode, cmdSeq), block,
388 /* moduleIdx */ 0 // placeholder, gets filled in after load
389 137 )));
390 274 }
391
392 16 void WasmSequencer ::WAIT_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
393 16 FW_ASSERT(this->m_wasm != nullptr);
394
395
3/3
✓ Branch 3 taken 16 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 14 times.
16 switch (this->controller_getState()) {
396 2 case WasmSequencer_ControllerStateMachine_State::IDLE:
397 case WasmSequencer_ControllerStateMachine_State::READY:
398 // Nothing is executing, respond immediately
399
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
400 2 break;
401 14 default: {
402
1/1
✓ Branch 7 taken 14 times.
14 const auto status = this->m_waiting.enqueue(WaitingCmd(opCode, cmdSeq));
403
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 13 times.
14 if (status != Fw::Success::SUCCESS) {
404
1/1
✓ Branch 5 taken 1 times.
1 this->log_WARNING_HI_TooManyBlockingCommands();
405
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
406 }
407 14 }
408 }
409 16 }
410
411 60 void WasmSequencer ::LOAD_cmdHandler(FwOpcodeType opCode,
412 U32 cmdSeq,
413 const Fw::CmdStringArg& fileName,
414 const Fw::CmdStringArg& name) {
415 60 FW_ASSERT(this->m_wasm != nullptr);
416
417
2/2
✓ Branch 12 taken 60 times.
✓ Branch 16 taken 60 times.
180 this->controller_sendSignal_load(Svc::WasmSequencer_LoadRequest(
418 fileName, name,
419
1/1
✓ Branch 2 taken 60 times.
240 Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::COMMAND_LOAD,
420
1/1
✓ Branch 2 taken 60 times.
120 WasmSequencer_CommandRequest(opCode, cmdSeq), Svc::BlockState::BLOCK,
421 /* moduleIdx */ 0 // placeholder, gets filled in after load
422 )));
423 60 }
424
425 13 void WasmSequencer ::INVOKE_cmdHandler(FwOpcodeType opCode,
426 U32 cmdSeq,
427 const Fw::CmdStringArg& module,
428 const Svc::BlockState& block) {
429 13 FW_ASSERT(this->m_wasm != nullptr);
430
431
2/2
✓ Branch 9 taken 13 times.
✓ Branch 13 taken 13 times.
39 this->controller_sendSignal_invoke(Svc::WasmSequencer_InvokeRequest(
432
1/1
✓ Branch 3 taken 13 times.
65 module, Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::COMMAND_INVOKE,
433
1/1
✓ Branch 2 taken 13 times.
26 WasmSequencer_CommandRequest(opCode, cmdSeq), block,
434 /* moduleIdx */ 0 // placeholder, gets filled in after invoke
435 13 )));
436 13 }
437
438 25 void WasmSequencer ::CANCEL_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
439 25 this->controller_sendSignal_cancel();
440
2/2
✓ Branch 6 taken 25 times.
✓ Branch 10 taken 25 times.
25 this->interpreter_sendSignal_cmdCancel(WasmSequencer_CommandRequest(opCode, cmdSeq));
441 25 }
442
443 9 void WasmSequencer ::PAUSE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
444
3/3
✓ Branch 3 taken 9 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 8 times.
9 if (this->interpreter_getState() == WasmSequencer_InterpreterStateMachine_State::IDLE) {
445 1 this->log_WARNING_LO_SequenceNotRunning();
446
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
447 1 return;
448 }
449
450 8 this->m_pendingPause = true;
451
2/2
✓ Branch 6 taken 8 times.
✓ Branch 9 taken 8 times.
8 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
452 }
453
454 5 void WasmSequencer ::CONTINUE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
455 5 FW_ASSERT(this->m_wasm != nullptr);
456
457
4/5
✓ Branch 3 taken 5 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 3 times.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
5 switch (this->interpreter_getState()) {
458 1 case WasmSequencer_InterpreterStateMachine_State::RUNNING_AWAITING_RESPONSE_SLEEPING:
459 case WasmSequencer_InterpreterStateMachine_State::RUNNING_AWAITING_RESPONSE_WAITING:
460 case WasmSequencer_InterpreterStateMachine_State::RUNNING_SPINNING:
461 // Already running
462
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
463 1 break;
464 3 case WasmSequencer_InterpreterStateMachine_State::RUNNING_PAUSED:
465 3 this->interpreter_sendSignal_cmd_CONTINUE();
466
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
467 3 break;
468 1 case WasmSequencer_InterpreterStateMachine_State::IDLE:
469 1 this->log_WARNING_LO_SequenceNotRunning();
470
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
471 1 break;
472 ✗ default:
473 ✗ FW_ASSERT(false, this->interpreter_getState());
474 }
475 5 }
476
477 9 void WasmSequencer ::GLOBAL_SET_I32_cmdHandler(FwOpcodeType opCode,
478 U32 cmdSeq,
479 const Fw::CmdStringArg& moduleName,
480 const Fw::CmdStringArg& name,
481 I32 value) {
482 9 FW_ASSERT(this->m_wasm != nullptr);
483
484 9 spacewasm_value_t s_value;
485 9 s_value.tag = SPACEWASM_I32;
486 9 s_value.u.i32_ = value;
487
488
1/1
✓ Branch 10 taken 9 times.
9 auto status = this->setGlobal(moduleName, name, s_value);
489
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (status == SPACEWASM_OK) {
490
2/2
✓ Branch 6 taken 5 times.
✓ Branch 9 taken 5 times.
5 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
491 } else {
492
2/2
✓ Branch 6 taken 4 times.
✓ Branch 16 taken 4 times.
4 this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status);
493
2/2
✓ Branch 6 taken 4 times.
✓ Branch 9 taken 4 times.
4 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
494 }
495 9 }
496
497 3 void WasmSequencer ::GLOBAL_SET_I64_cmdHandler(FwOpcodeType opCode,
498 U32 cmdSeq,
499 const Fw::CmdStringArg& moduleName,
500 const Fw::CmdStringArg& name,
501 I64 value) {
502 3 FW_ASSERT(this->m_wasm != nullptr);
503
504 3 spacewasm_value_t s_value;
505 3 s_value.tag = SPACEWASM_I64;
506 3 s_value.u.i64_ = value;
507
508
1/1
✓ Branch 10 taken 3 times.
3 auto status = this->setGlobal(moduleName, name, s_value);
509
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (status == SPACEWASM_OK) {
510
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
511 } else {
512
2/2
✓ Branch 6 taken 1 times.
✓ Branch 16 taken 1 times.
1 this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status);
513
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
514 }
515 3 }
516
517 3 void WasmSequencer ::GLOBAL_SET_F32_cmdHandler(FwOpcodeType opCode,
518 U32 cmdSeq,
519 const Fw::CmdStringArg& moduleName,
520 const Fw::CmdStringArg& name,
521 F32 value) {
522 3 FW_ASSERT(this->m_wasm != nullptr);
523
524 3 spacewasm_value_t s_value;
525 3 s_value.tag = SPACEWASM_F32;
526 3 s_value.u.f32_ = value;
527
528
1/1
✓ Branch 10 taken 3 times.
3 auto status = this->setGlobal(moduleName, name, s_value);
529
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (status == SPACEWASM_OK) {
530
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
531 } else {
532
2/2
✓ Branch 6 taken 1 times.
✓ Branch 16 taken 1 times.
1 this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status);
533
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
534 }
535 3 }
536
537 3 void WasmSequencer ::GLOBAL_SET_F64_cmdHandler(FwOpcodeType opCode,
538 U32 cmdSeq,
539 const Fw::CmdStringArg& moduleName,
540 const Fw::CmdStringArg& name,
541 F64 value) {
542 3 FW_ASSERT(this->m_wasm != nullptr);
543
544 3 spacewasm_value_t g_value;
545 3 g_value.tag = SPACEWASM_F64;
546 3 g_value.u.f64_ = value;
547
548
1/1
✓ Branch 10 taken 3 times.
3 auto status = this->setGlobal(moduleName, name, g_value);
549
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (status == SPACEWASM_OK) {
550
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
551 } else {
552
2/2
✓ Branch 6 taken 1 times.
✓ Branch 16 taken 1 times.
1 this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status);
553
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
554 }
555 3 }
556
557 25 void WasmSequencer ::GLOBAL_GET_cmdHandler(FwOpcodeType opCode,
558 U32 cmdSeq,
559 const Fw::CmdStringArg& moduleName,
560 const Fw::CmdStringArg& name) {
561 25 FW_ASSERT(this->m_wasm != nullptr);
562
563 25 spacewasm_value_t g_value;
564
1/1
✓ Branch 10 taken 25 times.
25 auto status = this->getGlobal(moduleName, name, g_value);
565
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 4 times.
25 if (status == SPACEWASM_OK) {
566
4/5
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
21 switch (g_value.tag) {
567 12 case SPACEWASM_I32:
568
1/1
✓ Branch 11 taken 12 times.
12 this->log_ACTIVITY_LO_GlobalValueI32(moduleName, name, g_value.u.i32_);
569 12 break;
570 3 case SPACEWASM_I64:
571
1/1
✓ Branch 11 taken 3 times.
3 this->log_ACTIVITY_LO_GlobalValueI64(moduleName, name, g_value.u.i64_);
572 3 break;
573 3 case SPACEWASM_F32:
574
1/1
✓ Branch 11 taken 3 times.
3 this->log_ACTIVITY_LO_GlobalValueF32(moduleName, name, g_value.u.f32_);
575 3 break;
576 3 case SPACEWASM_F64:
577
1/1
✓ Branch 11 taken 3 times.
3 this->log_ACTIVITY_LO_GlobalValueF64(moduleName, name, g_value.u.f64_);
578 3 break;
579 ✗ default:
580 ✗ FW_ASSERT(false, g_value.tag);
581 }
582
583
2/2
✓ Branch 6 taken 21 times.
✓ Branch 9 taken 21 times.
21 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
584 } else {
585
2/2
✓ Branch 6 taken 4 times.
✓ Branch 16 taken 4 times.
4 this->log_WARNING_LO_GlobalGetFailed(moduleName, name, status);
586
2/2
✓ Branch 6 taken 4 times.
✓ Branch 9 taken 4 times.
4 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
587 }
588 25 }
589
590 } // namespace Svc
591