/* * eth_ecat_telegram.hpp * * Created on: Jun 5, 2023 * Author: algin */ #ifndef FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_TELEGRAM_HPP_ #define FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_TELEGRAM_HPP_ #include "free_rtos/ethernet/eth.hpp" #include "free_rtos/timer/timer.hpp" #include "free_rtos/profiler/quick_profiler_static.hpp" #include "free_rtos/ethernet_industry/eth_ecat_datagram.hpp" namespace free_rtos { namespace telegram { enum class EcatTelegramResult : uint16_t { SUCCESS = 0, BUSY, WARNING_TRANSFER_ERROR, WARNING_TIMEOUT_ERROR, WARNING_WKC_ERROR, FATAL_ERROR }; struct EcatDescription { const char* string; const size_t length; }; struct EcatTelegramStatus { uint16_t transfer_errors{0x0000}; uint16_t expected_wkc_errors{0x0000}; uint16_t attempts_exceeded_errors{0x0000}; EcatTelegramResult result = EcatTelegramResult::BUSY; const EcatDescription& get_description() { return descriptions[static_cast(result)]; } const EcatDescription& get_description(EcatTelegramResult res) { return descriptions[static_cast(res)]; } private: static const char SuccessString[]; static const char BusyString[]; static const char WarningTransferErrorString[]; static const char WarningTimeoutErrorString[]; static const char WarningWkcErrorString[]; static const char FatalErrorString[]; static const EcatDescription descriptions[]; }; class EcatTelegram : public Handler { public: EcatTelegram(Eth& eth, Timer& ecat_timer) : eth_{eth} , ecat_timer_(ecat_timer) , tx_flow_{*eth.getTxFlowPtr()} , eth_stack_{*eth.getEthStackPtr()} { } const EcatTelegramStatus& get_status() { return status_; } virtual int32_t Process(uint8_t *p_data, uint32_t len) override; virtual uint16_t Sender(HandlerArgs& handlerArgs, size_t scatter_segment) override; void init(TEthMacPorts port_id, uint32_t period_microsec, uint32_t max_transfer_attempts) { port_id_ = port_id; period_microsec_ = period_microsec; counter_timeout_ticks_ = (semaphore_timeout_ticks_*1000)/period_microsec; max_transfer_attempts_ = max_transfer_attempts; eth_.getEthStackPtr()->Register(ETH_PROT_ECAT_LE, this); } inline static uint32_t diff(uint32_t tick_counter_start, uint32_t tick_counter_current) { uint32_t tick_counter_diff; if(tick_counter_current >= tick_counter_start) { tick_counter_diff = tick_counter_current - tick_counter_start; }else{ tick_counter_diff = tick_counter_current + (0xFFFFFFFF - tick_counter_start); } return tick_counter_diff; } bool transfer(datagram::IEcatDatagram& next); bool transfer(queue::Queue& next); private: static constexpr uint32_t semaphore_timeout_ticks_ = 3; static constexpr uint32_t semaphore_timeout_tolerance_ = 4; Eth& eth_; Timer& ecat_timer_; EthTxFlowIface& tx_flow_; EthStackIface& eth_stack_; TEthMacPorts port_id_; uint32_t period_microsec_{250}; uint32_t counter_timeout_ticks_{8}; uint32_t max_transfer_attempts_{4}; free_rtos::Semaphore rx_sem_; uint8_t idx_{0x00}; queue::Queue datagram_queue_; //datagram::IEcatDatagram *datagram_queue_{nullptr}; EcatTelegramStatus status_{0x0000, 0x0000, 0x0000, EcatTelegramResult::BUSY}; bool transfer(); uint8_t* pack(uint8_t *raw); uint8_t* unpack(uint8_t *raw); }; } } #endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_TELEGRAM_HPP_ */