38 const std::string& host, uint16_t
port) {
44 std::lock_guard<std::mutex>
lk(
mtx_);
47 for (
const auto& role : roles) {
52 <<
"[PressureFeed] \"" << role
53 <<
"\" is not declared by any enabled PT board or T7 PT input — not subscribed"
58 std::cout <<
"[PressureFeed] \"" << role <<
"\" -> "
59 << (ref->t7 ?
"LabJack T7 " :
"board ") <<
int(ref->board_number)
60 << (ref->t7 ?
" AIN " :
" ch ") << ref->channel <<
" (table 0x" << std::hex
61 <<
int(ref->table_hi) <<
",0x" << int(ref->table_lo) << std::dec <<
")"
80 auto last_resubscribe = std::chrono::steady_clock::now();
82 bool silent_logged =
false;
88 if (!client.is_connected()) {
89 if (!client.connect(host,
port)) {
90 std::this_thread::sleep_for(std::chrono::milliseconds(kReconnectBackoffMs));
93 std::vector<std::pair<uint8_t, uint8_t>>
tables;
95 std::lock_guard<std::mutex>
lk(
mtx_);
102 if (!client.subscribe_tables(
tables)) {
103 std::cerr <<
"[PressureFeed] subscribe failed — dropping the socket to retry"
106 std::this_thread::sleep_for(std::chrono::milliseconds(kReconnectBackoffMs));
111 client.set_recv_timeout_ms(kRecvTimeoutMs);
112 std::cout <<
"[PressureFeed] subscribed to " <<
tables.size()
113 <<
" calibrated PT table(s)" << std::endl;
114 last_resubscribe = std::chrono::steady_clock::now();
115 silent_logged =
false;
123 if (client.is_connected()) {
124 const auto now = std::chrono::steady_clock::now();
125 if (now - last_resubscribe >= std::chrono::milliseconds(kResubscribeMs)) {
126 std::vector<std::pair<uint8_t, uint8_t>> missing;
128 std::lock_guard<std::mutex>
lk(
mtx_);
131 missing.push_back(
id);
133 if (!missing.empty()) {
134 if (!silent_logged) {
135 std::cout <<
"[PressureFeed] " << missing.size()
136 <<
" table(s) have produced nothing yet — re-subscribing until "
137 "their publisher registers"
139 silent_logged =
true;
141 client.subscribe_tables(missing);
142 }
else if (silent_logged) {
143 std::cout <<
"[PressureFeed] every subscribed table is delivering" << std::endl;
144 silent_logged =
false;
146 last_resubscribe = now;
151 const ssize_t
n = client.read_packet(buf,
sizeof(buf));
161 const uint8_t type_hi = buf[5];
162 const uint8_t type_lo = buf[6];
166 std::lock_guard<std::mutex>
lk(
mtx_);
173 const size_t payload_len =
static_cast<size_t>(
n) - 8;
181 r.psi =
static_cast<double>(msg.
getField<3>());
183 r.at = std::chrono::steady_clock::now();
188 std::lock_guard<std::mutex>
lk(
mtx_);
196 std::lock_guard<std::mutex>
lk(
mtx_);
198 bool subscribed =
false;
212 const auto age = std::chrono::duration_cast<std::chrono::milliseconds>(
213 std::chrono::steady_clock::now() - it->second.at)
217 if (it->second.cal_status != 1)
220 psi = it->second.psi;
227 return role +
" is readable";
229 return role +
" is not subscribed (no script reads it, or config does not declare it)";
231 return role +
" has produced no reading yet";
233 return role +
"'s last reading is older than " + std::to_string(
kMaxAgeMs) +
" ms";
236 " is publishing UNCALIBRATED values (a cubic model with no captured "
237 "points streams a plausible 0.0 PSI)";
239 return role +
" cannot be read";
243 std::lock_guard<std::mutex>
lk(
mtx_);
244 std::vector<std::string> out;
Standalone Elodin database client.
Status
Why a role could not be read.
void start(const fsw::config::Config &cfg, const std::vector< std::string > &roles, const std::string &host, uint16_t port)
Subscribe to exactly the roles given, and nothing else.
std::vector< std::string > subscribedRoles() const
Roles this feed is subscribed to, for diagnostics.
std::atomic< bool > running_
Status read(const std::string &role, double &psi) const
std::map< std::pair< uint8_t, uint8_t >, std::string > role_by_table_
Elodin table id -> canonical role name, built once from config.
void runLoop(std::string host, uint16_t port)
static std::string explain(const std::string &role, Status s)
Human phrasing for a refusal, e.g.
std::map< std::string, Reading > readings_
static constexpr int kMaxAgeMs
How old a reading may be and still be acted on.
static const emmc_port_t port
CommsMessage< uint64_t, uint8_t, std::array< uint8_t, 3 >, float, uint32_t, uint8_t > CalibratedPTMessage
Calibrated Pressure Transducer message for Elodin.
std::optional< PtRoleRef > find_pt_role(const Config &cfg, const std::string &role)
Resolve one role by its canonical config name.
*brief user defined string literal for JSON values *sa std::size_t n
constexpr int kResubscribeMs
How often a table that has never delivered is asked for again.
constexpr int kRecvTimeoutMs
Long enough that the loop is not spinning, short enough that stop() is prompt.
constexpr int kReconnectBackoffMs
void deserialize(const uint8_t *buffer)
static constexpr std::size_t nbytes()
The whole parsed config.toml, restricted to what C++ consumes.
static SlugTables tables()
The tables every case validates against.