2023-05-03 14:01:32 +03:00
|
|
|
|
/*
|
|
|
|
|
|
* eth_ecat.hpp
|
|
|
|
|
|
*
|
2024-02-21 10:41:56 +03:00
|
|
|
|
* Created on: 16 апр. 2023 г.
|
|
|
|
|
|
* Author: algin
|
2023-05-03 14:01:32 +03:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_HPP_
|
|
|
|
|
|
#define FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_HPP_
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
2023-05-04 18:00:43 +03:00
|
|
|
|
#include <utility>
|
|
|
|
|
|
#include <kernel/dpl/ClockP.h>
|
2023-05-03 14:01:32 +03:00
|
|
|
|
|
2023-06-26 18:22:30 +03:00
|
|
|
|
#include "free_rtos/handler_store/handler.hpp"
|
|
|
|
|
|
#include "free_rtos/ethernet/eth_frame.h"
|
|
|
|
|
|
#include "free_rtos/timer/timer.hpp"
|
|
|
|
|
|
#include "free_rtos/mutex/mutex.hpp"
|
|
|
|
|
|
#include "free_rtos/semaphore/semaphore.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include "free_rtos/ethernet/eth.hpp"
|
|
|
|
|
|
#include "free_rtos/ethernet_industry/ethercattype.hpp"
|
|
|
|
|
|
#include "free_rtos/ethernet_industry/eth_ecat_types.h"
|
|
|
|
|
|
#include "free_rtos/ethernet_industry/eth_ecat_command.hpp"
|
|
|
|
|
|
#include "free_rtos/ethernet_industry/eth_ecat_datagram.hpp"
|
|
|
|
|
|
#include "free_rtos/ethernet_industry/eth_ecat_telegram.hpp"
|
|
|
|
|
|
#include "free_rtos/ethernet_industry/eth_ecat_eeprom.hpp"
|
2023-05-03 14:01:32 +03:00
|
|
|
|
|
|
|
|
|
|
namespace free_rtos {
|
|
|
|
|
|
|
2023-05-04 18:00:43 +03:00
|
|
|
|
struct ALSTAT {
|
|
|
|
|
|
uint16_t state;
|
|
|
|
|
|
uint16_t fault;
|
2023-05-03 14:01:32 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class EcatSlave {
|
|
|
|
|
|
public:
|
2023-05-04 18:00:43 +03:00
|
|
|
|
EcatSlave(address::SlaveAddresses&& slave_addresses)
|
|
|
|
|
|
: slave_addresses_{slave_addresses} {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-26 16:21:27 +03:00
|
|
|
|
EcatSlave() { }
|
2023-05-03 14:01:32 +03:00
|
|
|
|
|
|
|
|
|
|
template<typename TypeT>
|
|
|
|
|
|
void set_slave_address(typename TypeT::TSlaveAddress&& slave_address) {
|
2023-05-25 10:20:33 +03:00
|
|
|
|
free_rtos::get<static_cast<size_t>(TypeT::type)>(slave_addresses_) = slave_address;
|
2023-05-03 14:01:32 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename TypeT>
|
|
|
|
|
|
typename TypeT::TSlaveAddress& get_slave_address() {
|
2023-05-25 10:20:33 +03:00
|
|
|
|
return free_rtos::get<static_cast<size_t>(TypeT::type)>(slave_addresses_);
|
2023-05-03 14:01:32 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-04 18:00:43 +03:00
|
|
|
|
template<typename TypeT>
|
2023-09-06 18:09:23 +03:00
|
|
|
|
bool enable_PDI(telegram::EcatTelegram& telegram, const datagram::TEcatWkc expected_wkc) {
|
2023-05-04 18:00:43 +03:00
|
|
|
|
using TCommand = command::EcatCommand<TypeT, command::WR>;
|
|
|
|
|
|
auto slave_address = get_slave_address<TypeT>();
|
|
|
|
|
|
uint8_t data{0x01};
|
2023-09-06 18:09:23 +03:00
|
|
|
|
datagram::EcatDatagram<TCommand, uint8_t> datagram{ {{slave_address, ECT_REG_EEPCFG}}, expected_wkc, data };
|
2023-05-04 18:00:43 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
return telegram.transfer(datagram);
|
2023-05-04 18:00:43 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename TypeT>
|
2023-09-06 18:09:23 +03:00
|
|
|
|
bool init_to_preop(telegram::EcatTelegram& telegram, const datagram::TEcatWkc expected_wkc) {
|
2023-05-04 18:00:43 +03:00
|
|
|
|
auto slave_address = get_slave_address<TypeT>();
|
|
|
|
|
|
ALSTAT stat{0x0000, 0x0000};
|
2023-09-06 18:09:23 +03:00
|
|
|
|
bool status;
|
2023-05-04 18:00:43 +03:00
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
using TCommand = command::EcatCommand<TypeT, command::WR>;
|
2023-05-10 15:10:01 +03:00
|
|
|
|
uint16_t data{EC_STATE_PRE_OP|EC_STATE_ACK};
|
2023-09-06 18:09:23 +03:00
|
|
|
|
datagram::EcatDatagram<TCommand, uint16_t> datagram{ {{slave_address, ECT_REG_ALCTL}}, expected_wkc, data };
|
2023-05-04 18:00:43 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
status = telegram.transfer(datagram);
|
|
|
|
|
|
|
|
|
|
|
|
if(status != true) {
|
|
|
|
|
|
return status;
|
|
|
|
|
|
}
|
2023-05-04 18:00:43 +03:00
|
|
|
|
}
|
2023-05-03 14:01:32 +03:00
|
|
|
|
|
2023-05-23 10:17:24 +03:00
|
|
|
|
ClockP_usleep(5000000ul);
|
2023-05-03 14:01:32 +03:00
|
|
|
|
|
2023-05-04 18:00:43 +03:00
|
|
|
|
{
|
|
|
|
|
|
using TCommand = command::EcatCommand<TypeT, command::RD>;
|
2023-09-06 18:09:23 +03:00
|
|
|
|
datagram::EcatDatagram<TCommand, ALSTAT> datagram{ {{slave_address, ECT_REG_ALSTAT}}, expected_wkc, stat };
|
|
|
|
|
|
|
|
|
|
|
|
status = telegram.transfer(datagram);
|
2023-05-04 18:00:43 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
if(status != true) {
|
|
|
|
|
|
return status;
|
|
|
|
|
|
}
|
2023-05-04 18:00:43 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-06-08 14:46:25 +03:00
|
|
|
|
DebugP_log((char*)"stat.state = %d, stat.fault = %d\r\n", stat.state, stat.fault);
|
2023-05-04 18:00:43 +03:00
|
|
|
|
|
2023-05-23 10:17:24 +03:00
|
|
|
|
if((stat.state & 0x0010) != 0) {
|
|
|
|
|
|
using TCommand = command::EcatCommand<TypeT, command::RD>;
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t stat_code{0x0000};
|
2023-09-06 18:09:23 +03:00
|
|
|
|
datagram::EcatDatagram<TCommand, uint16_t> datagram{ {{slave_address, ECT_REG_ALSTATCODE}}, expected_wkc, stat_code};
|
|
|
|
|
|
|
|
|
|
|
|
status = telegram.transfer(datagram);
|
2023-05-23 10:17:24 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
if(status != true) {
|
|
|
|
|
|
return status;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DebugP_log((char*)"stat_code = 0x%02x\r\n", stat_code);
|
2023-05-23 10:17:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
status = ((stat.state == EC_STATE_PRE_OP) && (stat.fault == 0));
|
|
|
|
|
|
|
|
|
|
|
|
return status;
|
2023-05-04 18:00:43 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-23 10:17:24 +03:00
|
|
|
|
template<typename TypeT>
|
2023-09-06 18:09:23 +03:00
|
|
|
|
bool preop_to_safeop(telegram::EcatTelegram& telegram, const datagram::TEcatWkc expected_wkc) {
|
2023-05-23 10:17:24 +03:00
|
|
|
|
auto slave_address = get_slave_address<TypeT>();
|
|
|
|
|
|
ALSTAT stat{0x0000, 0x0000};
|
|
|
|
|
|
uint32_t zero{0x00000000};
|
2023-09-06 18:09:23 +03:00
|
|
|
|
bool status;
|
2023-05-23 10:17:24 +03:00
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
using TCommand = command::EcatCommand<TypeT, command::WR>;
|
|
|
|
|
|
uint16_t data{EC_STATE_SAFE_OP};
|
2023-09-06 18:09:23 +03:00
|
|
|
|
datagram::EcatDatagram<TCommand, uint16_t> datagram{ {{slave_address, ECT_REG_ALCTL}}, expected_wkc, data };
|
2023-05-23 10:17:24 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
status = telegram.transfer(datagram);
|
|
|
|
|
|
|
|
|
|
|
|
if(status != true) {
|
|
|
|
|
|
return status;
|
|
|
|
|
|
}
|
2023-05-23 10:17:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-15 15:37:33 +03:00
|
|
|
|
ClockP_usleep(1500000ul);
|
2023-05-23 10:17:24 +03:00
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
using TCommand = command::EcatCommand<TypeT, command::RD>;
|
2023-09-06 18:09:23 +03:00
|
|
|
|
datagram::EcatDatagram<TCommand, ALSTAT, uint32_t> datagram{ {{slave_address, ECT_REG_ALSTAT}}, expected_wkc, stat, zero };
|
|
|
|
|
|
|
|
|
|
|
|
status = telegram.transfer(datagram);
|
2023-05-23 10:17:24 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
if(status != true) {
|
|
|
|
|
|
return status;
|
|
|
|
|
|
}
|
2023-05-23 10:17:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-06-08 14:46:25 +03:00
|
|
|
|
DebugP_log((char*)"stat.state = %d, stat.fault = %d\r\n", stat.state, stat.fault);
|
2023-05-23 10:17:24 +03:00
|
|
|
|
|
|
|
|
|
|
if((stat.state & 0x0010) != 0) {
|
|
|
|
|
|
using TCommand = command::EcatCommand<TypeT, command::RD>;
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t stat_code{0x0000};
|
2023-09-06 18:09:23 +03:00
|
|
|
|
datagram::EcatDatagram<TCommand, uint16_t> datagram{ {{slave_address, ECT_REG_ALSTATCODE}}, expected_wkc, stat_code};
|
|
|
|
|
|
|
|
|
|
|
|
status = telegram.transfer(datagram);
|
2023-05-23 10:17:24 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
if(status != true) {
|
|
|
|
|
|
return status;
|
|
|
|
|
|
}
|
2023-05-23 10:17:24 +03:00
|
|
|
|
|
2023-06-08 14:46:25 +03:00
|
|
|
|
DebugP_log((char*)"stat_code = 0x%02x\r\n", stat_code);
|
2023-05-23 10:17:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
status = ((stat.state == EC_STATE_SAFE_OP) && (stat.fault == 0));
|
|
|
|
|
|
|
|
|
|
|
|
return status;
|
2023-05-23 10:17:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-04 18:00:43 +03:00
|
|
|
|
private:
|
|
|
|
|
|
address::SlaveAddresses slave_addresses_;
|
2023-05-03 14:01:32 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
2023-05-25 17:24:47 +03:00
|
|
|
|
class EthEcat {
|
2023-05-03 14:01:32 +03:00
|
|
|
|
public:
|
|
|
|
|
|
struct Statistic {
|
|
|
|
|
|
uint32_t rx_pkt;
|
|
|
|
|
|
uint32_t tx_pkt;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
EthEcat(Eth& eth);
|
|
|
|
|
|
|
2023-06-19 11:33:11 +03:00
|
|
|
|
void Init(TEthMacPorts port_id, uint32_t period_microsec);
|
2023-05-03 14:01:32 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
bool set_slaves_to_default();
|
2023-05-03 14:01:32 +03:00
|
|
|
|
uint16_t slaves_detecting();
|
2023-09-06 18:09:23 +03:00
|
|
|
|
bool set_addresses_of_slaves(uint16_t number_of_slaves, uint16_t address_base);
|
|
|
|
|
|
bool get_addresses_of_slaves();
|
2023-10-04 10:33:21 +03:00
|
|
|
|
bool connection_test();
|
2023-05-03 14:01:32 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
bool config_init(uint16_t address_base);
|
2023-05-04 18:00:43 +03:00
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
bool enable_PDI();
|
2023-05-23 10:17:24 +03:00
|
|
|
|
|
2023-05-04 18:00:43 +03:00
|
|
|
|
bool init_to_preop();
|
2023-05-23 10:17:24 +03:00
|
|
|
|
bool preop_to_safeop();
|
|
|
|
|
|
bool safeop_to_op();
|
2023-05-04 18:00:43 +03:00
|
|
|
|
|
2023-05-03 14:01:32 +03:00
|
|
|
|
/*
|
|
|
|
|
|
* Тип адресации slave_address зависит от типа команды CommandT
|
|
|
|
|
|
* Может иметь тип Position, Broadcast, Node
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<typename TypeT, typename DirT, typename EcatDgDataT>
|
|
|
|
|
|
void simple_send_datagram(typename TypeT::TSlaveAddress& slave_address, uint16_t offset, EcatDgDataT& data) {
|
|
|
|
|
|
using TCommand = command::EcatCommand<TypeT, DirT>;
|
|
|
|
|
|
datagram::EcatDatagram<TCommand, EcatDgDataT> datagram{ {{slave_address, offset}}, data };
|
|
|
|
|
|
|
|
|
|
|
|
telegram_.transfer(datagram);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-06-06 10:27:01 +03:00
|
|
|
|
telegram::EcatTelegram& get_telegram() {
|
2023-05-03 14:01:32 +03:00
|
|
|
|
return telegram_;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-06 18:09:23 +03:00
|
|
|
|
const telegram::EcatTelegramStatus& get_telegram_status() {
|
|
|
|
|
|
return telegram_.get_status();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-03 14:01:32 +03:00
|
|
|
|
eeprom::EEPROM& get_eeprom() {
|
|
|
|
|
|
return eeprom_;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-04 18:00:43 +03:00
|
|
|
|
std::vector<EcatSlave>& get_slaves() {
|
|
|
|
|
|
return slaves_;
|
|
|
|
|
|
}
|
2023-05-03 14:01:32 +03:00
|
|
|
|
|
2023-06-06 10:27:01 +03:00
|
|
|
|
free_rtos::Timer& get_ecat_timer() {
|
|
|
|
|
|
return ecat_timer_;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-23 18:41:31 +03:00
|
|
|
|
free_rtos::Semaphore& get_init_sem() {
|
|
|
|
|
|
return init_sem_;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
free_rtos::Semaphore& get_process_sem() {
|
|
|
|
|
|
return process_sem_;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-03 14:01:32 +03:00
|
|
|
|
bool is_ready() { return ready_; }
|
|
|
|
|
|
|
|
|
|
|
|
Statistic getStat() { return stat_;}
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
enum {
|
|
|
|
|
|
e_pktFirst,
|
|
|
|
|
|
e_pktSecond,
|
|
|
|
|
|
e_pktTotal
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2023-09-20 15:52:57 +03:00
|
|
|
|
static constexpr uint32_t process_timeout_ticks_ = 5000;
|
2023-09-15 15:37:33 +03:00
|
|
|
|
|
2023-06-06 10:27:01 +03:00
|
|
|
|
free_rtos::Timer ecat_timer_;
|
|
|
|
|
|
|
2023-05-03 14:01:32 +03:00
|
|
|
|
free_rtos::Semaphore rx_sem_;
|
|
|
|
|
|
|
2023-05-23 18:41:31 +03:00
|
|
|
|
free_rtos::Semaphore init_sem_;
|
|
|
|
|
|
free_rtos::Semaphore process_sem_;
|
|
|
|
|
|
|
2023-05-03 14:01:32 +03:00
|
|
|
|
Eth& eth_;
|
|
|
|
|
|
EthTxFlowIface& tx_flow_;
|
|
|
|
|
|
|
2023-06-06 10:27:01 +03:00
|
|
|
|
telegram::EcatTelegram telegram_;
|
2023-05-03 14:01:32 +03:00
|
|
|
|
eeprom::EEPROM eeprom_;
|
|
|
|
|
|
|
2024-02-21 10:41:56 +03:00
|
|
|
|
TEthMacPorts port_id_;
|
2023-05-03 14:01:32 +03:00
|
|
|
|
|
|
|
|
|
|
bool ready_;
|
|
|
|
|
|
|
|
|
|
|
|
Statistic stat_;
|
|
|
|
|
|
|
2023-05-04 18:00:43 +03:00
|
|
|
|
std::vector<EcatSlave> slaves_;
|
2023-05-03 14:01:32 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_HPP_ */
|