pdcomm::Secs1Endpoint
Class
Move-only owner of one SECS-I (SEMI E4) endpoint over caller-provided serial I/O.
class Secs1EndpointThe endpoint runs the SEMI E4 block transfer protocol: ENQ/EOT line control, master/slave contention, blocks of at most 244 data bytes with a length byte, 10-byte header and checksum, ACK/NAK replies, retries, duplicate block detection, and reassembly of multi-block messages. It does not open a serial port. The I/O object passed to the constructor (Secs1IoAdapter or Secs1BorrowedIo) supplies nonblocking read and write callbacks, and you drive the endpoint by calling poll() with your own clock.
The endpoint transfers messages only. It does not match replies to primaries, run the T3 reply timer, filter received messages by device ID or direction, or parse bodies as SECS-II; correlate replies by system_bytes in your application.
Lifecycle: construct, start(), then poll(), submit() and drain nextEvent(). A fault stops all I/O until reset(). stop() discards all runtime state without invoking callbacks, and a later start() begins a fresh generation.
pdcomm::Secs1IoAdapter<SerialPort> io;
pdcomm::Secs1Endpoint endpoint(io, options);
endpoint.start();
while (running) {
endpoint.poll(nowMilliseconds());
while (auto event = endpoint.nextEvent()) {
const auto info = event.info();
if (info.kind == PDCOMM_SECS1_EVENT_INBOUND) {
std::vector<uint8_t> body = event.body();
// Decode the body; answer with submit() when info.reply_expected is 1.
}
}
}
endpoint.stop();Notes
- Move-only. The native endpoint is bound to the thread that constructed it: call every member, including destruction, on that thread. Calls from another thread, concurrent calls and calls from inside a callback throw pdcomm::Error with
PDCOMM_INVALID_STATE; destruction on another thread or from inside a callback does nothing and leaks the native endpoint. Moving the wrapper does not change the bound thread. A moved-from endpoint owns no handle, and its calls throw withPDCOMM_INVALID_ARGUMENT. After an internal panic, every call except state() throws withPDCOMM_POISONED, and state() reportspoisoned.
Members
Secs1Endpoint
Constructor
Creates a stopped SECS-I endpoint with pdcomm_secs1_create().
template <typename Io> Secs1Endpoint(Io &io, const PdcommSecs1Options &options)Validates the callback table and options without calling either callback, copies them, and binds the endpoint to the calling thread. The new endpoint has generation 1 and performs no I/O until it is started and polled.
Parameters
| Name | Description |
|---|---|
Io | Secs1IoAdapter or Secs1BorrowedIo, or any type whose native() member returns a const PdcommSecs1Io &. |
io | I/O binding. It is borrowed and must outlive the endpoint. |
options | Line settings and limits. Every timer is a nonzero duration in your tick unit, and every limit is application policy; PDComm does not substitute SEMI E4 default values. Copied during the call. |
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_ARGUMENTwhen the callback table has anullptrcontext or callback, astruct_sizeis too small,versionor a reserved field is wrong,priorityis unknown, a timer is zero, or the limits are zero or inconsistent;PDCOMM_ALLOCATION_FAILEDwhen the event queue cannot be reserved;PDCOMM_LIMIT_EXCEEDEDwhen the process has run out of endpoint identifiers;PDCOMM_INTERNAL_ERRORwhen the library contained an internal panic.
Secs1Endpoint
Constructor
Takes ownership of the native handle owned by other.
Secs1Endpoint(Secs1Endpoint &&other) noexceptThe native endpoint stays bound to the thread that constructed it.
Parameters
| Name | Description |
|---|---|
other | Source wrapper; it becomes empty. |
Secs1Endpoint
Constructor
Copying is disabled; the wrapper exclusively owns its native handle.
Secs1Endpoint(const Secs1Endpoint &) = deletenativeHandle
Method
Returns the owned native handle for direct C API calls.
PdcommSecs1Endpoint *nativeHandle() noexceptReturns
The handle, or nullptr for a moved-from endpoint. Ownership stays with this wrapper.
nativeHandle
Method
Returns the owned native handle for read-only C API calls.
const PdcommSecs1Endpoint *nativeHandle() const noexceptReturns
The handle, or nullptr for a moved-from endpoint. Ownership stays with this wrapper.
nextEvent
Method
Takes the oldest queued event, with pdcomm_secs1_next_event().
Secs1Event nextEvent()Returns
The next event, or an empty Secs1Event when the queue is empty.
Notes
- Throws
pdcomm::Error:PDCOMM_ALLOCATION_FAILEDwhen the event could not be allocated; the event stays staged and the next call returns it, and until then start(), poll(), submit(), reset() and stop() throw withPDCOMM_BACKPRESSURE;PDCOMM_INVALID_STATEwhen the endpoint is stopped, or on a wrong-thread, concurrent or reentrant call;PDCOMM_POISONED.
operator=
Method
Releases the current handle, then takes ownership of the handle owned by other.
Secs1Endpoint &operator=(Secs1Endpoint &&other) noexceptReleasing follows the destructor's rules, so do it on the thread that constructed the current endpoint.
Parameters
| Name | Description |
|---|---|
other | Source wrapper; it becomes empty. |
Returns
This wrapper.
operator=
Method
Copy assignment is disabled; the wrapper exclusively owns its native handle.
Secs1Endpoint &operator=(const Secs1Endpoint &) = deletepoll
Method
Runs line control, timers and callback I/O for one time slice, with pdcomm_secs1_poll().
size_t poll(uint64_t now)Each call performs up to PdcommSecs1Options::poll_budget steps: it starts the next outbound block when the line is idle, fires expired timers, handles received characters and completed writes, and alternates write and read callback attempts. The callbacks run only inside this call. Results are queued as events; drain them with nextEvent(). A faulted endpoint performs no work and returns 0.
Parameters
| Name | Description |
|---|---|
now | Current time in your ticks, the same unit as the *_ticks options. It must not be smaller than the value passed to the previous call. |
Returns
Number of steps performed.
Notes
- Throws
pdcomm::Error:PDCOMM_BACKPRESSUREwhen a staged event must be retrieved first or the event queue is full (the pending step is kept; drain events and poll again);PDCOMM_INVALID_STATEwhen the endpoint is not started, or on a wrong-thread, concurrent or reentrant call;PDCOMM_LIMIT_EXCEEDEDwhennowis smaller than the previous value or a timer deadline overflows;PDCOMM_ALLOCATION_FAILEDwhen an internal buffer cannot be allocated;PDCOMM_INVALID_ARGUMENTwhen an internal protocol check rejected a step;PDCOMM_POISONED. - An I/O failure is not an exception: it produces a
PDCOMM_SECS1_EVENT_FAULTevent, and the call returns normally.
reset
Method
Clears a terminal fault so the endpoint can transfer messages again, with pdcomm_secs1_reset().
void reset()Returns the line to idle and discards pending writes, the aborted submission and partially received data. Queued events, the generation and submission numbering are kept.
Notes
- Throws
pdcomm::Error:PDCOMM_BACKPRESSUREwhen a staged event must be retrieved first;PDCOMM_INVALID_STATEwhen the endpoint is not started, is stopped or is not faulted, or on a wrong-thread, concurrent or reentrant call;PDCOMM_POISONED.
start
Method
Starts a created or stopped endpoint with pdcomm_secs1_start().
void start()Starting never performs I/O. Starting after stop() creates a fresh protocol runtime, increments the generation, and restarts submission numbering at 1.
Notes
- Throws
pdcomm::Error:PDCOMM_BACKPRESSUREwhen a staged event must be retrieved first;PDCOMM_INVALID_STATEwhen the endpoint is already started, or on a wrong-thread, concurrent or reentrant call;PDCOMM_LIMIT_EXCEEDEDwhen the generation counter is exhausted;PDCOMM_ALLOCATION_FAILEDwhen the new runtime cannot be allocated;PDCOMM_POISONED.
state
Method
Reads the identity and lifecycle flags of the endpoint, with pdcomm_secs1_state().
PdcommSecs1State state()Valid in every lifecycle state, including before start and after stop, and not blocked by a staged event. It is the only call that still succeeds after the endpoint is poisoned, so it can report poisoned.
Returns
Endpoint ID, generation, and the started, stopped, faulted and poisoned flags.
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEon a wrong-thread, concurrent or reentrant call;PDCOMM_POISONEDwhen reading the state itself panics.
stop
Method
Stops a started endpoint and discards its runtime state, with pdcomm_secs1_stop().
void stop()Queued events, the message being sent and partially received data are dropped without events and without invoking callbacks. Bytes already written stay on the wire. nextEvent() throws with PDCOMM_INVALID_STATE until the endpoint is started again.
Notes
- Throws
pdcomm::Error:PDCOMM_BACKPRESSUREwhen a staged event must be retrieved first;PDCOMM_INVALID_STATEwhen the endpoint is not started, or on a wrong-thread, concurrent or reentrant call;PDCOMM_POISONED.
submit
Method
Queues one message for transmission, with pdcomm_secs1_submit().
PdcommSecs1Token submit(const PdcommSecs1Message &message)The endpoint sends one message at a time: it accepts the next submission after the current one produced PDCOMM_SECS1_EVENT_OUTBOUND_COMPLETE, PDCOMM_SECS1_EVENT_OUTBOUND_FAILED or a fault. The body is copied on acceptance and split into blocks of at most 244 bytes. Success means acceptance only; transmission happens in poll().
Parameters
| Name | Description |
|---|---|
message | Message to send. Its fields map to the SEMI E4 block header: device ID, direction (R-bit), stream, function, W-bit and the system bytes you choose; a reply carries the system bytes of its primary. The message and its body stay yours and may be released when the call returns. |
Returns
The submission token, repeated by the outbound and fault events of this message.
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_ARGUMENTwhen a message field is invalid or the body exceedsmax_outbound_body_bytes,max_body_bytes,max_outbound_blocksormax_blocks;PDCOMM_BACKPRESSUREwhen a staged event must be retrieved first or another message is still being sent;PDCOMM_INVALID_STATEwhen the endpoint is not started or is faulted, or on a wrong-thread, concurrent or reentrant call;PDCOMM_LIMIT_EXCEEDEDwhen the submission numbers of this generation are exhausted;PDCOMM_ALLOCATION_FAILEDwhen the body or blocks cannot be copied;PDCOMM_POISONED.
~Secs1Endpoint
Method
Releases the endpoint with pdcomm_secs1_destroy(), without invoking callbacks.
~Secs1Endpoint()Pending messages, queued events and partial data are discarded; bytes already written stay on the wire. Events already taken stay valid. Destroy the endpoint on the thread that constructed it: elsewhere, or from inside a callback, the native endpoint is not released. An empty endpoint releases nothing.