Motion Master 6.0.0-alpha.111
Next-generation motion control software
Loading...
Searching...
No Matches
spoe_fieldbus_driver.h
Go to the documentation of this file.
1#pragma once
2
3// The fieldbus driver for SPoE: one TCP connection to the netX of each drive.
4//
5// Where the SPoE specification and the firmware disagree, this driver follows the firmware. The
6// differences are listed in issue #36.
7//
8// A position is the place of an address in the configured list, and it never changes. A drive that
9// does not answer keeps its position with no state known, so the positions after it stay where
10// they are.
11//
12// There is no ESC, so SII, ESC registers, DC and the ESC diagnostics answer "not supported".
13
14#include <chrono>
15#include <cstdint>
16#include <expected>
17#include <functional>
18#include <memory>
19#include <optional>
20#include <span>
21#include <stop_token>
22#include <string>
23#include <vector>
24
27#include "comm/spoe_frame.h"
28
29namespace mm::comm::spoe {
30
32enum class PdoMode : uint8_t {
33 kNone = 0x00,
34 kMonitor = 0x01,
35 kControl = 0x02,
36};
37
40enum class SpoeMode : uint8_t {
43};
44
47 std::vector<std::string> hosts;
48 uint16_t port = 8080;
51 uint32_t watchdogMs = 75;
53 std::chrono::milliseconds requestTimeout{1000};
54 std::chrono::milliseconds connectTimeout{1000};
58 std::chrono::milliseconds fileTimeout{30000};
61 std::chrono::microseconds exchangePeriod{1000};
62};
63
66constexpr std::size_t kInputQueueLimit = 30;
67
71constexpr uint16_t kProtocolVersion100 = 0x0100;
72constexpr uint16_t kProtocolVersion102 = 0x0102;
73
77constexpr std::size_t kParameterEntrySize = 68;
78
83 uint32_t subindexCount = 0;
84};
85
89std::vector<ParameterEntry> decodeParameterEntries(std::span<const uint8_t> bytes);
90
92std::string sdoStatusName(uint16_t status);
93
95 public:
97 ~SpoeFieldbusDriver() override;
98
101
102 std::expected<void, std::string> init() override;
103 std::expected<int, std::string> scan() override;
104 SlaveInfo slaveInfo(uint16_t position) const override;
105 uint16_t slaveState(uint16_t position) const override;
106 uint16_t mailboxProtocols(uint16_t position) const override;
107
108 std::expected<void, std::string> configureProcessData() override;
109 PdoLayout processDataLayout() override;
110 int exchangeProcessData(std::span<const uint8_t> outputs, std::span<uint8_t> inputs) override;
111 void stop() override;
112
113 std::expected<std::vector<SlaveStateRaw>, std::string> readStates(
114 const std::vector<uint16_t>& positions) override;
115
116 std::expected<std::vector<uint8_t>, std::string> readSdo(uint16_t slavePosition, uint16_t index,
117 uint8_t subindex) override;
118 std::expected<void, std::string> writeSdo(uint16_t slavePosition, uint16_t index,
119 uint8_t subindex,
120 std::span<const uint8_t> data) override;
121 std::expected<OdRead, std::string> readObjectDictionary(uint16_t slavePosition) override;
122
123 std::expected<std::vector<uint8_t>, FoeError> readFile(
124 uint16_t slavePosition, const std::string& filename,
125 std::chrono::milliseconds timeout) override;
126 std::expected<void, FoeError> writeFile(uint16_t slavePosition, const std::string& filename,
127 std::span<const uint8_t> data) override;
128
129 std::expected<void, std::string> readRegister(uint16_t slavePosition, uint16_t address,
130 std::span<uint8_t> data) override;
131 std::expected<void, std::string> writeRegister(uint16_t slavePosition, uint16_t address,
132 std::span<const uint8_t> data) override;
133
134 void transitionToState(const std::vector<uint16_t>& positions,
135 std::optional<EtherCatState> requiredState, EtherCatState targetState,
136 std::chrono::steady_clock::duration timeout,
137 std::chrono::steady_clock::duration resendInterval,
138 std::function<void()> tick, std::function<bool()> shouldAbort) override;
139
140 std::optional<std::string> stateChangeRefusal() const override;
141
142 bool supportsEsc() const override { return false; }
143 uint64_t droppedInputFrames() const override;
144 bool supportsLocate() const override { return true; }
145 std::expected<void, std::string> locate(uint16_t slavePosition, bool on) override;
146 std::expected<FirmwareActivation, std::string> activateFirmware(
147 uint16_t slavePosition, std::chrono::steady_clock::duration timeout) override;
148
149 private:
150 struct Drive;
151
152 Drive* driveAt(uint16_t position) const;
153 void closeAll();
154 void releaseDrives();
155 void stopExchanges();
156 void runExchange(Drive& drive, const std::stop_token& stopToken);
157 std::expected<uint32_t, std::string> assignedBits(Drive& drive, uint16_t assignIndex);
158 // request, readSdoFrom and connectAndIdentify take no lock. The caller holds bus_, shared or
159 // exclusive. filePacket takes bus_ shared itself, for one packet.
160 std::expected<Frame, std::string> request(Drive& drive, MessageType type,
161 std::span<const uint8_t> data, uint16_t status = 0);
162 std::expected<std::vector<uint8_t>, std::string> readSdoFrom(Drive& drive, uint16_t index,
163 uint8_t subindex);
164 void connectAndIdentify(Drive& drive);
165 std::expected<Frame, FoeError> filePacket(Drive& drive, MessageType type, uint8_t packetState,
166 std::span<const uint8_t> data,
167 std::chrono::milliseconds timeout);
168 std::expected<std::vector<uint8_t>, FoeError> readFileFrom(Drive& drive,
169 const std::string& filename,
170 std::chrono::milliseconds timeout);
171
173 // Held exclusive by scan, configureProcessData and stop, which rebuild the connections, the drive
174 // information and the layout. Every other request holds it shared for that one request, so a scan
175 // waits for the requests in flight and never for a whole transfer. A transfer that a scan
176 // interrupts fails on its next packet. The order is a drive's sequenceMutex, then this lock, then
177 // the connection's mutex. mutable so the const accessors can lock.
178 mutable BusLock bus_;
179 // Sized once in the constructor and never resized, so a position indexes it without a lock.
180 std::vector<std::unique_ptr<Drive>> drives_;
181 // Written by configureProcessData while no exchange runs, read by processDataLayout.
182 PdoLayout layout_;
183};
184
185} // namespace mm::comm::spoe
A reader/writer lock that lets no new reader in while a writer waits.
Definition control_plane_locks.h:23
Abstract interface for an EtherCAT fieldbus driver.
Definition fieldbus_driver.h:474
Definition spoe_fieldbus_driver.h:94
SlaveInfo slaveInfo(uint16_t position) const override
Returns the immutable identity fields for the slave at position.
Definition spoe_fieldbus_driver.cc:304
std::expected< void, std::string > init() override
Opens the network interface and initialises the master context.
Definition spoe_fieldbus_driver.cc:222
SpoeFieldbusDriver & operator=(const SpoeFieldbusDriver &)=delete
bool supportsEsc() const override
True when the devices have an EtherCAT Slave Controller: SII, ESC registers, DC and the ESC diagnosti...
Definition spoe_fieldbus_driver.h:142
std::expected< int, std::string > scan() override
Scans the bus for slaves and configures their sync managers and FMMUs.
Definition spoe_fieldbus_driver.cc:293
void transitionToState(const std::vector< uint16_t > &positions, std::optional< EtherCatState > requiredState, EtherCatState targetState, std::chrono::steady_clock::duration timeout, std::chrono::steady_clock::duration resendInterval, std::function< void()> tick, std::function< bool()> shouldAbort) override
Commands a set of devices to targetState and blocks until all arrive or timeout elapses.
Definition spoe_fieldbus_driver.cc:917
~SpoeFieldbusDriver() override
Definition spoe_fieldbus_driver.cc:182
uint64_t droppedInputFrames() const override
Input frames dropped since the process data was configured, summed over all devices.
Definition spoe_fieldbus_driver.cc:979
void stop() override
Closes the network interface, releasing the master context.
Definition spoe_fieldbus_driver.cc:522
SpoeFieldbusDriver(const SpoeFieldbusDriver &)=delete
bool supportsLocate() const override
True when locate can blink a device's LEDs. No bus I/O.
Definition spoe_fieldbus_driver.h:144
std::optional< std::string > stateChangeRefusal() const override
Returns why this driver refuses every state change, or nullopt when it accepts them.
Definition spoe_fieldbus_driver.cc:1061
std::expected< void, FoeError > writeFile(uint16_t slavePosition, const std::string &filename, std::span< const uint8_t > data) override
Writes a file to the slave via File over EtherCAT (FoE).
Definition spoe_fieldbus_driver.cc:861
uint16_t slaveState(uint16_t position) const override
Returns the last-known AL status for a slave without any bus I/O.
Definition spoe_fieldbus_driver.cc:310
std::expected< OdRead, std::string > readObjectDictionary(uint16_t slavePosition) override
Enumerates the entire CoE object dictionary of a slave via SDO Info.
Definition spoe_fieldbus_driver.cc:620
std::expected< void, std::string > locate(uint16_t slavePosition, bool on) override
Starts or stops blinking the LEDs of a device, so that someone can find it.
Definition spoe_fieldbus_driver.cc:986
PdoLayout processDataLayout() override
Returns the current process-data layout established by configureProcessData.
Definition spoe_fieldbus_driver.cc:490
std::expected< std::vector< uint8_t >, FoeError > readFile(uint16_t slavePosition, const std::string &filename, std::chrono::milliseconds timeout) override
Reads a file from the slave via File over EtherCAT (FoE).
Definition spoe_fieldbus_driver.cc:826
uint16_t mailboxProtocols(uint16_t position) const override
Returns the slave's advertised mailbox-protocol bits without any bus I/O.
Definition spoe_fieldbus_driver.cc:315
int exchangeProcessData(std::span< const uint8_t > outputs, std::span< uint8_t > inputs) override
Exchanges one cycle of process data: sends outputs, receives into inputs.
Definition spoe_fieldbus_driver.cc:495
std::expected< FirmwareActivation, std::string > activateFirmware(uint16_t slavePosition, std::chrono::steady_clock::duration timeout) override
Makes a device apply the firmware files written to it in BOOT.
Definition spoe_fieldbus_driver.cc:1000
std::expected< void, std::string > writeRegister(uint16_t slavePosition, uint16_t address, std::span< const uint8_t > data) override
Writes bytes to an ESC register via a Configured-Address Write (FPWR) datagram.
Definition spoe_fieldbus_driver.cc:912
std::expected< std::vector< SlaveStateRaw >, std::string > readStates(const std::vector< uint16_t > &positions) override
Reads the current AL Status for each slave in positions.
Definition spoe_fieldbus_driver.cc:541
std::expected< void, std::string > writeSdo(uint16_t slavePosition, uint16_t index, uint8_t subindex, std::span< const uint8_t > data) override
Writes an object dictionary entry to a slave (CoE SDO download).
Definition spoe_fieldbus_driver.cc:589
std::expected< void, std::string > configureProcessData() override
Maps the process data and lays out the IOmap (one-time, control-plane).
Definition spoe_fieldbus_driver.cc:369
std::expected< void, std::string > readRegister(uint16_t slavePosition, uint16_t address, std::span< uint8_t > data) override
Reads bytes from an ESC register via a Configured-Address Read (FPRD) datagram.
Definition spoe_fieldbus_driver.cc:906
std::expected< std::vector< uint8_t >, std::string > readSdo(uint16_t slavePosition, uint16_t index, uint8_t subindex) override
Reads an object dictionary entry via CoE SDO upload.
Definition spoe_fieldbus_driver.cc:578
uint8_t subindex
Definition esi_entry.cc:283
Definition spoe_connection.cc:15
constexpr std::size_t kInputQueueLimit
Definition spoe_fieldbus_driver.h:66
std::string sdoStatusName(uint16_t status)
Names an SPoE SDO status, which is one of the firmware's SDO_REQUEST_ERROR_* codes.
Definition spoe_fieldbus_driver.cc:103
MessageType
The message types the firmware handles. A reply carries the type of its request.
Definition spoe_frame.h:20
constexpr std::size_t kParameterEntrySize
Definition spoe_fieldbus_driver.h:77
PdoMode
ETHERNET_PDO_MODE_* in the firmware.
Definition spoe_fieldbus_driver.h:32
constexpr uint16_t kProtocolVersion102
Definition spoe_fieldbus_driver.h:72
std::vector< ParameterEntry > decodeParameterEntries(std::span< const uint8_t > bytes)
Definition spoe_fieldbus_driver.cc:74
constexpr uint16_t kProtocolVersion100
Definition spoe_fieldbus_driver.h:71
SpoeMode
Definition spoe_fieldbus_driver.h:40
EtherCatState
EtherCAT Application Layer state values.
Definition fieldbus_driver.h:45
std::chrono::milliseconds timeout
Definition somanet_procedures.cc:464
std::size_t bytes
Definition spoe_connection.cc:24
A structured FoE failure. String-like where a caller only forwards it (operator<<,...
Definition foe_error.h:110
Schema of a single object dictionary entry uploaded from a slave.
Definition fieldbus_driver.h:187
Layout of the process-data images, produced by configureProcessData.
Definition fieldbus_driver.h:241
Immutable identity fields read from a slave's EEPROM during configuration.
Definition fieldbus_driver.h:159
One entry of the parameter list.
Definition spoe_fieldbus_driver.h:80
OdEntry entry
Definition spoe_fieldbus_driver.h:81
uint32_t subindexCount
The subindex count, which the firmware reports on subindex 0 only.
Definition spoe_fieldbus_driver.h:83
Definition spoe_fieldbus_driver.h:45
std::vector< std::string > hosts
One IPv4 or IPv6 address per drive. The list order is the position order.
Definition spoe_fieldbus_driver.h:47
SpoeMode mode
Definition spoe_fieldbus_driver.h:49
uint32_t watchdogMs
The Control-mode watchdog. The firmware raises a smaller value to 50 ms.
Definition spoe_fieldbus_driver.h:51
std::chrono::milliseconds requestTimeout
The time a drive has to answer one request. The specification suggests 1 s.
Definition spoe_fieldbus_driver.h:53
std::chrono::milliseconds connectTimeout
Definition spoe_fieldbus_driver.h:54
std::chrono::microseconds exchangePeriod
Definition spoe_fieldbus_driver.h:61
std::chrono::milliseconds fileTimeout
Definition spoe_fieldbus_driver.h:58
uint16_t port
Definition spoe_fieldbus_driver.h:48