pdcomm::GemEndpoint
Class
Common base of GemHost and GemEquipment: one HSMS endpoint with a GEM role.
class GemEndpointA GemEndpoint owns a TcpEndpoint (SEMI E37 HSMS) and the GEM state attached to it. It starts no threads and has no callbacks: your loop calls poll(), drains tcp().nextEvent(), and passes every event to handleEvent() in queue order. Requests return a PdcommTcpToken immediately; the reply arrives later as a GemResult whose GemResultInfo::token equals that token.
Both roles share the process program store and transfer calls (S7F1 to S7F6, plus the host-only S7F17 and S7F19) and, on equipment, the spool calls (S2F43/F44, S2F59/F60, S6F23/F24 and spooled delivery).
Throughout this class, a call fails with PDCOMM_BACKPRESSURE while a TCP event is staged but not yet handled, and with PDCOMM_POISONED after an internal panic.
pdcomm::GemEndpoint *endpoint = hostRole ? static_cast<pdcomm::GemEndpoint *>(host.get())
: equipment.get();
endpoint->start();
while (running) {
endpoint->poll();
while (auto event = endpoint->tcp().nextEvent()) {
auto result = endpoint->handle(event);
// Inspect result.info() and act on it.
}
}
endpoint->stop();Notes
- Move-only. Serialize all calls on one endpoint, including TCP calls, GEM calls and destruction; a quiescent endpoint may move to another thread. Calls that build temporary arrays can also throw
std::bad_alloc.
Members
GemEndpoint
Constructor
Moves the endpoint; the source no longer owns a native endpoint.
GemEndpoint(GemEndpoint &&) noexcept = defaultGemEndpoint
Constructor
Copying is disabled; the endpoint exclusively owns its native handle.
GemEndpoint(const GemEndpoint &) = deletecancelProgramGrant
Method
Cancels the S7F1 grant activated by result.
void cancelProgramGrant(const GemResult &result)Grants are identified by their original result, never by a matching program ID.
Parameters
| Name | Description |
|---|---|
result | Result of the S7F1 request that activated the grant. |
Notes
- Throws
pdcomm::Error:PDCOMM_STALE_TOKENwhen the grant is stale or no longer active;PDCOMM_INVALID_STATEwhenresultis not an activated S7F1 request.
completeSpoolDelivery
Method
Finishes a spooled delivery attempt and, on success, removes the head entry.
GemSpoolWriteResult completeSpoolDelivery(GemResult &result, bool success)For a W-bit message, report success only after inspecting the reply body against your own success policy; a matching function number alone is not success. For a message without W-bit, success means a complete local write, not peer receipt. Failure keeps the entry and stops the transmit run.
Parameters
| Name | Description |
|---|---|
result | Delivery result (GemOutcome::SpoolDeliveryResponse or GemOutcome::SpoolDeliveryWritten). |
success | true to accept the delivery and dequeue; false to stop the run. |
Returns
PDCOMM_OK or PDCOMM_SPOOL_UNCONFIRMED with the mutation details. After an unconfirmed dequeue the entry is already removed: never complete it again.
Notes
- Throws
pdcomm::Error: for other statuses, for examplePDCOMM_STALE_TOKENfor a foreign, stale or already completed proof.
configurePrograms
Method
Attaches the process program store and enables stream 7 program transfers.
void configurePrograms(const GemProgramOptions &options, const std::string &path = {})Call once while the endpoint is stopped, after the role is configured. With an empty path the store lives in memory. Otherwise the file is opened under an exclusive lock and its bounded snapshot is loaded and validated; a missing file starts empty, and a corrupt file is never replaced. File I/O runs synchronously on the calling thread.
Parameters
| Name | Description |
|---|---|
options | Limits built with gemProgramOptions(). |
path | UTF-8 file path without NUL bytes, or empty for memory only. The parent directory must exist. Program IDs are never used as paths. |
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEwhen the endpoint is not stopped, has no role, or already has a program store;PDCOMM_INVALID_ARGUMENTfor invalid options or path;PDCOMM_BACKPRESSUREwhen another process holds the file lock;PDCOMM_IO_ERRORfor file errors;PDCOMM_INVALID_DATAfor a corrupt file;PDCOMM_LIMIT_EXCEEDEDwhen the file exceedsmax_serialized_bytes.
confirmProgramReply
Method
Accepts an unconfirmed installation so that its retained reply can be sent.
void confirmProgramReply(GemResult &result)After respondProgram() returned PDCOMM_PROGRAM_UNCONFIRMED, call this to accept the uncertainty, then call respondProgram() again with the same arguments. It does not synchronize the file and does not send anything; call resyncPrograms() first if you need a confirmed synchronization.
Parameters
| Name | Description |
|---|---|
result | Result that is waiting for confirmation. |
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEwhen the result needs no confirmation or is not a program request of this endpoint.
confirmSpoolReply
Method
Accepts an unconfirmed spool installation so that its retained reply can be sent.
void confirmSpoolReply(GemResult &result)After respondSpool() returned PDCOMM_SPOOL_UNCONFIRMED, call this, then call respondSpool() again. It neither synchronizes nor sends; the reply then reports GemSpoolDurability::Confirmed and the original persistence error stays visible.
Parameters
| Name | Description |
|---|---|
result | Result that is waiting for confirmation. |
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEwhen no confirmation is needed;PDCOMM_STALE_TOKENfor a stale result.
handle
Method
Alias of handleEvent().
GemResult handle(TcpEvent &event)Parameters
| Name | Description |
|---|---|
event | Event returned by TcpEndpoint::nextEvent() on this endpoint. |
Returns
An owned result.
Notes
- Throws
pdcomm::Error: Same statuses as handleEvent().
handleEvent
Method
Processes one TCP event with the GEM layer.
GemResult handleEvent(TcpEvent &event)Handle every event from tcp().nextEvent() in queue order. The event is borrowed only during the call; its TCP metadata and body stay readable afterwards. On success the event is marked as consumed by GEM. The library replies automatically to many primaries (see GemResultInfo::replySent); others wait for an explicit respond call.
Parameters
| Name | Description |
|---|---|
event | Event returned by TcpEndpoint::nextEvent() on this endpoint. |
Returns
An owned result; GemResultKind::Ignored for events unrelated to GEM.
Notes
- Throws
pdcomm::Error:PDCOMM_STALE_TOKENwhen the event was already handled, comes from another endpoint, or belongs to an older connection generation;PDCOMM_BACKPRESSUREorPDCOMM_ALLOCATION_FAILEDbefore commit, in which case the event stays retryable;PDCOMM_INVALID_STATEwhen no GEM role is configured;PDCOMM_INVALID_ARGUMENTfor an empty event.
nextEvent
Method
Takes the next queued TCP event; forwards to TcpEndpoint::nextEvent().
TcpEvent nextEvent()Returns
The next event, or an empty TcpEvent when the queue is empty.
Notes
- Throws
pdcomm::Error: with the status of pdcomm_tcp_next_event().
operator=
Method
Destroys the current native endpoint, then takes over the one owned by the source.
GemEndpoint &operator=(GemEndpoint &&) noexcept = defaultReturns
This endpoint.
operator=
Method
Copy assignment is disabled; the endpoint exclusively owns its native handle.
GemEndpoint &operator=(const GemEndpoint &) = deletepoll
Method
Drives the HSMS endpoint; forwards to TcpEndpoint::poll().
size_t poll()May block up to the connect timeout during an active connection attempt.
Returns
Number of internal actions taken; not the number of events queued.
Notes
- Throws
pdcomm::Error: with the status of pdcomm_tcp_poll().
program
Method
Returns a copy of the body stored under id.
SecsItem program(const SecsItem &id)The ID format is part of its identity: ASCII "A" and Binary 0x41 differ.
Parameters
| Name | Description |
|---|---|
id | Program ID item (non-empty ASCII or Binary). |
Returns
The body, or an empty item when no program has that ID.
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEwhen no program store is configured;PDCOMM_INVALID_ARGUMENTfor an invalid ID item.
programAt
Method
Returns a copy of one stored program in store order.
GemProgramEntry programAt(size_t index)Parameters
| Name | Description |
|---|---|
index | Zero-based position, less than GemProgramState::programCount. |
Returns
Independently owned ID and body items.
Notes
- Throws
pdcomm::Error:PDCOMM_OUT_OF_RANGEfor an invalidindex;PDCOMM_INVALID_STATEwhen no program store is configured.
programDeleteLocal
Method
Deletes programs from the local store.
GemProgramWriteResult programDeleteLocal(const std::vector<const SecsItem *> &ids = {})Allowed only while the endpoint is stopped. The selected IDs must be distinct and present.
Parameters
| Name | Description |
|---|---|
ids | Program IDs to delete; an empty vector deletes all programs. The items are borrowed during the call. |
Returns
PDCOMM_OK, or PDCOMM_PROGRAM_UNCONFIRMED when the deletion was installed but the file synchronization is unconfirmed. Do not repeat it in that case.
Notes
- Throws
pdcomm::Error: for any other status, for examplePDCOMM_INVALID_STATEorPDCOMM_INVALID_ARGUMENTfor an unknown or duplicate ID.
programGrant
Method
Sends S7F1 Process Program Load Inquire.
PdcommTcpToken programGrant(const SecsItem &id, uint32_t length)Requires a program store and the Communicating state. The reply arrives as a result with GemOutcome::ProgramGrantReceived. No grant negotiation is automatic.
Parameters
| Name | Description |
|---|---|
id | Program ID to load. |
length | Program body size in payload bytes (LENGTH). |
Returns
Token of the submitted request.
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEwhen not communicating or no store is configured;PDCOMM_BACKPRESSUREwhen all 32 pending request slots are in use or a TCP event is staged;PDCOMM_LIMIT_EXCEEDEDwhen the pending program ID budget is exhausted;PDCOMM_INVALID_ARGUMENTfor an invalid ID.
programPut
Method
Writes one program to the local store.
GemProgramWriteResult programPut(const SecsItem &id, const SecsItem &body, GemProgramMode mode)Allowed only while the endpoint is stopped. Validation and preparation happen before persistence and the in-memory commit; no wire message is involved.
Parameters
| Name | Description |
|---|---|
id | Program ID: non-empty ASCII or Binary, at most min(limit, 120) bytes. |
body | Program body in A, B, I1, I2, I4, I8, U1, U2, U4 or U8 format; raw bytes and empty values are kept. |
mode | Create, replace or upsert. |
Returns
PDCOMM_OK, or PDCOMM_PROGRAM_UNCONFIRMED when the change was installed but the file synchronization is unconfirmed. Do not repeat the write in that case; inspect GemProgramWriteInfo::applied and GemProgramWriteInfo::durability.
Notes
- Throws
pdcomm::Error: for any other status, for examplePDCOMM_INVALID_STATEwhen the endpoint is not stopped or has no store,PDCOMM_INVALID_ARGUMENTfor an invalid ID or body or a mode conflict,PDCOMM_LIMIT_EXCEEDEDfor store limits, orPDCOMM_IO_ERROR. The store is unchanged on these errors.
programRequest
Method
Sends S7F5 Process Program Request.
PdcommTcpToken programRequest(const SecsItem &id)The reply arrives as a result with GemOutcome::ProgramDataReceived; the received program is not installed automatically.
Parameters
| Name | Description |
|---|---|
id | Program ID to request. |
Returns
Token of the submitted request.
Notes
- Throws
pdcomm::Error: Same statuses as programGrant().
programSend
Method
Sends S7F3 Process Program Send.
PdcommTcpToken programSend(const SecsItem &id, const SecsItem &body)The reply arrives as a result with GemOutcome::ProgramAckReceived. A received S7F4 does not mean the peer selected or executed the program.
Parameters
| Name | Description |
|---|---|
id | Program ID. |
body | Program body. |
Returns
Token of the submitted request.
Notes
- Throws
pdcomm::Error: Same statuses as programGrant().
programState
Method
Returns counters of the process program store.
GemProgramState programState()Returns
Program, byte and grant counters.
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEwhen no program store is configured;PDCOMM_BACKPRESSUREwhile a TCP event is staged.
respondProgram
Method
Replies to a received process program request and returns the native status.
PdcommStatus respondProgram(GemResult &result, GemProgramMode mode, uint8_t decision = 0)Use it for results with GemOutcome::ProgramReceived. For S7F1 the decision is the PPGNT; a grant activates only after S7F2 is queued. For S7F3 and S7F17 the decision is the ACKC7, and an accepted change is installed and committed before the reply is queued. S7F5 and S7F19 need decision 0. If sending fails after installation, retry with the same mode and decision: only the retained reply is sent again.
This method never throws for native statuses; check the return value.
Parameters
| Name | Description |
|---|---|
result | Result of the received request; it is updated with the reply state. |
mode | Write mode used by S7F1 and S7F3. |
decision | 0 to accept; 1 to 5 to reject with that PPGNT (S7F1) or ACKC7 (S7F3, S7F17) code. |
Returns
PDCOMM_OK; PDCOMM_PROGRAM_UNCONFIRMED when the change was installed but no reply was sent (see confirmProgramReply()); PDCOMM_BACKPRESSURE or another send failure with the reply retained; PDCOMM_STALE_TOKEN for a stale, consumed or already answered request; PDCOMM_INVALID_ARGUMENT for an invalid decision.
respondSpool
Method
Replies to a received spool request and returns the native status.
PdcommStatus respondSpool(GemResult &result)Use it at the equipment for results with GemOutcome::SpoolReceived (S2F43, S2F59 or S6F23). The library builds the fixed reply: S2F44 with per-stream errors, S2F60 with the current selection, or S6F24 (busy, no data, or accepted). Configuration and purge are installed before their success acknowledgement, and a transmit run starts only after an accepted S6F24 is queued. Requires a current GemEquipment::syncSpool().
This method never throws for native statuses; check the return value.
Parameters
| Name | Description |
|---|---|
result | Result of the received request. |
Returns
PDCOMM_OK; PDCOMM_SPOOL_UNCONFIRMED when installed with no reply sent (see confirmSpoolReply()); PDCOMM_BACKPRESSURE or another send failure with the reply retained for retry; PDCOMM_STALE_TOKEN for a stale, consumed or already answered request.
resyncPrograms
Method
Retries synchronization of the program file's parent directory.
void resyncPrograms()It never rewrites data and never confirms a retained remote reply.
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEfor a memory-only store or no store;PDCOMM_IO_ERRORwhen synchronization fails again.
resyncSpool
Method
Retries synchronization of the spool file's parent directory.
void resyncSpool()It never rewrites data, sends an acknowledgement, confirms a reply or dequeues.
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEfor a memory-only spool or no spool;PDCOMM_IO_ERRORwhen synchronization fails again.
retrySpoolDequeue
Method
Retries removing an entry whose delivery was accepted but whose dequeue failed.
GemSpoolWriteResult retrySpoolDequeue()Performs only persistence and dequeue, without sending again. It stays available after a reconnect, without the original delivery result.
Returns
PDCOMM_OK or PDCOMM_SPOOL_UNCONFIRMED with the mutation details.
Notes
- Throws
pdcomm::Error: for other statuses, for examplePDCOMM_INVALID_STATEwhen no dequeue is pending.
sendNextSpool
Method
Sends the message at the head of the spool during an accepted transmit run.
PdcommTcpToken sendNextSpool()Sends exactly one message; there is no automatic loop. A W-bit message uses a native pending slot and its reply arrives as GemOutcome::SpoolDeliveryResponse; a message without W-bit reports GemOutcome::SpoolDeliveryWritten after the full write. Nothing is removed until completeSpoolDelivery().
Returns
Token of the submitted message.
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEwhen no transmit run is active or the spool is not synchronized;PDCOMM_BACKPRESSUREwhen a delivery is already in flight or no pending slot is free for a W-bit message;PDCOMM_OUT_OF_RANGEwhen the spool is empty. A failure before submission keeps the queue and stops the run.
spoolCatalogAt
Method
Returns one registered spoolable stream and function pair.
GemSpoolMessageKey spoolCatalogAt(size_t index)Parameters
| Name | Description |
|---|---|
index | Zero-based catalog position, less than GemSpoolState::catalogCount. |
Returns
Stream and function.
Notes
- Throws
pdcomm::Error:PDCOMM_OUT_OF_RANGEfor an invalidindex;PDCOMM_INVALID_STATEwhen spooling is not configured.
spoolEntryAt
Method
Returns a copy of one stored spool entry in queue order, including its capture time.
GemSpoolEntry spoolEntryAt(size_t index)The wrapper makes two native calls, pdcomm_gem_spool_entry_at() and pdcomm_gem_spool_entry_time_at(), for the same index.
Parameters
| Name | Description |
|---|---|
index | Zero-based queue position, less than GemSpoolState::messageCount. |
Returns
Entry metadata, owned body and capture time.
Notes
- Throws
pdcomm::Error:PDCOMM_OUT_OF_RANGEfor an invalidindex;PDCOMM_INVALID_STATEwhen spooling is not configured.
spoolSelectionAt
Method
Returns one selected stream of the current spooling selection.
GemSpoolSelection spoolSelectionAt(size_t index)Parameters
| Name | Description |
|---|---|
index | Zero-based position, less than GemSpoolState::selectionCount. |
Returns
Stream and functions; an empty list selects every registered primary.
Notes
- Throws
pdcomm::Error:PDCOMM_OUT_OF_RANGEfor an invalidindex;PDCOMM_INVALID_STATEwhen spooling is not configured.
spoolState
Method
Returns the state of the equipment spool.
GemSpoolState spoolState()Returns
Counters, policy and flags. synchronized is false while a GemEquipment::syncSpool() call is required.
Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEon a host or when spooling is not configured.
start
Method
Starts the HSMS endpoint; forwards to TcpEndpoint::start().
void start()Configure the GEM role and every store before starting.
Notes
- Throws
pdcomm::Error: with the status of pdcomm_tcp_start().
state
Method
Returns the current GEM state.
GemState state()Synchronizes the GEM state with the HSMS session first, so a new connection generation or a lost selection is visible immediately.
Returns
Role, communication and control states, identity and pending counts.
Notes
- Throws
pdcomm::Error:PDCOMM_BACKPRESSUREwhile a TCP event is staged;PDCOMM_INVALID_STATEwhen no GEM role is configured.
stop
Method
Stops the HSMS endpoint; forwards to TcpEndpoint::stop().
void stop()For a graceful close, keep polling and draining events until the TCP state reports closed before destroying the endpoint.
Notes
- Throws
pdcomm::Error: with the status of pdcomm_tcp_stop().
stopSpoolTransmit
Method
Ends the current transmit run.
void stopSpoolTransmit()Notes
- Throws
pdcomm::Error:PDCOMM_INVALID_STATEwhile a delivery is in flight or an accepted dequeue is pending.
tcp
Method
Returns the underlying HSMS endpoint.
TcpEndpoint &tcp() noexceptUse it for TCP-level calls such as TcpEndpoint::nextEvent(), TcpEndpoint::state(), TcpEndpoint::localAddress(), TcpEndpoint::linktest() and TcpEndpoint::reply().
Returns
The owned TcpEndpoint; valid as long as this object lives.
tcp
Method
Returns the underlying HSMS endpoint for read-only calls.
const TcpEndpoint &tcp() const noexceptReturns
The owned TcpEndpoint; valid as long as this object lives.