diff --git a/soem_master/soem_driver.h b/soem_master/soem_driver.h index c75da08..6b86c2f 100644 --- a/soem_master/soem_driver.h +++ b/soem_master/soem_driver.h @@ -105,6 +105,22 @@ class SoemDriver return (ec_state)(m_datap->state); }; + virtual int getInputByteLength(){ + return (int)(m_datap->Ibytes); + }; + + virtual int getOutputByteLength(){ + return (int)(m_datap->Obytes); + }; + + virtual int getInputBitLength(){ + return (int)(m_datap->Ibits); + }; + + virtual int getOutputBitLength(){ + return (int)(m_datap->Obits); + }; + protected: SoemDriver(ec_slavet* mem_loc) : m_datap(mem_loc), m_name("Slave_" + to_string(m_datap->configadr, @@ -114,6 +130,10 @@ class SoemDriver m_service->addOperation("checkState",&SoemDriver::checkState,this).doc("check the slaves state").arg("state","state value to check"); m_service->addOperation("getState",&SoemDriver::getState,this).doc("request slave state"); m_service->addOperation("configure",&SoemDriver::configure,this).doc("Configure slave"); + m_service->addOperation("getInputByteLength",&SoemDriver::getInputByteLength,this).doc("retrieve the length of the input cyclic data in bytes"); + m_service->addOperation("getOutputByteLength",&SoemDriver::getOutputByteLength,this).doc("retrieve the length of the output cyclic data in bytes"); + m_service->addOperation("getInputBitLength",&SoemDriver::getInputBitLength,this).doc("retrieve the length of the input cyclic data in bits"); + m_service->addOperation("getOutputBitLength",&SoemDriver::getOutputBitLength,this).doc("retrieve the length of the output cyclic data in bits"); } ; ec_slavet* m_datap; diff --git a/soem_master/soem_master_component.cpp b/soem_master/soem_master_component.cpp old mode 100644 new mode 100755 index 1936f58..8960d30 --- a/soem_master/soem_master_component.cpp +++ b/soem_master/soem_master_component.cpp @@ -17,8 +17,7 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -extern "C" -{ +extern "C" { #include "ethercattype.h" #include "nicdrv.h" #include "ethercatbase.h" @@ -36,237 +35,373 @@ extern "C" #include "rtt/Component.hpp" -ORO_CREATE_COMPONENT( soem_master::SoemMasterComponent ) +ORO_CREATE_COMPONENT(soem_master::SoemMasterComponent) -namespace soem_master -{ +namespace soem_master { using namespace RTT; SoemMasterComponent::SoemMasterComponent(const std::string& name) : - TaskContext(name, PreOperational) -{ - this->addProperty("ifname", prop_ifname1="eth0").doc( - "interface to which the ethercat device is connected"); - this->addProperty("ifname2", prop_ifname2="eth1").doc( - "Second (redundant) interface to which the ethercat device is connected"); - this->addProperty("redundant", prop_redundant=false).doc( - "Whether to use a redundant nic"); - SoemDriverFactory& driver_factory = SoemDriverFactory::Instance(); - this->addOperation("displayAvailableDrivers", - &SoemDriverFactory::displayAvailableDrivers, &driver_factory).doc( - "display all available drivers for the soem master"); - //this->addOperation("start",&TaskContext::start,this,RTT::OwnThread); + TaskContext(name, PreOperational) { + this->addProperty("ifname", prop_ifname1 = "eth0").doc( + "interface to which the ethercat device is connected"); + this->addProperty("ifname2", prop_ifname2 = "eth1").doc( + "Second (redundant) interface to which the ethercat device is connected"); + this->addProperty("redundant", prop_redundant = false).doc( + "Whether to use a redundant nic"); + this->addProperty("slavesCoeParameters", parameters).doc( + "Vector of parameters to be sent to the slaves using CoE SDO"); + + SoemDriverFactory& driver_factory = SoemDriverFactory::Instance(); + this->addOperation("displayAvailableDrivers", + &SoemDriverFactory::displayAvailableDrivers, &driver_factory).doc( + "display all available drivers for the soem master"); + this->addOperation("writeCoeSdo", &SoemMasterComponent::writeCoeSdo, this).doc( + "send a CoE SDO write " + "(blocking: not to be done while slaves are in OP)"); + this->addOperation("readCoeSdo", &SoemMasterComponent::readCoeSdo, this).doc( + "send a CoE SDO read " + "(blocking: not to be done while slaves are in OP)"); + + // To teach RTT the ec_state constants + RTT::types::GlobalsRepository::shared_ptr globals = + RTT::types::GlobalsRepository::Instance(); + globals->setValue(new Constant("EC_STATE_INIT", EC_STATE_INIT)); + globals->setValue(new Constant("EC_STATE_PRE_OP", EC_STATE_PRE_OP)); + globals->setValue( + new Constant("EC_STATE_SAFE_OP", EC_STATE_SAFE_OP)); + globals->setValue( + new Constant("EC_STATE_OPERATIONAL", EC_STATE_OPERATIONAL)); + globals->setValue(new Constant("EC_STATE_BOOT", EC_STATE_BOOT)); + + RTT::types::Types()->addType(new ec_stateTypeInfo()); + + // To teach RTT SOEM fixed length types + RTT::types::Types()->addType(new types::StdTypeInfo("uint8")); + RTT::types::Types()->addType(new types::StdTypeInfo("uint16")); + RTT::types::Types()->addType(new types::StdTypeInfo("uint32")); + + // To teach RTT how to manage the CoE parameters + // that can be load from soem.cpf + RTT::types::Types()->addType(new parameterTypeInfo()); + RTT::types::Types()->addType( + new types::SequenceTypeInfo >( + "std.vector")); + + //this->addOperation("start",&TaskContext::start,this,RTT::OwnThread); } -SoemMasterComponent::~SoemMasterComponent() -{ +SoemMasterComponent::~SoemMasterComponent() { } -bool SoemMasterComponent::configureHook() -{ - Logger::In in(this->getName()); - - int ret; - if(prop_redundant && !prop_ifname1.empty() && !prop_ifname2.empty()) - ret = ec_init_redundant((char*)prop_ifname1.c_str(),(char*)prop_ifname2.c_str()); - else - ret = ec_init((char*)prop_ifname1.c_str()); - // initialise SOEM, bind socket to ifname - if ( ret > 0) - { - log(Info) << "ec_init on " << prop_ifname1 << (prop_redundant ? std::string("and ") + prop_ifname2 : "")<<" succeeded." << endlog(); - - //Initialise default configuration, using the default config table (see ethercatconfiglist.h) - if (ec_config_init(FALSE) > 0) - { - while (EcatError) - { - log(Error) << ec_elist2string() << endlog(); - } - - log(Info) << ec_slavecount << " slaves found and configured." - << endlog(); - log(Info) << "Request pre-operational state for all slaves" - << endlog(); - ec_slave[0].state = EC_STATE_PRE_OP; - ec_writestate(0); - // wait for all slaves to reach PRE_OP state - ec_statecheck(0, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); - - for (int i = 1; i <= ec_slavecount; i++) - { - SoemDriver - * driver = SoemDriverFactory::Instance().createDriver( - &ec_slave[i]); - if (driver) - { - m_drivers.push_back(driver); - log(Info) << "Created driver for " << ec_slave[i].name - << ", with address " << ec_slave[i].configadr - << endlog(); - //Adding driver's services to master component - this->provides()->addService(driver->provides()); - log(Info) << "Put configured parameters in the slaves." - << endlog(); - if (!driver->configure()) - return false; - } - else - { - log(Warning) << "Could not create driver for " - << ec_slave[i].name << endlog(); - } - } - - ec_config_map(&m_IOmap); - while (EcatError) - { - log(Error) << ec_elist2string() << endlog(); - } - - for (unsigned int i = 0; i < m_drivers.size(); i++) - if (!m_drivers[i]->start()){ - log(Error)<<"Could not start driver for "<getName()); + + int ret; + if (prop_redundant && !prop_ifname1.empty() && !prop_ifname2.empty()) + ret = ec_init_redundant((char*) prop_ifname1.c_str(), + (char*) prop_ifname2.c_str()); + else + ret = ec_init((char*) prop_ifname1.c_str()); + // Initialise SOEM, bind socket to ifname + if (ret > 0) { + log(Info) << "ec_init on " << prop_ifname1 + << (prop_redundant ? std::string("and ") + prop_ifname2 : "") + << " succeeded." << endlog(); + + // Initialise default configuration, using the default config table + // (see ethercatconfiglist.h) + if (ec_config_init(FALSE) > 0) { + if (EcatError) + notifySoemErrors(); + + log(Info) << ec_slavecount << " slaves found and configured." << endlog(); + + setSlavesTargetState(EC_STATE_PRE_OP); + // Wait for all slaves to reach PRE_OP state + if (!checkSlavesStateReachedWaiting(EC_STATE_PRE_OP, EC_TIMEOUTSTATE)) + return false; + // The parameters to be sent to the slaves are loaded from the soem.cpf: + // parameters could be changed without modifying the code + for (unsigned int i = 0; i < parameters.size(); i++) { + bool sdoWriteDone; + AddressInfo tmpAddressInfo; + tmpAddressInfo.slave_position = (uint16) parameters[i].slave_position; + tmpAddressInfo.index = (uint16) parameters[i].index; + tmpAddressInfo.sub_index = (uint8) parameters[i].sub_index; + + sdoWriteDone = writeCoeSdo(tmpAddressInfo, + parameters[i].complete_access, parameters[i].size, + ¶meters[i].param); + + if (!sdoWriteDone) { + log(Error) << "SDO write requested from soem.cpf failed." << endlog(); + return false; } - else - { - log(Error) << "Configuration of slaves failed!!!" << endlog(); + } + + for (int i = 1; i <= ec_slavecount; i++) { + SoemDriver * driver = SoemDriverFactory::Instance().createDriver( + &ec_slave[i]); + if (driver) { + m_drivers.push_back(driver); + log(Info) << "Created driver for " << ec_slave[i].name + << ", with address " << ec_slave[i].configadr << endlog(); + // Adding driver's services to master component + this->provides()->addService(driver->provides()); + log(Info) << "Put configured parameters in the slaves." << endlog(); + if (!driver->configure()) return false; + } else { + log(Warning) << "Could not create driver for " << ec_slave[i].name + << endlog(); } - return true; - } - else - { - log(Error) << "Could not initialize master on " << prop_ifname1 << (prop_redundant ? std::string("and ") + prop_ifname2 : "") << endlog(); - return false; + } + + ec_config_map(&m_IOmap); + if (EcatError) + notifySoemErrors(); + + for (unsigned int i = 0; i < m_drivers.size(); i++) + if (!m_drivers[i]->start()) { + log(Error) << "Could not start driver for " << m_drivers[i] + << getName() << endlog(); + return false; + } + + // Configure distributed clock + // ec_configdc(); + // Read the state of all slaves + + // ec_readstate(); + + } else { + log(Error) << "Configuration of slaves failed!!! \n" + << "The NIC currently used for EtherCAT is " << prop_ifname1.c_str() + << ". Another could be chosen by editing soem.cpf." << endlog(); + return false; } + return true; + } else { + log(Error) << "Could not initialize master on " << prop_ifname1 + << (prop_redundant ? std::string("and ") + prop_ifname2 : "") + << endlog(); + return false; + } } -bool SoemMasterComponent::startHook() -{ - log(Info) << "Request safe-operational state for all slaves" << endlog(); - ec_slave[0].state = EC_STATE_SAFE_OP; - ec_writestate(0); - // wait for all slaves to reach SAFE_OP state - ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); - - if (ec_slave[0].state == EC_STATE_SAFE_OP) - { - log(Info) << "Safe operational state reached for all slaves." - << endlog(); - while (EcatError) - { - log(Error) << ec_elist2string() << endlog(); - } - } - else - { - log(Error) << "Not all slaves reached safe operational state." - << endlog(); - ec_readstate(); - //If not all slaves operational find out which one - for (int i = 0; i <= ec_slavecount; i++) - { - if (ec_slave[i].state != EC_STATE_SAFE_OP) - { - log(Error) << "Slave " << i << " State= " << to_string( - ec_slave[i].state, std::hex) << " StatusCode=" - << ec_slave[i].ALstatuscode << " : " - << ec_ALstatuscode2string( - ec_slave[i].ALstatuscode) << endlog(); - } - } - //return false; - } - - log(Info) << "Request operational state for all slaves" << endlog(); - ec_slave[0].state = EC_STATE_OPERATIONAL; - - // send one valid process data to make outputs in slaves happy - ec_send_processdata(); - - ec_writestate(0); - while (EcatError) - { - log(Error) << ec_elist2string() << endlog(); - } - - // wait for all slaves to reach OP state - ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); - if (ec_slave[0].state == EC_STATE_OPERATIONAL) - { - log(Info) << "Operational state reached for all slaves." - << endlog(); - } - else - { - log(Error) << "Not all slaves reached operational state." - << endlog(); - //If not all slaves operational find out which one - for (int i = 1; i <= ec_slavecount; i++) - { - if (ec_slave[i].state != EC_STATE_OPERATIONAL) - { - log(Error) << "Slave " << i << " State= " << to_string( - ec_slave[i].state, std::hex) << " StatusCode=" - << ec_slave[i].ALstatuscode << " : " - << ec_ALstatuscode2string( - ec_slave[i].ALstatuscode) << endlog(); - } - } - return false; - - } - return true; +bool SoemMasterComponent::startHook() { + bool state_reached; + + setSlavesTargetState(EC_STATE_SAFE_OP); + // Wait for all slaves to reach SAFE_OP state + state_reached = checkSlavesStateReachedWaiting(EC_STATE_SAFE_OP, + EC_TIMEOUTSTATE); + + if (EcatError) + notifySoemErrors(); + + if (!state_reached) + return false; + + // Send one valid process data to make outputs in slaves happy + ec_send_processdata(); + + setSlavesTargetState(EC_STATE_OPERATIONAL); + + if (EcatError) + notifySoemErrors(); + + // Wait for all slaves to reach OP state + state_reached = checkSlavesStateReachedWaiting(EC_STATE_OPERATIONAL, + EC_TIMEOUTSTATE); + + if (EcatError) + notifySoemErrors(); + + if (!state_reached) + return false; + + return true; } -void SoemMasterComponent::updateHook() -{ - bool success = true; - Logger::In in(this->getName()); - if (ec_receive_processdata(EC_TIMEOUTRET) == 0) - { - success = false; - log(Warning) << "receiving data failed" << endlog(); +void SoemMasterComponent::updateHook() { + bool success = true; + Logger::In in(this->getName()); + if (ec_receive_processdata(EC_TIMEOUTRET) == 0) { + success = false; + log(Warning) << "receiving data failed" << endlog(); + } + + if (success) + for (unsigned int i = 0; i < m_drivers.size(); i++) + m_drivers[i]->update(); + + if (ec_send_processdata() == 0) { + success = false; + log(Warning) << "sending process data failed" << endlog(); + } + if (EcatError) + notifySoemErrors(); +} + +void SoemMasterComponent::cleanupHook() { + for (unsigned int i = 0; i < m_drivers.size(); i++) { + this->provides()->removeService(m_drivers[i]->provides()->getName()); + delete m_drivers[i]; + } + + // stop SOEM, close socket + ec_close(); +} + +bool SoemMasterComponent::writeCoeSdo(const AddressInfo& address, + bool complete_access, int size, void* data) { + if (ec_slave[address.slave_position].mbx_proto & ECT_MBXPROT_COE) { + // Working counter of the EtherCAT datagram that ends the CoE + // download procedure. + // This value is written into the frame by the slave and is used + // to confirm that the command has been executed. + // In this case the expected working counter is 1. + int working_counter = ec_SDOwrite(address.slave_position, address.index, + address.sub_index, complete_access, size, data, EC_TIMEOUTRXM); + + if (working_counter == 1) + return true; + else { + log(Warning) << "Slave_" << ec_slave[address.slave_position].configadr + << " CoE SDO write failed for {index[" << address.index + << "] sub_index[" << (int) address.sub_index << "] size " << size + << "} wkc " << working_counter << endlog(); + + return false; } + } else { + log(Error) << "Slave_" << ec_slave[address.slave_position].configadr + << " does not support CoE" << " but a CoE SDO write has been requested" + " for this slave." << endlog(); + + return false; + } +} + +bool SoemMasterComponent::readCoeSdo(const AddressInfo& address, + bool complete_access, int* size, void* data) { + if (ec_slave[address.slave_position].mbx_proto & ECT_MBXPROT_COE) { + // Working counter of the EtherCAT datagram that ends the CoE + // download procedure. + // This value is written into the frame by the slave and is used + // to confirm that the command has been executed. + // In this case the expected working counter is 1. + int working_counter = ec_SDOread(address.slave_position, address.index, + address.sub_index, complete_access, size, data, EC_TIMEOUTRXM); + + if (working_counter == 1) + return true; + else { + log(Warning) << "Slave_" << ec_slave[address.slave_position].configadr + << " CoE SDO read failed for {index[" << address.index + << "] sub_index[" << (int) address.sub_index << "] size " << size + << "} wkc " << working_counter << endlog(); + + return false; + } + } else { + log(Error) << "Slave_" << ec_slave[address.slave_position].configadr + << " does not support CoE" << " but a CoE SDO read has been requested" + " for this slave." << endlog(); + + return false; + } +} - if (success) - for (unsigned int i = 0; i < m_drivers.size(); i++) - m_drivers[i]->update(); +void SoemMasterComponent::setSlavesTargetState(ec_state target_state) { + log(Info) << "Request" << target_state << " state for all slaves" << endlog(); + ec_slave[0].state = (uint16) target_state; + ec_writestate(0); +} + +bool SoemMasterComponent::checkSlavesStateReachedWaiting(ec_state desired_state, + int timeout) { + bool state_is_reached = true; + bool error_detected = false; - if (ec_send_processdata() == 0) - { - success = false; - log(Warning) << "sending process data failed" << endlog(); + uint16 network_state = ec_statecheck(0, desired_state, timeout); + + if ((network_state & EC_STATE_ERROR) == 0) { + // No slave has toggled the error flag so the AlStatusCode + // (even if different from 0) should be ignored + for (int i = 0; i < ec_slavecount; i++) { + ec_slave[i].ALstatuscode = 0x0000; } - while (EcatError) - { - log(Error) << ec_elist2string() << endlog(); + } else { + error_detected = true; + } + + switch (network_state) { + case EC_STATE_INIT: + case EC_STATE_PRE_OP: + case EC_STATE_BOOT: + case EC_STATE_SAFE_OP: + case EC_STATE_OPERATIONAL: + if (!error_detected) { + // All the slaves have reached the same state so we can update + // the state of every slave + for (int i = 1; i <= ec_slavecount; i++) { + ec_slave[i].state = network_state; + } + } else { + // The state should be verified for every single slave + // since at least one of them is in error + ec_readstate(); } + break; + default: + // The state should be verified for every single slave + // since not all have the same state + ec_readstate(); + break; + } + if (ec_slave[0].state == desired_state) { + log(Info) << (ec_state) ec_slave[0].state + << " state reached for all slaves." << endlog(); + } else { + log(Error) << "Not all slaves reached" << desired_state << endlog(); + + // If not all slaves reached target state find out which one + // It may happens that since more time is passing all the slaves reach the + // target state before reading their state one by one. + // In that case the timeout should be increased + for (int i = 1; i <= ec_slavecount; i++) { + if (ec_slave[i].state != desired_state) { + state_is_reached = false; + + log(Error) << "Slave " << i << " State= " + << (ec_state) ec_slave[i].state << " StatusCode=" + << ec_slave[i].ALstatuscode << " : " + << ec_ALstatuscode2string(ec_slave[i].ALstatuscode) << endlog(); + } + } + } + + return state_is_reached; } -void SoemMasterComponent::cleanupHook() -{ - for (unsigned int i = 0; i < m_drivers.size(); i++){ - this->provides()->removeService(m_drivers[i]->provides()->getName()); - delete m_drivers[i]; +bool SoemMasterComponent::notifySoemErrors() { + // The EcatError flag is updated by SOEM library and set to 0 if + // in the SOEM error list there are no more errors + bool errorDetected = EcatError; + + // All the errors are retrieved from the list and notified + while (EcatError) { + log(Error) << ec_elist2string() << endlog(); } - //stop SOEM, close socket - ec_close(); + return errorDetected; } -}//namespace + +} // namespace diff --git a/soem_master/soem_master_component.h b/soem_master/soem_master_component.h old mode 100644 new mode 100755 index ce87a57..7711933 --- a/soem_master/soem_master_component.h +++ b/soem_master/soem_master_component.h @@ -25,33 +25,93 @@ #include #include "soem_driver.h" +#include "soem_master_types.hpp" -namespace soem_master -{ +namespace soem_master { -class SoemMasterComponent: public RTT::TaskContext -{ +/** CoE addressing info */ +struct AddressInfo { + /** Position of the slave in the EtherCAT network starting from 1 */ + uint16 slave_position; + /** Index of the CoE object. */ + uint16 index; + /** Subindex of the CoE object. */ + uint8 sub_index; +}; + +class SoemMasterComponent: public RTT::TaskContext { public: - SoemMasterComponent(const std::string& name); - ~SoemMasterComponent(); + SoemMasterComponent(const std::string& name); + ~SoemMasterComponent(); protected: - virtual bool configureHook(); - virtual bool startHook(); - virtual void updateHook(); - virtual void stopHook() - { - } - ; - virtual void cleanupHook(); + virtual bool configureHook(); + virtual bool startHook(); + virtual void updateHook(); + virtual void stopHook() { + } + virtual void cleanupHook(); private: - std::string prop_ifname1, prop_ifname2; - bool prop_redundant; - char m_IOmap[4096]; - std::vector m_drivers; -};//class + std::string prop_ifname1, prop_ifname2; + bool prop_redundant; + char m_IOmap[4096]; + std::vector m_drivers; + std::vector parameters; + + /** + * Perform a CoE SDO write (blocking) + * @param[in] address = structure that identifies the slave and the object + * @param[in] complete_access = FALSE = single subindex. + * TRUE = Complete Access, all subindexes written. + * @param[in] size = Size in bytes of the object to be written + * @param[in] data = Pointer to the data to be written + * @return true if it succeeds false if it fails + */ + bool writeCoeSdo(const AddressInfo& address, bool complete_access, int size, + void* data); + + /** + * Perform a CoE SDO read (blocking) + * @param[in] address = structure that identifies the slave and the object + * @param[in] complete_access = FALSE = single subindex. + * TRUE = Complete Access, all subindexes written. + * @param[in,out] size = Size in bytes of the read object + * @param[out] data = Pointer to the read data + * @return true if it succeeds false if it fails + */ + bool readCoeSdo(const AddressInfo& address, bool complete_access, int* size, + void* data); + + /** + * Set the EtherCAT target state to be reached by all the slaves + * @param[in] target_state = target EtherCAT state + */ + void setSlavesTargetState(ec_state target_state); + + /** + * Keep refreshing and checking the network state till all slaves reach the + * desired state or a certain amount of time has elapsed (blocking) + * @param[in] desired_state = target EtherCAT state + * @param[in] timeout = timeout in ms + * @return true if the state has been reached within the set timeout + */ + bool checkSlavesStateReachedWaiting(ec_state desired_state, int timeout); + + /** + * Notify if SOEM library detected an error. (non blocking) + * This function is not blocking because it simply retrieve if an error has + * already been detected. + * Possible errors are: packet errors, CoE Emergency messages, + * CoE SDO errors, FoE errors and SoE errors + * Note: Only packets error are possible in EC_STATE_OPERATIONAL if the User + * does not explicitly require a mail box service (CoE, FoE, SoE) + * @return true if at least one error has been detected + */ + bool notifySoemErrors(); + +}; -}//namespace +} // namespace soem_master #endif diff --git a/soem_master/soem_master_types.hpp b/soem_master/soem_master_types.hpp new file mode 100644 index 0000000..ffd821e --- /dev/null +++ b/soem_master/soem_master_types.hpp @@ -0,0 +1,124 @@ +/*************************************************************************** + soem_master_types.hpp - description + ------------------- + begin : Wed October 12 2016 + copyright : (C) 2016 + email : luca@intermodalics.eu + + *************************************************************************** + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307 USA * + * * + ***************************************************************************/ +#include +#include +#include +#include +#include + +extern "C" { +#include "ethercattype.h" +} + +namespace rtt_soem { +/** The structure that contains the information to be sent for each CoE SDO */ +struct Parameter { + /** slave's index starting from 1 and depending on position */ + int slave_position; + /** Index of the CoE object */ + int index; + /** Subindex of the CoE object */ + int sub_index; + /** Falg to enable complete access */ + bool complete_access; + /** Size of the CoE object to be written in bytes */ + int size; + /** The value of the parameter to be written + * (TODO change to a vector of chars to send parameters of any dimension) + */ + int param; + std::string name; + std::string description; + +}; +} + +namespace boost { +namespace serialization { +// The helper function which you write yourself: +template +void serialize(Archive & a, rtt_soem::Parameter & cd, unsigned int) { + using boost::serialization::make_nvp; + a & make_nvp("slavePosition", cd.slave_position); + a & make_nvp("index", cd.index); + a & make_nvp("subIndex", cd.sub_index); + a & make_nvp("completeAccess", cd.complete_access); + a & make_nvp("size", cd.size); + a & make_nvp("param", cd.param); + a & make_nvp("name", cd.name); + a & make_nvp("description", cd.description); + +} +} +} + +// The RTT helper class which uses the above function behind the scenes: +struct parameterTypeInfo: public RTT::types::StructTypeInfo { + parameterTypeInfo() : + RTT::types::StructTypeInfo("Parameter") { + } +}; + +// To manage ec_state enum + +// Displaying: +std::ostream& operator<<(std::ostream& os, const ec_state& ecat_state) { + switch (ecat_state & 0x0f) { + case EC_STATE_INIT: + os << "EC_STATE_INIT"; + break; + case EC_STATE_PRE_OP: + os << "EC_STATE_PRE_OP"; + break; + case EC_STATE_BOOT: + os << "EC_STATE_BOOT"; + break; + case EC_STATE_SAFE_OP: + os << "EC_STATE_SAFE_OP"; + break; + case EC_STATE_OPERATIONAL: + os << "EC_STATE_OPERATIONAL"; + break; + default: + os << "EC_STATE_UNKNOWN"; + break; + } + + if (ecat_state & EC_STATE_ERROR) + os << "-Error"; + + return os; +} +// Reading : +std::istream& operator>>(std::istream& is, ec_state& cd) { + return is; +} + +struct ec_stateTypeInfo: public RTT::types::TemplateTypeInfo { + ec_stateTypeInfo() : + RTT::types::TemplateTypeInfo("ec_state") { + + } +};