RFD 0004Document view
RFD 0004
discussionmdx0004.mdx

Notional Thruster Test Stand Controller Interface

A discussion of deterministic FPGA-owned thruster sequencing, CCSDS-style UDP commands, observable status telemetry, and the active-high digital interface.

Authors
Ian Cleary
Updated
Jul 28, 2026, 12:00 AM

Summary

This RFD captures a notional interface for a Thruster Test Stand Controller implemented on a Digilent Arty A7-100T. The central design choice is that the FPGA, rather than a host operating system or microcontroller software loop, owns every time-critical output edge after an actuation command is accepted.

The host configures the sequence, asks for an operation, receives a structured acknowledgement, and records a loss-detectable 1 kHz status stream. The FPGA uses a local microsecond counter to schedule active-high 3.3 V logic outputs for Spark, Fuel, Oxidizer, three HitHold observations, and two heaters.

The proposed determination is:

  • use one fixed, versioned UDP command and status contract;
  • use CCSDS-style primary headers while keeping Project 14 time fields in the secondary status body;
  • keep command values in milliseconds but execute edges from the FPGA's local microsecond counter;
  • keep setup commands separate from actuation commands;
  • reject ambiguous, overlapping, out-of-range, or replay-adjacent fire requests before any output changes;
  • report physical outputs, controller state, diagnostics, operation identity, and queue overflow in every status packet;
  • keep the interactive model in this RFD non-transmitting and allocate only waveform transition nodes rather than sampled traces.

This is a discussion artifact and prototype interface, not a safety-rated, flight-qualified, or propellant-test authorization.

Problem statement

A host can conveniently describe a fire sequence, but a general-purpose operating system cannot guarantee the relative timing of ignition and valve edges. Network latency also cannot be made deterministic merely by choosing Ethernet or UDP.

The interface therefore separates two timing questions:

  1. When does the FPGA receive and accept the request? This remains subject to host, network, parsing, and queue latency.
  2. What happens after the FPGA accepts it? This is scheduled by synchronous FPGA logic against one local counter, independent of later host scheduling.

The contract needs to make that boundary visible. It also needs enough diagnostic information for the host to distinguish acceptance, rejection, busy state, idempotent no-change behavior, telemetry loss, and queue overload.

Goals

The notional controller should:

  • produce deterministic relative edge timing after command acceptance;
  • expose a small command surface with exact binary layouts;
  • preserve command identity with nonzero request IDs;
  • return one structured acknowledgement for every addressed command that reaches Project 14 validation;
  • stream status at 1 kHz without making status delivery part of the actuation timing loop;
  • make overflow and packet loss observable;
  • force every controlled output low on controller reset;
  • keep heaters independent from fire sequencing and fire cutoff;
  • provide Python methods for every command plus decoded and raw recording.

Non-goals

This RFD does not propose:

  • DHCP, TCP, routing, DNS, or a general network stack;
  • deterministic Ethernet delivery;
  • a standardized CCSDS mission time code;
  • cryptographic authentication or a complete durable replay window;
  • direct valve, solenoid, heater, or igniter drive;
  • isolation, flyback suppression, arm/permissive, emergency stop, or watchdog hardware;
  • flight qualification or energized test approval;
  • behavior for the still-undefined Boost signal.

System boundary

Notional thruster controller boundary
Notional thruster controller boundary
Scroll horizontally for the full diagram

The wire diagrams begin at the UDP payload. Ethernet, IPv4, and UDP headers are outside the CCSDS-style packet. The FPGA uses fixed identity:

ItemValue
Board MAC02:00:00:00:00:7A
Board IPv4169.254.209.0/16
Board UDP port24576 (0x6000)
Recommended host IPv4169.254.209.1/16
Command APID0x120
Telemetry APID0x121
Interface version0x01
Status telemetry ID0x4101

The direct link has no gateway requirement. DNS is not implemented in the FPGA.

Concept of operations

A nominal non-energetic workflow is:

  1. Reset the controller and independently make every external load safe.
  2. Establish link and use ARP plus time.get for non-actuating identity checks.
  3. Store a valid Fire Sequence, HitHold duration, and fire maximum duration.
  4. Configure independent heater maximums if heaters will be used.
  5. Start periodic telemetry and begin raw plus decoded recording.
  6. Send one actuation command with an explicit nonzero request ID and adequate delay for any negative edge offsets.
  7. Correlate the acknowledgement by request ID.
  8. Let the FPGA own every scheduled edge through normal completion, cutoff, or reset.
  9. Stop telemetry and preserve capture evidence.

