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
17 
18 #include <ros/ros.h>
19 #include <ros/console.h>
20 
21 namespace rokubimini
22 {
23 namespace soem_interface
24 {
30 {
31 public:
32  using PdoSizePair = std::pair<uint16_t, uint16_t>;
33  using PdoSizeMap = std::unordered_map<std::string, PdoSizePair>;
34 
35  EthercatBusBase() = delete;
40  explicit EthercatBusBase(const std::string& name);
41 
45  ~EthercatBusBase() = default;
46 
51  const std::string& getName() const
52  {
53  return name_;
54  }
55 
61  {
62  return updateReadStamp_;
63  }
64 
70  {
71  return updateWriteStamp_;
72  }
73 
79  static bool busIsAvailable(const std::string& name);
80 
84  static void printAvailableBusses();
85 
90  bool busIsAvailable() const;
91 
96  int getNumberOfSlaves() const;
97 
103  bool addSlave(const EthercatSlaveBasePtr& slave);
104 
110  bool startup(const bool sizeCheck = true);
111 
115  void updateRead();
116 
120  void updateWrite();
121 
125  void shutdown();
126 
132  void setState(const uint16_t state, const uint16_t slave = 0);
133 
142  bool waitForState(const uint16_t state, const uint16_t slave = 0, const unsigned int maxRetries = 40,
143  const double retrySleep = 0.001);
144 
150  std::string getErrorString(ec_errort error);
151 
157  void printALStatus(const uint16_t slave = 0);
158 
165  bool checkForSdoErrors(const uint16_t slave, const uint16_t index);
166 
175  void syncDistributedClock0(const uint16_t slave, const bool activate, const double cycleTime,
176  const double cycleShift);
177 
187 
197 
207  template <typename Value>
208  bool sendSdoWrite(const uint16_t slave, const uint16_t index, const uint8_t subindex, const bool completeAccess,
209  const Value value)
210  {
211  assert(static_cast<int>(slave) <= getNumberOfSlaves());
212  const int size = sizeof(Value);
213  Value value_copy = value; // copy value to make it modifiable
214  int wkc = 0;
215  {
216  std::lock_guard<std::recursive_mutex> guard(contextMutex_);
217  wkc = ecx_SDOwrite(&ecatContext_, slave, index, subindex, static_cast<boolean>(completeAccess), size, &value_copy,
218  EC_TIMEOUTRXM);
219  }
220  if (wkc <= 0)
221  {
222  ROS_ERROR_STREAM("Slave " << slave << ": Working counter too low (" << wkc << ") for writing SDO (ID: 0x"
223  << std::setfill('0') << std::setw(4) << std::hex << index << ", SID 0x"
224  << std::setfill('0') << std::setw(2) << std::hex << static_cast<uint16_t>(subindex)
225  << ").");
226  return false;
227  }
228  return true;
229  }
230 
240  template <typename Value>
241  bool sendSdoRead(const uint16_t slave, const uint16_t index, const uint8_t subindex, const bool completeAccess,
242  Value& value)
243  {
244  assert(static_cast<int>(slave) <= getNumberOfSlaves());
245  int size = sizeof(Value);
246  int wkc = 0;
247  {
248  std::lock_guard<std::recursive_mutex> guard(contextMutex_);
249  wkc = ecx_SDOread(&ecatContext_, slave, index, subindex, static_cast<boolean>(completeAccess), &size, &value,
250  EC_TIMEOUTRXM);
251  }
252  if (wkc <= 0)
253  {
254  ROS_ERROR_STREAM("Slave " << slave << ": Working counter too low (" << wkc << ") for reading SDO (ID: 0x"
255  << std::setfill('0') << std::setw(4) << std::hex << index << ", SID 0x"
256  << std::setfill('0') << std::setw(2) << std::hex << static_cast<uint16_t>(subindex)
257  << ").");
258  return false;
259  }
260  if (size != sizeof(Value))
261  {
262  ROS_ERROR_STREAM("Slave " << slave << ": Size mismatch (expected " << sizeof(Value) << " bytes, read " << size
263  << " bytes) for reading SDO (ID: 0x" << std::setfill('0') << std::setw(4) << std::hex
264  << index << ", SID 0x" << std::setfill('0') << std::setw(2) << std::hex
265  << static_cast<uint16_t>(subindex) << ").");
266  return false;
267  }
268  return true;
269  }
270 
276  int getExpectedWorkingCounter(const uint16_t slave = 0) const;
277 
282  bool workingCounterIsOk() const;
283 
289  template <typename TxPdo>
290  void readTxPdo(const uint16_t slave, TxPdo& txPdo) const
291  {
292  assert(static_cast<int>(slave) <= getNumberOfSlaves());
293  std::lock_guard<std::recursive_mutex> guard(contextMutex_);
294  assert(sizeof(TxPdo) == ecatContext_.slavelist[slave].Ibytes);
295  memcpy(&txPdo, ecatContext_.slavelist[slave].inputs, sizeof(TxPdo));
296  }
297 
303  template <typename RxPdo>
304  void writeRxPdo(const uint16_t slave, const RxPdo& rxPdo)
305  {
306  assert(static_cast<int>(slave) <= getNumberOfSlaves());
307  std::lock_guard<std::recursive_mutex> guard(contextMutex_);
308  assert(sizeof(RxPdo) == ecatContext_.slavelist[slave].Obytes);
309  memcpy(ecatContext_.slavelist[slave].outputs, &rxPdo, sizeof(RxPdo));
310  }
311 
322  int writeFile(const uint16_t slave, const std::string& fileName, const uint32_t& password, const int fileSize,
323  char* fileBuffer, int timeout = EC_TIMEOUTSTATE * 10);
333  bool writeFirmware(const uint16_t slave, const std::string& fileName, const uint32_t& password, const int fileSize,
334  char* fileBuffer);
335 
342  bool isRunning()
343  {
344  return isRunning_;
345  }
346 
347 protected:
349  std::string name_;
350 
352  std::vector<EthercatSlaveBasePtr> slaves_;
353 
355  bool sentProcessData_{ false };
356 
358  std::atomic<int> wkc_;
359 
361  std::atomic<bool> isRunning_;
362 
367 
369  const unsigned int ecatConfigMaxRetries_{ 5 };
371  const double ecatConfigRetrySleep_{ 1.0 };
372 
373  // EtherCAT input/output mapping of the slaves within the datagrams.
374  char ioMap_[4096];
375 
376  // EtherCAT context data elements:
377 
378  // Port reference.
380  // List of slave data. Index 0 is reserved for the master, higher indices for the slaves.
382  // Number of slaves found in the network.
383  int ecatSlavecount_{ 0 };
384  // Slave group structure.
386  // Internal, reference to EEPROM cache buffer.
388  // Internal, reference to EEPROM cache map.
390  // Internal, reference to error list.
392  // Internal, reference to processdata stack buffer info.
394  // Boolean indicating if an error is available in error stack.
395  boolean ecatError_{ FALSE };
396  // Reference to last DC time from slaves.
398  // Internal, SM buffer.
400  // Internal, PDO assign list.
402  // Internal, PDO description list.
404  // Internal, SM list from EEPROM.
406  // Internal, FMMU list from EEPROM.
408 
409  mutable std::recursive_mutex contextMutex_;
410  // EtherCAT context data.
411  // Note: SOEM does not use dynamic memory allocation (new/delete). Therefore
412  // all context pointers must be null or point to an existing member.
414  &ecatSlavelist_[0],
416  EC_MAXSLAVE,
417  &ecatGrouplist_[0],
418  EC_MAXGROUP,
419  &ecatEsiBuf_[0],
420  &ecatEsiMap_[0],
421  0,
422  &ecatEList_,
423  &ecatIdxStack_,
424  &ecatError_,
425  0,
426  0,
427  &ecatDcTime_,
428  &ecatSmCommtype_[0],
429  &ecatPdoAssign_[0],
430  &ecatPdoDesc_[0],
431  &ecatSm_,
432  &ecatFmmu_,
433  nullptr };
434 };
435 
436 using EthercatBusBasePtr = std::shared_ptr<EthercatBusBase>;
437 
438 } // namespace soem_interface
439 } // namespace rokubimini
#define EC_MAXGROUP
int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subindex, boolean CA, int *psize, void *p, int timeout)
bool checkForSdoErrors(const uint16_t slave, const uint16_t index)
#define EC_TIMEOUTSTATE
void readTxPdo(const uint16_t slave, TxPdo &txPdo) const
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)
const ros::Time & getUpdateWriteStamp() 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
PACKED_END struct ec_idxstack ec_idxstackT
std::atomic< int > wkc_
Working counter of the most recent PDO.
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
const ros::Time & getUpdateReadStamp() const
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
int getExpectedWorkingCounter(const uint16_t slave=0) const
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.
uint8_t state
#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 Wed Mar 3 2021 03:09:16