Skip to content
Start free evaluation

pdcomm::Secs1Endpoint

Class

Move-only owner of one SECS-I (SEMI E4) endpoint over caller-provided serial I/O.

class Secs1Endpoint

Declared in: #include <pdcomm_secs1.hpp>

The 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 with PDCOMM_INVALID_ARGUMENT. After an internal panic, every call except state() throws with PDCOMM_POISONED, and state() reports poisoned.

Members

Secs1Endpoint

Constructor

Creates a stopped SECS-I endpoint with pdcomm_secs1_create().

template <typename Io> Secs1Endpoint(Io &io, const PdcommSecs1Options &options)

Declared in: #include <pdcomm_secs1.hpp>

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

NameDescription
IoSecs1IoAdapter or Secs1BorrowedIo, or any type whose native() member returns a const PdcommSecs1Io &.
ioI/O binding. It is borrowed and must outlive the endpoint.
optionsLine 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_ARGUMENT when the callback table has a nullptr context or callback, a struct_size is too small, version or a reserved field is wrong, priority is unknown, a timer is zero, or the limits are zero or inconsistent; PDCOMM_ALLOCATION_FAILED when the event queue cannot be reserved; PDCOMM_LIMIT_EXCEEDED when the process has run out of endpoint identifiers; PDCOMM_INTERNAL_ERROR when the library contained an internal panic.

Secs1Endpoint

Constructor

Takes ownership of the native handle owned by other.

Secs1Endpoint(Secs1Endpoint &&other) noexcept

Declared in: #include <pdcomm_secs1.hpp>

The native endpoint stays bound to the thread that constructed it.

Parameters

NameDescription
otherSource wrapper; it becomes empty.

Secs1Endpoint

Constructor

Copying is disabled; the wrapper exclusively owns its native handle.

Secs1Endpoint(const Secs1Endpoint &) = delete

Declared in: #include <pdcomm_secs1.hpp>

nativeHandle

Method

Returns the owned native handle for direct C API calls.

PdcommSecs1Endpoint *nativeHandle() noexcept

Declared in: #include <pdcomm_secs1.hpp>

Returns

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 noexcept

Declared in: #include <pdcomm_secs1.hpp>

Returns

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()

Declared in: #include <pdcomm_secs1.hpp>

Returns

The next event, or an empty Secs1Event when the queue is empty.

Notes

  • Throws pdcomm::Error: PDCOMM_ALLOCATION_FAILED when 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 with PDCOMM_BACKPRESSURE; PDCOMM_INVALID_STATE when 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) noexcept

Declared in: #include <pdcomm_secs1.hpp>

Releasing follows the destructor's rules, so do it on the thread that constructed the current endpoint.

Parameters

NameDescription
otherSource wrapper; it becomes empty.

Returns

This wrapper.

operator=

Method

Copy assignment is disabled; the wrapper exclusively owns its native handle.

Secs1Endpoint &operator=(const Secs1Endpoint &) = delete

Declared in: #include <pdcomm_secs1.hpp>

poll

Method

Runs line control, timers and callback I/O for one time slice, with pdcomm_secs1_poll().

size_t poll(uint64_t now)

Declared in: #include <pdcomm_secs1.hpp>

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

NameDescription
nowCurrent 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_BACKPRESSURE when 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_STATE when the endpoint is not started, or on a wrong-thread, concurrent or reentrant call; PDCOMM_LIMIT_EXCEEDED when now is smaller than the previous value or a timer deadline overflows; PDCOMM_ALLOCATION_FAILED when an internal buffer cannot be allocated; PDCOMM_INVALID_ARGUMENT when an internal protocol check rejected a step; PDCOMM_POISONED.
  • An I/O failure is not an exception: it produces a PDCOMM_SECS1_EVENT_FAULT event, and the call returns normally.

reset

Method

Clears a terminal fault so the endpoint can transfer messages again, with pdcomm_secs1_reset().

void reset()

Declared in: #include <pdcomm_secs1.hpp>

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_BACKPRESSURE when a staged event must be retrieved first; PDCOMM_INVALID_STATE when 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()

Declared in: #include <pdcomm_secs1.hpp>

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_BACKPRESSURE when a staged event must be retrieved first; PDCOMM_INVALID_STATE when the endpoint is already started, or on a wrong-thread, concurrent or reentrant call; PDCOMM_LIMIT_EXCEEDED when the generation counter is exhausted; PDCOMM_ALLOCATION_FAILED when 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()

Declared in: #include <pdcomm_secs1.hpp>

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_STATE on a wrong-thread, concurrent or reentrant call; PDCOMM_POISONED when reading the state itself panics.

stop

Method

Stops a started endpoint and discards its runtime state, with pdcomm_secs1_stop().

void stop()

Declared in: #include <pdcomm_secs1.hpp>

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_BACKPRESSURE when a staged event must be retrieved first; PDCOMM_INVALID_STATE when 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)

Declared in: #include <pdcomm_secs1.hpp>

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

NameDescription
messageMessage 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_ARGUMENT when a message field is invalid or the body exceeds max_outbound_body_bytes, max_body_bytes, max_outbound_blocks or max_blocks; PDCOMM_BACKPRESSURE when a staged event must be retrieved first or another message is still being sent; PDCOMM_INVALID_STATE when the endpoint is not started or is faulted, or on a wrong-thread, concurrent or reentrant call; PDCOMM_LIMIT_EXCEEDED when the submission numbers of this generation are exhausted; PDCOMM_ALLOCATION_FAILED when the body or blocks cannot be copied; PDCOMM_POISONED.

~Secs1Endpoint

Method

Releases the endpoint with pdcomm_secs1_destroy(), without invoking callbacks.

~Secs1Endpoint()

Declared in: #include <pdcomm_secs1.hpp>

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.