The setup commands store values only. They do not establish time zero and do not actuate an output. An accepted fire.single or fire.duty snapshots the stored Fire Sequence, cutoff tail, HitHold duration, and fire maximum.

Timing model

For Single Fire and the first Duty Cycle:

t0=tvalidated receipt+1000delaymst_0 = t_{\mathrm{validated\ receipt}} + 1000 \cdot delay_{ms} tedge=t0+1000offsetmst_{\mathrm{edge}} = t_0 + 1000 \cdot offset_{ms}

The six edge offsets are signed milliseconds relative to t0. Each channel's OFF offset must be strictly greater than its ON offset. An actuation request is rejected if any calculated edge would precede command receipt.

For later Duty Cycle iterations:

periodms=oxidizer_offms+off_durationmsperiod_{ms} = oxidizer\_off_{ms} + off\_duration_{ms} t0,n+1=t0,n+1000periodmst_{0,n+1} = t_{0,n} + 1000 \cdot period_{ms}

The latest prior-cycle OFF edge must be strictly earlier than the next safe boundary. That boundary also accounts for a negative ON offset in the next cycle. Equality rejects rather than relying on event ordering within one tick.

Digital signal contract

All outputs are active-high 3.3 V logic. 0 means OFF and 1 means ON.

PMOD pinSignalBehavior
JD1SparkIndependent Fire Sequence window
JD2FuelIndependent Fire Sequence window
JD3OxidizerIndependent Fire Sequence window and cutoff tail
JD4HitHoldSharedFuelHitHold OR OxidizerHitHold
JD7FuelHitHoldPulse on each Fuel rising edge
JD8OxidizerHitHoldPulse on each Oxidizer rising edge
JC1FuelHeaterIndependent maximum-duration heater output
JC2OxidizerHeaterIndependent maximum-duration heater output

A Fuel rising edge starts FuelHitHold; an Oxidizer rising edge starts OxidizerHitHold. A same-channel retrigger restarts its full configured duration. The shared output is derived, not independently scheduled.

At the fire maximum-duration deadline:

  • Spark and Fuel immediately turn OFF;
  • both per-propellant HitHold outputs immediately turn OFF;
  • later Spark, Fuel, and HitHold edges are suppressed;
  • Oxidizer stays ON only if it was already ON;
  • an already-high Oxidizer stays ON for the configured max_duration_oxidizer_tail_ms, then turns OFF;
  • the cutoff never creates a new Oxidizer rising edge;
  • remaining Duty Cycle iterations are canceled;
  • heaters are unchanged.

Command interface

Every command has a six-byte CCSDS-style primary header, an eight-byte Project 14 command header, and an exact fixed-binary argument block. Multi-byte values are big-endian. Signed values use two's-complement representation.

CommandIDArgumentsArgument bytes
fire.set_sequence0x3001six i32 edge offsets, u32 oxidizer tail28
hithold.set_duration0x3002u32 duration_ms4
fire.set_max_duration0x3003u32 duration_ms4
time.get0x3004none0
fire.single0x3010u32 delay_ms4
fire.duty0x3011u32 delay_ms, u32 off_duration_ms, u16 cycles10
heater.on0x3020u8 target1
heater.off0x3021u8 target1
heater.set_max0x3022u8 target, u32 duration_ms5
telemetry.start0x3030none0
telemetry.stop0x3031none0

The fixed command header contains:

Bit offsetBitsFieldRequired value
03CCSDS version0
31Packet type1
41Secondary-header flag1
511APID0x120
162Sequence flags0b11
1814Sequence countHost-selected
3216Packet lengthBytes after primary header minus one
488Interface version0x01
568Message type0x01
6416Command IDCatalog value
8016Request ID1..65535
968Argument format0x01
1048Argument lengthExact catalog length

Request ID zero is reserved for unsolicited periodic telemetry. The FPGA rejects a zero-ID command with a structured REQUEST_ID / FIELD_OUT_OF_RANGE diagnostic. The host allocator wraps 65535 to 1, but allocator state is process-local and not a durable replay policy.

Telemetry interface

