STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
PressureFeed Class Reference

Live calibrated pressures, by ROLE NAME, for the sequencer. More...

#include <PressureFeed.hpp>

Collaboration diagram for PressureFeed:
[legend]

Classes

struct  Reading

Public Types

enum class  Status {
  Ok , NotSubscribed , NoReading , Stale ,
  Uncalibrated
}
 Why a role could not be read. More...

Public Member Functions

 PressureFeed ()=default
 PressureFeed (const PressureFeed &)=delete
 ~PressureFeed ()
PressureFeed & operator= (const PressureFeed &)=delete
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.
void stop ()
Status read (const std::string &role, double &psi) const
std::vector< std::string > subscribedRoles () const
 Roles this feed is subscribed to, for diagnostics.

Static Public Member Functions

static std::string explain (const std::string &role, Status s)
 Human phrasing for a refusal, e.g.

Static Public Attributes

static constexpr int kMaxAgeMs = 1000
 How old a reading may be and still be acted on.

Private Member Functions

void runLoop (std::string host, uint16_t port)

Private Attributes

std::thread thread_
std::atomic< bool > running_ {false}
std::mutex mtx_
std::map< std::string, Reading > readings_
std::map< std::pair< uint8_t, uint8_t >, std::string > role_by_table_
 Elodin table id -> canonical role name, built once from config.

Detailed Description

Live calibrated pressures, by ROLE NAME, for the sequencer.

PressureFeed: the sequencer's one reader of live calibrated pressure.

The sequencer is otherwise pressure-blind — its only recv() is the controller's FIRE ack, and its ElodinClient is publish-only. This is the one thing that reads.

── Why it is keyed by role and not by channel ────────────────────────────────────────────────

ControllerService keys its measurements by channel number, and that is how its P_copv came to be assigned from channel 6 — which on this rig is "GN2 Regulated", the regulated downstream pressure, not the COPV at all. Its subscriber also filters the table id to board 1, which silently drops every sensor on PT board 2, "GN2 High" included. Resolving each role through fsw::config::find_pt_role makes both mistakes unrepresentable: there is no range filter to get wrong, because the table id is computed from the role.

── Why a reading can be refused ──────────────────────────────────────────────────────────────

A PT whose calibration model is "cubic" with no captured points publishes a smooth, plausible 0.0 PSI with calibration_status = 0. A script that reads that for a COPV and takes 90% of it computes a target of zero — and then does nothing at all, successfully, while an operator watches the state enter and cleanly exit believing the tank came up to pressure. A stale reading is the same hazard from the other direction: a press loop cycling a valve against a number that stopped moving. Both are refused rather than returned.

Driven against a fake elodin-db so the whole path is exercised — connect, subscribe, decode, key by table, gate — with no real database and no boards.

The two failures this is really here to prevent are both silent:

  1. Reading the WRONG SENSOR. ControllerService keys its measurements by channel number, which is how its P_copv came to be assigned from channel 6 — "GN2 Regulated" on this rig, the regulated downstream pressure, not the COPV. Here the table id is computed from the role, so the test asserts that a packet on board 2's table lands under the board-2 role and nowhere else.
  2. Acting on a number that must not be acted on. A PT whose model is "cubic" with no captured points publishes a smooth, plausible 0.0 PSI with calibration_status = 0. A script taking 90% of that computes a target of zero and then does nothing at all, successfully, while an operator watches the state enter and cleanly exit. Both that and a stale reading must be refused rather than returned.

Definition at line 41 of file PressureFeed.hpp.

Member Enumeration Documentation

◆ Status

Why a role could not be read.

Reported so a refusal can say which sensor and why.

Enumerator
Ok 
NotSubscribed 
NoReading 
Stale 
Uncalibrated 

Definition at line 50 of file PressureFeed.hpp.

Constructor & Destructor Documentation

◆ PressureFeed() [1/2]

◆ PressureFeed() [2/2]

◆ ~PressureFeed()

Member Function Documentation

◆ explain()

std::string sequencer::PressureFeed::explain ( const std::string & role,
Status s )
static

Human phrasing for a refusal, e.g.

"GN2 High has no calibrated reading".

Definition at line 224 of file PressureFeed.cpp.

Referenced by main().

◆ operator=()

PressureFeed & sequencer::PressureFeed::operator= ( const PressureFeed & )
delete

◆ read()

PressureFeed::Status sequencer::PressureFeed::read ( const std::string & role,
double & psi ) const
Returns
Ok and fills psi only when the reading may be acted on.

Definition at line 195 of file PressureFeed.cpp.

◆ runLoop()

void sequencer::PressureFeed::runLoop ( std::string host,
uint16_t port )
private

Say "still waiting" once, not once a second for the life of the process.

Definition at line 78 of file PressureFeed.cpp.

◆ start()

void sequencer::PressureFeed::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.

Elodin has no wildcard — "every subscriber must name what it consumes" — so the list comes from the union of every loaded script's pressure() slugs. A role that no script reads costs no traffic, and with no roles at all the thread never starts.

Safe to call once, at config load. Roles that config cannot resolve to a board+channel are reported and skipped; a script naming one was already refused at load.

Definition at line 37 of file PressureFeed.cpp.

◆ stop()

Definition at line 72 of file PressureFeed.cpp.

◆ subscribedRoles()

std::vector< std::string > sequencer::PressureFeed::subscribedRoles ( ) const

Roles this feed is subscribed to, for diagnostics.

Definition at line 242 of file PressureFeed.cpp.

Member Data Documentation

◆ kMaxAgeMs

int sequencer::PressureFeed::kMaxAgeMs = 1000
staticconstexpr

How old a reading may be and still be acted on.

Definition at line 89 of file PressureFeed.hpp.

Referenced by main().

◆ mtx_

std::mutex sequencer::PressureFeed::mtx_
mutableprivate

Definition at line 97 of file PressureFeed.hpp.

◆ readings_

std::map<std::string, Reading> sequencer::PressureFeed::readings_
private

Definition at line 98 of file PressureFeed.hpp.

◆ role_by_table_

std::map<std::pair<uint8_t, uint8_t>, std::string> sequencer::PressureFeed::role_by_table_
private

Elodin table id -> canonical role name, built once from config.

Keyed by the whole id: an ESP32 PT ({0x20, lo}) and a LabJack T7 PT ({0x26, lo}) can share a low byte.

Definition at line 101 of file PressureFeed.hpp.

◆ running_

std::atomic<bool> sequencer::PressureFeed::running_ {false}
private

Definition at line 95 of file PressureFeed.hpp.

◆ thread_

std::thread sequencer::PressureFeed::thread_
private

Definition at line 94 of file PressureFeed.hpp.


The documentation for this class was generated from the following files: