|
Motion Master 6.0.0-alpha.86
Next-generation motion control software
|
Owns the active monitorings and turns each into a lossless stream of recorded rows. More...
#include <monitoring_manager.h>
Public Types | |
| using | PublishFn = std::function< void(std::string topic, std::string json)> |
Publishes one batch: json (a {"type":"monitoring","topic",...} envelope) under topic. Wired in the composition root to the WebSocket server's topic publish. | |
Public Member Functions | |
| MonitoringManager (DeviceManager &deviceManager) | |
Constructs the manager over deviceManager. Does not start sampling — call start(). | |
| ~MonitoringManager () | |
| Stops the owned refresher (and, once added, the sampler thread). | |
| MonitoringManager (const MonitoringManager &)=delete | |
| MonitoringManager & | operator= (const MonitoringManager &)=delete |
| void | setPublish (PublishFn publish) |
Sets the batch publish callback. Call before start(). | |
| std::expected< Monitoring, std::string > | create (Monitoring config) |
Validates config, classifies its parameters, registers SDO ones with the refresher, and registers the monitoring. | |
| bool | remove (const std::string &topic) |
| Removes a monitoring, releasing its SDO parameters from the refresher. | |
| std::optional< nlohmann::json > | get (const std::string &topic) const |
Returns the monitoring resource as JSON (config + per-parameter source + buffer fill), or nullopt if topic is unknown. | |
| nlohmann::json | list () const |
| Returns all monitoring resources as a JSON array, in topic order. | |
| void | start () |
| Starts the owned refresher (and, once added, the sampler thread). Idempotent. | |
| void | stop () |
| Stops the owned refresher (and, once added, the sampler thread). Idempotent. | |
| void | keepFresh (uint16_t devicePosition, uint16_t index, uint8_t subindex, std::chrono::milliseconds period) |
| Keeps an SDO-only object's value fresh in the background, for a cyclic task to read. | |
| void | stopKeepingFresh (uint16_t devicePosition, uint16_t index, uint8_t subindex) |
Drops a reference taken by keepFresh. Polling stops when the last one is released. | |
| void | sampleAll () |
| Flushes every monitoring once: delivers each one's recorded cycles since its last flush. The deterministic core the scheduler thread drives; exposed for tests. | |
| std::size_t | monitoringCount () const |
| Number of registered monitorings. For tests / status. | |
| std::size_t | polledSdoCount () const |
| Number of distinct SDO objects currently polled by the refresher. For tests / status. | |
Owns the active monitorings and turns each into a lossless stream of recorded rows.
A client creates a Monitoring (topic, interval, parameters); the manager validates it, classifies every parameter by how its value is sourced, and on each flush ships every process-data cycle recorded since the last flush. The stream is lossless: each monitoring holds a read cursor into the recorder ring and, each time it is due, decodes and publishes every cycle-row in [cursor, recorderHead()) as one batch, then advances the cursor. interval is the flush cadence, not a sample rate — a longer interval means a bigger batch, never dropped cycles. A cursor that falls more than a whole ring behind (a stalled client) is logged and resynced to the oldest available cycle; the gap is never silent.
Sourcing (decided once at create, against the published process image):
ParameterRefresher which polls it in the background, and the sampler reads the cached value. See Why a refresher exists at all below.Monitoring is live-only: a parameter whose owning device is not exchanging (SAFE-OP/OP) samples null. Topics are unique.
Why a refresher exists at all. The sampler must never touch the bus: it serves a lossless per-cycle stream, and an SDO upload is a blocking mailbox round-trip that queues behind the driver's control-plane lock — one per cycle per object is not an option at kHz rates. PDO parameters need no bus access (they decode out of the recorder ring), but an SDO-sourced parameter has no cyclic source at all, so something has to fetch it on a slower cadence, off the flush path. The refresher polls into each device's parameter cache in the background and the flush reads only that cache — which is why every row in one batch shares the same SDO value (slow telemetry, not a per-cycle signal). This manager drives acquire / release rather than merely reading, because the classification is dynamic: a re-map can flip a parameter PDO→SDO or SDO→PDO, and recaptureIfRemapped moves it between the two.
Thread-safe. Owns a private ParameterRefresher because monitoring is its only client today. That is an ownership choice, not a coupling: the refresher depends on nothing but DeviceManager&, its entries are reference-counted per object, and its start / stop are idempotent — so it is usable on its own, and a second client would be served by constructing it in the composition root and injecting it here instead. The App wires only this manager (with a DeviceManager& and a publish callback).
| using mm::node::MonitoringManager::PublishFn = std::function<void(std::string topic, std::string json)> |
Publishes one batch: json (a {"type":"monitoring","topic",...} envelope) under topic. Wired in the composition root to the WebSocket server's topic publish.
|
explicit |
Constructs the manager over deviceManager. Does not start sampling — call start().
| mm::node::MonitoringManager::~MonitoringManager | ( | ) |
Stops the owned refresher (and, once added, the sampler thread).
|
delete |
| std::expected< Monitoring, std::string > mm::node::MonitoringManager::create | ( | Monitoring | config | ) |
Validates config, classifies its parameters, registers SDO ones with the refresher, and registers the monitoring.
Validation: topic URL-safe; not already registered; interval between 5 ms and 2000 ms (the flush cadence); parameters non-empty; and every parameter is either PDO-mapped or present in its device's object dictionary (otherwise it cannot be sourced).
| std::optional< nlohmann::json > mm::node::MonitoringManager::get | ( | const std::string & | topic | ) | const |
Returns the monitoring resource as JSON (config + per-parameter source + buffer fill), or nullopt if topic is unknown.
| void mm::node::MonitoringManager::keepFresh | ( | uint16_t | devicePosition, |
| uint16_t | index, | ||
| uint8_t | subindex, | ||
| std::chrono::milliseconds | period | ||
| ) |
Keeps an SDO-only object's value fresh in the background, for a cyclic task to read.
The Tier-3 door onto the refresher this class owns. A cyclic task reads every value the same way — Device::value<T>() off the parameter's cell — but only PDO-mapped objects are refilled by the RT exchange. An object left out of the process image because it changes slowly (a temperature, a drive's own error register) has no cyclic source, so something has to poll it; that is what the refresher does, and this is how a program asks for it without inventing a monitoring and a WebSocket topic it will never subscribe to.
Reference-counted with stopKeepingFresh and with the monitorings that need the same object: several requesters poll it once, at the shortest period any of them asked for, and it stops being polled when the last one lets go. period is clamped to an internal floor — SDO is slow, and hammering the mailbox would starve the control plane.
Call it off the RT thread, before or during the loop — never from inside a cycle. It takes the refresher's mutex and may allocate. That is the only restriction: registering while the loop runs is fine, since the refresher's thread never touches the RT path.
| devicePosition | 1-based bus position. |
| index | CoE object index. |
| subindex | CoE object subindex. |
| period | Desired maximum time between polls. |
| nlohmann::json mm::node::MonitoringManager::list | ( | ) | const |
Returns all monitoring resources as a JSON array, in topic order.
| std::size_t mm::node::MonitoringManager::monitoringCount | ( | ) | const |
Number of registered monitorings. For tests / status.
|
delete |
| std::size_t mm::node::MonitoringManager::polledSdoCount | ( | ) | const |
Number of distinct SDO objects currently polled by the refresher. For tests / status.
| bool mm::node::MonitoringManager::remove | ( | const std::string & | topic | ) |
Removes a monitoring, releasing its SDO parameters from the refresher.
true if a monitoring with topic existed, false otherwise. | void mm::node::MonitoringManager::sampleAll | ( | ) |
Flushes every monitoring once: delivers each one's recorded cycles since its last flush. The deterministic core the scheduler thread drives; exposed for tests.
| void mm::node::MonitoringManager::setPublish | ( | PublishFn | publish | ) |
Sets the batch publish callback. Call before start().
| void mm::node::MonitoringManager::start | ( | ) |
Starts the owned refresher (and, once added, the sampler thread). Idempotent.
| void mm::node::MonitoringManager::stop | ( | ) |
Stops the owned refresher (and, once added, the sampler thread). Idempotent.
| void mm::node::MonitoringManager::stopKeepingFresh | ( | uint16_t | devicePosition, |
| uint16_t | index, | ||
| uint8_t | subindex | ||
| ) |
Drops a reference taken by keepFresh. Polling stops when the last one is released.