-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NOT FOR MERGE] Feature/coe parametrization #12
base: master
Are you sure you want to change the base?
Changes from 13 commits
e881a13
72ef26e
e3a1f7a
95b61fd
c4b7c2f
59de91a
749a4d8
2170278
0194536
ee637f7
40615fa
9970b65
f7ccbfe
65bbbd5
88f0907
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,10 +52,29 @@ SoemMasterComponent::SoemMasterComponent(const std::string& name) : | |
"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( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: space after comma, here and for added operations below. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
"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)"); | ||
|
||
RTT::types::GlobalsRepository::shared_ptr globals = RTT::types::GlobalsRepository::Instance(); | ||
globals->setValue( new Constant<ec_state>("EC_STATE_INIT",EC_STATE_INIT) ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: No space after ( nor before ), add space after comma. Here and below. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
globals->setValue( new Constant<ec_state>("EC_STATE_PRE_OP",EC_STATE_PRE_OP) ); | ||
globals->setValue( new Constant<ec_state>("EC_STATE_SAFE_OP",EC_STATE_SAFE_OP) ); | ||
globals->setValue( new Constant<ec_state>("EC_STATE_OPERATIONAL",EC_STATE_OPERATIONAL) ); | ||
globals->setValue( new Constant<ec_state>("EC_STATE_BOOT",EC_STATE_BOOT) ); | ||
|
||
RTT::types::Types()->addType(new ec_stateTypeInfo()); | ||
RTT::types::Types()->addType(new parameterTypeInfo()); | ||
RTT::types::Types()->addType(new types::SequenceTypeInfo< std::vector<rtt_soem::Parameter> >("std.vector<Parameter>")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: wrap line at 80 cols. Applies to other long lines in the diff. No need to fix existing code violating this, but new code should strive to comply with our style guide. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK |
||
|
||
//this->addOperation("start",&TaskContext::start,this,RTT::OwnThread); | ||
} | ||
|
||
|
@@ -91,8 +110,38 @@ bool SoemMasterComponent::configureHook() | |
<< 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); | ||
//Wait for all slaves to reach PRE_OP state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Space after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK |
||
if(!checkNetworkState(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++) | ||
{ | ||
int wkc; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider giving wkc and tmp more descriptive names. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree but wkc is the standard name for the "working counter" in the EtherCAT specifications and in few EtherCAT libraries such as SOEM and Etherlab. Is it enough in your opinion? Or should I change it anyway? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is a well understood acronym in this context, it can remain as-is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the sake of clarity, I would use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK |
||
AddressInfo tmp; | ||
tmp.slave_position = parameters[i].slave_position; | ||
tmp.index = parameters[i].index; | ||
tmp.sub_index = parameters[i].sub_index; | ||
|
||
if(ec_slave[tmp.slave_position].mbx_proto & ECT_MBXPROT_COE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: space after if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
{ | ||
wkc = writeCoeSdo(tmp,parameters[i].complete_access,parameters[i].size,¶meters[i].param); | ||
|
||
if(wkc == 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: space after if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
{ | ||
log(Error) << "Slave_" << ec_slave[tmp.slave_position].configadr <<" SDOwrite{index["<< tmp.index | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should configuration fail on error? If not (best effort?), consider lowering severity to warning. Consider also documenting on the header the circumstances under which configure can fail. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, in this case you should return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 on returning false here, we're still configuring, if things go wrong here, don't expect anything to work. |
||
<< "] sub_index["<< (int)tmp.sub_index <<"] size "<< parameters[i].size | ||
<< " value "<< parameters[i].param << "} wkc "<< wkc << endlog(); | ||
} | ||
} | ||
else | ||
{ | ||
log(Error) << "Slave_" << ec_slave[tmp.slave_position].configadr <<" does not support CoE" | ||
<< " but in soem.cpf there is a CoE parameter for this slave." << endlog(); | ||
} | ||
|
||
} | ||
|
||
for (int i = 1; i <= ec_slavecount; i++) | ||
{ | ||
|
@@ -142,6 +191,7 @@ bool SoemMasterComponent::configureHook() | |
else | ||
{ | ||
log(Error) << "Configuration of slaves failed!!!" << endlog(); | ||
log(Error) << "The NIC currently used for EtherCAT is "<< prop_ifname1.c_str() << " . Another could be chosen by editing soem.cpf." << endlog(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: If msg is part of the above error, prefer using a newline instead of two separate log statements. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 80-char wrapping. |
||
return false; | ||
} | ||
return true; | ||
|
@@ -156,40 +206,13 @@ bool SoemMasterComponent::configureHook() | |
|
||
bool SoemMasterComponent::startHook() | ||
{ | ||
bool state_reached; | ||
|
||
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; | ||
} | ||
checkNetworkState(EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 for less code dup :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name of the method is a bit misleading, as a check is something that I would expect to not have side-effects. Consider:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well maybe I can rename the function to waitNetworkStateReached() since its goal is To achieve this goal the function does three things
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would additionally replace Network with Slave --> updateSlaveStates or something similar. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So maybe "checkSlavesStateReachedWaiting" ? |
||
|
||
log(Info) << "Request operational state for all slaves" << endlog(); | ||
ec_slave[0].state = EC_STATE_OPERATIONAL; | ||
|
@@ -204,31 +227,9 @@ bool SoemMasterComponent::startHook() | |
} | ||
|
||
// 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; | ||
if(!checkNetworkState(EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE)) | ||
return false; | ||
|
||
} | ||
return true; | ||
} | ||
|
||
|
@@ -269,4 +270,96 @@ void SoemMasterComponent::cleanupHook() | |
//stop SOEM, close socket | ||
ec_close(); | ||
} | ||
|
||
int SoemMasterComponent::writeCoeSdo(const AddressInfo& address, bool complete_access, int size, void* data) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As we discussed offline:
@smits What do you think about this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would clearly indicate the behavior in the documentation of the function. I agree that the user should be allowed to to SDO writes when he feels like it, given that he knows what he's doing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok,
Notes:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't see the comment on time :) |
||
{ | ||
return ec_SDOwrite(address.slave_position,address.index,address.sub_index,complete_access,size,data,EC_TIMEOUTRXM); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style, here and below: 80 col wrap and space after comma. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
} | ||
|
||
int SoemMasterComponent::readCoeSdo(const AddressInfo& address, bool complete_access, int* size, void* data) | ||
{ | ||
return ec_SDOread(address.slave_position,address.index,address.sub_index,complete_access,size,data,EC_TIMEOUTRXM); | ||
} | ||
|
||
bool SoemMasterComponent::checkNetworkState(ec_state desired_state, int timeout) | ||
{ | ||
bool state_is_reached = true; | ||
bool error_detected = false; | ||
|
||
uint16 network_state = ec_statecheck(0, desired_state, timeout); | ||
|
||
if((network_state & 0xf0) == 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; | ||
} | ||
} | ||
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 | ||
{ | ||
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(); | ||
while (EcatError) | ||
{ | ||
log(Error) << ec_elist2string() << endlog(); | ||
} | ||
} | ||
else | ||
{ | ||
log(Error) << "Not all slaves reached safe operational state." | ||
<< endlog(); | ||
|
||
//If not all slaves reached target state find out which one | ||
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; | ||
} | ||
|
||
}//namespace |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,14 @@ | |
namespace soem_master | ||
{ | ||
|
||
/** CoE addressing info */ | ||
struct AddressInfo | ||
{ | ||
unsigned short slave_position; | ||
unsigned short index; | ||
unsigned char sub_index; | ||
}; | ||
|
||
class SoemMasterComponent: public RTT::TaskContext | ||
{ | ||
public: | ||
|
@@ -50,6 +58,11 @@ class SoemMasterComponent: public RTT::TaskContext | |
bool prop_redundant; | ||
char m_IOmap[4096]; | ||
std::vector<SoemDriver*> m_drivers; | ||
std::vector <rtt_soem::Parameter> parameters; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: No space after std::vector. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
int writeCoeSdo(const AddressInfo& address, bool complete_access, int size, void* data); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add some doc on what the methods do, what the params represent, and the meaning of the return value. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
int readCoeSdo(const AddressInfo& address, bool complete_access, int* size, void* data); | ||
bool checkNetworkState(ec_state desired_state, int timeout); | ||
|
||
};//class | ||
|
||
}//namespace | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed in this header? but in
soem_master_component.h
instead?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done