| 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 | 339 | U8* WasmSequencer ::globalAllocCallback(void* userdata, size_t size, size_t align) { | |
| 32 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 339 times.
|
339 | if (userdata == nullptr) { |
| 33 | ✗ | return nullptr; | |
| 34 | } | ||
| 35 | 339 | return static_cast<WasmSequencer*>(userdata)->globalAlloc(static_cast<U32>(size), static_cast<U32>(align)); | |
| 36 | } | ||
| 37 | |||
| 38 | 339 | 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 339 times.
✗ Branch 1 not taken.
|
339 | if (userdata != nullptr) { |
| 42 | 339 | static_cast<WasmSequencer*>(userdata)->globalDealloc(ptr); | |
| 43 | } | ||
| 44 | 339 | } | |
| 45 | |||
| 46 | // ---------------------------------------------------------------------- | ||
| 47 | // Component construction and destruction | ||
| 48 | // ---------------------------------------------------------------------- | ||
| 49 | |||
| 50 | 224 | WasmSequencer ::WasmSequencer(const char* const compName) | |
| 51 | : WasmSequencerComponentBase(compName), | ||
| 52 | 224 | m_heapPages(nullptr), | |
| 53 | 224 | m_heapPagesUsed(0), | |
| 54 | 224 | m_heapPoisoned(false), | |
| 55 | 224 | m_guestPool(nullptr), | |
| 56 | 224 | m_guestPoolOffset(0), | |
| 57 | 224 | m_wasm(nullptr), | |
| 58 | 224 | m_hasExecutingContext(false), | |
| 59 |
1/1✓ Branch 5 taken 224 times.
|
224 | m_pendingTimer(), |
| 60 | 224 | m_hasPendingTimer(false), | |
| 61 |
1/1✓ Branch 5 taken 224 times.
|
224 | m_hostFunctionStart(), |
| 62 | 224 | m_hasHostFunctionStart(false), | |
| 63 | 224 | m_dequeueSucceeded(false), | |
| 64 | 224 | m_invokeStatus(SPACEWASM_OK), | |
| 65 | 224 | m_pendingPause(false), | |
| 66 | 224 | m_cancelRequested(false), | |
| 67 |
12/12✓ Branch 17 taken 224 times.
✓ Branch 23 taken 224 times.
✓ Branch 29 taken 224 times.
✓ Branch 35 taken 224 times.
✓ Branch 41 taken 224 times.
✓ Branch 51 taken 224 times.
✓ Branch 57 taken 224 times.
✓ Branch 63 taken 1120 times.
✓ Branch 66 taken 1120 times.
✓ Branch 67 taken 224 times.
✓ Branch 73 taken 224 times.
✓ Branch 79 taken 224 times.
|
1792 | m_sequencesStarted(0) {} |
| 68 | |||
| 69 | 222 | void WasmSequencer ::configure(const Config& cfg, Fw::MemAllocator& mallocator) { | |
| 70 | 222 | FW_ASSERT(this->m_wasm == nullptr); | |
| 71 | 222 | FW_ASSERT(this->m_allocator == nullptr); | |
| 72 | |||
| 73 | 222 | getGlobalAllocatorLock()->lock(); | |
| 74 | 222 | const auto status = spacewasm_fprime_register_global_allocator(&globalAllocCallback, &globalDeallocCallback, this); | |
| 75 | 222 | getGlobalAllocatorLock()->unlock(); | |
| 76 | |||
| 77 | 222 | FW_ASSERT(status == SPACEWASM_OK, status); | |
| 78 | |||
| 79 | 222 | this->m_config = cfg; | |
| 80 | |||
| 81 | // Allocate the heap memory pool | ||
| 82 | { | ||
| 83 | 222 | 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 | 222 | FwSizeType actualSize = sizeof(U8*) * this->m_config.heapPages; | |
| 90 |
1/1✓ Branch 4 taken 222 times.
|
222 | auto ptr = mallocator.checkedAllocate(0, actualSize); |
| 91 | 222 | this->m_heapPages = reinterpret_cast<U8**>(ptr); | |
| 92 | } | ||
| 93 | |||
| 94 | // Allocate each heap page | ||
| 95 |
2/2✓ Branch 4 taken 888 times.
✓ Branch 5 taken 222 times.
|
1110 | for (FwSizeType i = 0; i < this->m_config.heapPages; i++) { |
| 96 | 888 | auto actualSize = Svc::WasmSequencerConfig::SPACEWASM_PAGE_SIZE; | |
| 97 | auto ptr = | ||
| 98 |
1/1✓ Branch 4 taken 888 times.
|
888 | mallocator.checkedAllocate(static_cast<FwIndexType>(i) + 1, actualSize, SPACEWASM_MEMORY_ALIGNMENT); |
| 99 | 888 | this->m_heapPages[i] = reinterpret_cast<U8*>(ptr); | |
| 100 | } | ||
| 101 | 222 | this->m_heapPagesUsed = 0; | |
| 102 | } | ||
| 103 | |||
| 104 | // Allocate the guest memory pool | ||
| 105 | { | ||
| 106 | 222 | auto actualSize = this->m_config.guestMemorySize; | |
| 107 |
1/1✓ Branch 8 taken 222 times.
|
222 | auto ptr = mallocator.checkedAllocate(static_cast<FwIndexType>(this->m_config.heapPages) + 1, actualSize, |
| 108 | SPACEWASM_MEMORY_ALIGNMENT); | ||
| 109 | 222 | this->m_guestPoolOffset = 0; | |
| 110 | 222 | this->m_guestPool = reinterpret_cast<U8*>(ptr); | |
| 111 | } | ||
| 112 | |||
| 113 | // Allocate the serialOut buffer | ||
| 114 |
2/2✓ Branch 4 taken 221 times.
✓ Branch 5 taken 1 times.
|
222 | if (this->m_config.serialOutMax > 0) { |
| 115 | 221 | auto actualSize = this->m_config.serialOutMax; | |
| 116 |
1/1✓ Branch 8 taken 221 times.
|
221 | auto ptr = mallocator.checkedAllocate(static_cast<FwIndexType>(this->m_config.heapPages) + 2, actualSize); |
| 117 |
1/1✓ Branch 6 taken 221 times.
|
221 | this->m_serialOutBuffer.setExtBuffer(reinterpret_cast<U8*>(ptr), actualSize); |
| 118 | } | ||
| 119 | |||
| 120 | // Allocate the serialIn queues | ||
| 121 | { | ||
| 122 |
1/1✓ Branch 5 taken 222 times.
|
222 | Os::ScopeLock scopeLock(this->m_serialInMutex); |
| 123 |
2/2✓ Branch 0 taken 1110 times.
✓ Branch 1 taken 222 times.
|
1332 | for (FwIndexType i = 0; i < NUM_SERIALIN_INPUT_PORTS; i++) { |
| 124 |
2/2✓ Branch 5 taken 1109 times.
✓ Branch 6 taken 1 times.
|
1110 | if (this->m_config.serialIn[i].size > 0) { |
| 125 | 1109 | auto actualSize = this->m_config.serialIn[i].size; | |
| 126 | auto ptr = | ||
| 127 |
1/1✓ Branch 8 taken 1109 times.
|
1109 | mallocator.checkedAllocate(static_cast<FwIndexType>(this->m_config.heapPages) + 3 + i, actualSize); |
| 128 |
1/1✓ Branch 5 taken 1109 times.
|
1109 | this->m_serialInQueue[i].setup(reinterpret_cast<U8*>(ptr), actualSize); |
| 129 | } | ||
| 130 | } | ||
| 131 | 222 | } | |
| 132 | |||
| 133 | // Allocate the initial store | ||
| 134 | 222 | this->m_allocator = &mallocator; | |
| 135 | 222 | this->createStore(); | |
| 136 | 222 | } | |
| 137 | |||
| 138 | 224 | void WasmSequencer ::deinit() { | |
| 139 |
2/2✓ Branch 4 taken 222 times.
✓ Branch 5 taken 2 times.
|
224 | if (this->m_wasm != nullptr) { |
| 140 | 222 | this->destroyStore(); | |
| 141 | } | ||
| 142 | |||
| 143 |
2/2✓ Branch 4 taken 222 times.
✓ Branch 5 taken 2 times.
|
224 | if (this->m_allocator != nullptr) { |
| 144 | // Deallocate each heap page | ||
| 145 |
2/2✓ Branch 4 taken 888 times.
✓ Branch 5 taken 222 times.
|
1110 | for (FwSizeType i = 0; i < this->m_config.heapPages; i++) { |
| 146 | 888 | this->m_allocator->deallocate(static_cast<FwIndexType>(i) + 1, this->m_heapPages[i]); | |
| 147 | 888 | this->m_heapPages[i] = nullptr; | |
| 148 | } | ||
| 149 | |||
| 150 | // Deallocate the heap page pool | ||
| 151 | 222 | this->m_allocator->deallocate(0, this->m_heapPages); | |
| 152 | |||
| 153 | // Deallocate the guest memory pool | ||
| 154 |
1/2✓ Branch 4 taken 222 times.
✗ Branch 5 not taken.
|
222 | if (this->m_guestPool != nullptr) { |
| 155 | 222 | this->m_allocator->deallocate(static_cast<FwIndexType>(this->m_config.heapPages) + 1, this->m_guestPool); | |
| 156 | } | ||
| 157 | |||
| 158 | // Deallocate the serialOut buffer | ||
| 159 |
2/2✓ Branch 6 taken 221 times.
✓ Branch 7 taken 1 times.
|
222 | if (this->m_serialOutBuffer.getBuffAddr() != nullptr) { |
| 160 | 442 | this->m_allocator->deallocate(static_cast<FwIndexType>(this->m_config.heapPages) + 2, | |
| 161 | 221 | this->m_serialOutBuffer.getBuffAddr()); | |
| 162 | } | ||
| 163 | |||
| 164 | // Deallocate the serialIn queues | ||
| 165 |
2/2✓ Branch 0 taken 1110 times.
✓ Branch 1 taken 222 times.
|
1332 | for (FwIndexType i = 0; i < NUM_SERIALIN_INPUT_PORTS; i++) { |
| 166 |
2/2✓ Branch 5 taken 1108 times.
✓ Branch 6 taken 2 times.
|
1110 | if (this->m_serialInQueue[i].get_capacity() > 0) { |
| 167 | 2216 | this->m_allocator->deallocate(static_cast<FwIndexType>(this->m_config.heapPages) + 3 + i, | |
| 168 | 1108 | 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 | 224 | getGlobalAllocatorLock()->lock(); | |
| 176 | 224 | (void)spacewasm_fprime_deregister_global_allocator(this); | |
| 177 | 224 | getGlobalAllocatorLock()->unlock(); | |
| 178 | |||
| 179 | // Clean up dangling pointers | ||
| 180 | 224 | this->m_allocator = nullptr; | |
| 181 | 224 | this->m_wasm = nullptr; | |
| 182 | |||
| 183 | 224 | WasmSequencerComponentBase::deinit(); | |
| 184 | 224 | } | |
| 185 | |||
| 186 | // ---------------------------------------------------------------------- | ||
| 187 | // Handler implementations for typed input ports | ||
| 188 | // ---------------------------------------------------------------------- | ||
| 189 | |||
| 190 | 11 | void WasmSequencer ::checkTimers_handler(FwIndexType portNum, U32 context) { | |
| 191 | // Drive the sleep-wake / host-function-timeout checks in the state machine. | ||
| 192 | 11 | this->interpreter_sendSignal_checkTimers(); | |
| 193 | 11 | } | |
| 194 | |||
| 195 | 18 | void WasmSequencer ::cmdResponseIn_handler(FwIndexType portNum, | |
| 196 | FwOpcodeType opCode, | ||
| 197 | U32 cmdSeq, | ||
| 198 | const Fw::CmdResponse& response) { | ||
| 199 | 18 | 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 | 18 | const U32 cmdUid = cmdSeq; | |
| 204 | 18 | const U16 sequenceIndex = static_cast<U16>((cmdUid & 0xFFFF0000) >> 16); | |
| 205 | 18 | const U16 cmdIndex = static_cast<U16>(cmdUid & 0xFFFF); | |
| 206 | 18 | const U16 currentSequenceIndex = static_cast<U16>(this->m_sequencesStarted & 0xFFFF); | |
| 207 | 18 | 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 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
|
18 | if (sequenceIndex != currentSequenceIndex) { |
| 213 | 2 | this->log_WARNING_LO_CmdResponseFromOldSequence(opCode, response, sequenceIndex, currentSequenceIndex); | |
| 214 | 2 | 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 |
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() != |
| 220 |
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 || |
| 221 | 11 | this->m_pendingHostFunction.kind != WasmSequencer_HostFunction::COMMAND) { | |
| 222 |
2/2✓ Branch 6 taken 5 times.
✓ Branch 10 taken 5 times.
|
5 | this->interpreter_sendSignal_hostResponseUnexpected(WasmSequencer_HostFunction::COMMAND); |
| 223 | 5 | 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 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
|
11 | if (cmdIndex != currentCmdIndex) { |
| 229 | 1 | this->log_WARNING_HI_WrongCmdResponseIndex(opCode, response, cmdIndex, currentCmdIndex); | |
| 230 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 10 taken 1 times.
|
1 | this->interpreter_sendSignal_hostResponseUnexpected(WasmSequencer_HostFunction::COMMAND); |
| 231 | 1 | return; | |
| 232 | } | ||
| 233 | |||
| 234 | 10 | this->m_pendingHostFunction.clear(); | |
| 235 | |||
| 236 | // Track commands that came back with a non-OK response. | ||
| 237 |
2/2✓ Branch 4 taken 1 times.
✓ Branch 5 taken 9 times.
|
10 | if (response != Fw::CmdResponse::OK) { |
| 238 | 1 | this->m_tlm.commandsFailed++; | |
| 239 | } | ||
| 240 | |||
| 241 |
1/2✗ Branch 7 not taken.
✓ Branch 8 taken 10 times.
|
10 | this->interpreter_sendSignal_hostResumeI32(static_cast<I32>(response.e)); |
| 242 | } | ||
| 243 | |||
| 244 | 28 | void WasmSequencer ::writeTelemetry_handler(FwIndexType portNum, U32 context) { | |
| 245 | 28 | FW_ASSERT(this->m_wasm != nullptr); | |
| 246 | |||
| 247 |
1/1✓ Branch 3 taken 28 times.
|
28 | auto now = this->getTime(); |
| 248 | |||
| 249 |
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); |
| 250 |
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); |
| 251 |
2/2✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
|
28 | this->tlmWrite_SequencesSucceeded(this->m_tlm.sequencesSucceeded, now); |
| 252 |
2/2✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
|
28 | this->tlmWrite_SequencesFailed(this->m_tlm.sequencesFailed, now); |
| 253 |
2/2✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
|
28 | this->tlmWrite_SequencesCancelled(this->m_tlm.sequencesCancelled, now); |
| 254 |
2/2✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
|
28 | this->tlmWrite_CommandsDispatched(this->m_tlm.commandsDispatched, now); |
| 255 |
2/2✓ Branch 6 taken 28 times.
✓ Branch 13 taken 28 times.
|
28 | this->tlmWrite_CommandsFailed(this->m_tlm.commandsFailed, now); |
| 256 |
2/2✓ Branch 6 taken 28 times.
✓ Branch 12 taken 28 times.
|
28 | this->tlmWrite_LastTrapReason(this->m_exit.lastTrapReason, now); |
| 257 |
2/2✓ Branch 6 taken 28 times.
✓ Branch 12 taken 28 times.
|
28 | this->tlmWrite_SeqName(this->m_tlm.sequenceName, now); |
| 258 | 56 | } | |
| 259 | |||
| 260 | 12 | void WasmSequencer ::seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& filename, const Svc::SeqArgs& args) { | |
| 261 | 12 | FW_ASSERT(this->m_wasm != nullptr); | |
| 262 | |||
| 263 |
1/1✓ Branch 2 taken 12 times.
|
12 | Fw::String runModuleName = ""; |
| 264 | |||
| 265 |
2/2✓ Branch 6 taken 12 times.
✓ Branch 10 taken 12 times.
|
36 | this->controller_sendSignal_run(Svc::WasmSequencer_LoadRequest( |
| 266 | filename, runModuleName, args, | ||
| 267 |
2/2✓ Branch 3 taken 12 times.
✓ Branch 7 taken 12 times.
|
24 | 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 | 24 | } | |
| 272 | |||
| 273 | 2 | void WasmSequencer ::seqCancelIn_handler(FwIndexType portNum) { | |
| 274 | 2 | this->controller_sendSignal_cancel(); | |
| 275 | 2 | this->interpreter_sendSignal_cancel(); | |
| 276 | 2 | } | |
| 277 | |||
| 278 | // ---------------------------------------------------------------------- | ||
| 279 | // Handler implementations for serial input ports | ||
| 280 | // ---------------------------------------------------------------------- | ||
| 281 | |||
| 282 | 32 | void WasmSequencer ::serialIn_handler(FwIndexType portNum, Fw::LinearBufferBase& buffer) { | |
| 283 | 32 | FW_ASSERT(portNum < NUM_SERIALIN_INPUT_PORTS, portNum, NUM_SERIALIN_INPUT_PORTS); | |
| 284 |
1/1✓ Branch 5 taken 32 times.
|
32 | Os::ScopeLock scopeLock(this->m_serialInMutex); |
| 285 | 32 | auto& queue = this->m_serialInQueue[portNum]; | |
| 286 | 32 | auto fullFullBehavior = this->m_config.serialIn[portNum].fullBehavior; | |
| 287 | |||
| 288 | // Each message is framed on the queue as [U32 length][payload] | ||
| 289 | 32 | const FwSizeType headerSize = sizeof(U32); | |
| 290 |
1/1✓ Branch 7 taken 32 times.
|
32 | const FwSizeType payloadSize = buffer.getSize(); |
| 291 |
1/1✓ Branch 2 taken 32 times.
|
32 | 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 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 29 times.
|
32 | 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 | 3 | const FwSizeType maxPayload = (capacity > headerSize) ? (capacity - headerSize) : 0; | |
| 299 |
1/1✓ Branch 5 taken 3 times.
|
3 | this->log_WARNING_HI_SerialInFrameTooLarge(static_cast<U32>(portNum), static_cast<U32>(payloadSize), |
| 300 | static_cast<U32>(maxPayload)); | ||
| 301 | 3 | return; | |
| 302 | } | ||
| 303 | |||
| 304 | // Total framed size; <= capacity by the assertions above, so it cannot overflow. | ||
| 305 | 29 | const FwSizeType frameSize = headerSize + payloadSize; | |
| 306 | |||
| 307 | // Check if we _can_ push the data to the queue | ||
| 308 |
3/3✓ Branch 2 taken 29 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 25 times.
|
29 | if (frameSize > queue.get_free_size()) { |
| 309 | // The queue is full and cannot push this data | ||
| 310 |
2/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
4 | switch (fullFullBehavior) { |
| 311 | 2 | case SerialInQueueFullBehavior::DROP_OLDEST: | |
| 312 | // Drop oldest messages until this one fits. | ||
| 313 |
3/3✓ Branch 2 taken 4 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
|
4 | while (frameSize > queue.get_free_size()) { |
| 314 | 2 | U32 nextMsgSize; | |
| 315 |
1/1✓ Branch 2 taken 2 times.
|
2 | auto status = queue.peek(nextMsgSize); |
| 316 | 2 | FW_ASSERT(status == Fw::FW_SERIALIZE_OK, portNum, status); | |
| 317 | |||
| 318 |
1/1✓ Branch 2 taken 2 times.
|
2 | const FwSizeType allocated = queue.get_allocated_size(); |
| 319 | 2 | FW_ASSERT(allocated >= headerSize, portNum, static_cast<FwAssertArgType>(allocated)); | |
| 320 | 2 | FW_ASSERT(static_cast<FwSizeType>(nextMsgSize) <= allocated - headerSize, portNum, | |
| 321 | static_cast<FwAssertArgType>(nextMsgSize), static_cast<FwAssertArgType>(allocated)); | ||
| 322 | |||
| 323 |
1/1✓ Branch 2 taken 2 times.
|
2 | status = queue.rotate(headerSize + nextMsgSize); |
| 324 | |||
| 325 | 2 | 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 | 2 | break; | |
| 330 | 2 | case SerialInQueueFullBehavior::DROP_NEWEST: | |
| 331 | // Drop this message | ||
| 332 | 2 | 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 |
1/1✓ Branch 2 taken 27 times.
|
54 | Fw::LinearBufferTemplate<sizeof(U32)> sizeSer; |
| 344 |
1/1✓ Branch 2 taken 27 times.
|
27 | auto status = sizeSer.serializeFrom(static_cast<U32>(payloadSize)); |
| 345 | 27 | FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); | |
| 346 | |||
| 347 |
1/1✓ Branch 4 taken 27 times.
|
27 | status = queue.serialize(sizeSer.getBuffAddr(), headerSize); |
| 348 | 27 | FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); | |
| 349 | |||
| 350 |
1/1✓ Branch 6 taken 27 times.
|
27 | status = queue.serialize(buffer.getBuffAddr(), payloadSize); |
| 351 | 27 | FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); | |
| 352 | |||
| 353 | // Wake up any blocking recv calls | ||
| 354 |
1/1✓ Branch 5 taken 27 times.
|
27 | this->interpreter_sendSignal_serialInMessage(portNum); |
| 355 | 32 | } | |
| 356 | |||
| 357 | // ---------------------------------------------------------------------- | ||
| 358 | // Handler implementations for commands | ||
| 359 | // ---------------------------------------------------------------------- | ||
| 360 | |||
| 361 | 143 | void WasmSequencer ::RUN_cmdHandler(FwOpcodeType opCode, | |
| 362 | U32 cmdSeq, | ||
| 363 | const Fw::CmdStringArg& fileName, | ||
| 364 | const Svc::BlockState& block, | ||
| 365 | const SeqArgs& seqArgs) { | ||
| 366 | 143 | FW_ASSERT(this->m_wasm != nullptr); | |
| 367 | |||
| 368 |
1/1✓ Branch 2 taken 143 times.
|
143 | Fw::String runModuleName = ""; |
| 369 |
2/2✓ Branch 9 taken 143 times.
✓ Branch 13 taken 143 times.
|
429 | this->controller_sendSignal_run(Svc::WasmSequencer_LoadRequest( |
| 370 | fileName, runModuleName, seqArgs, | ||
| 371 |
1/1✓ Branch 3 taken 143 times.
|
715 | Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::COMMAND_RUN, |
| 372 |
1/1✓ Branch 2 taken 143 times.
|
286 | WasmSequencer_CommandRequest(opCode, cmdSeq), block, |
| 373 | /* moduleIdx */ 0 // placeholder, gets filled in after load | ||
| 374 | 143 | ))); | |
| 375 | 286 | } | |
| 376 | |||
| 377 | 16 | void WasmSequencer ::WAIT_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 378 | 16 | FW_ASSERT(this->m_wasm != nullptr); | |
| 379 | |||
| 380 |
3/3✓ Branch 3 taken 16 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 14 times.
|
16 | switch (this->controller_getState()) { |
| 381 | 2 | case WasmSequencer_ControllerStateMachine_State::IDLE: | |
| 382 | case WasmSequencer_ControllerStateMachine_State::READY: | ||
| 383 | // Nothing is executing, respond immediately | ||
| 384 |
2/2✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
|
2 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 385 | 2 | break; | |
| 386 | 14 | default: { | |
| 387 |
1/1✓ Branch 7 taken 14 times.
|
14 | const auto status = this->m_waiting.enqueue(WaitingCmd(opCode, cmdSeq)); |
| 388 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 13 times.
|
14 | if (status != Fw::Success::SUCCESS) { |
| 389 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_TooManyBlockingCommands(); |
| 390 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 391 | } | ||
| 392 | 14 | } | |
| 393 | } | ||
| 394 | 16 | } | |
| 395 | |||
| 396 | 60 | void WasmSequencer ::LOAD_cmdHandler(FwOpcodeType opCode, | |
| 397 | U32 cmdSeq, | ||
| 398 | const Fw::CmdStringArg& fileName, | ||
| 399 | const Fw::CmdStringArg& name) { | ||
| 400 | 60 | FW_ASSERT(this->m_wasm != nullptr); | |
| 401 | |||
| 402 |
2/2✓ Branch 12 taken 60 times.
✓ Branch 16 taken 60 times.
|
180 | this->controller_sendSignal_load(Svc::WasmSequencer_LoadRequest( |
| 403 |
1/1✓ Branch 2 taken 60 times.
|
120 | fileName, name, Svc::SeqArgs(), |
| 404 |
1/1✓ Branch 2 taken 60 times.
|
240 | Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::COMMAND_LOAD, |
| 405 |
1/1✓ Branch 2 taken 60 times.
|
120 | WasmSequencer_CommandRequest(opCode, cmdSeq), Svc::BlockState::BLOCK, |
| 406 | /* moduleIdx */ 0 // placeholder, gets filled in after load | ||
| 407 | ))); | ||
| 408 | 60 | } | |
| 409 | |||
| 410 | 13 | 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 | 13 | FW_ASSERT(this->m_wasm != nullptr); | |
| 416 | |||
| 417 |
2/2✓ Branch 9 taken 13 times.
✓ Branch 13 taken 13 times.
|
39 | this->controller_sendSignal_invoke(Svc::WasmSequencer_InvokeRequest( |
| 418 | module, seqArgs, | ||
| 419 |
1/1✓ Branch 3 taken 13 times.
|
65 | Svc::WasmSequencer_RequestContext(WasmSequencer_SignalSource::COMMAND_INVOKE, |
| 420 |
1/1✓ Branch 2 taken 13 times.
|
26 | WasmSequencer_CommandRequest(opCode, cmdSeq), block, |
| 421 | /* moduleIdx */ 0 // placeholder, gets filled in after invoke | ||
| 422 | 13 | ))); | |
| 423 | 13 | } | |
| 424 | |||
| 425 | 25 | void WasmSequencer ::CANCEL_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 426 | 25 | this->controller_sendSignal_cancel(); | |
| 427 |
2/2✓ Branch 6 taken 25 times.
✓ Branch 10 taken 25 times.
|
25 | this->interpreter_sendSignal_cmdCancel(WasmSequencer_CommandRequest(opCode, cmdSeq)); |
| 428 | 25 | } | |
| 429 | |||
| 430 | 9 | void WasmSequencer ::PAUSE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 431 |
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) { |
| 432 | 1 | this->log_WARNING_LO_SequenceNotRunning(); | |
| 433 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 434 | 1 | return; | |
| 435 | } | ||
| 436 | |||
| 437 | 8 | this->m_pendingPause = true; | |
| 438 |
2/2✓ Branch 6 taken 8 times.
✓ Branch 9 taken 8 times.
|
8 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 439 | } | ||
| 440 | |||
| 441 | 5 | void WasmSequencer ::CONTINUE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 442 | 5 | FW_ASSERT(this->m_wasm != nullptr); | |
| 443 | |||
| 444 |
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()) { |
| 445 | 1 | 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 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 450 | 1 | break; | |
| 451 | 3 | case WasmSequencer_InterpreterStateMachine_State::RUNNING_PAUSED: | |
| 452 | 3 | this->interpreter_sendSignal_cmd_CONTINUE(); | |
| 453 |
2/2✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
|
3 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 454 | 3 | break; | |
| 455 | 1 | case WasmSequencer_InterpreterStateMachine_State::IDLE: | |
| 456 | 1 | this->log_WARNING_LO_SequenceNotRunning(); | |
| 457 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 458 | 1 | break; | |
| 459 | ✗ | default: | |
| 460 | ✗ | FW_ASSERT(false, this->interpreter_getState()); | |
| 461 | } | ||
| 462 | 5 | } | |
| 463 | |||
| 464 | 9 | 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 | 9 | FW_ASSERT(this->m_wasm != nullptr); | |
| 470 | |||
| 471 | 9 | spacewasm_value_t s_value; | |
| 472 | 9 | s_value.tag = SPACEWASM_I32; | |
| 473 | 9 | s_value.u.i32_ = value; | |
| 474 | |||
| 475 |
1/1✓ Branch 10 taken 9 times.
|
9 | auto status = this->setGlobal(moduleName, name, s_value); |
| 476 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
|
9 | if (status == SPACEWASM_OK) { |
| 477 |
2/2✓ Branch 6 taken 5 times.
✓ Branch 9 taken 5 times.
|
5 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 478 | } else { | ||
| 479 |
2/2✓ Branch 6 taken 4 times.
✓ Branch 16 taken 4 times.
|
4 | this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status); |
| 480 |
2/2✓ Branch 6 taken 4 times.
✓ Branch 9 taken 4 times.
|
4 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 481 | } | ||
| 482 | 9 | } | |
| 483 | |||
| 484 | 3 | 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 | 3 | FW_ASSERT(this->m_wasm != nullptr); | |
| 490 | |||
| 491 | 3 | spacewasm_value_t s_value; | |
| 492 | 3 | s_value.tag = SPACEWASM_I64; | |
| 493 | 3 | s_value.u.i64_ = value; | |
| 494 | |||
| 495 |
1/1✓ Branch 10 taken 3 times.
|
3 | auto status = this->setGlobal(moduleName, name, s_value); |
| 496 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (status == SPACEWASM_OK) { |
| 497 |
2/2✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
|
2 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 498 | } else { | ||
| 499 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 16 taken 1 times.
|
1 | this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status); |
| 500 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 501 | } | ||
| 502 | 3 | } | |
| 503 | |||
| 504 | 3 | 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 | 3 | FW_ASSERT(this->m_wasm != nullptr); | |
| 510 | |||
| 511 | 3 | spacewasm_value_t s_value; | |
| 512 | 3 | s_value.tag = SPACEWASM_F32; | |
| 513 | 3 | s_value.u.f32_ = value; | |
| 514 | |||
| 515 |
1/1✓ Branch 10 taken 3 times.
|
3 | auto status = this->setGlobal(moduleName, name, s_value); |
| 516 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (status == SPACEWASM_OK) { |
| 517 |
2/2✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
|
2 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 518 | } else { | ||
| 519 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 16 taken 1 times.
|
1 | this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status); |
| 520 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 521 | } | ||
| 522 | 3 | } | |
| 523 | |||
| 524 | 3 | 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 | 3 | FW_ASSERT(this->m_wasm != nullptr); | |
| 530 | |||
| 531 | 3 | spacewasm_value_t g_value; | |
| 532 | 3 | g_value.tag = SPACEWASM_F64; | |
| 533 | 3 | g_value.u.f64_ = value; | |
| 534 | |||
| 535 |
1/1✓ Branch 10 taken 3 times.
|
3 | auto status = this->setGlobal(moduleName, name, g_value); |
| 536 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (status == SPACEWASM_OK) { |
| 537 |
2/2✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
|
2 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 538 | } else { | ||
| 539 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 16 taken 1 times.
|
1 | this->log_WARNING_LO_GlobalSetFailed(moduleName, name, status); |
| 540 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 541 | } | ||
| 542 | 3 | } | |
| 543 | |||
| 544 | 25 | void WasmSequencer ::GLOBAL_GET_cmdHandler(FwOpcodeType opCode, | |
| 545 | U32 cmdSeq, | ||
| 546 | const Fw::CmdStringArg& moduleName, | ||
| 547 | const Fw::CmdStringArg& name) { | ||
| 548 | 25 | FW_ASSERT(this->m_wasm != nullptr); | |
| 549 | |||
| 550 | 25 | spacewasm_value_t g_value; | |
| 551 |
1/1✓ Branch 10 taken 25 times.
|
25 | auto status = this->getGlobal(moduleName, name, g_value); |
| 552 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 4 times.
|
25 | if (status == SPACEWASM_OK) { |
| 553 |
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) { |
| 554 | 12 | case SPACEWASM_I32: | |
| 555 |
1/1✓ Branch 11 taken 12 times.
|
12 | this->log_ACTIVITY_LO_GlobalValueI32(moduleName, name, g_value.u.i32_); |
| 556 | 12 | break; | |
| 557 | 3 | case SPACEWASM_I64: | |
| 558 |
1/1✓ Branch 11 taken 3 times.
|
3 | this->log_ACTIVITY_LO_GlobalValueI64(moduleName, name, g_value.u.i64_); |
| 559 | 3 | break; | |
| 560 | 3 | case SPACEWASM_F32: | |
| 561 |
1/1✓ Branch 11 taken 3 times.
|
3 | this->log_ACTIVITY_LO_GlobalValueF32(moduleName, name, g_value.u.f32_); |
| 562 | 3 | break; | |
| 563 | 3 | case SPACEWASM_F64: | |
| 564 |
1/1✓ Branch 11 taken 3 times.
|
3 | this->log_ACTIVITY_LO_GlobalValueF64(moduleName, name, g_value.u.f64_); |
| 565 | 3 | break; | |
| 566 | ✗ | default: | |
| 567 | ✗ | FW_ASSERT(false, g_value.tag); | |
| 568 | } | ||
| 569 | |||
| 570 |
2/2✓ Branch 6 taken 21 times.
✓ Branch 9 taken 21 times.
|
21 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 571 | } else { | ||
| 572 |
2/2✓ Branch 6 taken 4 times.
✓ Branch 16 taken 4 times.
|
4 | this->log_WARNING_LO_GlobalGetFailed(moduleName, name, status); |
| 573 |
2/2✓ Branch 6 taken 4 times.
✓ Branch 9 taken 4 times.
|
4 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 574 | } | ||
| 575 | 25 | } | |
| 576 | |||
| 577 | } // namespace Svc | ||
| 578 |