GCC Code Coverage Report


Directory: ./
File: WasmSequencer.cpp
Date: 2026-10-14 22:13:20
Exec Total Coverage
Lines: 89 295 30.2%
Functions: 7 23 30.4%
Branches: 55 216 25.5%

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