37 #include "dll/ethercat_device_addressed_telegram.h"
44 #define ERR_MODE "\033[41m"
45 #define STD_MODE "\033[0m"
46 #define WARN_MODE "\033[43m"
47 #define GOOD_MODE "\033[42m"
48 #define INFO_MODE "\033[44m"
50 #define ERROR_HDR "\033[41mERROR\033[0m"
51 #define WARN_HDR "\033[43mERROR\033[0m"
95 fprintf(stderr,
"size of %d is too large for write\n",
length);
104 fprintf(stderr,
"size of %d is too large for read\n",
length);
109 assert(0 &&
"invalid MbxCmdType");
165 int timediff_ms(
const timespec ¤t,
const timespec &start)
168 + (current.tv_nsec-
start.tv_nsec)/1000000;
182 int result = clock_gettime(clk_id, time);
185 fprintf(stderr,
"safe_clock_gettime : %s\n", strerror(error));
201 assert(usec<1000000);
204 struct timespec req, rem;
206 req.tv_nsec = usec*1000;
207 while (nanosleep(&req, &rem)!=0) {
209 fprintf(stderr,
"%s : Error : %s\n", __func__, strerror(error));
210 if (error != EINTR) {
223 tg->set_idx(logic->get_idx());
224 tg->set_wkc(logic->get_wkc());
230 if ((error = pthread_mutex_init(&mailbox_lock_, NULL)) != 0)
232 ROS_ERROR(
"WG0X : init mailbox mutex :%s", strerror(error));
236 bool WGMailbox::initialize(EtherCAT_SlaveHandler *sh)
242 bool WGMailbox::verifyDeviceStateForMailboxOperation()
245 EC_State state = sh_->get_state();
246 if ((state != EC_SAFEOP_STATE) && (state != EC_OP_STATE)) {
248 "cannot do mailbox read in current device state = %d\n", __func__, state);
264 void WGMailbox::diagnoseMailboxError(
EthercatCom *com)
279 if (!verifyDeviceStateForMailboxOperation()){
283 EC_Logic *logic = EC_Logic::instance();
284 EC_UINT station_addr = sh_->get_station_address();
289 unsigned char unused[1] = {0};
290 NPRD_Telegram read_start(
297 NPRD_Telegram read_end(
300 MBX_STATUS_PHY_ADDR+MBX_STATUS_SIZE-1,
304 read_start.attach(&read_end);
305 EC_Ethernet_Frame frame(&read_start);
310 static const unsigned MAX_DROPS = 15;
311 for (
unsigned tries=0; tries<MAX_DROPS; ++tries) {
312 success = com->txandrx_once(&frame);
322 " too much packet loss\n", __func__);
328 if (read_start.get_wkc() != read_end.get_wkc()) {
330 "read mbx working counters are inconsistant, %d, %d\n",
331 __func__, read_start.get_wkc(), read_end.get_wkc());
334 if (read_start.get_wkc() > 1) {
336 "more than one device (%d) responded \n", __func__, read_start.get_wkc());
339 if (read_start.get_wkc() == 1) {
341 " read mbx contained garbage data\n", __func__);
359 bool WGMailbox::waitForReadMailboxReady(
EthercatCom *com)
362 static const int MAX_WAIT_TIME_MS = 100;
364 unsigned good_results=0;
367 struct timespec start_time, current_time;
374 uint8_t SyncManStatus=0;
375 const unsigned SyncManAddr = 0x805+(MBX_STATUS_SYNCMAN_NUM*8);
378 const uint8_t MailboxStatusMask = (1<<3);
379 if (SyncManStatus & MailboxStatusMask) {
388 }
while (timediff < MAX_WAIT_TIME_MS);
390 if (good_results == 0) {
392 " error reading from device\n", __func__);
395 " error read mbx not full after %d ms\n", __func__, timediff);
411 bool WGMailbox::waitForWriteMailboxReady(
EthercatCom *com)
414 static const int MAX_WAIT_TIME_MS = 100;
416 unsigned good_results=0;
419 struct timespec start_time, current_time;
426 uint8_t SyncManStatus=0;
427 const unsigned SyncManAddr = 0x805+(MBX_COMMAND_SYNCMAN_NUM*8);
430 const uint8_t MailboxStatusMask = (1<<3);
431 if ( !(SyncManStatus & MailboxStatusMask) ) {
440 }
while (timediff < MAX_WAIT_TIME_MS);
442 if (good_results == 0) {
444 " error reading from device\n", __func__);
447 " error write mbx not empty after %d ms\n", __func__, timediff);
466 bool WGMailbox::writeMailboxInternal(
EthercatCom *com,
void const *data,
unsigned length)
468 if (
length > MBX_COMMAND_SIZE) {
469 assert(
length <= MBX_COMMAND_SIZE);
474 if (!verifyDeviceStateForMailboxOperation()){
478 EC_Logic *logic = EC_Logic::instance();
479 EC_UINT station_addr = sh_->get_station_address();
485 static const unsigned TELEGRAM_OVERHEAD = 50;
486 bool split_write = (
length+TELEGRAM_OVERHEAD) < MBX_COMMAND_SIZE;
488 unsigned write_length = MBX_COMMAND_SIZE;
498 unsigned char unused[1] = {0};
499 NPWR_Telegram write_start(
502 MBX_COMMAND_PHY_ADDR,
505 (
const unsigned char*) data);
509 MBX_COMMAND_PHY_ADDR+MBX_COMMAND_SIZE-1,
515 write_start.attach(&write_end);
518 EC_Ethernet_Frame frame(&write_start);
523 for (
unsigned tries=0; (tries<10) && !success; ++tries) {
544 " too much packet loss\n", __func__);
549 if (split_write && (write_start.get_wkc() !=
write_end.get_wkc())) {
551 " write mbx working counters are inconsistant\n", __func__);
555 if (write_start.get_wkc() > 1)
558 " multiple (%d) devices responded to mailbox write\n", __func__, write_start.get_wkc());
561 else if (write_start.get_wkc() != 1)
567 " initial mailbox write refused\n", __func__);
574 " repeated mailbox write refused\n", __func__);
582 bool WGMailbox::readMailboxRepeatRequest(
EthercatCom *com)
584 bool success = _readMailboxRepeatRequest(com);
585 ++mailbox_diagnostics_.retries_;
587 ++mailbox_diagnostics_.retry_errors_;
592 bool WGMailbox::_readMailboxRepeatRequest(
EthercatCom *com)
599 " could not read status mailbox syncman (1)\n", __func__);
604 if (sm.activate.repeat_request != sm.pdi_control.repeat_ack) {
606 " syncman repeat request and ack do not match\n", __func__);
611 SyncManActivate orig_activate(sm.activate);
612 sm.activate.repeat_request = ~orig_activate.repeat_request;
615 " could not write syncman repeat request\n", __func__);
621 static const int MAX_WAIT_TIME_MS = 100;
624 struct timespec start_time, current_time;
632 " could not read status mailbox syncman (2)\n", __func__);
636 if (sm.activate.repeat_request == sm.pdi_control.repeat_ack) {
638 if (sm.status.mailbox_status != 1) {
640 " got repeat response, but read mailbox is still empty\n", __func__);
647 if ( (sm.activate.repeat_request) == (orig_activate.repeat_request) ) {
649 " syncman repeat request was changed while waiting for response\n", __func__);
661 }
while (timediff < MAX_WAIT_TIME_MS);
664 " error repeat request not acknowledged after %d ms\n", __func__, timediff);
681 bool WGMailbox::readMailboxInternal(
EthercatCom *com,
void *data,
unsigned length)
683 static const unsigned MAX_TRIES = 10;
684 static const unsigned MAX_DROPPED = 10;
686 if (
length > MBX_STATUS_SIZE) {
687 assert(
length <= MBX_STATUS_SIZE);
692 if (!verifyDeviceStateForMailboxOperation()){
696 EC_Logic *logic = EC_Logic::instance();
697 EC_UINT station_addr = sh_->get_station_address();
703 static const unsigned TELEGRAM_OVERHEAD = 50;
704 bool split_read = (
length+TELEGRAM_OVERHEAD) < MBX_STATUS_SIZE;
706 unsigned read_length = MBX_STATUS_SIZE;
711 unsigned char unused[1] = {0};
712 NPRD_Telegram read_start(
718 (
unsigned char*) data);
719 NPRD_Telegram read_end(
722 MBX_STATUS_PHY_ADDR+MBX_STATUS_SIZE-1,
728 read_start.attach(&read_end);
731 EC_Ethernet_Frame frame(&read_start);
734 unsigned total_dropped =0;
735 for (tries=0; tries<MAX_TRIES; ++tries) {
739 for (dropped=0; dropped<MAX_DROPPED; ++dropped) {
748 if (dropped>=MAX_DROPPED) {
750 " too many dropped packets : %d\n", __func__, dropped);
753 if (split_read && (read_start.get_wkc() != read_end.get_wkc())) {
755 "read mbx working counters are inconsistant\n", __func__);
759 if (read_start.get_wkc() == 0) {
762 " inconsistancy : got wkc=%d with no dropped packets\n",
763 __func__, read_start.get_wkc());
764 fprintf(stderr,
"total dropped = %d\n", total_dropped);
770 " asking for read repeat after dropping %d packets\n", __func__, dropped);
771 if (!readMailboxRepeatRequest(com)) {
776 }
else if (read_start.get_wkc() == 1) {
781 " invalid wkc for read : %d\n", __func__, read_start.get_wkc());
782 diagnoseMailboxError(com);
787 if (tries >= MAX_TRIES) {
789 " could not get responce from device after %d retries, %d total dropped packets\n",
790 __func__, tries, total_dropped);
791 diagnoseMailboxError(com);
812 int WGMailbox::readMailbox(
EthercatCom *com,
unsigned address,
void *data,
unsigned length)
817 int result = readMailbox_(com, address, data,
length);
819 ++mailbox_diagnostics_.read_errors_;
831 int WGMailbox::readMailbox_(
EthercatCom *com,
unsigned address,
void *data,
unsigned length)
834 if (!verifyDeviceStateForMailboxOperation()){
839 if (!clearReadMailbox(com))
842 " clearing read mbx\n", __func__);
852 " builing mbx header\n", __func__);
856 if (!writeMailboxInternal(com, &
cmd.hdr_,
sizeof(
cmd.hdr_)))
858 fprintf(stderr,
"%s : " ERROR_HDR " write of cmd failed\n", __func__);
864 if (!waitForReadMailboxReady(com))
867 "waiting for read mailbox\n", __func__);
883 memset(&stat,0,
sizeof(stat));
885 if (!readMailboxInternal(com, &stat,
length+1))
887 fprintf(stderr,
"%s : " ERROR_HDR " read failed\n", __func__);
894 "checksum error reading mailbox data\n", __func__);
895 fprintf(stderr,
"length = %d\n",
length);
898 memcpy(data, &stat,
length);
906 bool WGMailbox::lockMailbox()
908 int error = pthread_mutex_lock(&mailbox_lock_);
910 fprintf(stderr,
"%s : " ERROR_HDR " getting mbx lock\n", __func__);
911 ++mailbox_diagnostics_.lock_errors_;
917 void WGMailbox::unlockMailbox()
919 int error = pthread_mutex_unlock(&mailbox_lock_);
921 fprintf(stderr,
"%s : " ERROR_HDR " freeing mbx lock\n", __func__);
922 ++mailbox_diagnostics_.lock_errors_;
939 int WGMailbox::writeMailbox(
EthercatCom *com,
unsigned address,
void const *data,
unsigned length)
944 int result = writeMailbox_(com, address, data,
length);
946 ++mailbox_diagnostics_.write_errors_;
959 int WGMailbox::writeMailbox_(
EthercatCom *com,
unsigned address,
void const *data,
unsigned length)
962 if (!verifyDeviceStateForMailboxOperation()){
970 fprintf(stderr,
"%s : " ERROR_HDR " builing mbx header\n", __func__);
974 unsigned write_length =
sizeof(
cmd.hdr_)+
length+
sizeof(
cmd.checksum_);
975 if (!writeMailboxInternal(com, &cmd, write_length)) {
976 fprintf(stderr,
"%s : " ERROR_HDR " write failed\n", __func__);
977 diagnoseMailboxError(com);
984 if (!waitForWriteMailboxReady(com)) {
986 "write mailbox\n", __func__);
996 mailbox_publish_diagnostics_ = mailbox_diagnostics_;
1003 d.addf(
"Mailbox Retries",
"%d", m.
retries_);