yarp-devices
PdoProtocol.hpp
1 // -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-
2 
3 #ifndef __PDO_PROTOCOL_HPP__
4 #define __PDO_PROTOCOL_HPP__
5 
6 #include <cstddef>
7 #include <cstdint>
8 
9 #include <functional>
10 #include <type_traits>
11 #include <utility> // std::forward
12 
13 #include "ICanSenderDelegate.hpp"
14 #include "SdoClient.hpp"
15 
16 namespace roboticslab
17 {
18 
26 {
27 public:
29  enum transmission_type : std::uint8_t
30  {
33  RTR_SYNCHRONOUS = 0xFC,
37  };
38 
40  constexpr PdoTransmissionType() = default;
41 
43  constexpr PdoTransmissionType(transmission_type type) : type(type)
44  { }
45 
47  constexpr operator std::uint8_t() const
48  { return type; }
49 
51  static constexpr PdoTransmissionType SYNCHRONOUS_CYCLIC_N(std::uint8_t n)
52  { return static_cast<transmission_type>(n); }
53 
55  template<std::uint8_t n>
57  {
58  // https://stackoverflow.com/a/12109644
59  static_assert(n >= 0x01 && n <= 0xF0, "Illegal argument."); // same as [1-240]
60  return static_cast<transmission_type>(n);
61  }
62 
63 private:
65 };
66 
67 class PdoProtocol;
68 
79 class PdoConfiguration final
80 {
81  friend PdoProtocol;
82 
83 public:
86 
89 
92 
95 
97  PdoConfiguration & setValid(bool value);
98 
100  PdoConfiguration & setRtr(bool value);
101 
104 
106  PdoConfiguration & setInhibitTime(std::uint16_t value);
107 
109  PdoConfiguration & setEventTimer(std::uint16_t value);
110 
112  PdoConfiguration & setSyncStartValue(std::uint8_t value);
113 
115  template<typename T>
116  PdoConfiguration & addMapping(std::uint16_t index, std::uint8_t subindex = 0x00)
117  {
118  static_assert(std::is_integral_v<T>, "Integral required.");
119  static_assert(sizeof(T) <= sizeof(std::uint32_t), "Size exceeds 4 bytes.");
120  addMappingInternal((index << 16) + (subindex << 8) + sizeof(T) * 8);
121  return *this;
122  }
123 
124 private:
125  void addMappingInternal(std::uint32_t value);
126 
127  class Private;
128  Private * priv;
129 };
130 
138 {
139 public:
141  PdoProtocol(std::uint8_t id, std::uint16_t cob, unsigned int n, SdoClient * sdo)
142  : id(id), cob(cob), n(n), sdo(sdo)
143  { }
144 
146  virtual ~PdoProtocol() = default;
147 
149  std::uint16_t getCobId() const
150  { return cob + id; };
151 
153  bool configure(const PdoConfiguration & config);
154 
155 protected:
157  enum class PdoType { RPDO, TPDO };
158 
160  virtual PdoType getType() const = 0;
161 
162  template<typename... Tn>
163  static constexpr std::size_t size()
164  { return (sizeof(Tn) + ... + 0); }
165 
166  std::uint8_t id;
167  std::uint16_t cob;
168  unsigned int n;
169 
170  SdoClient * sdo;
171 };
172 
177 class ReceivePdo final : public PdoProtocol
178 {
179 public:
181  ReceivePdo(std::uint8_t id, std::uint16_t cob, unsigned int n, SdoClient * sdo, ICanSenderDelegate * sender = nullptr)
182  : PdoProtocol(id, cob, n, sdo), sender(sender)
183  { }
184 
187  { this->sender = sender; }
188 
196  template<typename... Ts>
197  bool write(Ts... data)
198  {
199  static_assert(sizeof...(Ts) > 0 && size<Ts...>() <= 8, "Illegal cumulative size.");
200  std::uint8_t raw[size<Ts...>()]; unsigned int count = 0;
201  (pack(&data, raw, &count), ...);
202  return writeInternal(raw, count);
203  }
204 
205 protected:
206  PdoType getType() const override
207  { return PdoType::RPDO; }
208 
209 private:
210  template<typename T>
211  void pack(const T * data, std::uint8_t * buff, unsigned int * count)
212  {
213  static_assert(std::is_integral_v<T>, "Integral required.");
214  packInternal(buff + *count, data, sizeof(T));
215  *count += sizeof(T);
216  }
217 
218  void packInternal(std::uint8_t * buff, const void * data, unsigned int size);
219  bool writeInternal(const std::uint8_t * data, unsigned int size);
220 
221  ICanSenderDelegate * sender;
222 };
223 
228 class TransmitPdo final : public PdoProtocol
229 {
230 public:
231  using PdoProtocol::PdoProtocol; // inherit parent constructor
232 
234  bool accept(const std::uint8_t * data, unsigned int size)
235  { return (bool)callback && callback(data, size); }
236 
244  template<typename... Ts, typename Fn>
245  void registerHandler(Fn && fn)
246  {
247  static_assert(sizeof...(Ts) > 0 && size<Ts...>() <= 8, "Illegal cumulative size.");
248  callback = [this, fn](const std::uint8_t * raw, unsigned int len)
249  { unsigned int count = 0;
250  return size<Ts...>() == len && (ordered_call{fn, unpack<Ts>(raw, &count)...}, true); };
251  }
252 
255  { callback = HandlerFn(); }
256 
257 protected:
258  PdoType getType() const override
259  { return PdoType::TPDO; }
260 
261 private:
262  using HandlerFn = std::function<bool(const std::uint8_t * data, unsigned int size)>;
263 
264  // https://stackoverflow.com/a/14058638
266  {
267  template<typename Fn, typename... Ts>
268  ordered_call(Fn && fn, Ts &&... ts)
269  { std::forward<Fn>(fn)(std::forward<Ts>(ts)...); }
270  };
271 
272  template<typename T>
273  T unpack(const std::uint8_t * buff, unsigned int * count)
274  {
275  static_assert(std::is_integral_v<T>, "Integral required.");
276  T data;
277  unpackInternal(&data, buff + *count, sizeof(T));
278  *count += sizeof(T);
279  return data;
280  }
281 
282  void unpackInternal(void * data, const std::uint8_t * buff, unsigned int size);
283 
284  HandlerFn callback;
285 };
286 
287 } // namespace roboticslab
288 
289 #endif // __PDO_PROTOCOL_HPP__
Implementation-agnostic consumer for TX CAN transfers.
Definition: ICanSenderDelegate.hpp:22
Set of SDO configuration values for a PdoProtocol.
Definition: PdoProtocol.hpp:80
PdoConfiguration & addMapping(std::uint16_t index, std::uint8_t subindex=0x00)
Configure PDO mapping, uses template parameter to deduce object size.
Definition: PdoProtocol.hpp:116
PdoConfiguration & setRtr(bool value)
Set or reset RTR bit.
Definition: PdoProtocol.cpp:62
~PdoConfiguration()
Destructor.
Definition: PdoProtocol.cpp:36
PdoConfiguration & setValid(bool value)
Set or reset valid bit.
Definition: PdoProtocol.cpp:56
PdoConfiguration & setEventTimer(std::uint16_t value)
Set event timer.
Definition: PdoProtocol.cpp:80
PdoConfiguration & setInhibitTime(std::uint16_t value)
Set inhibit time.
Definition: PdoProtocol.cpp:74
PdoConfiguration & operator=(const PdoConfiguration &)
Copy assignment operator.
Definition: PdoProtocol.cpp:45
PdoConfiguration()
Constructor.
Definition: PdoProtocol.cpp:32
PdoConfiguration & setSyncStartValue(std::uint8_t value)
Set sync start value.
Definition: PdoProtocol.cpp:86
PdoConfiguration & setTransmissionType(PdoTransmissionType value)
Set transmission type.
Definition: PdoProtocol.cpp:68
Abstract representation of PDO protocol.
Definition: PdoProtocol.hpp:138
bool configure(const PdoConfiguration &config)
Configure this PDO drive-side via SDO packages.
Definition: PdoProtocol.cpp:97
virtual ~PdoProtocol()=default
Virtual destructor.
PdoType
PDO type.
Definition: PdoProtocol.hpp:157
std::uint16_t getCobId() const
Retrieve COB ID.
Definition: PdoProtocol.hpp:149
PdoProtocol(std::uint8_t id, std::uint16_t cob, unsigned int n, SdoClient *sdo)
Constructor, registers SDO client handle.
Definition: PdoProtocol.hpp:141
virtual PdoType getType() const =0
Retrieve PDO type.
Wrapped enumeration of a PDO transmission type.
Definition: PdoProtocol.hpp:26
transmission_type
Wrapped enumerators.
Definition: PdoProtocol.hpp:30
@ EVENT_DRIVEN_DEVICE_APP_PROFILE
Device application profile-specific event-driven.
Definition: PdoProtocol.hpp:36
@ SYNCHRONOUS_ACYCLIC
Synchronous acyclic.
Definition: PdoProtocol.hpp:31
@ RTR_EVENT_DRIVEN
Event-driven RTR.
Definition: PdoProtocol.hpp:34
@ RTR_SYNCHRONOUS
Synchronous RTR.
Definition: PdoProtocol.hpp:33
@ EVENT_DRIVEN_MANUFACTURER
Manufacturer-specific event-driven.
Definition: PdoProtocol.hpp:35
@ SYNCHRONOUS_CYCLIC
Synchronous cyclic.
Definition: PdoProtocol.hpp:32
constexpr PdoTransmissionType()=default
Default constructor.
static constexpr PdoTransmissionType SYNCHRONOUS_CYCLIC_N(std::uint8_t n)
Cast input byte to an PdoTransmissionType enumerator.
Definition: PdoProtocol.hpp:51
constexpr PdoTransmissionType(transmission_type type)
Constructor, accepts initial transmission type.
Definition: PdoProtocol.hpp:43
static constexpr PdoTransmissionType SYNCHRONOUS_CYCLIC_N()
Cast input byte to an PdoTransmissionType enumerator, performs static check on range [0x01-0xF0].
Definition: PdoProtocol.hpp:56
Representation of RPDO protocol.
Definition: PdoProtocol.hpp:178
void configureSender(ICanSenderDelegate *sender)
Configure CAN sender delegate handle.
Definition: PdoProtocol.hpp:186
PdoType getType() const override
Retrieve PDO type.
Definition: PdoProtocol.hpp:206
ReceivePdo(std::uint8_t id, std::uint16_t cob, unsigned int n, SdoClient *sdo, ICanSenderDelegate *sender=nullptr)
Constructor, registers SDO and CAN sender handles.
Definition: PdoProtocol.hpp:181
bool write(Ts... data)
Send data to the drive.
Definition: PdoProtocol.hpp:197
Representation of SDO client protocol.
Definition: SdoClient.hpp:32
Representation of TPDO protocol.
Definition: PdoProtocol.hpp:229
void registerHandler(Fn &&fn)
Register callback.
Definition: PdoProtocol.hpp:245
void unregisterHandler()
Unregister callback.
Definition: PdoProtocol.hpp:254
PdoType getType() const override
Retrieve PDO type.
Definition: PdoProtocol.hpp:258
bool accept(const std::uint8_t *data, unsigned int size)
Invoke registered callback on raw CAN message data.
Definition: PdoProtocol.hpp:234
The main, catch-all namespace for Robotics Lab UC3M.
Definition: groups.dox:6
Definition: PdoProtocol.hpp:266