Motion Master
Loading...
Searching...
No Matches
soem.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <functional>
5#include <map>
6#include <memory>
7#include <mutex>
8#include <string>
9#include <type_traits>
10#include <unordered_map>
11#include <utility>
12#include <variant>
13#include <vector>
14
15#include "base.h"
16#include "ethercat.h"
17#include "loguru.h"
18
19namespace mm::comm::soem {
20
32std::map<std::string, std::string> mapMacAddressesToInterfaces();
33
49inline std::string uiConfigWithDefaultPdoMapping = R"(
50{
51 "pdoMapping": {
52 "rx": {
53 "0x1600": [
54 "0x60400010",
55 "0x60600008",
56 "0x60710010",
57 "0x607a0020",
58 "0x60ff0020",
59 "0x60b20010",
60 "0x27010020"
61 ],
62 "0x1601": [
63 "0x60fe0120",
64 "0x60fe0220"
65 ],
66 "0x1602": [
67 "0x27030020",
68 "0x60b10020",
69 "0x20120120"
70 ]
71 },
72 "tx": {
73 "0x1a00": [
74 "0x60410010",
75 "0x60610008",
76 "0x60640020",
77 "0x606c0020",
78 "0x60770010",
79 "0x60f40020",
80 "0x21110220",
81 "0x21130220"
82 ],
83 "0x1a01": [
84 "0x24010010",
85 "0x24020010",
86 "0x24030010",
87 "0x24040010",
88 "0x27020020"
89 ],
90 "0x1a02": [
91 "0x60fd0020"
92 ],
93 "0x1a03": [
94 "0x27040020",
95 "0x20f00020",
96 "0x60fc0020",
97 "0x606b0020",
98 "0x60740010",
99 "0x60790020"
100 ]
101 }
102 }
103})";
104
129int setPdoMappingFromUiConfig(ecx_contextt* context, uint16 slave);
130
148void checkPdoMapping(ecx_contextt* context, uint16 slave);
149
173uint16_t getSlaveState(ecx_contextt* context, uint16_t slave,
174 bool forceRefresh);
175
195std::string convertSlaveStateToString(int state);
196
213bool transitionToHigherSlaveState(ecx_contextt* context, uint16_t slave,
214 int targetState);
215
238void updateMailboxSyncManagersOnNextState(ecx_contextt* context, uint16_t slave,
239 int targetState);
240
256void configureDetectedSmmModule(ecx_contextt* context, uint16_t slave);
257
274bool setSlaveState(ecx_contextt* context, uint16_t slave, int targetState);
275
309std::vector<uint8_t> readSii(ecx_contextt* context, uint16 position);
310
322mm::comm::base::PdoMappings readPdoMappings(ecx_contextt* context,
323 uint16_t slave);
324
340 const std::vector<mm::comm::base::PdoMappingEntry>& entries);
341
353void logIoMap(uint8_t* ioMap, size_t totalBytes);
354
369struct Fieldbus {
370 ecx_contextt context;
371 std::string iface;
372 uint8 group;
374
375 /* Used by the context */
376 uint8 map[4096];
377 ecx_portt port;
378 ec_slavet slavelist[EC_MAXSLAVE];
380 ec_groupt grouplist[EC_MAXGROUP];
381 uint8 esibuf[EC_MAXEEPBUF];
382 uint32 esimap[EC_MAXEEPBITMAP];
383 ec_eringt elist;
384 ec_idxstackT idxstack;
385 boolean ecaterror;
386 int64 DCtime;
387 ec_SMcommtypet SMcommtype[EC_MAX_MAPT];
388 ec_PDOassignt PDOassign[EC_MAX_MAPT];
389 ec_PDOdesct PDOdesc[EC_MAX_MAPT];
390 ec_eepromSMt eepSM;
391 ec_eepromFMMUt eepFMMU;
392};
393
408 uint16_t readLength;
409
416 uint16_t readOffset;
417
429
436 uint16_t writeLength;
437
444 uint16_t writeOffset;
445};
446
448 supportedProtocols, writeLength, writeOffset)
449
450
457struct SlaveInfoSyncManager {
466 uint32_t flags;
467
474 uint16_t length;
475
481 uint16_t startAddress;
482
493 uint8_t type;
494};
495
496NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SlaveInfoSyncManager, flags, length,
497 startAddress, type)
498
499
506struct SlaveInfoFmmu {
512 uint8_t active;
513
520 uint8_t logicalEndBit;
521
528 uint8_t logicalStartBit;
529
535 uint32_t logicalStartAddress;
536
542 uint16_t logicalLength;
543
550 uint8_t physicalStartBit;
551
557 uint16_t physicalStartAddress;
558
565 uint8_t type;
566};
567
568NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SlaveInfoFmmu, active, logicalEndBit,
569 logicalStartBit, logicalStartAddress,
570 logicalLength, physicalStartBit,
571 physicalStartAddress, type)
572
573
579struct SlaveInfo {
586 uint16_t alStatusCode;
587
594 uint16_t aliasAddress;
595
601 std::vector<SlaveInfoFmmu> fmmus;
602
609 SlaveInfoMailbox mailbox;
610
618 uint32_t productCode;
619
625 uint32_t position;
626
634 uint32_t revisionNumber;
635
642 std::vector<SlaveInfoSyncManager> syncManagers;
643
649 std::string name;
650
659 uint32_t vendorId;
660};
661
662NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SlaveInfo, alStatusCode, aliasAddress, fmmus,
663 mailbox, productCode, position,
664 revisionNumber, syncManagers, name, vendorId)
665
666
678SlaveInfo getSlaveInfo(ecx_contextt* context, uint16 position);
679
696void logSlaveInfo(ecx_contextt* context, uint16 position);
697
715void initFieldbus(std::unique_ptr<Fieldbus>& fieldbus,
716 const std::string& iface);
717
722class Slave {
723 public:
734 explicit Slave(ecx_contextt& context, uint16_t position);
735
744 uint16_t getPosition() const;
745
754 uint32_t getVendorId() const;
755
764 uint32_t getProductCode() const;
765
774 uint32_t getRevisionNumber() const;
775
787 int getState(bool forceRefresh = true) const;
788
808 bool setState(int targetState, int timeoutMs = 0, int intervalMs = 100);
809
831 void loadParameters(bool readValues = false);
832
845 void logParameters() const;
846
863
880
887 void clearParameters();
888
897 std::unordered_map<mm::comm::base::Parameter::Address,
900
913 mm::comm::base::Parameter& findParameter(uint16_t index, uint8_t subindex);
914
942 template <typename T = std::vector<uint8_t>>
943 T upload(uint16_t index, uint8_t subindex, bool refresh = true) {
944 // Lock the mailbox mutex to ensure thread safety
945 std::lock_guard<std::mutex> lock(mailboxMutex_);
946
947 // Check if the device is in a valid state for uploading
948 auto state = getState(false);
949 if (state == EC_STATE_INIT || state == EC_STATE_BOOT) {
950 throw std::runtime_error(
951 "To upload object dictionary entries, the device must be in the (2) "
952 "PRE-OPERATIONAL, (4) SAFE-OPERATIONAL, or (8) OPERATIONAL state. "
953 "The current state is " +
954 convertSlaveStateToString(state) + ".");
955 }
956
957 // Find the previously loaded parameter
958 auto& parameter = findParameter(index, subindex);
959
960 // Refresh data if needed (SDO read)
961 if (refresh) {
962 const std::unique_ptr<std::uint8_t[]> data =
963 std::make_unique<std::uint8_t[]>(parameter.byteLength);
964 auto wkc = ecx_SDOread(&context_, position_, parameter.index,
965 parameter.subindex, false, &parameter.byteLength,
966 data.get(), EC_TIMEOUTRXM * 3);
967 if (wkc <= 0) {
968 LOG_F(ERROR, "Device %d: SDO read failed for %#04x:%02x! WKC: %d",
969 position_, parameter.index, parameter.subindex, wkc);
970 auto id = mm::comm::base::makeParameterId(parameter.index,
971 parameter.subindex);
972 throw std::runtime_error("Device " + std::to_string(position_) +
973 ": SDO read failed for " + id +
974 "! WKC: " + std::to_string(wkc));
975 } else {
976 std::vector<uint8_t> receivedData(data.get(),
977 data.get() + parameter.byteLength);
978 if (!parameter.trySetValue(receivedData)) {
979 LOG_F(ERROR,
980 "Device %d: Failed to set the value of parameter %#04x:%02x!",
981 position_, parameter.index, parameter.subindex);
982 }
983 }
984 }
985
986 // Return the appropriate type
987 if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
988 return parameter.data; // parameter.data should be std::vector<uint8_t>
989 } else {
990 // Otherwise, try to get the value as the requested type T
991 auto value = parameter.getValue();
992 if (auto ptr = std::get_if<T>(&value)) {
993 return *ptr;
994 } else {
995 throw std::bad_variant_access(); // Type mismatch
996 }
997 }
998 }
999
1024 template <typename T = std::vector<uint8_t>>
1025 bool download(uint16_t index, uint8_t subindex, const T& value) {
1026 std::lock_guard<std::mutex> lock(mailboxMutex_);
1027
1028 // Check if device is in valid state for download
1029 auto state = getState(false);
1030 if (state == EC_STATE_INIT || state == EC_STATE_BOOT) {
1031 throw std::runtime_error(
1032 "To download object dictionary entries, the device must be in the "
1033 "(2) PRE-OPERATIONAL, (4) SAFE-OPERATIONAL, or (8) OPERATIONAL "
1034 "state. The current state is " +
1035 convertSlaveStateToString(state) + ".");
1036 }
1037
1038 auto& parameter = findParameter(index, subindex);
1039
1040 // Convert value to raw byte data
1041 std::vector<uint8_t> data;
1042 if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
1043 data = value;
1044 } else {
1045 // Set the value in the parameter model
1046 if (!parameter.trySetValue(value)) {
1047 LOG_F(ERROR,
1048 "Device %d: Failed to set the value of parameter %#04x:%02x!",
1049 position_, parameter.index, parameter.subindex);
1050 return false;
1051 }
1052 data = parameter.data; // Use the parameter's byte representation
1053 }
1054
1055 // Check if data size matches the expected parameter size
1056 if (data.size() != parameter.byteLength) {
1057 LOG_F(ERROR, "Data size mismatch: expected %d, got %zu",
1058 parameter.byteLength, data.size());
1059 throw std::runtime_error("Data size does not match the parameter size!");
1060 }
1061
1062 // Perform the SDO write
1063 auto wkc = ecx_SDOwrite(&context_, position_, parameter.index,
1064 parameter.subindex, false, parameter.byteLength,
1065 data.data(), EC_TIMEOUTRXM * 3);
1066
1067 // Check write result
1068 if (wkc <= 0) {
1069 LOG_F(ERROR, "Device %d: SDO write failed for %#04x:%02x! WKC: %d",
1070 position_, parameter.index, parameter.subindex, wkc);
1071 return false;
1072 }
1073
1074 return true;
1075 }
1076
1086
1095 void updatePdoMappings();
1096
1108 void logPdoMappings() const;
1109
1115 mm::comm::base::PdoMappings& getPdoMappings();
1116
1139 void updateOutputs();
1140
1162 void updateParametersFromInputs();
1163
1164 std::vector<uint8_t> readFile(
1165 const std::string& filename,
1166 const std::chrono::steady_clock::duration expiryTime);
1167
1168 private:
1169 ecx_contextt& context_;
1170 const uint16_t position_;
1173 std::mutex mailboxMutex_;
1174 std::unordered_map<mm::comm::base::Parameter::Address,
1176 parametersMap_;
1179 pdoMappings_;
1180};
1181
1182class Master {
1183 public:
1190 explicit Master();
1191
1202 explicit Master(const std::string& iface);
1203
1255 void init(const std::string& iface);
1256
1267 void deinit();
1268
1275 ~Master();
1276
1286 Fieldbus& getFieldbus() const;
1287
1296 std::string getInterfaceName() const;
1297
1306 size_t getIoMapSize() const;
1307
1370 int initSlaves();
1371
1383 const std::vector<std::unique_ptr<Slave>>& getSlaves() const;
1384
1394 inline int expectedWkc() const {
1395 return fieldbus_->context.grouplist[fieldbus_->group].outputsWKC * 2 +
1396 fieldbus_->context.grouplist[fieldbus_->group].inputsWKC;
1397 }
1398
1408 int roundtrip();
1409
1439
1450 bool start();
1451
1452 private:
1466 std::unique_ptr<Fieldbus> fieldbus_;
1467
1479 std::vector<std::unique_ptr<Slave>> slaves_;
1480};
1481}; // namespace mm::comm::soem
Represents a device parameter identified by index and subindex.
Definition base.h:533
std::pair< uint16_t, uint8_t > Address
Alias for a pair of uint16_t and uint8_t representing a parameter address.
Definition base.h:543
int roundtrip()
Performs a complete send/receive process data cycle on the fieldbus.
Definition soem.cc:1342
int initSlaves()
Initializes the slave devices on the EtherCAT network.
Definition soem.cc:1315
Master()
Default constructor for the Master class.
Definition soem.cc:1263
void exchangeProcessDataAndUpdateParameters()
Exchanges process data with slaves and updates parameters based on the response.
Definition soem.cc:1347
size_t getIoMapSize() const
Returns the total size of the I/O map for the current group.
Definition soem.cc:1310
const std::vector< std::unique_ptr< Slave > > & getSlaves() const
Returns a reference to the list of slaves.
Definition soem.cc:1338
Fieldbus & getFieldbus() const
Returns a reference to the Fieldbus instance.
Definition soem.cc:1306
void init(const std::string &iface)
Initializes the fieldbus using the specified network interface.
Definition soem.cc:1270
std::string getInterfaceName() const
Retrieves the interface name used by the fieldbus.
Definition soem.cc:1308
void deinit()
Deinitializes the fieldbus and releases associated resources.
Definition soem.cc:1288
bool start()
Initializes and starts the fieldbus master.
Definition soem.cc:1370
~Master()
Destructor for the Master class.
Definition soem.cc:1304
int expectedWkc() const
Calculates the expected working counter (WKC) for the current fieldbus group.
Definition soem.h:1394
void loadParameters(bool readValues=false)
Loads the parameters (object dictionary entries) from the EtherCAT slave device.
Definition soem.cc:892
mm::comm::base::Parameter & findParameter(uint16_t index, uint8_t subindex)
Finds and returns a reference to a Parameter in the parameters map.
Definition soem.cc:1096
T upload(uint16_t index, uint8_t subindex, bool refresh=true)
Uploads a parameter value from the device's object dictionary.
Definition soem.h:943
int getState(bool forceRefresh=true) const
Retrieves the current state of the slave.
Definition soem.cc:864
uint32_t getProductCode() const
Gets the Product Code of the slave device.
Definition soem.cc:856
uint32_t getRevisionNumber() const
Gets the Revision Number of the slave device.
Definition soem.cc:860
std::unordered_map< mm::comm::base::Parameter::Address, mm::comm::base::Parameter > & getParametersMap()
Returns a reference to the internal parameters map.
Definition soem.cc:1092
void clearParameters()
Clears all loaded object dictionary parameters.
Definition soem.cc:1088
void logTxPdoMappedParameters()
Logs all mapped TxPDO parameters with their current values.
Definition soem.cc:1073
Slave(ecx_contextt &context, uint16_t position)
Constructs a Slave object with a given context and position.
Definition soem.cc:847
void logRxPdoMappedParameters()
Logs all mapped RxPDO parameters with their current values.
Definition soem.cc:1058
uint16_t getPosition() const
Gets the position of the slave.
Definition soem.cc:850
bool setState(int targetState, int timeoutMs=0, int intervalMs=100)
Attempts to set the slave to the specified EtherCAT state and optionally waits until it is reached.
Definition soem.cc:868
void logParameters() const
Logs all loaded object dictionary parameters.
Definition soem.cc:1052
uint32_t getVendorId() const
Gets the Vendor ID of the slave device.
Definition soem.cc:852
bool download(uint16_t index, uint8_t subindex, const T &value)
Downloads a value to the specified object dictionary entry via SDO.
Definition soem.h:1025
uint8_t type
Definition co_dictionary.h:1
const char ** name
Definition co_dictionary.h:7
uint8_t * value
Definition co_dictionary.h:9
uint16_t index
Definition co_dictionary.h:0
std::string makeParameterId(int index, int subindex)
Formats the given index and subindex into a parameter identifier string.
Definition base.h:1654
Definition soem.cc:34
mm::comm::base::PdoMappings readPdoMappings(ecx_contextt *context, uint16_t slave)
Read and parse all mapped PDO entries for a given slave.
Definition soem.cc:754
void logPdoMappingEntries(const std::vector< mm::comm::base::PdoMappingEntry > &entries)
Logs PDO mapping entries grouped by PDO index.
Definition soem.cc:816
std::string convertSlaveStateToString(int state)
Converts a numeric EtherCAT state value into a human-readable string.
Definition soem.cc:413
bool transitionToHigherSlaveState(ecx_contextt *context, uint16_t slave, int targetState)
Transitions a slave to a higher EtherCAT state.
Definition soem.cc:442
std::string uiConfigWithDefaultPdoMapping
Default UI configuration used for PDO mapping.
Definition soem.h:49
void initFieldbus(std::unique_ptr< Fieldbus > &fieldbus, const std::string &iface)
Initializes a Fieldbus instance for EtherCAT communication.
Definition soem.cc:1230
void updateMailboxSyncManagersOnNextState(ecx_contextt *context, uint16_t slave, int targetState)
Updates the mailbox and sync manager (SM) configurations for an EtherCAT slave when transitioning to ...
Definition soem.cc:504
void logIoMap(uint8_t *ioMap, size_t totalBytes)
Logs the I/O map as a formatted hexadecimal string.
Definition soem.cc:837
void checkPdoMapping(ecx_contextt *context, uint16 slave)
Diagnoses and prints the PDO mapping for a given slave.
Definition soem.cc:310
void configureDetectedSmmModule(ecx_contextt *context, uint16_t slave)
Reads the detected SMM module ID from the slave device and configures the module identification objec...
Definition soem.cc:579
std::map< std::string, std::string > mapMacAddressesToInterfaces()
Maps MAC addresses to their corresponding network interface names.
Definition soem.cc:36
int setPdoMappingFromUiConfig(ecx_contextt *context, uint16 slave)
Sets PDO mapping for a specified EtherCAT slave using UI configuration.
Definition soem.cc:215
uint16_t getSlaveState(ecx_contextt *context, uint16_t slave, bool forceRefresh)
Retrieves the current state of a specific EtherCAT slave.
Definition soem.cc:392
uint16 position
Definition soem.h:678
void logSlaveInfo(ecx_contextt *context, uint16 position)
Logs detailed information about a specific EtherCAT slave in JSON format.
Definition soem.cc:209
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SlaveInfoMailbox, readLength, readOffset, supportedProtocols, writeLength, writeOffset) struct SlaveInfoSyncManager
Information about a slave's Sync Manager (SM) configuration.
Definition soem.h:447
bool setSlaveState(ecx_contextt *context, uint16_t slave, int targetState)
Sets the state of a specified EtherCAT slave.
Definition soem.cc:609
SlaveInfo getSlaveInfo(ecx_contextt *context, uint16 position)
Definition soem.cc:157
std::vector< uint8_t > readSii(ecx_contextt *context, uint16 position)
Read the complete Slave Information Interface (SII) EEPROM from an EtherCAT slave device.
Definition soem.cc:711
Specialization of std::hash for std::pair<uint16_t, uint8_t>.
Definition util.h:609
Represents the mapped PDO entries for a slave device.
Definition base.h:175
Structure representing the Fieldbus configuration and context for EtherCAT communication.
Definition soem.h:369
boolean ecaterror
Definition soem.h:385
ec_idxstackT idxstack
Definition soem.h:384
ec_eepromFMMUt eepFMMU
Definition soem.h:391
ec_groupt grouplist[EC_MAXGROUP]
Definition soem.h:380
std::string iface
Definition soem.h:371
uint8 group
Definition soem.h:372
int slavecount
Definition soem.h:379
uint8 esibuf[EC_MAXEEPBUF]
Definition soem.h:381
uint32 esimap[EC_MAXEEPBITMAP]
Definition soem.h:382
int64 DCtime
Definition soem.h:386
ec_eepromSMt eepSM
Definition soem.h:390
ec_PDOassignt PDOassign[EC_MAX_MAPT]
Definition soem.h:388
uint8 map[4096]
Definition soem.h:376
ecx_contextt context
Definition soem.h:370
int roundtripTime
Definition soem.h:373
ec_PDOdesct PDOdesc[EC_MAX_MAPT]
Definition soem.h:389
ecx_portt port
Definition soem.h:377
ec_slavet slavelist[EC_MAXSLAVE]
Definition soem.h:378
ec_SMcommtypet SMcommtype[EC_MAX_MAPT]
Definition soem.h:387
ec_eringt elist
Definition soem.h:383
Information about a slave's mailbox configuration.
Definition soem.h:401
uint16_t writeOffset
Offset of the mailbox write area within the slave's memory.
Definition soem.h:444
uint16_t supportedProtocols
Supported mailbox protocols as a bitmask.
Definition soem.h:428
uint16_t readOffset
Offset of the mailbox read area within the slave's memory.
Definition soem.h:416
uint16_t readLength
Length of the mailbox read area (in bytes).
Definition soem.h:408
uint16_t writeLength
Length of the mailbox write area (in bytes).
Definition soem.h:436