/* * eth_ecat.cpp * * Created on: 16 ���. 2023 �. * Author: sychev */ #include "ethernet_industry/eth_ecat.hpp" #include #include namespace free_rtos { EthEcat::EthEcat(Eth& eth) : p_pkt_{&pkt_[e_pktFirst]} , p_pkt_next_{&pkt_[e_pktSecond]} , eth_{eth} , tx_flow_{*eth.getTxFlowPtr()} , telegram_{eth} , eeprom_{telegram_} { } void EthEcat::Init(TEthMacPorts port_id) { port_id_ = port_id; telegram_.init(port_id); } void EthEcat::set_slaves_to_default() { address::Broadcast broadcast{0x0000}; /* deact loop manual */ uint8_t a_data_out{0x00}; datagram::EcatDatagram a{ {{broadcast, ECT_REG_DLPORT}}, a_data_out }; /* set IRQ mask */ uint16_t b_data_out{0x0C04}; datagram::EcatDatagram b{ {{broadcast, ECT_REG_IRQMASK}}, b_data_out }; /* reset CRC counters */ std::array c_data_out; c_data_out.fill(0x00); datagram::EcatDatagram> c{ {{broadcast, ECT_REG_RXERR}}, c_data_out }; /* reset FMMU's */ std::array d_data_out; d_data_out.fill(0x00); datagram::EcatDatagram> d{ {{broadcast, ECT_REG_FMMU0}}, d_data_out }; /* reset SyncM */ std::array e_data_out; e_data_out.fill(0x00); datagram::EcatDatagram> e{ {{broadcast, ECT_REG_SM0}}, e_data_out }; /* reset activation register */ uint8_t f_data_out{0x00}; datagram::EcatDatagram f{ {{broadcast, ECT_REG_DCSYNCACT}}, f_data_out }; /* reset system time+ofs */ std::array g_data_out; g_data_out.fill(0x00); datagram::EcatDatagram> g{ {{broadcast, ECT_REG_DCSYSTIME}}, g_data_out }; /* DC speedstart */ uint16_t h_data_out{0x1000}; datagram::EcatDatagram h{ {{broadcast, ECT_REG_DCSPEEDCNT}}, h_data_out }; /* DC filt expr */ uint16_t i_data_out{0x0C00}; datagram::EcatDatagram i{ {{broadcast, ECT_REG_DCTIMEFILT}}, i_data_out }; /* Ignore Alias register */ uint8_t j_data_out{0x00}; datagram::EcatDatagram j{ {{broadcast, ECT_REG_DLALIAS}}, j_data_out }; /* Reset all slaves to Init */ uint16_t k_data_out{EC_STATE_INIT|EC_STATE_ACK}; datagram::EcatDatagram k{ {{broadcast, ECT_REG_ALCTL}}, k_data_out }; /* force Eeprom from PDI */ uint8_t l_data_out{0x02}; datagram::EcatDatagram l{ {{broadcast, ECT_REG_EEPCFG}}, l_data_out }; /* set Eeprom to master */ uint8_t m_data_out{0x00}; datagram::EcatDatagram m{ {{broadcast, ECT_REG_EEPCFG}}, m_data_out }; a + b + c + d + e + f + g + h + i + j + k + l + m; telegram_.transfer(a); //telegram_.transfer(b); //telegram_.transfer(c); //telegram_.transfer(d); //telegram_.transfer(e); //telegram_.transfer(f); //telegram_.transfer(g); //telegram_.transfer(h); //telegram_.transfer(i); //telegram_.transfer(j); //telegram_.transfer(k); //telegram_.transfer(l); //telegram_.transfer(m); DebugP_log("a.get_wkc() = %d\r\n", a.get_wkc()); DebugP_log("b.get_wkc() = %d\r\n", b.get_wkc()); DebugP_log("c.get_wkc() = %d\r\n", c.get_wkc()); DebugP_log("d.get_wkc() = %d\r\n", d.get_wkc()); DebugP_log("e.get_wkc() = %d\r\n", e.get_wkc()); DebugP_log("f.get_wkc() = %d\r\n", f.get_wkc()); DebugP_log("g.get_wkc() = %d\r\n", g.get_wkc()); DebugP_log("h.get_wkc() = %d\r\n", h.get_wkc()); DebugP_log("i.get_wkc() = %d\r\n", i.get_wkc()); DebugP_log("j.get_wkc() = %d\r\n", j.get_wkc()); DebugP_log("k.get_wkc() = %d\r\n", k.get_wkc()); DebugP_log("l.get_wkc() = %d\r\n", l.get_wkc()); DebugP_log("m.get_wkc() = %d\r\n", m.get_wkc()); } uint16_t EthEcat::slaves_detecting() { address::Broadcast broadcast{0x0000}; uint16_t data{0x0000}; datagram::EcatDatagram datagram{ {{broadcast, ECT_REG_TYPE}}, data }; telegram_.transfer(datagram); return datagram.get_wkc(); } void EthEcat::set_addresses_of_slaves(uint16_t number_of_slaves, uint16_t address_base) { // Setting Station address (FP) of slave via Position addressing (AP) // Station address is datagram data std::vector> datagrams; slaves_.reserve(number_of_slaves); datagrams.reserve(number_of_slaves); for(uint16_t i = 0; i < number_of_slaves; i++) { address::Position position{static_cast(-i)}; address::Station node{static_cast(address_base + i)}; address::SlaveAddresses slave_addresses{position, 0x0000, node, 0x00000000}; slaves_.push_back(EcatSlave{std::move(slave_addresses)}); datagrams.push_back({ {{position, ECT_REG_STADR}}, slaves_.back().get_slave_address() }); } for(uint16_t i = 1; i < number_of_slaves; i++) { datagrams[i - 1] + datagrams[i]; } telegram_.transfer(datagrams[0]); } void EthEcat::get_addresses_of_slaves() { std::vector> datagrams; datagrams.reserve(slaves_.size()); for(EcatSlave& slave : slaves_) { datagrams.push_back({ {{slave.get_slave_address(), ECT_REG_STADR}}, slave.get_slave_address() }); } for(uint16_t i = 1; i < slaves_.size(); i++) { datagrams[i - 1] + datagrams[i]; } telegram_.transfer(datagrams[0]); for(EcatSlave& slave : slaves_) { DebugP_log("Slave %d address = %d\r\n", -slave.get_slave_address(), slave.get_slave_address()); } } uint16_t EthEcat::config_init() { DebugP_log("Initializing slaves...\r\n"); set_slaves_to_default(); uint16_t number_of_slaves = slaves_detecting(); DebugP_log("number_of_slaves = %d\r\n", number_of_slaves); set_addresses_of_slaves(number_of_slaves, 0x1000); get_addresses_of_slaves(); return number_of_slaves; } void EthEcat::enable_PDI() { for(EcatSlave& slave : slaves_) { slave.enable_PDI(telegram_); } } bool EthEcat::init_to_preop() { bool success = true; for(EcatSlave& slave : slaves_) { success &= slave.init_to_preop(telegram_); } DebugP_log("success = %d\r\n", success); return success; } bool EthEcat::preop_to_safeop() { bool success = true; for(EcatSlave& slave : slaves_) { success &= slave.preop_to_safeop(telegram_); } DebugP_log("success = %d\r\n", success); return success; } bool EthEcat::safeop_to_op() { bool success; address::Broadcast broadcast{0x0000}; ALSTAT stat{0x0000, 0x0000}; uint16_t zero{0x00000000}; process_sem_.post(); init_sem_.pend(); { uint16_t data{EC_STATE_OPERATIONAL}; datagram::EcatDatagram datagram{ {{broadcast, ECT_REG_ALCTL}}, data }; telegram_.transfer(datagram); DebugP_log("datagram.get_wkc() = %d\r\n", datagram.get_wkc()); } process_sem_.post(); init_sem_.pend(); { datagram::EcatDatagram datagram{ {{broadcast, ECT_REG_ALSTAT}}, stat, zero }; telegram_.transfer(datagram); DebugP_log("datagram.get_wkc() = %d\r\n", datagram.get_wkc()); } success = (stat.state == EC_STATE_OPERATIONAL) && (stat.fault == 0); //ClockP_usleep(3000000ul); if(success == true) { process_sem_.post(); } DebugP_log("stat.state = %d, stat.fault = %d\r\n", stat.state, stat.fault); DebugP_log("success = %d\r\n", success); return success; } }