GCC Code Coverage Report


Directory: ./
File: Svc/WasmSequencer/WasmSequencer.cpp
Date: 2026-09-23 22:11:34
Exec Total Coverage
Lines: 89 296 30.1%
Functions: 7 23 30.4%
Branches: 56 218 25.7%

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
12/12
✓ 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 1 times.
✓ Branch 24 taken 5 times.
✓ Branch 26 taken 5 times.
✓ Branch 27 taken 1 times.
✓ Branch 29 taken 1 times.
✓ Branch 32 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 121 void WasmSequencer ::checkTimers_handler(FwIndexType portNum, U32 context) {
191 // Drive the sleep-wake / host-function-timeout checks in the state machine.
192 121 this->interpreter_sendSignal_checkTimers();
193 121 }
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 121 void WasmSequencer ::writeTelemetry_handler(FwIndexType portNum, U32 context) {
245 121 FW_ASSERT(this->m_wasm != nullptr);
246
247
1/1
✓ Branch 1 taken 121 times.
121 auto now = this->getTime();
248
249
3/3
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
✓ Branch 7 taken 121 times.
121 this->tlmWrite_ControllerState(this->controller_getState(), now);
250
3/3
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
✓ Branch 7 taken 121 times.
121 this->tlmWrite_InterpreterState(this->interpreter_getState(), now);
251
2/2
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
121 this->tlmWrite_SequencesSucceeded(this->m_tlm.sequencesSucceeded, now);
252
2/2
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
121 this->tlmWrite_SequencesFailed(this->m_tlm.sequencesFailed, now);
253
2/2
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
121 this->tlmWrite_SequencesCancelled(this->m_tlm.sequencesCancelled, now);
254
2/2
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
121 this->tlmWrite_CommandsDispatched(this->m_tlm.commandsDispatched, now);
255
2/2
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
121 this->tlmWrite_CommandsFailed(this->m_tlm.commandsFailed, now);
256
2/2
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
121 this->tlmWrite_LastTrapReason(this->m_exit.lastTrapReason, now);
257
2/2
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
121 this->tlmWrite_SeqName(this->m_tlm.sequenceName, now);
258 121 }
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, args,
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 const SeqArgs& seqArgs) {
366 ✗ FW_ASSERT(this->m_wasm != nullptr);
367
368 ✗ Fw::String runModuleName = "";
369 ✗ this->controller_sendSignal_run(Svc::WasmSequencer_LoadRequest(
370 fileName, runModuleName, seqArgs,
371 ✗ Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::COMMAND_RUN,
372 ✗ WasmSequencer_CommandRequest(opCode, cmdSeq), block,
373 /* moduleIdx */ 0 // placeholder, gets filled in after load
374 )));
375 ✗ }
376
377 ✗ void WasmSequencer ::WAIT_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
378 ✗ FW_ASSERT(this->m_wasm != nullptr);
379
380 ✗ switch (this->controller_getState()) {
381 ✗ case WasmSequencer_ControllerStateMachine_State::IDLE:
382 case WasmSequencer_ControllerStateMachine_State::READY:
383 // Nothing is executing, respond immediately
384 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
385 ✗ break;
386 ✗ default: {
387 ✗ const auto status = this->m_waiting.enqueue(WaitingCmd(opCode, cmdSeq));
388 ✗ if (status != Fw::Success::SUCCESS) {
389 ✗ this->log_WARNING_HI_TooManyBlockingCommands();
390 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
391 }
392 ✗ }
393 }
394 ✗ }
395
396 ✗ void WasmSequencer ::LOAD_cmdHandler(FwOpcodeType opCode,
397 U32 cmdSeq,
398 const Fw::CmdStringArg& fileName,
399 const Fw::CmdStringArg& name) {
400 ✗ FW_ASSERT(this->m_wasm != nullptr);
401
402 ✗ this->controller_sendSignal_load(Svc::WasmSequencer_LoadRequest(
403 ✗ fileName, name, Svc::SeqArgs(),
404 ✗ Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::COMMAND_LOAD,
405 ✗ WasmSequencer_CommandRequest(opCode, cmdSeq), Svc::BlockState::BLOCK,
406 /* moduleIdx */ 0 // placeholder, gets filled in after load
407 )));
408 ✗ }
409
410 ✗ void WasmSequencer ::INVOKE_cmdHandler(FwOpcodeType opCode,
411 U32 cmdSeq,
412 const Fw::CmdStringArg& module,
413 const Svc::BlockState& block,
414 const Svc::SeqArgs& seqArgs) {
415 ✗ FW_ASSERT(this->m_wasm != nullptr);
416
417 ✗ this->controller_sendSignal_invoke(Svc::WasmSequencer_InvokeRequest(
418 module, seqArgs,
419 ✗ Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::COMMAND_INVOKE,
420 ✗ WasmSequencer_CommandRequest(opCode, cmdSeq), block,
421 /* moduleIdx */ 0 // placeholder, gets filled in after invoke
422 )));
423 ✗ }
424
425 ✗ void WasmSequencer ::CANCEL_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
426 ✗ this->controller_sendSignal_cancel();
427 ✗ this->interpreter_sendSignal_cmdCancel(WasmSequencer_CommandRequest(opCode, cmdSeq));
428 ✗ }
429
430 ✗ void WasmSequencer ::PAUSE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
431 ✗ if (this->interpreter_getState() == WasmSequencer_InterpreterStateMachine_State::IDLE) {
432 ✗ this->log_WARNING_LO_SequenceNotRunning();
433 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
434 ✗ return;
435 }
436
437 ✗ this->m_pendingPause = true;
438 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
439 }
440
441 ✗ void WasmSequencer ::CONTINUE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
442 ✗ FW_ASSERT(this->m_wasm != nullptr);
443
444 ✗ switch (this->interpreter_getState()) {
445 ✗ case WasmSequencer_InterpreterStateMachine_State::RUNNING_AWAITING_RESPONSE_SLEEPING:
446 case WasmSequencer_InterpreterStateMachine_State::RUNNING_AWAITING_RESPONSE_WAITING:
447 case WasmSequencer_InterpreterStateMachine_State::RUNNING_SPINNING:
448 // Already running
449 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
450 ✗ break;
451 ✗ case WasmSequencer_InterpreterStateMachine_State::RUNNING_PAUSED:
452 ✗ this->interpreter_sendSignal_cmd_CONTINUE();
453 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
454 ✗ break;
455 ✗ case WasmSequencer_InterpreterStateMachine_State::IDLE:
456 ✗ this->log_WARNING_LO_SequenceNotRunning();
457 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
458 ✗ break;
459 ✗ default:
460 ✗ FW_ASSERT(false, this->interpreter_getState());
461 }
462 ✗ }
463
464 ✗ void WasmSequencer ::GLOBAL_SET_I32_cmdHandler(FwOpcodeType opCode,
465 U32 cmdSeq,
466 const Fw::CmdStringArg& moduleName,
467 const Fw::CmdStringArg& name,
468 I32 value) {
469 ✗ FW_ASSERT(this->m_wasm != nullptr);
470
471 spacewasm_value_t s_value;
472 ✗ s_value.tag = SPACEWASM_I32;
473 ✗ s_value.u.i32_ = value;
474
475 ✗ auto status = this->setGlobal(moduleName, name, s_value);
476 ✗ if (status == SPACEWASM_OK) {
477 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
478 } else {
479 ✗ this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status);
480 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
481 }
482 ✗ }
483
484 ✗ void WasmSequencer ::GLOBAL_SET_I64_cmdHandler(FwOpcodeType opCode,
485 U32 cmdSeq,
486 const Fw::CmdStringArg& moduleName,
487 const Fw::CmdStringArg& name,
488 I64 value) {
489 ✗ FW_ASSERT(this->m_wasm != nullptr);
490
491 spacewasm_value_t s_value;
492 ✗ s_value.tag = SPACEWASM_I64;
493 ✗ s_value.u.i64_ = value;
494
495 ✗ auto status = this->setGlobal(moduleName, name, s_value);
496 ✗ if (status == SPACEWASM_OK) {
497 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
498 } else {
499 ✗ this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status);
500 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
501 }
502 ✗ }
503
504 ✗ void WasmSequencer ::GLOBAL_SET_F32_cmdHandler(FwOpcodeType opCode,
505 U32 cmdSeq,
506 const Fw::CmdStringArg& moduleName,
507 const Fw::CmdStringArg& name,
508 F32 value) {
509 ✗ FW_ASSERT(this->m_wasm != nullptr);
510
511 spacewasm_value_t s_value;
512 ✗ s_value.tag = SPACEWASM_F32;
513 ✗ s_value.u.f32_ = value;
514
515 ✗ auto status = this->setGlobal(moduleName, name, s_value);
516 ✗ if (status == SPACEWASM_OK) {
517 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
518 } else {
519 ✗ this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status);
520 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
521 }
522 ✗ }
523
524 ✗ void WasmSequencer ::GLOBAL_SET_F64_cmdHandler(FwOpcodeType opCode,
525 U32 cmdSeq,
526 const Fw::CmdStringArg& moduleName,
527 const Fw::CmdStringArg& name,
528 F64 value) {
529 ✗ FW_ASSERT(this->m_wasm != nullptr);
530
531 spacewasm_value_t g_value;
532 ✗ g_value.tag = SPACEWASM_F64;
533 ✗ g_value.u.f64_ = value;
534
535 ✗ auto status = this->setGlobal(moduleName, name, g_value);
536 ✗ if (status == SPACEWASM_OK) {
537 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
538 } else {
539 ✗ this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status);
540 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
541 }
542 ✗ }
543
544 ✗ void WasmSequencer ::GLOBAL_GET_cmdHandler(FwOpcodeType opCode,
545 U32 cmdSeq,
546 const Fw::CmdStringArg& moduleName,
547 const Fw::CmdStringArg& name) {
548 ✗ FW_ASSERT(this->m_wasm != nullptr);
549
550 spacewasm_value_t g_value;
551 ✗ auto status = this->getGlobal(moduleName, name, g_value);
552 ✗ if (status == SPACEWASM_OK) {
553 ✗ switch (g_value.tag) {
554 ✗ case SPACEWASM_I32:
555 ✗ this->log_ACTIVITY_LO_GlobalValueI32(moduleName, name, g_value.u.i32_);
556 ✗ break;
557 ✗ case SPACEWASM_I64:
558 ✗ this->log_ACTIVITY_LO_GlobalValueI64(moduleName, name, g_value.u.i64_);
559 ✗ break;
560 ✗ case SPACEWASM_F32:
561 ✗ this->log_ACTIVITY_LO_GlobalValueF32(moduleName, name, g_value.u.f32_);
562 ✗ break;
563 ✗ case SPACEWASM_F64:
564 ✗ this->log_ACTIVITY_LO_GlobalValueF64(moduleName, name, g_value.u.f64_);
565 ✗ break;
566 ✗ default:
567 ✗ FW_ASSERT(false, g_value.tag);
568 }
569
570 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
571 } else {
572 ✗ this->log_WARNING_LO_GlobalGetFailed(moduleName, name, status);
573 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
574 }
575 ✗ }
576
577 } // namespace Svc
578