Solicited acknowledgements and unsolicited periodic status use one fixed 54-byte packet. The status packet reports:

  • command request ID or zero for periodic status;
  • disposition (ACCEPTED, BUSY, ACCEPTED_NO_CHANGE, or REJECTED);
  • all eight physical output states;
  • pending, active, Duty Cycle, cutoff/tail, telemetry, and overflow flags;
  • rejected field, error code, observed value, and reference value;
  • 64-bit FPGA time_us and retained/current t0_us;
  • 32-bit sample_sequence;
  • active request ID, cycle index, and cycle count;
  • saturating RX and TX overflow counters.

The complete 54-byte UDP-payload layout is:

Byte offsetBytesFieldWire typeValue or meaning
02Primary header wordbit-packed u16Version 0, telemetry type 0, secondary header 1, APID 0x121
22Sequence wordbit-packed u16Flags 0b11; low 14 bits mirror sample_sequence
42Packet lengthbig-endian u1647 (bytes after the primary header minus one)
61Interface versionu80x01
71Message typeu80x02 status telemetry
82Request IDbig-endian u16Correlated command ID; zero for periodic status
102Telemetry IDbig-endian u160x4101
121Dispositionu80x80 accepted, 0x81 busy, 0x82 no change, 0xE0 rejected
131Output flagsbit-packed u8Physical output state bitmap
141Controller flagsbit-packed u8Sequencer, stream, and sticky-overflow bitmap
151Rejected fieldu8Field identifier, or zero
162Error codebig-endian u16Diagnostic identifier, or zero
184Observed valuebig-endian i32Rejected or computed value
224Reference valuebig-endian i32Limit or comparison value
268time_usbig-endian u64FPGA time since reset
348t0_usbig-endian u64Retained/current cycle reference
424sample_sequencebig-endian u32Loss-detection sequence
462Active request IDbig-endian u16Zero while idle
482Duty Cycle indexbig-endian u16Current zero-based cycle
502Duty Cycle countbig-endian u16Snapshotted requested count
521RX overflow countu8Saturating counter
531TX overflow countu8Saturating counter

Output flag bits 0..7 are Spark, Fuel, Oxidizer, FuelHitHold, OxidizerHitHold, HitHoldShared, FuelHeater, and OxidizerHeater. Controller flag bits 0..6 are pending, active, Duty Cycle, cutoff active, sticky RX overflow, sticky TX overflow, and telemetry streaming; bit 7 is reserved and transmitted as zero.

The CCSDS primary header does not inherently include a timestamp. This interface places its local time-since-reset values in the Project 14 status body. They are not UTC and are not synchronized to an external clock.

The 32-bit sample sequence is the loss-detection authority. Its low 14 bits are also placed in the CCSDS sequence count. A recorder should classify missing, duplicate, reordered, and modulo-32-bit rollover behavior while preserving the validated 54-byte packets verbatim.

Interactive notional model

The explorer below is intentionally non-transmitting. It serializes the selected command in memory, shows every field and exact byte, applies the notional validation rules, and derives output transitions.

The waveform is not a sampled telemetry trace. Each active interval contributes only four point-line nodes: low to the rising edge, vertical high, horizontal to the falling edge, and vertical low. Flat signals need only domain endpoints. Duty Cycle rendering is capped at six cycles even when the packet requests more.

Notional thruster interface explorer
Builds a local packet preview and sparse output schedule. It never opens a network connection or sends a command.

Command and values

Stored waveform context

These values affect the waveform preview but are not serialized in the selected command.

Values satisfy the scalar and cross-field checks modeled by this explorer.
Command packet
42 UDP-payload bytes · argument length 28 · CCSDS length 35
ID 0x3001
Serialized bytes
19 20 C0 01 00 23 01 01 30 01 44 01 01 1C 00 00 
00 64 00 00 00 C8 00 00 00 32 00 00 03 20 00 00 
00 64 00 00 03 52 00 00 05 DC
Bit offsetBitsFieldValueEndianness
03version0MSB-first
31packet_type1MSB-first
41secondary_header_flag1MSB-first
511apid0x120MSB-first
162sequence_flags0b11MSB-first
1814sequence_count1Big-endian
3216packet_length35Big-endian
488interface_version0x01Single octet
568message_type0x01Single octet
6416command_id0x3001Big-endian
8016request_id0x4401Big-endian
968argument_format0x01Single octet
1048argument_length28Single octet
11232spark_on_offset_ms100 msBig-endian
14432spark_off_offset_ms200 msBig-endian
17632fuel_on_offset_ms50 msBig-endian
20832fuel_off_offset_ms800 msBig-endian
24032oxidizer_on_offset_ms100 msBig-endian
27232oxidizer_off_offset_ms850 msBig-endian
30432max_duration_oxidizer_tail_ms1500 msBig-endian
Digital output edge model
Point-line steps only; no sampled trace or telemetry array is allocated.
1 modeled cycle
Thruster controller sparse digital waveformEight active-high digital outputs represented only by horizontal and vertical edge segments.-34 ms150 ms333 ms517 ms700 ms884 msreceiptSparkFuelOxidizerFuelHitHoldOxidizerHitHoldHitHoldSharedFuelHeaterOxidizerHeater

