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 ]
70 },
71 "tx": {
72 "0x1a00": [
73 "0x60410010",
74 "0x60610008",
75 "0x60640020",
76 "0x606c0020",
77 "0x60770010",
78 "0x60f40020",
79 "0x21110220",
80 "0x21130220"
81 ],
82 "0x1a01": [
83 "0x24010010",
84 "0x24020010",
85 "0x24030010",
86 "0x24040010",
87 "0x27020020"
88 ],
89 "0x1a02": [
90 "0x60fd0020"
91 ],
92 "0x1a03": [
93 "0x27040020",
94 "0x20f00020",
95 "0x60fc0020",
96 "0x606b0020",
97 "0x60740010",
98 "0x60790020"
99 ]
100 }
101 }
102})";
103
128int setPdoMappingFromUiConfig(ecx_contextt* context, uint16 slave);
129
147void checkPdoMapping(ecx_contextt* context, uint16 slave);
148
172uint16_t getSlaveState(ecx_contextt* context, uint16_t slave,
173 bool forceRefresh);
174
194std::string convertSlaveStateToString(int state);
195
212bool transitionToHigherSlaveState(ecx_contextt* context, uint16_t slave,
213 int targetState);
214
237void updateMailboxSyncManagersOnNextState(ecx_contextt* context, uint16_t slave,
238 int targetState);
239
255void configureDetectedSmmModule(ecx_contextt* context, uint16_t slave);
256
273bool setSlaveState(ecx_contextt* context, uint16_t slave, int targetState);
274
286mm::comm::base::PdoMappings readPdoMappings(ecx_contextt* context,
287 uint16_t slave);
288
304 const std::vector<mm::comm::base::PdoMappingEntry>& entries);
305
317void logIoMap(uint8_t* ioMap, size_t totalBytes);
318
333struct Fieldbus {
334 ecx_contextt context;
335 std::string iface;
336 uint8 group;
338
339 /* Used by the context */
340 uint8 map[4096];
341 ecx_portt port;
342 ec_slavet slavelist[EC_MAXSLAVE];
344 ec_groupt grouplist[EC_MAXGROUP];
345 uint8 esibuf[EC_MAXEEPBUF];
346 uint32 esimap[EC_MAXEEPBITMAP];
347 ec_eringt elist;
348 ec_idxstackT idxstack;
349 boolean ecaterror;
350 int64 DCtime;
351 ec_SMcommtypet SMcommtype[EC_MAX_MAPT];
352 ec_PDOassignt PDOassign[EC_MAX_MAPT];
353 ec_PDOdesct PDOdesc[EC_MAX_MAPT];
354 ec_eepromSMt eepSM;
355 ec_eepromFMMUt eepFMMU;
356};
357
375void initFieldbus(std::unique_ptr<Fieldbus>& fieldbus,
376 const std::string& iface);
377
382class Slave {
383 public:
394 explicit Slave(ecx_contextt& context, uint16_t position);
395
404 uint16_t getPosition() const;
405
414 uint32_t getVendorId() const;
415
424 uint32_t getProductCode() const;
425
434 uint32_t getRevisionNumber() const;
435
447 int getState(bool forceRefresh = true) const;
448
468 bool setState(int targetState, int timeoutMs = 0, int intervalMs = 100);
469
491 void loadParameters(bool readValues = false);
492
505 void logParameters() const;
506
523
540
547 void clearParameters();
548
557 std::unordered_map<mm::comm::base::Parameter::Address,
560
573 mm::comm::base::Parameter& findParameter(uint16_t index, uint8_t subindex);
574
602 template <typename T = std::vector<uint8_t>>
603 T upload(uint16_t index, uint8_t subindex, bool refresh = true) {
604 // Lock the mailbox mutex to ensure thread safety
605 std::lock_guard<std::mutex> lock(mailboxMutex_);
606
607 // Check if the device is in a valid state for uploading
608 auto state = getState(false);
609 if (state == EC_STATE_INIT || state == EC_STATE_BOOT) {
610 throw std::runtime_error(
611 "To upload object dictionary entries, the device must be in the (2) "
612 "PRE-OPERATIONAL, (4) SAFE-OPERATIONAL, or (8) OPERATIONAL state. "
613 "The current state is " +
614 convertSlaveStateToString(state) + ".");
615 }
616
617 // Find the previously loaded parameter
618 auto& parameter = findParameter(index, subindex);
619
620 // Refresh data if needed (SDO read)
621 if (refresh) {
622 const std::unique_ptr<std::uint8_t[]> data =
623 std::make_unique<std::uint8_t[]>(parameter.byteLength);
624 auto wkc = ecx_SDOread(&context_, position_, parameter.index,
625 parameter.subindex, false, &parameter.byteLength,
626 data.get(), EC_TIMEOUTRXM * 3);
627 if (wkc <= 0) {
628 LOG_F(ERROR, "Device %d: SDO read failed for %#04x:%02x! WKC: %d",
629 position_, parameter.index, parameter.subindex, wkc);
630 auto id = mm::comm::base::makeParameterId(parameter.index,
631 parameter.subindex);
632 throw std::runtime_error("Device " + std::to_string(position_) +
633 ": SDO read failed for " + id +
634 "! WKC: " + std::to_string(wkc));
635 } else {
636 std::vector<uint8_t> receivedData(data.get(),
637 data.get() + parameter.byteLength);
638 if (!parameter.trySetValue(receivedData)) {
639 LOG_F(ERROR,
640 "Device %d: Failed to set the value of parameter %#04x:%02x!",
641 position_, parameter.index, parameter.subindex);
642 }
643 }
644 }
645
646 // Return the appropriate type
647 if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
648 return parameter.data; // parameter.data should be std::vector<uint8_t>
649 } else {
650 // Otherwise, try to get the value as the requested type T
651 auto value = parameter.getValue();
652 if (auto ptr = std::get_if<T>(&value)) {
653 return *ptr;
654 } else {
655 throw std::bad_variant_access(); // Type mismatch
656 }
657 }
658 }
659
684 template <typename T = std::vector<uint8_t>>
685 bool download(uint16_t index, uint8_t subindex, const T& value) {
686 std::lock_guard<std::mutex> lock(mailboxMutex_);
687
688 // Check if device is in valid state for download
689 auto state = getState(false);
690 if (state == EC_STATE_INIT || state == EC_STATE_BOOT) {
691 throw std::runtime_error(
692 "To download object dictionary entries, the device must be in the "
693 "(2) PRE-OPERATIONAL, (4) SAFE-OPERATIONAL, or (8) OPERATIONAL "
694 "state. The current state is " +
695 convertSlaveStateToString(state) + ".");
696 }
697
698 auto& parameter = findParameter(index, subindex);
699
700 // Convert value to raw byte data
701 std::vector<uint8_t> data;
702 if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
703 data = value;
704 } else {
705 // Set the value in the parameter model
706 if (!parameter.trySetValue(value)) {
707 LOG_F(ERROR,
708 "Device %d: Failed to set the value of parameter %#04x:%02x!",
709 position_, parameter.index, parameter.subindex);
710 return false;
711 }
712 data = parameter.data; // Use the parameter's byte representation
713 }
714
715 // Check if data size matches the expected parameter size
716 if (data.size() != parameter.byteLength) {
717 LOG_F(ERROR, "Data size mismatch: expected %d, got %zu",
718 parameter.byteLength, data.size());
719 throw std::runtime_error("Data size does not match the parameter size!");
720 }
721
722 // Perform the SDO write
723 auto wkc = ecx_SDOwrite(&context_, position_, parameter.index,
724 parameter.subindex, false, parameter.byteLength,
725 data.data(), EC_TIMEOUTRXM * 3);
726
727 // Check write result
728 if (wkc <= 0) {
729 LOG_F(ERROR, "Device %d: SDO write failed for %#04x:%02x! WKC: %d",
730 position_, parameter.index, parameter.subindex, wkc);
731 return false;
732 }
733
734 return true;
735 }
736
746
755 void updatePdoMappings();
756
768 void logPdoMappings() const;
769
776
799 void updateOutputs();
800
823
824 std::vector<uint8_t> readFile(
825 const std::string& filename,
826 const std::chrono::steady_clock::duration expiryTime);
827
828 private:
829 ecx_contextt& context_;
830 const uint16_t position_;
833 std::mutex mailboxMutex_;
834 std::unordered_map<mm::comm::base::Parameter::Address,
836 parametersMap_;
839 pdoMappings_;
840};
841
842class Master {
843 public:
850 explicit Master();
851
862 explicit Master(const std::string& iface);
863
915 void init(const std::string& iface);
916
927 void deinit();
928
935 ~Master();
936
946 Fieldbus& getFieldbus() const;
947
956 std::string getInterfaceName() const;
957
966 size_t getIoMapSize() const;
967
1030 int initSlaves();
1031
1043 const std::vector<std::unique_ptr<Slave>>& getSlaves() const;
1044
1054 inline int expectedWkc() const {
1055 return fieldbus_->context.grouplist[fieldbus_->group].outputsWKC * 2 +
1056 fieldbus_->context.grouplist[fieldbus_->group].inputsWKC;
1057 }
1058
1068 int roundtrip();
1069
1099
1110 bool start();
1111
1112 private:
1126 std::unique_ptr<Fieldbus> fieldbus_;
1127
1139 std::vector<std::unique_ptr<Slave>> slaves_;
1140};
1141}; // namespace mm::comm::soem
Represents a device parameter identified by index and subindex.
Definition base.h:466
std::pair< uint16_t, uint8_t > Address
Alias for a pair of uint16_t and uint8_t representing a parameter address.
Definition base.h:476
int roundtrip()
Performs a complete send/receive process data cycle on the fieldbus.
Definition soem.cc:1234
int initSlaves()
Initializes the slave devices on the EtherCAT network.
Definition soem.cc:1207
Master()
Default constructor for the Master class.
Definition soem.cc:1166
void exchangeProcessDataAndUpdateParameters()
Exchanges process data with slaves and updates parameters based on the response.
Definition soem.cc:1239
size_t getIoMapSize() const
Returns the total size of the I/O map for the current group.
Definition soem.cc:1202
const std::vector< std::unique_ptr< Slave > > & getSlaves() const
Returns a reference to the list of slaves.
Definition soem.cc:1230
Fieldbus & getFieldbus() const
Returns a reference to the Fieldbus instance.
Definition soem.cc:1198
void init(const std::string &iface)
Initializes the fieldbus using the specified network interface.
Definition soem.cc:1173
std::string getInterfaceName() const
Retrieves the interface name used by the fieldbus.
Definition soem.cc:1200
void deinit()
Deinitializes the fieldbus and releases associated resources.
Definition soem.cc:1191
bool start()
Initializes and starts the fieldbus master.
Definition soem.cc:1262
~Master()
Destructor for the Master class.
Definition soem.cc:1196
int expectedWkc() const
Calculates the expected working counter (WKC) for the current fieldbus group.
Definition soem.h:1054
mm::comm::base::PdoMappings readPdoMappings() const
Reads the PDO mappings from the slave device.
Definition soem.cc:1011
void updateOutputs()
Updates the outputs for the slave device.
Definition soem.cc:1034
void logPdoMappings() const
Logs the PDO (Process Data Object) mappings for the device.
Definition soem.cc:1026
void loadParameters(bool readValues=false)
Loads the parameters (object dictionary entries) from the EtherCAT slave device.
Definition soem.cc:795
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:999
std::vector< uint8_t > readFile(const std::string &filename, const std::chrono::steady_clock::duration expiryTime)
Definition soem.cc:1068
T upload(uint16_t index, uint8_t subindex, bool refresh=true)
Uploads a parameter value from the device's object dictionary.
Definition soem.h:603
int getState(bool forceRefresh=true) const
Retrieves the current state of the slave.
Definition soem.cc:767
uint32_t getProductCode() const
Gets the Product Code of the slave device.
Definition soem.cc:759
uint32_t getRevisionNumber() const
Gets the Revision Number of the slave device.
Definition soem.cc:763
std::unordered_map< mm::comm::base::Parameter::Address, mm::comm::base::Parameter > & getParametersMap()
Returns a reference to the internal parameters map.
Definition soem.cc:995
void updatePdoMappings()
Updates the PDO mapping entries for the slave.
Definition soem.cc:1018
void clearParameters()
Clears all loaded object dictionary parameters.
Definition soem.cc:991
void logTxPdoMappedParameters()
Logs all mapped TxPDO parameters with their current values.
Definition soem.cc:976
Slave(ecx_contextt &context, uint16_t position)
Constructs a Slave object with a given context and position.
Definition soem.cc:750
void logRxPdoMappedParameters()
Logs all mapped RxPDO parameters with their current values.
Definition soem.cc:961
uint16_t getPosition() const
Gets the position of the slave.
Definition soem.cc:753
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:771
mm::comm::base::PdoMappings & getPdoMappings()
Returns a reference to the cached PDO mappings.
Definition soem.cc:1032
void updateParametersFromInputs()
Updates parameters from the received input data.
Definition soem.cc:1051
void logParameters() const
Logs all loaded object dictionary parameters.
Definition soem.cc:955
uint32_t getVendorId() const
Gets the Vendor ID of the slave device.
Definition soem.cc:755
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:685
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:1577
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:653
void logPdoMappingEntries(const std::vector< mm::comm::base::PdoMappingEntry > &entries)
Logs PDO mapping entries grouped by PDO index.
Definition soem.cc:719
std::string convertSlaveStateToString(int state)
Converts a numeric EtherCAT state value into a human-readable string.
Definition soem.cc:355
bool transitionToHigherSlaveState(ecx_contextt *context, uint16_t slave, int targetState)
Transitions a slave to a higher EtherCAT state.
Definition soem.cc:384
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:1133
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:446
void logIoMap(uint8_t *ioMap, size_t totalBytes)
Logs the I/O map as a formatted hexadecimal string.
Definition soem.cc:740
void checkPdoMapping(ecx_contextt *context, uint16 slave)
Diagnoses and prints the PDO mapping for a given slave.
Definition soem.cc:252
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:521
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:157
uint16_t getSlaveState(ecx_contextt *context, uint16_t slave, bool forceRefresh)
Retrieves the current state of a specific EtherCAT slave.
Definition soem.cc:334
bool setSlaveState(ecx_contextt *context, uint16_t slave, int targetState)
Sets the state of a specified EtherCAT slave.
Definition soem.cc:551
Represents the mapped PDO entries for a slave device.
Definition base.h:148
Structure representing the Fieldbus configuration and context for EtherCAT communication.
Definition soem.h:333
boolean ecaterror
Definition soem.h:349
ec_idxstackT idxstack
Definition soem.h:348
ec_eepromFMMUt eepFMMU
Definition soem.h:355
ec_groupt grouplist[EC_MAXGROUP]
Definition soem.h:344
std::string iface
Definition soem.h:335
uint8 group
Definition soem.h:336
int slavecount
Definition soem.h:343
uint8 esibuf[EC_MAXEEPBUF]
Definition soem.h:345
uint32 esimap[EC_MAXEEPBITMAP]
Definition soem.h:346
int64 DCtime
Definition soem.h:350
ec_eepromSMt eepSM
Definition soem.h:354
ec_PDOassignt PDOassign[EC_MAX_MAPT]
Definition soem.h:352
uint8 map[4096]
Definition soem.h:340
ecx_contextt context
Definition soem.h:334
int roundtripTime
Definition soem.h:337
ec_PDOdesct PDOdesc[EC_MAX_MAPT]
Definition soem.h:353
ecx_portt port
Definition soem.h:341
ec_slavet slavelist[EC_MAXSLAVE]
Definition soem.h:342
ec_SMcommtypet SMcommtype[EC_MAX_MAPT]
Definition soem.h:351
ec_eringt elist
Definition soem.h:347