|
Motion Master 6.0.0-alpha.50
Next-generation motion control software
|
Owns the fieldbus driver and node collection, and drives PDO exchange. More...
#include <device_manager.h>
Classes | |
| struct | PdoSampleSpec |
| Everything needed to decode one PDO object from a raw process-image snapshot: which image it lives in, where, and how wide / what type. More... | |
Public Member Functions | |
| DeviceManager () | |
| ~DeviceManager () | |
Defined out-of-line so unique_ptr<ProcessData> can hold an incomplete type. | |
| std::expected< void, std::string > | init (std::unique_ptr< mm::comm::FieldbusDriver > driver, const DeviceManagerConfig &config={}) |
Takes ownership of driver and initialises it. | |
| void | configureParameterCache (const ParameterCacheConfig &config) |
| Sets the on-disk parameter-cache policy and location. | |
| const ParameterCache & | parameterCache () const |
| The on-disk parameter cache, for the management API (list / download / remove). | |
| std::expected< int, std::string > | scan () |
| Scans the bus for nodes and populates the device list. | |
| void | reset () |
| Stops the fieldbus driver and clears the device list. | |
| bool | initialised () const |
Whether a driver is currently held (i.e. init() has succeeded and reset() has not since been called). | |
| const std::vector< Device > & | devices () const |
| Returns the list of discovered devices. | |
| const Device * | findDevice (uint16_t slavePosition) const |
| Finds a device by its 1-based bus position. | |
| Device * | findDevice (uint16_t slavePosition) |
Mutable overload of findDevice. | |
| uint64_t | topologyGeneration () const |
Monotonic counter bumped every time the device set is rebuilt (scan / reset). | |
| std::expected< void, std::string > | configureProcessData () |
| Maps process data and publishes the process image for exchange. | |
| void | exchangeProcessData () |
| Exchanges one cycle of process data: sends staged outputs, captures inputs. | |
| bool | processDataConfigured () const |
Whether configureProcessData has published a process image for exchange. | |
| uint64_t | processImageGeneration () const |
| Monotonic counter bumped every time a new process image is published (each (re)map). | |
| int | lastWorkingCounter () const |
| The working counter from the most recent process-data exchange (0 before any). | |
| int | expectedWorkingCounter () const |
| The working counter expected from the devices currently exchanging (SAFE-OP/OP). | |
| bool | processDataHealthy () const |
| Whether every device that should be exchanging is contributing to the cycle. | |
| ProcessImageInfo | processImageInfo () const |
| Snapshots the published process image and its runtime health for the API. | |
| std::expected< std::string, std::string > | dumpProcessData () |
Serialises the recorder's current span to a .mmpd dump file and returns its path. | |
| std::expected< std::string, std::string > | dumpProcessDataBuffer () |
Serialises the recorder dump into an in-memory buffer — the same .mmpd bytes dumpProcessData writes to disk — for streaming over HTTP. | |
| std::vector< SlaveConfigInfo > | busConfig () const |
| Snapshots each slave's static ESC configuration (SM, FMMU, mailbox, DC) for the API. | |
| std::expected< std::vector< DeviceStateInfo >, std::string > | transitionToState (const std::vector< uint16_t > &positions, mm::comm::EtherCatState targetState, std::chrono::steady_clock::duration timeout) |
Transitions a set of devices to targetState, blocking until all arrive or timeout elapses, and reports the final state of each. | |
| std::expected< std::vector< DeviceStateInfo >, std::string > | getDeviceStates (const std::vector< uint16_t > &positions) |
| Reads the current AL state for a set of devices. | |
| std::expected< std::vector< DeviceDiagnosticsInfo >, std::string > | getDeviceDiagnostics (const std::vector< uint16_t > &positions) |
| Reads live ESC health diagnostics (link quality, error counters, watchdogs) for a set of devices, resolving each slave's device name. | |
| std::expected< std::vector< DcSyncInfo >, std::string > | getDcSync (const std::vector< uint16_t > &positions) |
| Reads live distributed-clock synchronisation status for a set of devices, resolving each slave's device name. | |
| std::expected< mm::comm::ProcessDataWatchdogConfig, std::string > | getProcessDataWatchdog (uint16_t slavePosition) |
| Reads the process-data (sync-manager) watchdog configuration of one device. | |
| std::expected< mm::comm::ProcessDataWatchdogConfig, std::string > | setProcessDataWatchdog (uint16_t slavePosition, std::chrono::nanoseconds timeout) |
| Sets the process-data (sync-manager) watchdog timeout of one device. | |
| std::expected< void, std::string > | initializeDeviceParameters (uint16_t slavePosition, bool readValues) |
Enumerates the CoE object dictionary of one device and populates its parameter map. See Device::initializeParameters for details. | |
| std::expected< void, std::string > | readAllDeviceParameters (uint16_t slavePosition) |
| Refreshes the cached value of every readable parameter of one device, in place. | |
| std::expected< DeviceParameterValue, std::string > | readDeviceParameter (uint16_t slavePosition, uint16_t index, uint8_t subindex) |
| Convenience: finds a device by position and reads one of its parameters. | |
| std::expected< DeviceParameter, std::string > | deviceParameterView (uint16_t slavePosition, uint16_t index, uint8_t subindex, bool refreshFromBus) |
| Returns a full parameter struct (value + metadata), optionally refreshed from the bus. | |
| std::expected< void, std::string > | writeDeviceParameter (uint16_t slavePosition, uint16_t index, uint8_t subindex, DeviceParameterValue newValue) |
| Convenience: finds a device by position and writes one of its parameters. | |
| std::expected< void, std::string > | writeDevicePdoMapping (uint16_t slavePosition, const PdoMapping &mapping) |
| Convenience: finds a device by position and writes its PDO mapping. | |
| std::expected< PdoMapping, std::string > | readDevicePdoMapping (uint16_t slavePosition) |
| Convenience: finds a device by position and reads its PDO mapping grouped by object. | |
| std::vector< OutputStageResult > | stageProcessDataOutputs (std::span< const OutputStageRequest > requests) |
| Stages a batch of output objects into the process image in one call. | |
| std::optional< DeviceParameterValue > | value (uint16_t slavePosition, uint16_t index, uint8_t subindex) const |
| Returns a copy of a parameter's cached value, no bus access. Thread-safe. | |
| std::optional< PdoSampleSpec > | pdoSampleSpec (uint16_t slavePosition, uint16_t index, uint8_t subindex) const |
| Resolves a PDO-mapped object's decode spec from the published image. Thread-safe. | |
| uint64_t | recorderHead () const |
The recorder ring's next sequence number; recorderHead()-1 is the newest recorded cycle and recorderHead()==0 means nothing has been recorded yet. Thread-safe. | |
| uint64_t | recorderOldestSeq () const |
The oldest sequence number still present in the ring (max(0, head - capacity)). A cursor below this has been lapped (overwritten) and must resync to it. Thread-safe. | |
| bool | readRecord (uint64_t seq, ProcessDataRing::Record &out) const |
Copies the recorded cycle for seq into out. Thread-safe, lock-free. | |
| bool | deviceExchangesProcessData (uint16_t slavePosition) const |
Whether the device at slavePosition is currently exchanging (SAFE-OP/OP). Thread-safe; reads the driver's cached AL state, no bus I/O. | |
Owns the fieldbus driver and node collection, and drives PDO exchange.
The driver is not required at construction — call init() to supply one. This allows the app to start without a driver and be initialised later via the HTTP API. Injected into GameLoop (for exchangeProcessData) and HttpServer (for SDO/state operations).
| mm::node::DeviceManager::DeviceManager | ( | ) |
|
default |
Defined out-of-line so unique_ptr<ProcessData> can hold an incomplete type.
| std::vector< SlaveConfigInfo > mm::node::DeviceManager::busConfig | ( | ) | const |
Snapshots each slave's static ESC configuration (SM, FMMU, mailbox, DC) for the API.
Passes through the driver's cached configuration (no bus I/O) and resolves each slave's device name. Returns an empty vector when no driver is set or the transport has no ESC (e.g. SPoE). Runs on the (non-RT) caller's thread.
| void mm::node::DeviceManager::configureParameterCache | ( | const ParameterCacheConfig & | config | ) |
Sets the on-disk parameter-cache policy and location.
The cache is a process-level concern (its directory comes from the config file, like the ports), independent of whether a driver is initialised — so this is called once at startup, not from init. The configured location is then correct for the management API and for every device's initializeParameters regardless of init order. Safe to call again to re-apply.
| std::expected< void, std::string > mm::node::DeviceManager::configureProcessData | ( | ) |
Maps process data and publishes the process image for exchange.
Calls FieldbusDriver::configureProcessData (which maps the IOmap and lays out the FMMUs), reads each device's PDO mapping via SDO, assembles a ProcessImage that resolves every mapped object to an absolute position, zero-initialises the output staging buffer, and publishes the image so exchangeProcessData begins exchanging. All devices must be in PRE-OP (mailbox active) for the mapping reads to succeed.
Re-runnable: a later call (e.g. after a device returns from a firmware download) re-maps the whole bus and republishes. While re-mapping it first unpublishes the image so exchangeProcessData becomes a no-op; call it with the GameLoop stopped or drained, as for init / reset (see the exchangeProcessData warning).
| bool mm::node::DeviceManager::deviceExchangesProcessData | ( | uint16_t | slavePosition | ) | const |
Whether the device at slavePosition is currently exchanging (SAFE-OP/OP). Thread-safe; reads the driver's cached AL state, no bus I/O.
The monitoring sampler's per-device live gate: only an exchanging device has live process data, so a non-exchanging device's parameters sample null. false for an unknown position.
| std::expected< DeviceParameter, std::string > mm::node::DeviceManager::deviceParameterView | ( | uint16_t | slavePosition, |
| uint16_t | index, | ||
| uint8_t | subindex, | ||
| bool | refreshFromBus | ||
| ) |
Returns a full parameter struct (value + metadata), optionally refreshed from the bus.
Backs the GET /api/devices/{pos}/parameters/{index}/{subindex} route. When refreshFromBus is true (the ?source=auto default) the cache is first synced via the live PDO image or an SDO upload (routing lives in Device::readParameter); when false (the ?source=cache path) the cached struct is returned without any bus I/O. Either way the returned value is a copy taken under the parameter-cache lock, so it is safe off-thread.
| slavePosition | 1-based bus position of the target device. |
| index | CoE object index. |
| subindex | CoE object subindex. |
| refreshFromBus | When true, sync the cache from the device before copying. |
| const std::vector< Device > & mm::node::DeviceManager::devices | ( | ) | const |
Returns the list of discovered devices.
scan(). | std::expected< std::string, std::string > mm::node::DeviceManager::dumpProcessData | ( | ) |
Serialises the recorder's current span to a .mmpd dump file and returns its path.
Freezes the recorder span at the instant of the call — [recorderOldestSeq(), recorderHead()) — and writes every cycle in it (full raw inputs + outputs, sequence, epoch-ns timestamp) plus the process image embedded as a header, so the file decodes fully offline. Works in any state: while exchanging (OP/SAFE-OP) it dumps tail→head at that moment and ignores cycles the producer records afterwards; after teardown it uses the most recent retained image generation. The header objects' names/data types come from each device's parameter map (empty/0 when the object dictionary has not been enumerated).
The file is written to the configured recorderDumpDir (created if absent); an empty recorderDumpDir (the default) resolves to a "motion-master" subdirectory of the OS temporary directory. The filename is dump-<UTC-timestamp>- <endSequence>.mmpd. Motion Master binds 127.0.0.1, so the file is on the caller's own machine — the path is all that is returned (no download/list/delete).
| std::expected< std::string, std::string > mm::node::DeviceManager::dumpProcessDataBuffer | ( | ) |
Serialises the recorder dump into an in-memory buffer — the same .mmpd bytes dumpProcessData writes to disk — for streaming over HTTP.
Buffers the whole span in memory (a deep recorder ring can be large; true row-by-row streaming is a future optimisation). Same image/span semantics as dumpProcessData; the RT producer is never blocked. Runs on the (non-RT) caller's thread.
| void mm::node::DeviceManager::exchangeProcessData | ( | ) |
Exchanges one cycle of process data: sends staged outputs, captures inputs.
Composes the output image from the per-object staging slots, calls FieldbusDriver::exchangeProcessData, and appends the cycle (both directions) to the recorder ring for non-RT readers. No-op until configureProcessData has published an image, so the GameLoop can call it unconditionally every cycle. Runs on the RT thread and takes no lock.
exchangeProcessData() runs on the RT GameLoop thread while init(), scan(), reset(), and configureProcessData() may be called from the HTTP server thread. The published-image pointer gates exchange off during a re-map, but driver_ / devices_ themselves are not otherwise locked across that boundary. Stop the loop (or drain one cycle) before calling init() / reset() / configureProcessData() via the API. | int mm::node::DeviceManager::expectedWorkingCounter | ( | ) | const |
The working counter expected from the devices currently exchanging (SAFE-OP/OP).
Computed from each device's PDO presence and current AL state, so it tracks a partially operational bus: an OP device with outputs and inputs contributes 3, a SAFE-OP device contributes 1 (inputs only), and PRE-OP/below contribute 0. Recomputed on configure and on each state transition — not the whole-bus all-OP figure.
| Device * mm::node::DeviceManager::findDevice | ( | uint16_t | slavePosition | ) |
Mutable overload of findDevice.
Hands back a writable Device so SDK callers can drive it directly — e.g. dm.findDevice(1)->writeValue(0x2030, 1, 123). nullptr if not found.
busMutex_. Off-thread consumers (monitoring) must go through the position-based methods such as readDeviceParameter, which look the device up under the lock and never hand out a pointer that scan / reset could dangle. | const Device * mm::node::DeviceManager::findDevice | ( | uint16_t | slavePosition | ) | const |
Finds a device by its 1-based bus position.
| slavePosition | 1-based position of the device on the fieldbus. |
Device, or nullptr if not found. | std::expected< std::vector< DcSyncInfo >, std::string > mm::node::DeviceManager::getDcSync | ( | const std::vector< uint16_t > & | positions | ) |
Reads live distributed-clock synchronisation status for a set of devices, resolving each slave's device name.
If positions is empty, all discovered devices are queried. Forwards to FieldbusDriver::readDcSync (FPRD reads — not cached) and wraps each result with its device name. The system-time difference is meaningful only while the bus is exchanging in SAFE-OP/OP; a page polls this and watches for a slave whose deviation from the reference clock stays large or grows rather than converging toward zero.
Must be called after both init() and scan().
| positions | 1-based slave positions to query; empty = all devices. |
| std::expected< std::vector< DeviceDiagnosticsInfo >, std::string > mm::node::DeviceManager::getDeviceDiagnostics | ( | const std::vector< uint16_t > & | positions | ) |
Reads live ESC health diagnostics (link quality, error counters, watchdogs) for a set of devices, resolving each slave's device name.
If positions is empty, all discovered devices are queried. Forwards to FieldbusDriver::readDiagnostics (FPRD reads — not cached) and wraps each result with its device name. The returned counters are monotonic since the last clear, so a diagnostics page polls this and watches for a rising delta rather than an absolute value.
Must be called after both init() and scan().
| positions | 1-based slave positions to query; empty = all devices. |
| std::expected< std::vector< DeviceStateInfo >, std::string > mm::node::DeviceManager::getDeviceStates | ( | const std::vector< uint16_t > & | positions | ) |
Reads the current AL state for a set of devices.
If positions is empty, all discovered devices are queried. Must be called after both init() and scan().
| positions | 1-based slave positions to query; empty = all devices. |
| std::expected< mm::comm::ProcessDataWatchdogConfig, std::string > mm::node::DeviceManager::getProcessDataWatchdog | ( | uint16_t | slavePosition | ) |
Reads the process-data (sync-manager) watchdog configuration of one device.
Forwards to FieldbusDriver::processDataWatchdog after resolving the device. Returns the configured timeout itself (the divider/time registers), not the expiration counter that getDeviceDiagnostics surfaces.
| slavePosition | 1-based bus position of the target device. |
| std::expected< void, std::string > mm::node::DeviceManager::init | ( | std::unique_ptr< mm::comm::FieldbusDriver > | driver, |
| const DeviceManagerConfig & | config = {} |
||
| ) |
Takes ownership of driver and initialises it.
Must be called before scan() and exchangeProcessData(). One-shot: fails if a driver is already held — call reset() first. Replacing a live driver would dangle the FieldbusDriver& that every Device holds.
| driver | Concrete fieldbus driver to own and operate. |
| config | Runtime tuning (recorder depth, cycle period). Defaults are used for any field left at its default; omit the argument entirely to use all defaults. |
|
inline |
| std::expected< void, std::string > mm::node::DeviceManager::initializeDeviceParameters | ( | uint16_t | slavePosition, |
| bool | readValues | ||
| ) |
Enumerates the CoE object dictionary of one device and populates its parameter map. See Device::initializeParameters for details.
| slavePosition | 1-based bus position of the target device. |
| readValues | When true, also issue an SDO upload for each entry and store the decoded value on the parameter. |
| int mm::node::DeviceManager::lastWorkingCounter | ( | ) | const |
The working counter from the most recent process-data exchange (0 before any).
| const ParameterCache & mm::node::DeviceManager::parameterCache | ( | ) | const |
The on-disk parameter cache, for the management API (list / download / remove).
A disk store independent of the bus; usable with or without a driver initialised.
| std::optional< DeviceManager::PdoSampleSpec > mm::node::DeviceManager::pdoSampleSpec | ( | uint16_t | slavePosition, |
| uint16_t | index, | ||
| uint8_t | subindex | ||
| ) | const |
Resolves a PDO-mapped object's decode spec from the published image. Thread-safe.
The sampler captures this once per PDO parameter (and re-captures when processImageGeneration changes), then for each recorded cycle reads the matching region of the ring record (inputs for an input object, outputs for an output) and runs extractBits + decodeSdoBytes itself — so the bus is never touched on the sampling path and every value in a row comes from the same cycle's record.
nullopt if no image is published, the object is not PDO-mapped, or its data type is unknown (object dictionary not enumerated). | bool mm::node::DeviceManager::processDataConfigured | ( | ) | const |
Whether configureProcessData has published a process image for exchange.
| bool mm::node::DeviceManager::processDataHealthy | ( | ) | const |
Whether every device that should be exchanging is contributing to the cycle.
True when process data is configured and the last working counter is at least the expected value. A drop below expected means a device that should be in SAFE-OP/OP stopped contributing (cable, fault, or an unexpected state change).
| uint64_t mm::node::DeviceManager::processImageGeneration | ( | ) | const |
Monotonic counter bumped every time a new process image is published (each (re)map).
A consumer that captured per-object layout (bit offsets/lengths) from the image compares this on each use: a change means the bus was re-mapped and offsets may have shifted, so the captured layout must be refreshed. Lock-free (atomic). Distinct from topologyGeneration (scan/reset), which signals the device set itself changed.
| ProcessImageInfo mm::node::DeviceManager::processImageInfo | ( | ) | const |
Snapshots the published process image and its runtime health for the API.
Resolves every mapped object to an absolute bit offset and a name (looked up from each device's parameter map, empty if the OD has not been enumerated) and reports the byte sizes, expected/last working counter, health, and the number of retained image generations. Returns configured false with empty object lists when no image is published. Runs on the (non-RT) caller's thread; reads the published image lock-free.
| std::expected< void, std::string > mm::node::DeviceManager::readAllDeviceParameters | ( | uint16_t | slavePosition | ) |
Refreshes the cached value of every readable parameter of one device, in place.
Unlike initializeDeviceParameters this does not re-enumerate the object dictionary — it re-reads the values of the parameters already loaded (PDO-aware per entry). See Device::readAllParameters for the per-entry semantics. Best-effort: a single object that fails to read is logged and the call still succeeds.
| slavePosition | 1-based bus position of the target device. |
| std::expected< DeviceParameterValue, std::string > mm::node::DeviceManager::readDeviceParameter | ( | uint16_t | slavePosition, |
| uint16_t | index, | ||
| uint8_t | subindex | ||
| ) |
Convenience: finds a device by position and reads one of its parameters.
Equivalent to findDevice(slavePosition)->readParameter(index, subindex) — see Device::readParameter for the online/offline semantics. Saves callers a manual lookup when they only have a position.
| slavePosition | 1-based bus position of the target device. |
| index | CoE object index. |
| subindex | CoE object subindex. |
| std::expected< PdoMapping, std::string > mm::node::DeviceManager::readDevicePdoMapping | ( | uint16_t | slavePosition | ) |
Convenience: finds a device by position and reads its PDO mapping grouped by object.
Equivalent to findDevice(slavePosition)->readPdoMapping() — see Device::readPdoMapping. Reads fresh over SDO (mailbox must be active: PRE-OP/SAFE-OP/OP). Used by the read side of the PDO-mapping route and to echo the verified read-back after a write.
| slavePosition | 1-based bus position of the target device. |
| bool mm::node::DeviceManager::readRecord | ( | uint64_t | seq, |
| ProcessDataRing::Record & | out | ||
| ) | const |
Copies the recorded cycle for seq into out. Thread-safe, lock-free.
true if seq is present and copied without a concurrent overwrite; false if it is no longer in the ring or the copy raced the producer (the caller skips it). | uint64_t mm::node::DeviceManager::recorderHead | ( | ) | const |
The recorder ring's next sequence number; recorderHead()-1 is the newest recorded cycle and recorderHead()==0 means nothing has been recorded yet. Thread-safe.
A monitoring holds a read cursor and ships every record in [cursor, recorderHead()) per flush, advancing the cursor — a non-destructive reader that never gates the RT producer.
| uint64_t mm::node::DeviceManager::recorderOldestSeq | ( | ) | const |
The oldest sequence number still present in the ring (max(0, head - capacity)). A cursor below this has been lapped (overwritten) and must resync to it. Thread-safe.
| void mm::node::DeviceManager::reset | ( | ) |
Stops the fieldbus driver and clears the device list.
Transitions all slaves to INIT state, closes the network interface, and removes all Device objects. After this returns, init() and scan() may be called again. Must not be called while exchangeProcessData() is running concurrently.
| std::expected< int, std::string > mm::node::DeviceManager::scan | ( | ) |
Scans the bus for nodes and populates the device list.
Must be called after init(). Forwards to FieldbusDriver::scan().
| std::expected< mm::comm::ProcessDataWatchdogConfig, std::string > mm::node::DeviceManager::setProcessDataWatchdog | ( | uint16_t | slavePosition, |
| std::chrono::nanoseconds | timeout | ||
| ) |
Sets the process-data (sync-manager) watchdog timeout of one device.
Forwards to FieldbusDriver::setProcessDataWatchdog after resolving the device. A larger timeout lets a device tolerate the brief PDO pause of a whole-bus re-map without faulting; a timeout of zero disables the watchdog. The achieved timeout is rounded to the device's watchdog tick base — the returned config reports what was programmed. The write persists until the ESC reloads EEPROM (power cycle).
| slavePosition | 1-based bus position of the target device. |
| timeout | Desired watchdog timeout; zero disables the watchdog. |
timeout is unrepresentable, or a register access fails. | std::vector< OutputStageResult > mm::node::DeviceManager::stageProcessDataOutputs | ( | std::span< const OutputStageRequest > | requests | ) |
Stages a batch of output objects into the process image in one call.
Backs POST /api/process-data/outputs, the "send all" action of the Process Data page: the user edits several outputs and ships them together. Each request is routed through Device::writeParameter (same coercion + PDO-staging path as writeDeviceParameter), and each gets an OutputStageResult reporting whether it actually landed in the cyclic output image — so the UI can flag any object that was not staged without failing the whole batch.
Best-effort atomicity: the slots are stored sequentially on this (non-RT) thread, so a batch can straddle two consecutive RT cycles (≤1 ms skew worst case). Composing every slot in a single cycle would require RT-side generation gating, which would break the lock-free output path — out of scope; the brief skew is acceptable for manual process-data writes.
| requests | The objects to stage, each with a value coerced to its declared type. |
| uint64_t mm::node::DeviceManager::topologyGeneration | ( | ) | const |
Monotonic counter bumped every time the device set is rebuilt (scan / reset).
An off-thread consumer that pinned work to a device position records this value and compares it on each use: a change means the topology was re-scanned (or cleared) and a previously-valid position may now name a different device or none at all, so the consumer must re-validate. Lock-free (atomic). Starts at 0; the first scan makes it 1.
| std::expected< std::vector< DeviceStateInfo >, std::string > mm::node::DeviceManager::transitionToState | ( | const std::vector< uint16_t > & | positions, |
| mm::comm::EtherCatState | targetState, | ||
| std::chrono::steady_clock::duration | timeout | ||
| ) |
Transitions a set of devices to targetState, blocking until all arrive or timeout elapses, and reports the final state of each.
If positions is empty, all discovered devices are targeted. After the transition settles, the final AL state of every targeted device is read back and returned — so callers see exactly where each device ended up rather than a bare success flag. A device reached the target when its returned snapshot has error clear and alState equal to targetState; otherwise alStatusCode explains why.
Must be called after both init() and scan().
| positions | 1-based slave positions to transition; empty = all devices. |
| targetState | Desired EtherCAT AL state. |
| timeout | Maximum time to wait for all devices. |
| std::optional< DeviceParameterValue > mm::node::DeviceManager::value | ( | uint16_t | slavePosition, |
| uint16_t | index, | ||
| uint8_t | subindex | ||
| ) | const |
Returns a copy of a parameter's cached value, no bus access. Thread-safe.
For monitoring's SDO objects: the value the ParameterRefresher last wrote to the cache.
nullopt if the device or parameter is unknown. | std::expected< void, std::string > mm::node::DeviceManager::writeDeviceParameter | ( | uint16_t | slavePosition, |
| uint16_t | index, | ||
| uint8_t | subindex, | ||
| DeviceParameterValue | newValue | ||
| ) |
Convenience: finds a device by position and writes one of its parameters.
Equivalent to findDevice(slavePosition)->writeParameter(index, subindex, value) — see Device::writeParameter for the online/offline semantics (offline edits succeed and are held as SyncState::Pending).
| slavePosition | 1-based bus position of the target device. |
| index | CoE object index. |
| subindex | CoE object subindex. |
| value | Value to set; coerced to the parameter's declared type. |
| std::expected< void, std::string > mm::node::DeviceManager::writeDevicePdoMapping | ( | uint16_t | slavePosition, |
| const PdoMapping & | mapping | ||
| ) |
Convenience: finds a device by position and writes its PDO mapping.
Equivalent to findDevice(slavePosition)->writePdoMapping(mapping) — see Device::writePdoMapping for the procedure and the PRE-OP requirement. Does not itself re-map the process image: the caller drives the device back to SAFE-OP/OP afterwards, and transitionToState re-reads the mapping and rebuilds the whole-bus image at that point.
| slavePosition | 1-based bus position of the target device. |
| mapping | Desired output (RxPDO) and input (TxPDO) mapping, in assignment order. |