Validation and rejection behavior

The controller rejects:

  • malformed Project 14 envelopes;
  • unsupported APIDs or command IDs;
  • bad argument format or length;
  • scalar values outside their controller range;
  • any channel whose OFF offset is not strictly later than ON;
  • an actuation edge that would precede command receipt;
  • a Duty Cycle whose prior output overlaps the next safe boundary;
  • actuation before a valid Fire Sequence is stored;
  • actuation while another fire operation owns the sequencer;
  • a heater target other than Fuel or Oxidizer;
  • a required nonzero maximum duration that is zero;
  • reuse of the most recently accepted Fire actuation request ID.

The duplicate check is deliberately narrow. It does not retain a durable history, does not cover heater commands, and clears on reset.

Queueing and loss

Complete command, response, ARP, and periodic-stream records cross clock domains through bounded asynchronous queues. A reserved response slot prevents a dispatched command acknowledgement from being lost when the response queue is temporarily full.

Command responses have transmit priority over ARP and periodic status. Periodic status is best-effort and loss-detectable. A dropped stream sample increments a saturating TX-overflow counter. Response backpressure does not.

This distinction keeps actuation command outcome reporting stronger than periodic observation without pretending that UDP itself is lossless.

Safety boundary

This interface is suitable only for logic-level prototyping until an external safety architecture is defined. The FPGA outputs shall not directly drive an igniter, valve, solenoid, relay coil, or heater.

External circuitry must provide:

  • galvanic isolation where required;
  • logic buffering and load-current drive;
  • inductive transient and flyback suppression;
  • safe output bias while the FPGA is unconfigured;
  • hardware arm/permissive and emergency-stop functions;
  • watchdog and fault-response behavior;
  • independent power removal appropriate to the hazard analysis.

Ethernet reachability, a valid acknowledgement, or a clean status stream is not an authorization to energize a fixture.

Alternatives considered

Host-timed output changes

The host could send one network command per edge. This is simple conceptually but makes relative timing depend on the host scheduler, network, parser, and queue state. It does not satisfy the main determinism goal.

Microcontroller-owned sequence

A microcontroller can provide good timing with a carefully designed hardware timer architecture. It remains a viable implementation, but the FPGA path provides explicit parallel edge comparators, clock-domain boundaries, and fixed-latency output state updates in the existing Arty Ethernet prototype.

Sampled waveform storage

The UI could allocate a value for every signal at every millisecond. That scales with duration and display resolution even though digital outputs change only at a small number of edges. Sparse point-lines preserve the exact ideal waveform with memory proportional to transitions.

Open questions

  • What hardware arm/permissive, emergency-stop, and watchdog signals must gate all energetic outputs?
  • Should command freshness use a larger persisted request space, time window, session nonce, or authenticated sequence?
  • Should a future interface use a standardized CCSDS time code or externally synchronized execution time?
  • What is the required response to link loss while a fire sequence or heater is active?
  • Should Boost be defined, assigned a pin and command, or removed from the controller vocabulary?
  • What Rigol probe mapping and electrical interface will become the approved timing-verification setup?

Determination

Proceed with the fixed, versioned command and status contract as a bench prototype. Keep deterministic edge ownership in the FPGA, keep host and network latency outside the accepted sequence, expose complete state and loss indicators, and preserve exact packet bytes in host recordings.

Do not treat the current replay check, reset behavior, PMOD outputs, or Ethernet observability as safety qualification. Energetic use remains blocked on an independent hardware safety design and explicit verification plan.