SlaveInterface.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <memory>
5
8
9#include "ErrorReporting.h"
10#include "SlaveIdentifier.h"
11
13{
14
15 class Bus;
16
18 using SlaveErrorRegistersDevicePtr = std::shared_ptr<SlaveErrorRegistersDevice>;
19
20 /**
21 * @class SlaveInterface
22 * @ingroup Library-ethercat
23 * @brief Brief description of class SlaveInterface.
24 *
25 * Detailed description of class SlaveInterface.
26 */
28 {
29
30 public:
32
33 virtual ~SlaveInterface() override
34 {
35 }
36
37 /**
38 * This is called after EtherCAT Bus is PreOp Mode. This is where the PDO Mapping can be configured for the slave.
39 */
40 virtual void doMappings() = 0;
41
42 /**
43 * This gets triggered by the bus controller before it will start the control loop.
44 * If a slave needs more preparation than just getting in EtherCAT Op-Mode this should be done here.
45 * So slaves can assume that the EtherCAT state machine is in Op-Mode so PDO's are available.
46 * Attention!!! This needs to be implemented cooperative
47 * @return true if the prepare is finished an don't needs to be called again
48 */
49 virtual bool prepareForRun() = 0;
50
51 /**
52 * This method gets triggered by the Bus Controller, this function hast to be implemented cooperative.
53 * The Bus controller will guarantee that the process data will be update before each call.
54 */
55 virtual void execute() = 0;
56
57 /**
58 * This gets triggered by the bus Controller before it will close the EtherCAT bus.
59 * So if the device need to do something before to get in a safe state, this can be done here.
60 * Attention!!! This needs to be implemented cooperative
61 * @return if slave is shut down
62 */
63 virtual bool shutdown() = 0;
64
65 virtual void setInputPDO(void* ptr) = 0;
66
67 virtual void setOutputPDO(void* ptr) = 0;
68
69 /**
70 * This gets called between the SafeOp an the Op state of the bus at the initizialisation.
71 * The slave can assume that the PDO is already mapped
72 */
73 virtual void prepareForOp() = 0;
74
75 /**
76 * @brief This gets called after prepareForOp() was called. This is useful if prepareForOp()
77 * executes a long running initialization and needs to be done before the slave goes into op
78 */
79 virtual void
83
84 virtual void
86 {
87 }
88
89 virtual void
93
94 /**
95 * This function indicates if there is a error or Problem with this slave. It should not
96 * @return true if there is an error/problem with this slave otherwise false;
97 */
98 virtual bool hasError() = 0;
99
100 virtual bool
102 {
103 return false;
104 }
105
106 virtual bool
108 {
109 return true;
110 }
111
112 /**
113 * This tries to clear oder fix the errors or problems of the slave or just gives detailed information about the problem.
114 * If hasError == false this function does nothing.
115 * @return true if the function is trying to recover the slave or there is no error, false is send if this just reports the info
116 */
117 virtual bool handleErrors();
118
119
120 std::uint16_t getSlaveNumber() const;
121
122 const SlaveIdentifier& getSlaveIdentifier() const;
123
124 virtual void setName(const std::string& name);
125 void setParentDeviceName(const std::string& name);
128
129 virtual bool
131 {
132 return false;
133 }
134
135 protected:
138 };
139
140 template <class InputT, class OutputT>
142 {
143
144 public:
146
147 void
148 setInputPDO(void* ptr) override
149 {
150 const auto ptrAsInt = reinterpret_cast<std::uint64_t>(ptr);
151 ARMARX_CHECK_EXPRESSION((ptrAsInt % alignof(InputT)) == 0)
152 << "\nThe alignment is wrong!\nIt has to be " << alignof(InputT)
153 << ", but the data is aligned with " << ptrAsInt % alignof(std::max_align_t)
154 << "!\nThis is an offset of " << (ptrAsInt % alignof(InputT))
155 << " bytes!\nThe datatype is " << GetTypeString<InputT>() << "\nIts size is "
156 << sizeof(InputT) << " bytes";
157 inputs = static_cast<InputT*>(ptr);
158 }
159
160 void
161 setOutputPDO(void* ptr) override
162 {
163 const auto ptrAsInt = reinterpret_cast<std::uint64_t>(ptr);
164 ARMARX_CHECK_EXPRESSION((ptrAsInt % alignof(OutputT)) == 0)
165 << "\nThe alignment is wrong!\nIt has to be " << alignof(OutputT)
166 << ", but the data is aligned with " << ptrAsInt % alignof(std::max_align_t)
167 << "!\nThis is an offset of " << (ptrAsInt % alignof(OutputT))
168 << " bytes!\nThe datatype is " << GetTypeString<OutputT>() << "\nIts size is "
169 << sizeof(OutputT) << " bytes";
170 outputs = static_cast<OutputT*>(ptr);
171 }
172
173 bool
174 hasPDOMapping() const final override
175 {
176 return true;
177 }
178
179 OutputT*
181 {
182 return outputs;
183 }
184
185 InputT*
187 {
188 return inputs;
189 }
190
191 protected:
192 InputT* inputs{nullptr};
193 OutputT* outputs;
194 };
195
196 template <typename Slave>
197 std::unique_ptr<armarx::control::ethercat::SlaveInterface>
199 {
200 SlaveIdentifier sidWithDefaultName(sid);
201 sidWithDefaultName.setName(Slave::getDefaultName());
202
203 if (Slave::isSlaveIdentifierAccepted(sidWithDefaultName))
204 {
205 return std::make_unique<Slave>(sidWithDefaultName);
206 }
207
208 return nullptr;
209 }
210
211} // namespace armarx::control::ethercat
Base Class for all Logging classes.
Definition Logging.h:240
Brief description of class Bus.
Definition Bus.h:57
Brief description of class SlaveErrorRegistersDevice.
The SlaveIdentifier class is a POD-type representing a unique set of values identifying an EtherCAT s...
bool setName(const std::string &name)
Sets the slave name of a SlaveIdentifier and returns whether the new name fits together with the pare...
SlaveInterface(const SlaveIdentifier &slaveIdentifier)
SlaveErrorRegistersDevicePtr getErrorRegistersDevice() const
SlaveErrorRegistersDevicePtr errorRegistersDevice
virtual void finishPreparingForOp()
This gets called after prepareForOp() was called.
virtual bool hasError()=0
This function indicates if there is a error or Problem with this slave.
virtual void doMappings()=0
This is called after EtherCAT Bus is PreOp Mode.
virtual void setOutputPDO(void *ptr)=0
virtual bool handleErrors()
This tries to clear oder fix the errors or problems of the slave or just gives detailed information a...
virtual void setInputPDO(void *ptr)=0
virtual void setName(const std::string &name)
SlaveInterface(const SlaveIdentifier &slaveIdentifier)
void setParentDeviceName(const std::string &name)
const SlaveIdentifier & getSlaveIdentifier() const
virtual bool prepareForRun()=0
This gets triggered by the bus controller before it will start the control loop.
virtual void execute()=0
This method gets triggered by the Bus Controller, this function hast to be implemented cooperative.
virtual bool shutdown()=0
This gets triggered by the bus Controller before it will close the EtherCAT bus.
std::uint16_t getSlaveNumber() const
This returns the slave number of the slave on the bus +1 because slave 0 is the master.
virtual void prepareForOp()=0
This gets called between the SafeOp an the Op state of the bus at the initizialisation.
void setErrorRegistersDevice(SlaveErrorRegistersDevicePtr errorRegistersDevice)
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
std::shared_ptr< SlaveErrorRegistersDevice > SlaveErrorRegistersDevicePtr
std::unique_ptr< armarx::control::ethercat::SlaveInterface > createSlave(const SlaveIdentifier &sid)
std::string GetTypeString(const std::type_info &tinf, bool withoutNamespaceSpecifier=false)