11 socket_ = std::make_unique<daq_comms::transport::TCPClient>();
26 std::cout <<
"[ElodinClient] Connecting to Elodin database at " << host <<
":" <<
port <<
"..."
37 std::cerr <<
"[ElodinClient] ❌ Connection failed: " <<
last_error_ << std::endl;
41 std::cout <<
"[ElodinClient] ✅ Connected to Elodin database at " << host <<
":" <<
port
49 last_error_ =
"No previous connection to reconnect to";
53 <<
"..." << std::endl;
64 std::cout <<
"[ElodinClient] Disconnecting from Elodin database..." << std::endl;
67 std::cout <<
"[ElodinClient] ✅ Disconnected" << std::endl;
76 uint16_t
id = (
static_cast<uint16_t
>(table_id[0]) << 8) | table_id[1];
92 socket_->set_recv_timeout_ms(timeout_ms);
97 for (
const auto& [hi, lo] : table_ids)
106 std::array<uint8_t, 2> msgstream_id = {0x11, 0x0d};
107 std::vector<uint8_t> data(10, 0x00);
108 uint32_t len = 2 + 4;
109 std::memcpy(data.data(), &len, 4);
111 data[5] = msgstream_id[0];
112 data[6] = msgstream_id[1];
115 data[7] = request_id;
118 return send_msg(msgstream_id, data);
154 return socket_->read(buffer, max_len);
164 return socket_->read_exact(header_buffer, 8);
173 return socket_->read_exact(buffer, len);
183 last_error_ =
"Buffer too small for packet header";
190 if (!
socket_->read_exact(packet_buffer, 8)) {
205 std::memcpy(&packet_len, packet_buffer,
sizeof(packet_len));
208 if (packet_len < 4) {
209 last_error_ =
"Invalid packet length: " + std::to_string(packet_len);
215 size_t payload_len = packet_len - 4;
221 if (packet_len + 4 > max_len) {
227 std::cerr <<
"[ElodinClient] packet " << packet_len <<
"B exceeds " << max_len
228 <<
"B buffer — skipping it" << std::endl;
230 size_t remaining = payload_len;
231 while (remaining > 0) {
232 const size_t chunk = std::min(remaining,
sizeof(
scratch));
241 last_error_ =
"Skipped oversized packet: " + std::to_string(packet_len);
245 if (payload_len > 0) {
246 if (!
socket_->read_exact(packet_buffer + 8, payload_len)) {
252 return static_cast<ssize_t
>(packet_len + 4);
256 const std::vector<uint8_t>& data) {
268 if (!
socket_->write_all(data.data(), data.size())) {
270 std::cerr <<
"[ElodinClient] ERROR: write_all failed: " <<
last_error_ <<
"\n";
274 static size_t send_count = 0;
276 std::cout <<
"[ElodinClient] ✅ Sent registration message #" << send_count
277 <<
", size=" << data.size() <<
" bytes" << std::endl;
280 }
catch (
const std::exception& e) {
281 last_error_ =
"Send MSG error: " + std::string(e.what());
282 std::cerr <<
"[ElodinClient] ERROR sending registration: " <<
last_error_ <<
"\n";
bool flush_batch()
Flush (send) the accumulated batch in a single TCP write.
bool is_connected() const
Check if connected.
bool send_msg(const std::array< uint8_t, 2 > &packet_id, const std::vector< uint8_t > &data)
Send a MSG packet (for VTable registration, etc.).
bool read_bytes_exact(uint8_t *buffer, size_t len)
Blocking read of exactly len bytes (for payload reads after header).
ssize_t read_data(void *buffer, size_t max_len)
Read incoming data packet from Elodin (non-blocking).
bool connect_locked(const std::string &host, uint16_t port)
std::string last_error() const
Get last error message.
void set_recv_timeout_ms(int timeout_ms)
Set socket receive timeout so read_packet() can yield.
void disconnect()
Disconnect from database.
bool subscribe_tables(const std::vector< std::pair< uint8_t, uint8_t > > &table_ids)
Subscribe to specific tables by ID.
std::unique_ptr< daq_comms::transport::TCPClient > socket_
void begin_batch()
Begin batching — subsequent publish() calls go into an internal buffer.
void register_table(const std::array< uint8_t, 2 > &table_id, const std::string &name)
Register a table ID with a name (for debugging/logging).
bool connect(const std::string &host, uint16_t port=2240)
Connect to Elodin database.
ssize_t read_packet(uint8_t *packet_buffer, size_t max_len)
Read complete packet from Elodin (header + payload).
std::mutex publish_mutex_
std::vector< uint8_t > batch_buffer_
bool subscribe_table(uint8_t hi, uint8_t lo, uint8_t request_id)
One table, under request_id, which the DB echoes if it refuses it (ErrorResponse [0xE0,...
void flush_buffer()
Flush the write buffer to the database.
bool read_packet_header(uint8_t *header_buffer)
Read packet header from Elodin (12 bytes).
bool reconnect()
Attempt to reconnect using the last-used host/port.
std::unordered_map< uint16_t, std::string > table_names_
static const emmc_port_t port
Motorized ball valve position: raw ADC counts -> % open.
static uint8_t scratch[BS]