F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
WasmSequencerHost.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title WasmSequencerHost.cpp
3 // \author tumbar
4 // \brief cpp file for WasmSequencer Wasm Host functions
5 // ======================================================================
6 
7 #include <limits>
8 
13 #include "Fw/Types/Assert.hpp"
22 #include "fprime.h"
23 #include "spacewasm.h"
24 
25 // Guest ABI cross-checks
26 namespace {
30 template <typename GuestEnum, typename FrameworkEnum>
31 constexpr bool sameOrdinal(GuestEnum guest, FrameworkEnum framework) {
32  return static_cast<I32>(guest) == static_cast<I32>(framework);
33 }
34 } // namespace
35 
36 static_assert(sameOrdinal(FPRIME_TLM_VALID, Fw::TlmValid::VALID), "guest FPRIME_TLM_* must match Fw::TlmValid");
37 static_assert(sameOrdinal(FPRIME_TLM_INVALID, Fw::TlmValid::INVALID), "guest FPRIME_TLM_* must match Fw::TlmValid");
38 
39 static_assert(sameOrdinal(FPRIME_PARAM_UNINIT, Fw::ParamValid::UNINIT),
40  "guest FPRIME_PARAM_* must match Fw::ParamValid");
41 static_assert(sameOrdinal(FPRIME_PARAM_VALID, Fw::ParamValid::VALID), "guest FPRIME_PARAM_* must match Fw::ParamValid");
42 static_assert(sameOrdinal(FPRIME_PARAM_INVALID, Fw::ParamValid::INVALID),
43  "guest FPRIME_PARAM_* must match Fw::ParamValid");
44 static_assert(sameOrdinal(FPRIME_PARAM_DEFAULT, Fw::ParamValid::DEFAULT),
45  "guest FPRIME_PARAM_* must match Fw::ParamValid");
46 
47 static_assert(sameOrdinal(FPRIME_CMD_OK, Fw::CmdResponse::OK), "guest FPRIME_CMD_* must match Fw::CmdResponse");
49  "guest FPRIME_CMD_* must match Fw::CmdResponse");
51  "guest FPRIME_CMD_* must match Fw::CmdResponse");
52 static_assert(sameOrdinal(FPRIME_CMD_FORMAT_ERROR, Fw::CmdResponse::FORMAT_ERROR),
53  "guest FPRIME_CMD_* must match Fw::CmdResponse");
55  "guest FPRIME_CMD_* must match Fw::CmdResponse");
56 static_assert(sameOrdinal(FPRIME_CMD_BUSY, Fw::CmdResponse::BUSY), "guest FPRIME_CMD_* must match Fw::CmdResponse");
57 static_assert(sameOrdinal(FPRIME_CMD_CLEARED, Fw::CmdResponse::CLEARED),
58  "guest FPRIME_CMD_* must match Fw::CmdResponse");
59 
60 static_assert(sameOrdinal(FPRIME_EVENT_FATAL, Fw::LogSeverity::FATAL),
61  "guest FPRIME_EVENT_* must match Fw::LogSeverity");
62 static_assert(sameOrdinal(FPRIME_EVENT_WARNING_HI, Fw::LogSeverity::WARNING_HI),
63  "guest FPRIME_EVENT_* must match Fw::LogSeverity");
64 static_assert(sameOrdinal(FPRIME_EVENT_WARNING_LO, Fw::LogSeverity::WARNING_LO),
65  "guest FPRIME_EVENT_* must match Fw::LogSeverity");
66 static_assert(sameOrdinal(FPRIME_EVENT_COMMAND, Fw::LogSeverity::COMMAND),
67  "guest FPRIME_EVENT_* must match Fw::LogSeverity");
68 static_assert(sameOrdinal(FPRIME_EVENT_ACTIVITY_HI, Fw::LogSeverity::ACTIVITY_HI),
69  "guest FPRIME_EVENT_* must match Fw::LogSeverity");
70 static_assert(sameOrdinal(FPRIME_EVENT_ACTIVITY_LO, Fw::LogSeverity::ACTIVITY_LO),
71  "guest FPRIME_EVENT_* must match Fw::LogSeverity");
72 static_assert(sameOrdinal(FPRIME_EVENT_DIAGNOSTIC, Fw::LogSeverity::DIAGNOSTIC),
73  "guest FPRIME_EVENT_* must match Fw::LogSeverity");
74 
75 namespace Svc {
76 
78 using HostFn = spacewasm_hostcall_result_t (WasmSequencer::*)(struct spacewasm_caller_t*,
79  const struct spacewasm_value_t*,
80  size_t,
82 
84 template <HostFn Handler>
86  void* userdata,
87  const struct spacewasm_value_t* params,
88  size_t n_params,
89  struct spacewasm_value_t* out_result) {
90  FW_ASSERT(userdata != nullptr);
91  return (static_cast<WasmSequencer*>(userdata)->*Handler)(caller, params, n_params, out_result);
92 }
93 
94 void WasmSequencer ::hostFprimeV1(spacewasm_host_t* host) {
95  spacewasm_status_t status;
96  U32 module_idx;
97  status = spacewasm_add_host_module(host, "fprime_v1", 12, 0, &module_idx);
98  FW_ASSERT(status == SPACEWASM_OK, status);
99 
100  status = spacewasm_add_host_function(host, module_idx, "exit", "i", "",
101  &hostFunctionTrampoline<&WasmSequencer::wasmExit>, this);
102  FW_ASSERT(status == SPACEWASM_OK, status);
103 
104  status = spacewasm_add_host_function(host, module_idx, "panic", "i", "",
105  &hostFunctionTrampoline<&WasmSequencer::wasmPanic>, this);
106  FW_ASSERT(status == SPACEWASM_OK, status);
107 
108  status = spacewasm_add_host_function(host, module_idx, "args", "ii", "i",
109  &hostFunctionTrampoline<&WasmSequencer::wasmArgs>, this);
110  FW_ASSERT(status == SPACEWASM_OK, status);
111 
112  status = spacewasm_add_host_function(host, module_idx, "time", "ii", "",
113  &hostFunctionTrampoline<&WasmSequencer::wasmTime>, this);
114  FW_ASSERT(status == SPACEWASM_OK, status);
115 
116  status = spacewasm_add_host_function(host, module_idx, "tlm", "Iiiii", "i",
117  &hostFunctionTrampoline<&WasmSequencer::wasmReadTelemetry>, this);
118  FW_ASSERT(status == SPACEWASM_OK, status);
119 
120  status = spacewasm_add_host_function(host, module_idx, "prm", "Iii", "i",
121  &hostFunctionTrampoline<&WasmSequencer::wasmReadParameter>, this);
122  FW_ASSERT(status == SPACEWASM_OK, status);
123 
124  status = spacewasm_add_host_function(host, module_idx, "cmd", "ii", "i",
125  &hostFunctionTrampoline<&WasmSequencer::wasmCommand>, this);
126  FW_ASSERT(status == SPACEWASM_OK, status);
127 
128  status = spacewasm_add_host_function(host, module_idx, "event", "iii", "",
129  &hostFunctionTrampoline<&WasmSequencer::wasmEvent>, this);
130  FW_ASSERT(status == SPACEWASM_OK, status);
131 
132  status = spacewasm_add_host_function(host, module_idx, "rsleep", "I", "",
133  &hostFunctionTrampoline<&WasmSequencer::wasmRsleep>, this);
134  FW_ASSERT(status == SPACEWASM_OK, status);
135 
136  status = spacewasm_add_host_function(host, module_idx, "asleep", "I", "",
137  &hostFunctionTrampoline<&WasmSequencer::wasmAsleep>, this);
138  FW_ASSERT(status == SPACEWASM_OK, status);
139 
140  status = spacewasm_add_host_function(host, module_idx, "serial_send", "iii", "",
141  &hostFunctionTrampoline<&WasmSequencer::wasmSerialOut>, this);
142  FW_ASSERT(status == SPACEWASM_OK, status);
143 
144  status = spacewasm_add_host_function(host, module_idx, "serial_recv", "iiiii", "i",
145  &hostFunctionTrampoline<&WasmSequencer::wasmSerialRecv>, this);
146  FW_ASSERT(status == SPACEWASM_OK, status);
147 }
148 
149 spacewasm_hostcall_result_t WasmSequencer::wasmExit(spacewasm_caller_t* caller,
150  const spacewasm_value_t* params,
151  size_t n_params,
153  FW_ASSERT(!this->m_pendingHostFunction.isPending());
154  FW_ASSERT(params != nullptr);
155  FW_ASSERT(n_params == 1, static_cast<FwAssertArgType>(n_params));
156 
157  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I32, params[0].tag);
158 
159  this->m_exit.reason = WasmSequencer_ExitReason::HOST_EXIT;
160  this->m_exit.code = params[0].u.i32_;
161 
162  return SPACEWASM_TRAP;
163 }
164 
165 spacewasm_hostcall_result_t WasmSequencer::wasmPanic(spacewasm_caller_t* caller,
166  const spacewasm_value_t* params,
167  size_t n_params,
169  FW_ASSERT(!this->m_pendingHostFunction.isPending());
170  FW_ASSERT(params != nullptr);
171  FW_ASSERT(n_params == 1, static_cast<FwAssertArgType>(n_params));
172 
173  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I32, params[0].tag);
174 
175  this->m_exit.reason = WasmSequencer_ExitReason::HOST_PANIC;
176  this->m_exit.code = params[0].u.i32_;
177 
178  return SPACEWASM_TRAP;
179 }
180 
181 spacewasm_hostcall_result_t WasmSequencer::wasmArgs(spacewasm_caller_t* caller,
182  const spacewasm_value_t* params,
183  size_t n_params,
184  spacewasm_value_t* ret) {
185  FW_ASSERT(!this->m_pendingHostFunction.isPending());
186  FW_ASSERT(params != nullptr);
187  FW_ASSERT(n_params == 2, static_cast<FwAssertArgType>(n_params));
188 
189  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I32, params[0].tag);
190  FW_ASSERT(params[1].tag == spacewasm_valtype_t::SPACEWASM_I32, params[1].tag);
191  FW_ASSERT(ret != nullptr);
192 
193  // Deprecated: this sequencer does not pass arguments to a sequence
195  ret->u.i32_ = 0;
196 
198 }
199 
200 spacewasm_hostcall_result_t WasmSequencer::wasmTime(spacewasm_caller_t* caller,
201  const spacewasm_value_t* params,
202  size_t n_params,
204  FW_ASSERT(!this->m_pendingHostFunction.isPending());
205  FW_ASSERT(params != nullptr);
206  FW_ASSERT(n_params == 2, static_cast<FwAssertArgType>(n_params));
207  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I32, params[0].tag);
208  FW_ASSERT(params[1].tag == spacewasm_valtype_t::SPACEWASM_I32, params[1].tag);
209 
210  const U32 time_ptr = static_cast<U32>(params[0].u.i32_);
211  const U32 time_size = static_cast<U32>(params[1].u.i32_);
212 
213  spacewasm_hostcall_result_t return_status;
214  if (time_size < Fw::Time::SERIALIZED_SIZE) {
215  // We expect an exact match for serialized time
217  return_status = SPACEWASM_TRAP;
218  } else if (time_size > Fw::Time::SERIALIZED_SIZE) {
219  // We expect an exact match for serialized time
221  return_status = SPACEWASM_TRAP;
222  } else {
223  this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::TIME;
224  this->m_pendingHostFunction.caller = caller;
225  this->m_pendingHostFunction.u.time.ptr = time_ptr;
226  this->m_pendingHostFunction.u.time.len = time_size;
227 
228  // Always pause the interpreter to allow the state machine to process this request
229  return_status = SPACEWASM_PAUSE;
230  }
231 
232  return return_status;
233 }
234 
235 spacewasm_hostcall_result_t WasmSequencer::wasmReadTelemetry(spacewasm_caller_t* caller,
236  const spacewasm_value_t* params,
237  size_t n_params,
239  FW_ASSERT(!this->m_pendingHostFunction.isPending());
240  // These are automatically validated by spacewasm so it should be safe to assert them
241  FW_ASSERT(params != nullptr);
242  FW_ASSERT(n_params == 5, static_cast<FwAssertArgType>(n_params));
243 
244  // FwChanIdType always in 64-bits
245  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I64, params[0].tag);
246  FW_ASSERT(params[1].tag == spacewasm_valtype_t::SPACEWASM_I32, params[1].tag);
247  FW_ASSERT(params[2].tag == spacewasm_valtype_t::SPACEWASM_I32, params[2].tag);
248  FW_ASSERT(params[3].tag == spacewasm_valtype_t::SPACEWASM_I32, params[3].tag);
249  FW_ASSERT(params[4].tag == spacewasm_valtype_t::SPACEWASM_I32, params[4].tag);
250 
251  I64 id = params[0].u.i64_;
252  const U32 time_ptr = static_cast<U32>(params[1].u.i32_);
253  const U32 time_size = static_cast<U32>(params[2].u.i32_);
254  const U32 value_ptr = static_cast<U32>(params[3].u.i32_);
255  const U32 value_size = static_cast<U32>(params[4].u.i32_);
256 
257  // The telemetry port is a plain (not required) output port, so guard against an
258  // unconnected deployment before dispatching; the generated invoker would FW_ASSERT.
259  if (!this->isConnected_getTlmChan_OutputPort(0)) {
261  return SPACEWASM_TRAP;
262  }
263 
264  spacewasm_hostcall_result_t return_status;
265  if (time_size < Fw::Time::SERIALIZED_SIZE) {
266  // We expect an exact match for serialized time
269  return_status = SPACEWASM_TRAP;
270  } else if (time_size > Fw::Time::SERIALIZED_SIZE) {
271  // We expect an exact match for serialized time
274  return_status = SPACEWASM_TRAP;
275  } else if (id < 0 || static_cast<U64>(id) > static_cast<U64>(std::numeric_limits<FwChanIdType>::max())) {
276  // A guest id that does not fit FwChanIdType would silently alias a different,
277  // valid channel if cast directly. Reject it instead of truncating.
279  return_status = SPACEWASM_TRAP;
280  } else {
281  this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::TELEMETRY;
282  this->m_pendingHostFunction.caller = caller;
283  this->m_pendingHostFunction.u.telemetry.chanId = static_cast<FwChanIdType>(id);
284  this->m_pendingHostFunction.u.telemetry.timePtr = time_ptr;
285  this->m_pendingHostFunction.u.telemetry.timeLen = time_size;
286  this->m_pendingHostFunction.u.telemetry.valuePtr = value_ptr;
287  this->m_pendingHostFunction.u.telemetry.valueLen = value_size;
288 
289  // Always pause the interpreter to allow the state machine to process this request
290  return_status = SPACEWASM_PAUSE;
291  }
292 
293  return return_status;
294 }
295 
296 spacewasm_hostcall_result_t WasmSequencer::wasmReadParameter(spacewasm_caller_t* caller,
297  const spacewasm_value_t* params,
298  size_t n_params,
300  FW_ASSERT(!this->m_pendingHostFunction.isPending());
301  // These are automatically validated by spacewasm so it should be safe to assert them
302  FW_ASSERT(params != nullptr);
303  FW_ASSERT(n_params == 3, static_cast<FwAssertArgType>(n_params));
304 
305  // FwPrmIdType always in 64-bits
306  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I64, params[0].tag);
307  FW_ASSERT(params[1].tag == spacewasm_valtype_t::SPACEWASM_I32, params[1].tag);
308  FW_ASSERT(params[2].tag == spacewasm_valtype_t::SPACEWASM_I32, params[2].tag);
309 
310  I64 id = params[0].u.i64_;
311  const U32 ptr = static_cast<U32>(params[1].u.i32_);
312  const U32 len = static_cast<U32>(params[2].u.i32_);
313 
314  // The parameter port is a plain (not required) output port, so guard against an
315  // unconnected deployment before dispatching; the generated invoker would FW_ASSERT.
316  if (!this->isConnected_getParam_OutputPort(0)) {
318  return SPACEWASM_TRAP;
319  }
320 
321  if (id < 0 || static_cast<U64>(id) > static_cast<U64>(std::numeric_limits<FwPrmIdType>::max())) {
322  // A guest id that does not fit FwPrmIdType would silently alias a different,
323  // valid parameter if cast directly. Reject it instead of truncating. Compare in U64 so the
324  // bound holds even if FwPrmIdType is configured wider than I64's positive range.
326  return SPACEWASM_TRAP;
327  }
328 
329  this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::PARAMETER;
330  this->m_pendingHostFunction.caller = caller;
331  this->m_pendingHostFunction.u.parameter.prmId = static_cast<FwPrmIdType>(id);
332  this->m_pendingHostFunction.u.parameter.ptr = ptr;
333  this->m_pendingHostFunction.u.parameter.len = len;
334 
335  // Always pause the interpreter to allow the state machine to process this request
336  return SPACEWASM_PAUSE;
337 }
338 
339 spacewasm_hostcall_result_t WasmSequencer::wasmCommand(struct spacewasm_caller_t* caller,
340  const struct spacewasm_value_t* params,
341  size_t n_params,
342  struct spacewasm_value_t* out_result) {
343  FW_ASSERT(!this->m_pendingHostFunction.isPending());
344  // These are automatically validated by spacewasm so it should be safe to assert them
345  FW_ASSERT(params != nullptr);
346  FW_ASSERT(n_params == 2, static_cast<FwAssertArgType>(n_params));
347  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I32, params[0].tag);
348  FW_ASSERT(params[1].tag == spacewasm_valtype_t::SPACEWASM_I32, params[1].tag);
349 
350  const U32 ptr = static_cast<U32>(params[0].u.i32_);
351  const U32 len = static_cast<U32>(params[1].u.i32_);
352 
353  // cmdOut is a plain (not required) output port, so guard against an unconnected
354  // deployment before dispatching; the generated invoker would FW_ASSERT.
355  if (!this->isConnected_cmdOut_OutputPort(0)) {
357  return SPACEWASM_TRAP;
358  }
359 
360  constexpr const U32 maxPayload = FW_COM_BUFFER_MAX_SIZE - sizeof(FwPacketDescriptorType);
361  spacewasm_hostcall_result_t return_status;
362  if (len > maxPayload) {
364  return_status = SPACEWASM_TRAP;
365  } else {
366  this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::COMMAND;
367  this->m_pendingHostFunction.caller = caller;
368  this->m_pendingHostFunction.u.command.ptr = ptr;
369  this->m_pendingHostFunction.u.command.len = len;
370 
371  // Always pause the interpreter to allow the state machine to process this request
372  return_status = SPACEWASM_PAUSE;
373  }
374 
375  return return_status;
376 }
377 
378 spacewasm_hostcall_result_t WasmSequencer::wasmEvent(spacewasm_caller_t* caller,
379  const spacewasm_value_t* params,
380  size_t n_params,
382  FW_ASSERT(!this->m_pendingHostFunction.isPending());
383  // These are automatically validated by spacewasm so it should be safe to assert them
384  FW_ASSERT(params != nullptr);
385  FW_ASSERT(n_params == 3, static_cast<FwAssertArgType>(n_params));
386  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I32, params[0].tag);
387  FW_ASSERT(params[1].tag == spacewasm_valtype_t::SPACEWASM_I32, params[1].tag);
388  FW_ASSERT(params[2].tag == spacewasm_valtype_t::SPACEWASM_I32, params[2].tag);
389 
390  // The requested severity is validated when the event is dispatched (see the
391  // EVENT case in dispatchPendingHostFunction). A forbidden or out-of-range
392  // severity is reported (with the guest message) rather than trapping, so we
393  // read the message here in all cases and stash the raw id.
394  U32 ptr = static_cast<U32>(params[1].u.i32_);
395  U32 len = static_cast<U32>(params[2].u.i32_);
396  if (len > FW_LOG_STRING_MAX_SIZE) {
398  }
399 
400  // Pend this event dispatch to be executed by the sequencer state machine
401  this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::EVENT;
402  this->m_pendingHostFunction.caller = caller;
403  this->m_pendingHostFunction.u.event.rawSeverity = static_cast<U32>(params[0].u.i32_);
404  this->m_pendingHostFunction.u.event.msgPtr = ptr;
405  this->m_pendingHostFunction.u.event.msgLen = len;
406 
407  return SPACEWASM_PAUSE;
408 }
409 
410 spacewasm_hostcall_result_t WasmSequencer::wasmRsleep(spacewasm_caller_t* caller,
411  const spacewasm_value_t* params,
412  size_t n_params,
414  FW_ASSERT(!this->m_pendingHostFunction.isPending());
415  FW_ASSERT(params != nullptr);
416  FW_ASSERT(n_params == 1, static_cast<FwAssertArgType>(n_params));
417  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I64, params[0].tag);
418 
419  const U64 us = static_cast<U64>(params[0].u.i64_);
420 
421  // The seconds part of the duration must fit the U32 fields of Fw::Time; a
422  // guest value large enough to overflow it would silently truncate. Reject it.
423  if ((us / 1000000u) > static_cast<U64>(std::numeric_limits<U32>::max())) {
425  return SPACEWASM_TRAP;
426  }
427 
428  this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::RSLEEP;
429  this->m_pendingHostFunction.caller = caller;
430  this->m_pendingHostFunction.u.rsleep.us = us;
431 
432  return SPACEWASM_PAUSE;
433 }
434 
435 spacewasm_hostcall_result_t WasmSequencer::wasmAsleep(spacewasm_caller_t* caller,
436  const spacewasm_value_t* params,
437  size_t n_params,
439  FW_ASSERT(!this->m_pendingHostFunction.isPending());
440  FW_ASSERT(params != nullptr);
441  FW_ASSERT(n_params == 1, static_cast<FwAssertArgType>(n_params));
442  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I64, params[0].tag);
443 
444  const U64 us = static_cast<U64>(params[0].u.i64_);
445 
446  // The seconds part of the duration must fit the U32 fields of Fw::Time; a
447  // guest value large enough to overflow it would silently truncate. Reject it.
448  if ((us / 1000000u) > static_cast<U64>(std::numeric_limits<U32>::max())) {
450  return SPACEWASM_TRAP;
451  }
452 
453  this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::ASLEEP;
454  this->m_pendingHostFunction.caller = caller;
455  this->m_pendingHostFunction.u.asleep.us = us;
456 
457  return SPACEWASM_PAUSE;
458 }
459 
460 spacewasm_hostcall_result_t WasmSequencer::wasmSerialOut(spacewasm_caller_t* caller,
461  const spacewasm_value_t* params,
462  size_t n_params,
464  FW_ASSERT(!this->m_pendingHostFunction.isPending());
465  // These are automatically validated by spacewasm so it should be safe to assert them
466  FW_ASSERT(params != nullptr);
467  FW_ASSERT(n_params == 3, static_cast<FwAssertArgType>(n_params));
468  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I32, params[0].tag);
469  FW_ASSERT(params[1].tag == spacewasm_valtype_t::SPACEWASM_I32, params[1].tag);
470  FW_ASSERT(params[2].tag == spacewasm_valtype_t::SPACEWASM_I32, params[2].tag);
471 
472  const I32 index = params[0].u.i32_;
473  const U32 ptr = static_cast<U32>(params[1].u.i32_);
474  const U32 len = static_cast<U32>(params[2].u.i32_);
475 
476  // Reject if the payload does not fit the copy-out buffer. A serialOut buffer that was never
477  // configured (serialOutMaxSize == 0 in configure()) is null-backed with capacity 0; trap even a
478  // zero-length send in that case rather than forwarding a null-backed buffer to serialOut_out.
479  if (len > this->m_serialOutBuffer.getCapacity() || this->m_serialOutBuffer.getBuffAddr() == nullptr) {
481  static_cast<U32>(this->m_serialOutBuffer.getCapacity()));
482  return SPACEWASM_TRAP;
483  }
484 
485  if (index < 0 || index >= this->getNum_serialOut_OutputPorts() ||
486  !this->isConnected_serialOut_OutputPort(static_cast<FwIndexType>(index))) {
488  static_cast<U32>(this->getNum_serialOut_OutputPorts()));
489  return SPACEWASM_TRAP;
490  }
491 
492  this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::SERIAL_OUT;
493  this->m_pendingHostFunction.caller = caller;
494  this->m_pendingHostFunction.u.serialOut.index = static_cast<U32>(index);
495  this->m_pendingHostFunction.u.serialOut.ptr = ptr;
496  this->m_pendingHostFunction.u.serialOut.len = len;
497 
498  // Always pause the interpreter to allow the state machine to process this request
499  return SPACEWASM_PAUSE;
500 }
501 
502 spacewasm_hostcall_result_t WasmSequencer::wasmSerialRecv(spacewasm_caller_t* caller,
503  const spacewasm_value_t* params,
504  size_t n_params,
506  FW_ASSERT(!this->m_pendingHostFunction.isPending());
507  // These are automatically validated by spacewasm so it should be safe to assert them
508  FW_ASSERT(params != nullptr);
509  FW_ASSERT(n_params == 5, static_cast<FwAssertArgType>(n_params));
510  FW_ASSERT(params[0].tag == spacewasm_valtype_t::SPACEWASM_I32, params[0].tag);
511  FW_ASSERT(params[1].tag == spacewasm_valtype_t::SPACEWASM_I32, params[1].tag);
512  FW_ASSERT(params[2].tag == spacewasm_valtype_t::SPACEWASM_I32, params[2].tag);
513  FW_ASSERT(params[3].tag == spacewasm_valtype_t::SPACEWASM_I32, params[3].tag);
514  FW_ASSERT(params[4].tag == spacewasm_valtype_t::SPACEWASM_I32, params[4].tag);
515 
516  const I32 index = params[0].u.i32_;
517  const U32 data_ptr = static_cast<U32>(params[1].u.i32_);
518  const U32 data_len = static_cast<U32>(params[2].u.i32_);
519  const U32 actual_size_ptr = static_cast<U32>(params[3].u.i32_);
520  const I32 block_type = params[4].u.i32_;
521 
522  if (index < 0 || index >= NUM_SERIALIN_INPUT_PORTS) {
525  return SPACEWASM_TRAP;
526  }
527 
528  if (block_type < 0 || block_type > static_cast<I32>(std::numeric_limits<Svc::BlockState::SerialType>::max()) ||
529  !Svc::BlockState::isValid(static_cast<Svc::BlockState::SerialType>(block_type))) {
530  this->log_WARNING_HI_InvalidBlockingTypeValue(block_type);
531  return SPACEWASM_TRAP;
532  }
533 
534  this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::SERIAL_RECV;
535  this->m_pendingHostFunction.caller = caller;
536  this->m_pendingHostFunction.u.serialRecv.index = static_cast<U32>(index);
537  this->m_pendingHostFunction.u.serialRecv.dataPtr = data_ptr;
538  this->m_pendingHostFunction.u.serialRecv.dataSize = data_len;
539  this->m_pendingHostFunction.u.serialRecv.actualSizePtr = actual_size_ptr;
540  this->m_pendingHostFunction.u.serialRecv.blockingType = static_cast<Svc::BlockState::T>(block_type);
541 
542  // Always pause the interpreter to allow the state machine to process this request
543  return SPACEWASM_PAUSE;
544 }
545 
546 } // namespace Svc
union spacewasm_value_payload_t u
Definition: spacewasm.h:412
U16 FwPacketDescriptorType
The width of packet descriptors when they are serialized by the framework.
void log_WARNING_HI_HostFunctionInvalidId(const Svc::WasmSequencer_HostFunction &host_function, I64 id) const
Command had execution error.
Definition: fprime.h:111
The interpreter exited via HOST_TRAP and we indicated HOST_PANIC in the host function.
void log_WARNING_HI_InvalidBlockingTypeValue(I32 invalidValue) const
Log event InvalidBlockingTypeValue.
Parameter has a valid value from the parameter database.
Definition: fprime.h:84
Invalid opcode dispatched.
A less serious but recoverable event.
Definition: fprime.h:133
FwIdType FwPrmIdType
The type of a parameter identifier.
Component busy.
Definition: fprime.h:113
Parameter is serving its compiled-in default value.
Definition: fprime.h:86
bool isConnected_getTlmChan_OutputPort(FwIndexType portNum) const
struct spacewasm_caller_t spacewasm_caller_t
Definition: spacewasm.h:369
spacewasm_status_t spacewasm_add_host_function(struct spacewasm_host_t *host, uint32_t module_idx, const char *name, const char *params_sig, const char *returns_sig, spacewasm_host_fn_t f, void *userdata)
bool isConnected_getParam_OutputPort(FwIndexType portNum) const
T
The raw enum type.
Serializable::SizeType getCapacity() const override
Get buffer capacity.
Invalid opcode dispatched.
Definition: fprime.h:105
Software diagnostic events.
Command tracking was cleared before the command completed.
Command failed validation.
Definition: fprime.h:107
Important informational events.
Definition: fprime.h:135
static spacewasm_hostcall_result_t hostFunctionTrampoline(struct spacewasm_caller_t *caller, void *userdata, const struct spacewasm_value_t *params, size_t n_params, struct spacewasm_value_t *out_result)
Named trampoline adapting spacewasm&#39;s C host-function ABI to a member handler.
Parameter storage has not been initialized.
Definition: fprime.h:83
void log_WARNING_HI_HostFunctionInvalidPort(const Svc::WasmSequencer_HostFunction &host_function, I32 index, U32 numPorts) const
Less important informational events.
Definition: fprime.h:136
U8 * getBuffAddr()
Get buffer address for data filling (non-const version)
Less important informational events.
An activity related to commanding.
A less serious but recoverable event.
bool isConnected_serialOut_OutputPort(FwIndexType portNum) const
A fatal non-recoverable event.
Definition: fprime.h:131
FwIdType FwChanIdType
The type of a telemetry channel identifier.
An activity related to commanding.
Definition: fprime.h:134
spacewasm_valtype_t tag
Definition: spacewasm.h:411
Parameter value is invalid (e.g. not found)
Definition: fprime.h:85
Software diagnostic events.
Definition: fprime.h:137
A serious but recoverable event.
Definition: fprime.h:132
A serious but recoverable event.
Command tracking was cleared before the command completed.
Definition: fprime.h:115
spacewasm_status_t spacewasm_add_host_module(struct spacewasm_host_t *host, const char *name, size_t max_functions, size_t max_globals, uint32_t *out_idx)
The interpreter exited via HOST_TRAP but a host function indicated it was a standard exit() ...
spacewasm_hostcall_result_t
Definition: spacewasm.h:160
Command successfully executed.
void log_WARNING_HI_BufferTooLarge(const Svc::WasmSequencer_HostFunction &host_function, U32 size, U32 maxSize) const
Command failed to deserialize.
static constexpr FwIndexType getNum_serialOut_OutputPorts()
Command had execution error.
Important informational events.
spacewasm_status_t
Definition: spacewasm.h:37
A fatal non-recoverable event.
Command failed to deserialize.
Definition: fprime.h:109
Command failed validation.
RateGroupDivider component implementation.
Command successfully executed.
Definition: fprime.h:103
spacewasm_hostcall_result_t(WasmSequencer::*)(struct spacewasm_caller_t *, const struct spacewasm_value_t *, size_t, struct spacewasm_value_t *) HostFn
Member-function signature of a spacewasm host-function handler.
void log_WARNING_HI_SleepDurationTooLarge(const Svc::WasmSequencer_HostFunction &host_function, U64 micros) const
#define FW_ASSERT(...)
Definition: Assert.hpp:14
bool isConnected_cmdOut_OutputPort(FwIndexType portNum) const
bool isValid() const
Check raw enum value for validity.
void log_WARNING_HI_BufferTooSmall(const Svc::WasmSequencer_HostFunction &host_function, U32 size, U32 valueSize) const