EthercatBusBase.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <cassert>
4 // std
5 #include <atomic>
6 #include <string>
7 #include <unordered_map>
8 #include <utility>
9 #include <vector>
10 
11 // soem
12 #include <soem/ethercat.h>
13 
14 // soem_interface
16 
17 #include <ros/ros.h>
18 #include <ros/console.h>
19 
20 namespace rokubimini
21 {
22 namespace soem_interface
23 {
29 {
30 public:
31  using PdoSizePair = std::pair<uint16_t, uint16_t>;
32  using PdoSizeMap = std::unordered_map<std::string, PdoSizePair>;
33 
34  EthercatBusBase() = delete;
39  explicit EthercatBusBase(const std::string& name);
40 
44  ~EthercatBusBase() = default;
45 
50  const std::string& getName() const
51  {
52  return name_;
53  }
54 
60  {
61  return updateReadStamp_;
62  }
63 
69  {
70  return updateWriteStamp_;
71  }
72 
78  static bool busIsAvailable(const std::string& name);
79 
83  static void printAvailableBusses();
84 
89  bool busIsAvailable() const;
90 
95  int getNumberOfSlaves() const;
96 
102  bool addSlave(const EthercatSlaveBasePtr& slave);
103 
110 
118 
124  bool startup(const bool sizeCheck = true);
125 
129  void updateRead();
130 
134  void updateWrite();
135 
139  void shutdown();
140 
146  void setState(const uint16_t state, const uint16_t slave = 0);
147 
156  bool waitForState(const uint16_t state, const uint16_t slave = 0, const unsigned int maxRetries = 40,
157  const double retrySleep = 0.001);
158 
164  std::string getErrorString(ec_errort error);
165 
171  void printALStatus(const uint16_t slave = 0);
172 
179  bool checkForSdoErrors(const uint16_t slave, const uint16_t index);
180 
189  void syncDistributedClock0(const uint16_t slave, const bool activate, const double cycleTime,
190  const double cycleShift);
191 
201 
211 
221  template <typename Value>
222  bool sendSdoWrite(const uint16_t slave, const uint16_t index, const uint8_t subindex, const bool completeAccess,
223  const Value value)
224  {
225  assert(static_cast<int>(slave) <= getNumberOfSlaves());
226  const int size = sizeof(Value);
227  Value value_copy = value; // copy value to make it modifiable
228  int wkc = 0;
229  {
230  std::lock_guard<std::recursive_mutex> guard(contextMutex_);
231  wkc = ecx_SDOwrite(&ecatContext_, slave, index, subindex, static_cast<boolean>(completeAccess), size, &value_copy,
232  EC_TIMEOUTRXM);
233  }
234  if (wkc <= 0)
235  {
236  ROS_ERROR_STREAM("Slave " << slave << ": Working counter too low (" << wkc << ") for writing SDO (ID: 0x"
237  << std::setfill('0') << std::setw(4) << std::hex << index << ", SID 0x"
238  << std::setfill('0') << std::setw(2) << std::hex << static_cast<uint16_t>(subindex)
239  << ").");
240  return false;
241  }
242  return true;
243  }
244 
254  template <typename Value>
255  bool sendSdoRead(const uint16_t slave, const uint16_t index, const uint8_t subindex, const bool completeAccess,
256  Value& value)
257  {
258  assert(static_cast<int>(slave) <= getNumberOfSlaves());
259  int size = sizeof(Value);
260  int wkc = 0;
261  {
262  std::lock_guard<std::recursive_mutex> guard(contextMutex_);
263  wkc = ecx_SDOread(&ecatContext_, slave, index, subindex, static_cast<boolean>(completeAccess), &size, &value,
264  EC_TIMEOUTRXM);
265  }
266  if (wkc <= 0)
267  {
268  ROS_ERROR_STREAM("Slave " << slave << ": Working counter too low (" << wkc << ") for reading SDO (ID: 0x"
269  << std::setfill('0') << std::setw(4) << std::hex << index << ", SID 0x"
270  << std::setfill('0') << std::setw(2) << std::hex << static_cast<uint16_t>(subindex)
271  << ").");
272  return false;
273  }
274  if (size != sizeof(Value))
275  {
276  ROS_ERROR_STREAM("Slave " << slave << ": Size mismatch (expected " << sizeof(Value) << " bytes, read " << size
277  << " bytes) for reading SDO (ID: 0x" << std::setfill('0') << std::setw(4) << std::hex
278  << index << ", SID 0x" << std::setfill('0') << std::setw(2) << std::hex
279  << static_cast<uint16_t>(subindex) << ").");
280  return false;
281  }
282  return true;
283  }
284 
290  int getExpectedWorkingCounter(const uint16_t slave = 0) const;
291 
296  bool workingCounterIsOk() const;
297 
302  std::string getDeviceName(const uint16_t& slave) const
303  {
304  return std::string(ecatContext_.slavelist[slave].name);
305  }
306 
311  bool isCorrectDeviceName(const uint16_t& slave, const std::string& deviceName) const
312  {
313  return getDeviceName(slave) == deviceName;
314  }
315 
321  template <typename TxPdo>
322  void readTxPdo(const uint16_t slave, TxPdo& txPdo) const
323  {
324  assert(static_cast<int>(slave) <= getNumberOfSlaves());
325  std::lock_guard<std::recursive_mutex> guard(contextMutex_);
326  assert(sizeof(TxPdo) == ecatContext_.slavelist[slave].Ibytes);
327  memcpy(&txPdo, ecatContext_.slavelist[slave].inputs, sizeof(TxPdo));
328  }
329 
335  template <typename RxPdo>
336  void writeRxPdo(const uint16_t slave, const RxPdo& rxPdo)
337  {
338  assert(static_cast<int>(slave) <= getNumberOfSlaves());
339  std::lock_guard<std::recursive_mutex> guard(contextMutex_);
340  assert(sizeof(RxPdo) == ecatContext_.slavelist[slave].Obytes);
341  memcpy(ecatContext_.slavelist[slave].outputs, &rxPdo, sizeof(RxPdo));
342  }
343 
354  int writeFile(const uint16_t slave, const std::string& fileName, const uint32_t& password, const int fileSize,
355  char* fileBuffer, int timeout = EC_TIMEOUTSTATE * 10);
365  bool writeFirmware(const uint16_t slave, const std::string& fileName, const uint32_t& password, const int fileSize,
366  char* fileBuffer);
367 
374  bool isRunning()
375  {
376  return isRunning_;
377  }
378 
379 protected:
381  std::string name_;
382 
384  std::vector<EthercatSlaveBasePtr> slaves_;
385 
387  bool sentProcessData_{ false };
388 
390  std::atomic<int> wkc_;
391 
393  std::atomic<bool> isRunning_;
394 
399 
401  const unsigned int ecatConfigMaxRetries_{ 5 };
403  const double ecatConfigRetrySleep_{ 1.0 };
404 
405  // EtherCAT input/output mapping of the slaves within the datagrams.
406  char ioMap_[4096];
407 
408  // EtherCAT context data elements:
409 
410  // Port reference.
412  // List of slave data. Index 0 is reserved for the master, higher indices for the slaves.
414  // Number of slaves found in the network.
415  int ecatSlavecount_{ 0 };
416  // Slave group structure.
418  // Internal, reference to EEPROM cache buffer.
420  // Internal, reference to EEPROM cache map.
422  // Internal, reference to error list.
424  // Internal, reference to processdata stack buffer info.
426  // Boolean indicating if an error is available in error stack.
427  boolean ecatError_{ FALSE };
428  // Reference to last DC time from slaves.
430  // Internal, SM buffer.
432  // Internal, PDO assign list.
434  // Internal, PDO description list.
436  // Internal, SM list from EEPROM.
438  // Internal, FMMU list from EEPROM.
440 
441  mutable std::recursive_mutex contextMutex_;
442  // EtherCAT context data.
443  // Note: SOEM does not use dynamic memory allocation (new/delete). Therefore
444  // all context pointers must be null or point to an existing member.
446  &ecatSlavelist_[0],
448  EC_MAXSLAVE,
449  &ecatGrouplist_[0],
450  EC_MAXGROUP,
451  &ecatEsiBuf_[0],
452  &ecatEsiMap_[0],
453  0,
454  &ecatEList_,
455  &ecatIdxStack_,
456  &ecatError_,
457  0,
458  0,
459  &ecatDcTime_,
460  &ecatSmCommtype_[0],
461  &ecatPdoAssign_[0],
462  &ecatPdoDesc_[0],
463  &ecatSm_,
464  &ecatFmmu_,
465  nullptr };
466 };
467 
468 using EthercatBusBasePtr = std::shared_ptr<EthercatBusBase>;
469 
470 } // namespace soem_interface
471 } // namespace rokubimini
void readTxPdo(const uint16_t slave, TxPdo &txPdo) const
#define EC_MAXGROUP
int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subindex, boolean CA, int *psize, void *p, int timeout)
bool isCorrectDeviceName(const uint16_t &slave, const std::string &deviceName) const
bool checkForSdoErrors(const uint16_t slave, const uint16_t index)
#define EC_TIMEOUTSTATE
void syncDistributedClock0(const uint16_t slave, const bool activate, const double cycleTime, const double cycleShift)
uint32 Ibytes
bool addSlave(const EthercatSlaveBasePtr &slave)
uint8 * outputs
uint8_t uint8
#define EC_MAXEEPBUF
uint32 Obytes
std::pair< uint16_t, uint16_t > PdoSizePair
std::unordered_map< std::string, PdoSizePair > PdoSizeMap
PACKED_BEGIN struct PACKED ec_SMcommtype ec_SMcommtypet
bool isRunning()
Returns if the instance is running.
bool writeFirmware(const uint16_t slave, const std::string &fileName, const uint32_t &password, const int fileSize, char *fileBuffer)
std::shared_ptr< EthercatBusBase > EthercatBusBasePtr
unsigned short uint16_t
bool startup(const bool sizeCheck=true)
int getExpectedWorkingCounter(const uint16_t slave=0) const
std::string getDeviceName(const uint16_t &slave) const
#define EC_MAXEEPBITMAP
unsigned char uint8_t
bool sendSdoWrite(const uint16_t slave, const uint16_t index, const uint8_t subindex, const bool completeAccess, const Value value)
#define EC_TIMEOUTRXM
uint16_t getSlaveALStatusCode(uint16_t slave)
Returns the AL Status Code of a slave.
PACKED_END struct ec_idxstack ec_idxstackT
std::atomic< int > wkc_
Working counter of the most recent PDO.
char name[EC_MAXNAME+1]
int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIndex, boolean CA, int psize, void *p, int Timeout)
int writeFile(const uint16_t slave, const std::string &fileName, const uint32_t &password, const int fileSize, char *fileBuffer, int timeout=EC_TIMEOUTSTATE *10)
unsigned int uint32_t
void setState(const uint16_t state, const uint16_t slave=0)
PACKED_END PACKED_BEGIN struct PACKED ec_PDOassign ec_PDOassignt
std::shared_ptr< EthercatSlaveBase > EthercatSlaveBasePtr
int slave
int64_t int64
#define FALSE
std::string getErrorString(ec_errort error)
bool sentProcessData_
Bool indicating whether PDO data has been sent and not read yet.
std::vector< EthercatSlaveBasePtr > slaves_
List of slaves.
#define EC_MAX_MAPT
std::atomic< bool > isRunning_
Internal flag to indicate if the instance is running.
bool sendSdoRead(const uint16_t slave, const uint16_t index, const uint8_t subindex, const bool completeAccess, Value &value)
PACKED_END PACKED_BEGIN struct PACKED ec_PDOdesc ec_PDOdesct
bool waitForState(const uint16_t state, const uint16_t slave=0, const unsigned int maxRetries=40, const double retrySleep=0.001)
int wkc
#define EC_MAXSLAVE
ros::Time updateReadStamp_
Time of the last successful PDO reading.
ros::Time updateWriteStamp_
Time of the last successful PDO writing.
uint32_t uint32
Class for managing an ethercat bus containing one or multiple slaves.
void printALStatus(const uint16_t slave=0)
Prints application layer status.
#define ROS_ERROR_STREAM(args)
const double ecatConfigRetrySleep_
Time to sleep between the retries.
const unsigned int ecatConfigMaxRetries_
Maximal number of retries to configure the EtherCAT bus.
void writeRxPdo(const uint16_t slave, const RxPdo &rxPdo)
ec_slavet * slavelist
uint8 * inputs


rokubimini_ethercat
Author(s):
autogenerated on Sat Apr 15 2023 02:51:33