#pragma once #include #include #include #include #include #include "secsgem/secs2/message.hpp" #include "secsgem/secsi/block.hpp" #include "secsgem/secsi/header.hpp" #include "secsgem/secsi/protocol.hpp" // SECS-I block framing tunneled over a TCP socket. Mirrors the // secsgem-py `secsitcp/` convenience layer — useful for back-to-back // testing and simulators where you want SECS-I semantics (ENQ/EOT/ACK, // retries) but no actual serial hardware. The on-wire bytes are // identical to what would travel over RS-232; only the carrier differs. namespace secsgem::secsi { class TcpTransport : public std::enable_shared_from_this { public: using MessageHandler = std::function; using ErrorHandler = std::function; using LogHandler = std::function; TcpTransport(asio::ip::tcp::socket socket, Role role, uint16_t device_id, Timers timers = {}); void set_message_handler(MessageHandler h) { on_message_ = std::move(h); } void set_error_handler(ErrorHandler h) { on_error_ = std::move(h); } void set_log_handler(LogHandler h) { on_log_ = std::move(h); } // Begin the read loop. Idempotent. void start(); // Queue a SECS-II message for transmission. Internally split into // SECS-I blocks if larger than kMaxBlockBody; system bytes are // auto-assigned monotonically. void send(secs2::Message msg); // Hard-close the underlying socket. No graceful teardown — SECS-I has // no equivalent of HSMS Separate.req at the protocol level. void close(); Protocol::State state() const { return fsm_.state(); } private: void read_loop(); void run_actions(std::vector& actions); void deliver_block(Block block); void start_timer(Timer which); void cancel_timer(Timer which); void log(const std::string& msg); asio::ip::tcp::socket socket_; Protocol fsm_; Timers timers_; uint16_t device_id_; bool started_ = false; bool closed_ = false; std::array read_buf_{}; std::vector assembler_; // partial multi-block message uint32_t next_system_bytes_ = 1; asio::steady_timer t1_; asio::steady_timer t2_; MessageHandler on_message_; ErrorHandler on_error_; LogHandler on_log_; }; } // namespace secsgem::secsi