/* * eth_ecat_telegram.cpp * * Created on: Jun 5, 2023 * Author: algin */ #include "free_rtos/ethernet_industry/eth_ecat_telegram.hpp" namespace free_rtos { namespace telegram { const char EcatTelegramStatus::SuccessString[] = "Success !"; const char EcatTelegramStatus::BusyString[] = "Busy. Transfer in progress..."; const char EcatTelegramStatus::WarningTransferErrorString[] = "Warning ! Transfer error. Check error counters"; const char EcatTelegramStatus::WarningTimeoutErrorString[] = "Warning ! Connection timeout error. Check error counters"; const char EcatTelegramStatus::WarningWkcErrorString[] = "Warning ! WKC error. Check error counters"; const char EcatTelegramStatus::FatalErrorString[] = "Fatal error ! Transfer attempts exceeded"; const EcatDescription EcatTelegramStatus::descriptions[] = { {EcatTelegramStatus::SuccessString, sizeof(EcatTelegramStatus::SuccessString)}, {EcatTelegramStatus::BusyString, sizeof(EcatTelegramStatus::BusyString)}, {EcatTelegramStatus::WarningTransferErrorString, sizeof(EcatTelegramStatus::WarningTransferErrorString)}, {EcatTelegramStatus::WarningTimeoutErrorString, sizeof(EcatTelegramStatus::WarningTimeoutErrorString)}, {EcatTelegramStatus::WarningWkcErrorString, sizeof(EcatTelegramStatus::WarningWkcErrorString)}, {EcatTelegramStatus::FatalErrorString, sizeof(EcatTelegramStatus::FatalErrorString)} }; int32_t EcatTelegram::Process(uint8_t *p_data, uint32_t len) { // TODO: Don't forget to subtract sizeof(TEthFrameHeader) ! uint8_t *p_datagram_last = unpack(p_data - sizeof(TEthFrameHeader)); if(p_datagram_last == nullptr) { //DebugP_log((char*)"Warning ! Repeated packet skipped\r\n"); return 0; } /* DebugP_log((char*)"Process started\r\n"); for(uint8_t *data = p_data; data < p_data + len; data++) { DebugP_log((char*)"0x%01x ", *data); } DebugP_log((char*)"\r\n"); */ rx_sem_.post(); return 0; } uint32_t EcatTelegram::Sender(uint8_t *p_data, size_t scatter_segment) { uint8_t *raw = pack(p_data); //DebugP_log((char*)"Sender started\r\n"); return raw - p_data; } uint8_t* EcatTelegram::pack(uint8_t *raw) { TEthFrameHeader *p_eth_hdr = new(raw) TEthFrameHeader{ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, ETH_PROT_ECAT_LE }; TEcatFrameHeader *p_hdr = new(raw + sizeof(TEthFrameHeader)) TEcatFrameHeader{ .bits = { .length = 0, .type = static_cast(ec_network::PROTOCOL_TYPE) } }; uint8_t *p_datagram_first = raw + sizeof(TEthFrameHeader) + sizeof(TEcatFrameHeader); uint8_t *p_datagram_last = p_datagram_first; auto first = datagram_queue_.get_first(); (void)p_eth_hdr; (void)p_hdr; if(first != nullptr) { p_datagram_last = first->pack_all(p_datagram_first, idx_); } p_hdr->bits.length = p_datagram_last - p_datagram_first; return p_datagram_last; } uint8_t* EcatTelegram::unpack(uint8_t *raw) { TEthFrameHeader *p_eth_hdr = reinterpret_cast(raw); TEcatFrameHeader *p_hdr = reinterpret_cast(raw + sizeof(TEthFrameHeader)); uint8_t *p_datagram_first = raw + sizeof(TEthFrameHeader) + sizeof(TEcatFrameHeader); uint8_t *p_datagram_last = p_datagram_first; auto first = datagram_queue_.get_first(); if(first != nullptr) { p_datagram_last = first->unpack_all(p_datagram_first, idx_); } return p_datagram_last; } bool EcatTelegram::transfer() { auto first = datagram_queue_.get_first(); uint32_t transfer_attempts = 0; bool status = (first == nullptr); if(status == true) { status_.result = EcatTelegramResult::SUCCESS; return status; } status_.result = EcatTelegramResult::BUSY; first->reset_all_wkc(); while(1) { ecat_timer_.Wait(); transfer_attempts++; status = (transfer_attempts <= max_transfer_attempts_); if(status == false) { DebugP_log((char*)"%s\r\n", status_.get_description().string); status_.attempts_exceeded_errors++; status_.result = EcatTelegramResult::FATAL_ERROR; DebugP_log((char*)"%s: %d\r\n", status_.get_description().string, max_transfer_attempts_); break; } // status = eth_stack_.send_pkt(port_id_, ETH_PROT_ECAT_LE, 1); status = tx_flow_.send(port_id_, this, 1); if(status == false) { status_.transfer_errors++; status_.result = EcatTelegramResult::WARNING_TRANSFER_ERROR; //DebugP_log((char*)"%s: %d\r\n", status_.get_description().string, status_.transfer_errors); continue; } status = (rx_sem_.pend(connection_timeout_ticks_) == SystemP_SUCCESS); if(status == false) { status_.transfer_errors++; status_.result = EcatTelegramResult::WARNING_TIMEOUT_ERROR; //DebugP_log((char*)"%s: %d\r\n", status_.get_description().string, status_.transfer_errors); continue; } status = first->all_as_expected(); if(status == false) { status_.expected_wkc_errors++; status_.result = EcatTelegramResult::WARNING_WKC_ERROR; //DebugP_log((char*)"%s: %d\r\n", status_.get_description().string, status_.expected_wkc_errors); continue; } status_.result = EcatTelegramResult::SUCCESS; break; } datagram_queue_.clear(); ++idx_; return status; } bool EcatTelegram::transfer(datagram::IEcatDatagram& next) { datagram_queue_ + next; return transfer(); } bool EcatTelegram::transfer(queue::Queue& next) { datagram_queue_ + next; return transfer(); } } }