From ae3cac8a7d1bf1d2e186b4df34d14126ca3b5b8f Mon Sep 17 00:00:00 2001 From: algin Date: Wed, 3 May 2023 14:01:32 +0300 Subject: [PATCH] feat: First commit Adds sitara_depot/free_rtos Original one is on server_gorbunov/SmartForce4.0/sitara_depot --- README.md | 1 + components/free_rtos/base/swap.h | 15 + components/free_rtos/clock/clock.cpp | 37 +++ components/free_rtos/clock/clock.hpp | 39 +++ components/free_rtos/ethernet/eth.cpp | 301 ++++++++++++++++++ components/free_rtos/ethernet/eth.hpp | 139 ++++++++ components/free_rtos/ethernet/eth_frame.h | 40 +++ components/free_rtos/ethernet/eth_ioctl.c | 41 +++ components/free_rtos/ethernet/eth_ioctl.h | 24 ++ components/free_rtos/ethernet/eth_rx_flow.cpp | 227 +++++++++++++ components/free_rtos/ethernet/eth_rx_flow.hpp | 73 +++++ .../free_rtos/ethernet/eth_ti_enet_inst.c | 160 ++++++++++ components/free_rtos/ethernet/eth_tx_flow.cpp | 227 +++++++++++++ components/free_rtos/ethernet/eth_tx_flow.hpp | 52 +++ .../free_rtos/ethernet/eth_tx_flow_iface.hpp | 22 ++ components/free_rtos/ethernet/eth_types.h | 17 + components/free_rtos/ethernet/eth_vlan.c | 300 +++++++++++++++++ components/free_rtos/ethernet/eth_vlan.h | 62 ++++ .../free_rtos/ethernet_industry/eth_ecat.cpp | 211 ++++++++++++ .../free_rtos/ethernet_industry/eth_ecat.hpp | 141 ++++++++ .../ethernet_industry/eth_ecat_command.hpp | 230 +++++++++++++ .../ethernet_industry/eth_ecat_datagram.cpp | 70 ++++ .../ethernet_industry/eth_ecat_datagram.hpp | 205 ++++++++++++ .../ethernet_industry/eth_ecat_eeprom.hpp | 82 +++++ .../ethernet_industry/eth_ecat_types.h | 60 ++++ .../ethernet_industry/ethercattype.hpp | 300 +++++++++++++++++ components/free_rtos/ethernet_ip/eth_arp.cpp | 206 ++++++++++++ components/free_rtos/ethernet_ip/eth_arp.hpp | 79 +++++ .../free_rtos/ethernet_ip/eth_arp_iface.hpp | 24 ++ .../free_rtos/ethernet_ip/eth_checksum.c | 27 ++ .../free_rtos/ethernet_ip/eth_checksum.h | 23 ++ components/free_rtos/ethernet_ip/eth_icmp.cpp | 42 +++ components/free_rtos/ethernet_ip/eth_icmp.hpp | 28 ++ .../free_rtos/ethernet_ip/eth_icmp_types.h | 57 ++++ components/free_rtos/ethernet_ip/eth_ip.cpp | 129 ++++++++ components/free_rtos/ethernet_ip/eth_ip.hpp | 50 +++ .../free_rtos/ethernet_ip/eth_ip_checksum.c | 22 ++ .../free_rtos/ethernet_ip/eth_ip_checksum.h | 23 ++ .../free_rtos/ethernet_ip/eth_ip_iface.hpp | 27 ++ .../free_rtos/ethernet_ip/eth_ip_prots_id.h | 16 + .../free_rtos/ethernet_ip/eth_ip_types.h | 51 +++ .../free_rtos/ethernet_ip/eth_prots_id.h | 19 ++ .../free_rtos/ethernet_ip/eth_stack.cpp | 101 ++++++ .../free_rtos/ethernet_ip/eth_stack.hpp | 71 +++++ .../free_rtos/ethernet_ip/eth_stack_iface.hpp | 43 +++ .../free_rtos/ethernet_ip/eth_udp_client.cpp | 129 ++++++++ .../free_rtos/ethernet_ip/eth_udp_client.hpp | 62 ++++ .../free_rtos/ethernet_ip/eth_udp_server.cpp | 75 +++++ .../free_rtos/ethernet_ip/eth_udp_server.hpp | 44 +++ .../ethernet_ip/eth_udp_server_iface.hpp | 28 ++ .../free_rtos/ethernet_ip/eth_udp_types.h | 21 ++ components/free_rtos/gpio/gpio.cpp | 54 ++++ components/free_rtos/gpio/gpio.hpp | 45 +++ .../free_rtos/handler_store/handler.hpp | 22 ++ .../free_rtos/handler_store/handler_store.cpp | 46 +++ .../free_rtos/handler_store/handler_store.hpp | 32 ++ components/free_rtos/mutex/mutex.cpp | 35 ++ components/free_rtos/mutex/mutex.hpp | 57 ++++ components/free_rtos/semaphore/semaphore.hpp | 57 ++++ components/free_rtos/task/task.cpp | 41 +++ components/free_rtos/task/task.hpp | 52 +++ components/free_rtos/timer/timer.cpp | 77 +++++ components/free_rtos/timer/timer.hpp | 56 ++++ components/free_rtos/timer_sw/timer_sw.cpp | 33 ++ components/free_rtos/timer_sw/timer_sw.hpp | 31 ++ 65 files changed, 5111 insertions(+) create mode 100644 components/free_rtos/base/swap.h create mode 100644 components/free_rtos/clock/clock.cpp create mode 100644 components/free_rtos/clock/clock.hpp create mode 100644 components/free_rtos/ethernet/eth.cpp create mode 100644 components/free_rtos/ethernet/eth.hpp create mode 100644 components/free_rtos/ethernet/eth_frame.h create mode 100644 components/free_rtos/ethernet/eth_ioctl.c create mode 100644 components/free_rtos/ethernet/eth_ioctl.h create mode 100644 components/free_rtos/ethernet/eth_rx_flow.cpp create mode 100644 components/free_rtos/ethernet/eth_rx_flow.hpp create mode 100644 components/free_rtos/ethernet/eth_ti_enet_inst.c create mode 100644 components/free_rtos/ethernet/eth_tx_flow.cpp create mode 100644 components/free_rtos/ethernet/eth_tx_flow.hpp create mode 100644 components/free_rtos/ethernet/eth_tx_flow_iface.hpp create mode 100644 components/free_rtos/ethernet/eth_types.h create mode 100644 components/free_rtos/ethernet/eth_vlan.c create mode 100644 components/free_rtos/ethernet/eth_vlan.h create mode 100644 components/free_rtos/ethernet_industry/eth_ecat.cpp create mode 100644 components/free_rtos/ethernet_industry/eth_ecat.hpp create mode 100644 components/free_rtos/ethernet_industry/eth_ecat_command.hpp create mode 100644 components/free_rtos/ethernet_industry/eth_ecat_datagram.cpp create mode 100644 components/free_rtos/ethernet_industry/eth_ecat_datagram.hpp create mode 100644 components/free_rtos/ethernet_industry/eth_ecat_eeprom.hpp create mode 100644 components/free_rtos/ethernet_industry/eth_ecat_types.h create mode 100644 components/free_rtos/ethernet_industry/ethercattype.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_arp.cpp create mode 100644 components/free_rtos/ethernet_ip/eth_arp.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_arp_iface.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_checksum.c create mode 100644 components/free_rtos/ethernet_ip/eth_checksum.h create mode 100644 components/free_rtos/ethernet_ip/eth_icmp.cpp create mode 100644 components/free_rtos/ethernet_ip/eth_icmp.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_icmp_types.h create mode 100644 components/free_rtos/ethernet_ip/eth_ip.cpp create mode 100644 components/free_rtos/ethernet_ip/eth_ip.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_ip_checksum.c create mode 100644 components/free_rtos/ethernet_ip/eth_ip_checksum.h create mode 100644 components/free_rtos/ethernet_ip/eth_ip_iface.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_ip_prots_id.h create mode 100644 components/free_rtos/ethernet_ip/eth_ip_types.h create mode 100644 components/free_rtos/ethernet_ip/eth_prots_id.h create mode 100644 components/free_rtos/ethernet_ip/eth_stack.cpp create mode 100644 components/free_rtos/ethernet_ip/eth_stack.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_stack_iface.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_udp_client.cpp create mode 100644 components/free_rtos/ethernet_ip/eth_udp_client.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_udp_server.cpp create mode 100644 components/free_rtos/ethernet_ip/eth_udp_server.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_udp_server_iface.hpp create mode 100644 components/free_rtos/ethernet_ip/eth_udp_types.h create mode 100644 components/free_rtos/gpio/gpio.cpp create mode 100644 components/free_rtos/gpio/gpio.hpp create mode 100644 components/free_rtos/handler_store/handler.hpp create mode 100644 components/free_rtos/handler_store/handler_store.cpp create mode 100644 components/free_rtos/handler_store/handler_store.hpp create mode 100644 components/free_rtos/mutex/mutex.cpp create mode 100644 components/free_rtos/mutex/mutex.hpp create mode 100644 components/free_rtos/semaphore/semaphore.hpp create mode 100644 components/free_rtos/task/task.cpp create mode 100644 components/free_rtos/task/task.hpp create mode 100644 components/free_rtos/timer/timer.cpp create mode 100644 components/free_rtos/timer/timer.hpp create mode 100644 components/free_rtos/timer_sw/timer_sw.cpp create mode 100644 components/free_rtos/timer_sw/timer_sw.hpp diff --git a/README.md b/README.md index 9fed7fd..468eb49 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # sitara_depot +Хранилище программных модулей для процессора Sitara AM64x diff --git a/components/free_rtos/base/swap.h b/components/free_rtos/base/swap.h new file mode 100644 index 0000000..6478d1a --- /dev/null +++ b/components/free_rtos/base/swap.h @@ -0,0 +1,15 @@ +/* + * swap.h + * + * Created on: 13 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_BASE_SWAP_H_ +#define FREE_RTOS_BASE_SWAP_H_ + +#define BASE_SWAP32(value) __builtin_bswap32(value) + +#define BASE_SWAP16(value) (uint16_t)__builtin_bswap16(value) + +#endif /* FREE_RTOS_BASE_SWAP_H_ */ diff --git a/components/free_rtos/clock/clock.cpp b/components/free_rtos/clock/clock.cpp new file mode 100644 index 0000000..c8b3182 --- /dev/null +++ b/components/free_rtos/clock/clock.cpp @@ -0,0 +1,37 @@ +/* + * clock.cpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ +#include "clock/clock.hpp" + +bool free_rtos::Clock::init(uint32_t period_ms, Callback cbk, void * arg) +{ + ClockP_Params clockParams; + ClockP_Params_init(&clockParams); + + prd_ms_ = period_ms; + + clockParams.timeout = ClockP_usecToTicks(prd_ms_ * 1000); + clockParams.period = clockParams.timeout; + clockParams.callback = cbk; + clockParams.args = arg; + + int32_t status = ClockP_construct(&obj_, &clockParams); + + return (SystemP_SUCCESS == status); +} + + +void free_rtos::Clock::start() { + ClockP_start(&obj_); +} + +void free_rtos::Clock::stop() { + ClockP_stop(&obj_); +} + +free_rtos::Clock::~Clock() { + ClockP_destruct (&obj_); +} diff --git a/components/free_rtos/clock/clock.hpp b/components/free_rtos/clock/clock.hpp new file mode 100644 index 0000000..ef05a46 --- /dev/null +++ b/components/free_rtos/clock/clock.hpp @@ -0,0 +1,39 @@ +/* + * clock.hpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_CLOCK_CLOCK_HPP_ +#define FREE_RTOS_CLOCK_CLOCK_HPP_ + +#include + +namespace free_rtos { + +class Clock { +public: + using Callback = void(*)(ClockP_Object *,void *); + + bool init(uint32_t period_ms, Callback cbk, void * arg); + + void start(); + + void stop(); + + uint32_t getPeriod() { + return prd_ms_; + } + + ~Clock(); +private: + ClockP_Object obj_; + uint32_t prd_ms_; /// +}; + + +} + + +#endif /* FREE_RTOS_CLOCK_CLOCK_HPP_ */ diff --git a/components/free_rtos/ethernet/eth.cpp b/components/free_rtos/ethernet/eth.cpp new file mode 100644 index 0000000..3f88d9b --- /dev/null +++ b/components/free_rtos/ethernet/eth.cpp @@ -0,0 +1,301 @@ +/* + * eth.cpp + * + * Created on: 9 ���. 2023 �. + * Author: sychev + */ +#include "ethernet/eth.hpp" +#include "ethernet/eth_vlan.h" +#include "ethernet/eth_ioctl.h" + +#include +#include +#include +#include + +/*----------------------------------------------------------------------*/ +/** + * ����� ������������ sysconfig. + * ������������ ����� ������� � ���������� � ����� /syscfg + */ +#include "ti_enet_config.h" + +#ifdef __cplusplus +extern "C" { +#endif +#include "ti_enet_open_close.h" +#ifdef __cplusplus +} +#endif + +/*----------------------------------------------------------------------*/ + +using namespace free_rtos; + +free_rtos::Eth::Eth() : + rx_flow_{{hostMacAddr_, eth_stack_}, {hostMacAddr_, eth_stack_}}, + sem_{Semaphore(Semaphore::e_semTypeCounting, 0, 10)}, + eth_stack_{tx_flow_} +{ + +} + +bool free_rtos::Eth::Init(Settings& sett) +{ + id_ = sett.id; + name_ = sett.name; + enetType_ = sett.enetType; + instId_ = sett.instId; + macPortNum_ = sett.macPortNum; + vlan_id_ = sett.vlan_id; + + if (instId_ != e_ethInstSwitch) { + EnetAppUtils_print("%s: Unsupported instId value: %u. Only %d(e_ethInstSwitch) instance id supported\r\n", name_.c_str(), instId_, e_ethInstSwitch); + return false; + } + + if (enetType_ != ENET_ICSSG_SWITCH) { + EnetAppUtils_print("%s: Unsupported enetType value: %u. Only %d(ENET_ICSSG_SWITCH) enet type supported\r\n", name_.c_str(), enetType_, ENET_ICSSG_SWITCH); + return false; + } + + if (sett.macPortNum != e_ethMacTotal) { + EnetAppUtils_print("%s: Invalid mac port number: %u. In SWITCH mode mac port number must be 2, current value: %u\r\n", name_.c_str(), macPortNum_); + return false; + } + + for (int i = 0; i < macPortNum_; ++i) { + linkUp_[i] = false; + macPort_[i] = sett.macPort[i]; + } + + core_id_ = EnetSoc_getCoreId(); + + host_ready_ = false; + + eth_stack_.init(sett.eth_stack_sett); + + return true; +} + +/// Callback ���������� ������ ioctl +static void eth_asyncIoctlCb(Enet_Event evt, + uint32_t evtNum, + void *evtCbArgs, + void *arg1, + void *arg2) +{ + Eth * eth = (Eth *)evtCbArgs; + + if (eth != nullptr) { + eth->ioctl_callback(); + } +} + +void free_rtos::Eth::ioctl_callback() +{ + sem_[e_signalIoctl].post(); +} + +static void eth_taskLinkTracking(void *args) { + Eth * eth = (Eth *)args; + + if (eth != nullptr) { + eth->link_task(); + } +} + +bool free_rtos::Eth::host_init() +{ + if (host_ready_) { + return true; + } + + Enet_IoctlPrms prms; + int32_t status = ENET_SOK; + uint16_t vlanId = (uint16_t)vlan_id_; + + if (enetType_ != ENET_ICSSG_SWITCH) + { + EnetAppUtils_print("%s: unsupported enet type: %u. Only %u(ENET_ICSSG_SWITCH) type supported\n\r", + name_.c_str(), enetType_, ENET_ICSSG_SWITCH); + return false; + } + + EnetAppUtils_print("%s: Host initialisation\n\r", name_.c_str()); + EnetAppUtils_print("%s: Set MAC addr: ", name_.c_str()); + EnetAppUtils_printMacAddr(&hostMacAddr_.bytes[0U]); + + Icssg_MacAddr addr; // FIXME Icssg_MacAddr type + + /* Set host port's MAC address */ + EnetUtils_copyMacAddr(&addr.macAddr[0U], &hostMacAddr_.bytes[0U]); + + ENET_IOCTL_SET_IN_ARGS(&prms, &addr); + + status = eth_ioctl(handleInfo_.hEnet, core_id_, ICSSG_HOSTPORT_IOCTL_SET_MACADDR, &prms); + + if (ENET_SOK != status) + { + EnetAppUtils_print("%s: ERROR: Host initialisation failure\n\r", name_.c_str()); + return false; + } + + status = eth_vlan_init(handleInfo_.hEnet, core_id_, vlanId, enetType_); + + if (ENET_SOK != status) + { + EnetAppUtils_print("%s: ERROR: Host initialisation failure\n\r", name_.c_str()); + return false; + } + + host_ready_ = true; + + return true; +} + + + +void free_rtos::Eth::link_task() +{ + bool linkUp; + Enet_MacPort macPort; + Enet_IoctlPrms prms; + IcssgMacPort_SetPortStateInArgs setPortStateInArgs; + + int32_t status = ENET_SOK; + while(1) + { + for (int i = 0; i < macPortNum_; ++i) + { + macPort = macPort_[i]; + linkUp = false; + + ENET_IOCTL_SET_INOUT_ARGS(&prms, &macPort, &linkUp); + status = eth_ioctl(handleInfo_.hEnet, core_id_, ENET_PER_IOCTL_IS_PORT_LINK_UP, &prms); + + if (status != ENET_SOK) + { + EnetAppUtils_print("link_task: %s: Failed to get port %u link status: %d\r\n", + name_.c_str(), ENET_MACPORT_ID(macPort), status); + linkUp = false; + continue; + } + + if (linkUp_[i] != linkUp) + { + EnetAppUtils_print("link_task: %s: Port %u link is %s\r\n", + name_.c_str(), ENET_MACPORT_ID(macPort), linkUp ? "up" : "down"); + if (linkUp) + { + EnetAppUtils_print("link_task: %s: Set port state to 'Forward'\r\n", name_.c_str()); + setPortStateInArgs.macPort = macPort; + setPortStateInArgs.portState = ICSSG_PORT_STATE_FORWARD; + + ENET_IOCTL_SET_IN_ARGS(&prms, &setPortStateInArgs); + status = eth_ioctl(handleInfo_.hEnet, core_id_, ICSSG_PER_IOCTL_SET_PORT_STATE, &prms); + + if (status == ENET_SINPROGRESS) + { + /* Wait for asyc ioctl to complete */ + do + { + Enet_poll(handleInfo_.hEnet, ENET_EVT_ASYNC_CMD_RESP, NULL, 0U); + status = sem_[e_signalIoctl].pend(); + } while(status != SystemP_SUCCESS); + + status = ENET_SOK; + } + else + { + EnetAppUtils_print("link_task: %s: Failed to set port state: %d\n", name_.c_str(), status); + continue; + } + + /// ����� �������� ������ ����(����� SWITCH) + if (!tx_flow_.open(i, ENET_DMA_TX_CH0)) + { + EnetAppUtils_print("link_task: %s: Failed to open tx flow\n", name_.c_str()); + continue; + } + + if (!rx_flow_[i].open(i, ENET_DMA_RX_CH0 + i)) + { + EnetAppUtils_print("link_task: %s: Failed to open rx flow: %u\n", name_.c_str(), i); + continue; + } + + /// e_ethMac0 + if (i == e_ethMac0) + { + if (!host_init()) { + EnetAppUtils_print("link_task: %s: Failed to init host\r\n", name_.c_str()); + continue; + } + } + else if (i == e_ethMac1) { + //rx_flow_[i].set_passive(); /// ���� � �������� ���������� �� - ���������, �� ������������ ������ + } + + tx_flow_.enable((TEthMacPorts)i); + } + else { + tx_flow_.disable((TEthMacPorts)i); + } + + linkUp_[i] = linkUp; + } + } + + + ClockP_usleep(100000); // 100ms /// ������ 10�� ���������� ��������� ����� + } +} + +bool free_rtos::Eth::Open() +{ + int32_t status; + + EnetAppUtils_print("%s: Init peripheral clocks\r\n", name_.c_str()); + EnetAppUtils_enableClocks(enetType_, instId_); + + EnetAppUtils_print("%s: Open enet driver\r\n", name_.c_str()); + + status = EnetApp_driverOpen(enetType_, instId_); + if (ENET_SOK != status) { + EnetAppUtils_print("%s: fail to open enet driver\r\n", name_.c_str()); + return false; + } + + EnetAppUtils_print("%s: Init handle info\r\n", name_.c_str()); + EnetApp_acquireHandleInfo(enetType_, instId_, &handleInfo_); + + EnetAppUtils_print("%s: Open peripherals\r\n", name_.c_str()); + + if (Enet_isIcssFamily(enetType_)) + { + EnetAppUtils_print("%s: Register async IOCTL callback\r\n", name_.c_str()); + Enet_registerEventCb(handleInfo_.hEnet, + ENET_EVT_ASYNC_CMD_RESP, + 0U, + eth_asyncIoctlCb, + (void *)this); + } + else { + EnetAppUtils_print("Error: the %s subsystem doesn't relates to Icss family\r\n", name_.c_str()); + return false; + } + + EnetAppUtils_print("%s: Attach core id %u on peripherals\r\n", name_.c_str(), core_id_); + EnetApp_coreAttach(enetType_, instId_, core_id_, &attachInfo_); + + EnetAppUtils_print("%s: Create link tracking tasks\r\n", name_.c_str()); + + if (!task_[e_taskLink].Create("LinkTask", e_linkTaskPriority, eth_taskLinkTracking, (void*)this, (10U * 1024U))) + { + EnetAppUtils_print("%s: Failed to create link task\r\n", name_.c_str()); + return false; + } + + return true; +} diff --git a/components/free_rtos/ethernet/eth.hpp b/components/free_rtos/ethernet/eth.hpp new file mode 100644 index 0000000..020d187 --- /dev/null +++ b/components/free_rtos/ethernet/eth.hpp @@ -0,0 +1,139 @@ +/* + * eth.hpp + * + * Created on: 6 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_HPP_ +#define FREE_RTOS_ETHERNET_ETH_HPP_ + +#include "ethernet/eth_rx_flow.hpp" +#include "ethernet/eth_tx_flow.hpp" + +#include "semaphore/semaphore.hpp" +#include "ethernet/eth_frame.h" +#include "task/task.hpp" + +#include +#include +#include +#include +#include + +#include "ethernet/eth_types.h" + +#include "ethernet_ip/eth_stack.hpp" + +namespace free_rtos { + +class Eth { +public: + typedef enum { + e_ethInstSwitch = 1, /// + e_ethInstDualMac_1, /// + e_ethInstDualMac_2 /// + }TEthInstId; + + struct Settings { + uint32_t id; /// + + /* Peripheral type */ + Enet_Type enetType; + + /* Peripheral instance */ + TEthInstId instId; + + /* Peripheral's MAC ports to use */ + Enet_MacPort macPort[e_ethMacTotal]; + + /* Number of MAC ports in macPorts array */ + uint32_t macPortNum; + + /* Name of this port to be used for logging */ + std::string name; + + uint32_t vlan_id; + + EthStack::Settings eth_stack_sett; + }; + + Eth(); + + bool Init(Settings& sett); + + bool Open(); + + void ioctl_callback(); + + void link_task(); + + EthUdpServerIface * getUdpServerPtr() {return eth_stack_.getUdpServerPtr(); } + + EthTxFlowIface * getTxFlowPtr() { return &tx_flow_; } + + EthStackIface * getEthStackPtr() {return ð_stack_;} + +private: + enum TaskPriority { + e_linkTaskPriority = 2 + }; + + bool host_init(); + + +private: + enum SignalsId { + e_signalIoctl, /// ioctl + e_signalTotal + }; + + enum TasksId { + e_taskLink, + e_taskTotal + }; + + uint32_t id_; /// + std::string name_; /// + + uint32_t core_id_; /// + + Enet_Type enetType_; /// + + /// mac: 1 - SWITCH, 2 3 DUAL MAC ( mac1 mac2 ) + uint32_t instId_; + + /// mac + Enet_MacPort macPort_[e_ethMacTotal]; + + /// MAC + uint32_t macPortNum_; + + /// ???? + EnetPer_AttachCoreOutArgs attachInfo_; + + /// Enet Udma . + EnetApp_HandleInfo handleInfo_; + + EthTxFlow tx_flow_; /// + EthRxFlow rx_flow_[e_ethMacTotal]; /// SWITCH + + Semaphore sem_[e_signalTotal]; + + Task task_[e_taskTotal]; + + bool linkUp_[e_ethMacTotal]; + + bool host_ready_; + + TEthFrameMacAddr hostMacAddr_; /// + + uint32_t vlan_id_; + + EthStack eth_stack_; /// +}; + +} + + +#endif /* FREE_RTOS_ETHERNET_ETH_HPP_ */ diff --git a/components/free_rtos/ethernet/eth_frame.h b/components/free_rtos/ethernet/eth_frame.h new file mode 100644 index 0000000..97d2e81 --- /dev/null +++ b/components/free_rtos/ethernet/eth_frame.h @@ -0,0 +1,40 @@ +/* + * eth_frame.h + * + * Created on: 7 ���. 2023 �. + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_FRAME_H_ +#define FREE_RTOS_ETHERNET_ETH_FRAME_H_ + +#include + +#define ETH_FRAME_MAC_ADDR_LEN_BYTES (6u) + +#define ETH_FRAME_MAC_ADDR_MASK (0xFFFFFFFFFFFFul) /// 6 ���� + +#define ETH_FRAME_MAC_ADDR_BROADCAST (0xFFFFFFFFFFFFul) /// ����������������� ����� + +#define ETH_FRAME_MIN_LEN (14u) /// ����������� ����� ������ + +#define ETH_FRAME_MAX_LEN (1518u) /// ������������ ����� ������ + +typedef union { + uint64_t addr; + uint8_t bytes[8]; +} __attribute__ ((packed)) TEthFrameMacAddr; + +typedef struct { + uint8_t mac_dest[ETH_FRAME_MAC_ADDR_LEN_BYTES]; + uint8_t mac_src[ETH_FRAME_MAC_ADDR_LEN_BYTES]; + uint16_t prot_id; +} __attribute__ ((packed)) TEthFrameHeader; + +typedef struct { + uint8_t data[ETH_FRAME_MAX_LEN]; //__attribute__ ((aligned(32))) + uint32_t length; +}TEthPkt; + + +#endif /* FREE_RTOS_ETHERNET_ETH_FRAME_H_ */ diff --git a/components/free_rtos/ethernet/eth_ioctl.c b/components/free_rtos/ethernet/eth_ioctl.c new file mode 100644 index 0000000..d9455ae --- /dev/null +++ b/components/free_rtos/ethernet/eth_ioctl.c @@ -0,0 +1,41 @@ +/* + * eth_ioctl.c + * + * Created on: 10 . 2023 . + * Author: sychev + */ +#include "ethernet/eth_ioctl.h" + +#include + +int32_t eth_ioctl(Enet_Handle handle, uint32_t core_id, uint32_t cmd, Enet_IoctlPrms * param) +{ + int32_t status = ENET_SOK; + /** + * , . + */ + switch(cmd) + { + case ENET_PER_IOCTL_IS_PORT_LINK_UP: + { + ENET_IOCTL(handle, core_id, ENET_PER_IOCTL_IS_PORT_LINK_UP, param, status); + } + break; + case ICSSG_PER_IOCTL_SET_PORT_STATE: + { + ENET_IOCTL(handle, core_id, ICSSG_PER_IOCTL_SET_PORT_STATE, param, status); + } + break; + case ICSSG_HOSTPORT_IOCTL_SET_MACADDR: + { + ENET_IOCTL(handle, core_id, ICSSG_HOSTPORT_IOCTL_SET_MACADDR, param, status); + } + break; + default: + status = ENET_EFAIL; + break; + } + + return status; +} + diff --git a/components/free_rtos/ethernet/eth_ioctl.h b/components/free_rtos/ethernet/eth_ioctl.h new file mode 100644 index 0000000..ef0b6e6 --- /dev/null +++ b/components/free_rtos/ethernet/eth_ioctl.h @@ -0,0 +1,24 @@ +/* + * eth_ioctl.h + * + * Created on: 10 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_IOCTL_H_ +#define FREE_RTOS_ETHERNET_ETH_IOCTL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t eth_ioctl(Enet_Handle handle, uint32_t core_id, uint32_t cmd, Enet_IoctlPrms * param); + +#ifdef __cplusplus +} +#endif + +#endif /* FREE_RTOS_ETHERNET_ETH_IOCTL_H_ */ diff --git a/components/free_rtos/ethernet/eth_rx_flow.cpp b/components/free_rtos/ethernet/eth_rx_flow.cpp new file mode 100644 index 0000000..007b360 --- /dev/null +++ b/components/free_rtos/ethernet/eth_rx_flow.cpp @@ -0,0 +1,227 @@ +/* + * eth_rx_flow.cpp + * + * Created on: 7 ���. 2023 �. + * Author: sychev + */ +#include "ethernet/eth_rx_flow.hpp" + +#include +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------------*/ +/** + * ����� ������������ sysconfig. + * ������������ ����� ������� � ���������� � ����� /syscfg + */ +#include "ti_enet_config.h" +/*----------------------------------------------------------------------*/ + +using namespace free_rtos; + +#define RX_TASK_STACK_SIZE (10U * 1024U) /// 10�� + +/** + * ���������� ������ ������ + */ +void free_rtos::rxIsrHandler(void *appData) +{ + EthRxFlow * rx_flow = (EthRxFlow *)appData; + if (rx_flow != nullptr) { + rx_flow->sem_[EthRxFlow::e_signalRxPkt].post(); + } +} + +void free_rtos::rxTaskHandler(void *appData) +{ + EthRxFlow * rx_flow = (EthRxFlow *)appData; + if (rx_flow != nullptr) { + rx_flow->rxProcessPktTask(); + } +} + +static void eth_initRxReadyPktQ(EnetDma_RxChHandle hRxCh, void * appPriv) +{ + EnetDma_PktQ rxReadyQ; + EnetDma_PktQ rxFreeQ; + EnetDma_Pkt *pPktInfo; + uint32_t i; + int32_t status; + + EnetQueue_initQ(&rxFreeQ); + + for (i = 0U; i < (ENET_SYSCFG_TOTAL_NUM_RX_PKT/2); ++i) + { + pPktInfo = EnetMem_allocEthPkt(appPriv, + ENET_MEM_LARGE_POOL_PKT_SIZE, + ENETDMA_CACHELINE_ALIGNMENT); + EnetAppUtils_assert(pPktInfo != NULL); + + ENET_UTILS_SET_PKT_APP_STATE(&pPktInfo->pktState, ENET_PKTSTATE_APP_WITH_FREEQ); + + EnetQueue_enq(&rxFreeQ, &pPktInfo->node); + } + + /* Retrieve any packets which are ready */ + EnetQueue_initQ(&rxReadyQ); + status = EnetDma_retrieveRxPktQ(hRxCh, &rxReadyQ); + EnetAppUtils_assert(status == ENET_SOK); + + /* There should not be any packet with DMA during init */ + EnetAppUtils_assert(EnetQueue_getQCount(&rxReadyQ) == 0U); + + EnetAppUtils_validatePacketState(&rxFreeQ, + ENET_PKTSTATE_APP_WITH_FREEQ, + ENET_PKTSTATE_APP_WITH_DRIVER); + + EnetDma_submitRxPktQ(hRxCh, &rxFreeQ); + + /* Assert here, as during init, the number of DMA descriptors should be equal to + * the number of free Ethernet buffers available with app */ + EnetAppUtils_assert(EnetQueue_getQCount(&rxFreeQ) == 0U); +} + +free_rtos::EthRxFlow::EthRxFlow(TEthFrameMacAddr& mac_addr, EthStackIface& eth_stack) : + mac_addr_{mac_addr}, + eth_stack_{eth_stack}, + passive_mode_{false} +{ + +} + +void free_rtos::EthRxFlow::rxProcessPktTask() +{ + EnetDma_PktQ rxReadyQ; /// ������� ������� ������� (������ � �������) + EnetDma_PktQ rxFreeQ; /// ������� ��������� ������� + EnetDma_Pkt* rxPktInfo; /// ����� � ������� + int32_t status; + + while(1) + { + /// ������� ������� + sem_[e_signalRxPkt].pend(); + + /// �������������� ������� (�������� ���� ��������) + EnetQueue_initQ(&rxReadyQ); + EnetQueue_initQ(&rxFreeQ); + + /// ��������� ������� � � �������� � rxReadyQ + status = EnetDma_retrieveRxPktQ(dma_handle_, &rxReadyQ); + EnetAppUtils_assert(status == ENET_SOK); + + // ��������� ����� �� ������� + rxPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rxReadyQ); + + while(rxPktInfo != nullptr) + { + /// � ��������� ������ �������� ������ �� ������������ + if (!passive_mode_) + { + /// � ����� ������ ����� ���� ��������� ��������� + for (int j = 0 ; j < rxPktInfo->sgList.numScatterSegments; ++j) + { + eth_stack_.rx_handler(rxPktInfo->sgList.list[j].bufPtr, rxPktInfo->sgList.list[j].segmentFilledLen); + } + } + + /// �������� ��������� ������ �� ��������. ����� ����������� � ������������� ����� ��������. + EnetDma_checkPktState(&rxPktInfo->pktState, + ENET_PKTSTATE_MODULE_APP, + ENET_PKTSTATE_APP_WITH_DRIVER, + ENET_PKTSTATE_APP_WITH_FREEQ); + + /// ������ ����� � ������� ��������� ������� + EnetQueue_enq(&rxFreeQ, &rxPktInfo->node); + + /// ��������� ��������� ���� �� ������� + rxPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rxReadyQ); + + /// ����������� ������� �������� ������� + ++rx_pkt_counter_; + } + + /** + * ��������� ��������� ���� ������� � �������(������ ���� ENET_PKTSTATE_APP_WITH_FREEQ) + * � �������� ��� �� ENET_PKTSTATE_APP_WITH_DRIVER. �������� ����� �� ������ ��� ���� + * ���� ������� ����� ������� EnetDma_checkPktState. + */ + EnetAppUtils_validatePacketState(&rxFreeQ, + ENET_PKTSTATE_APP_WITH_FREEQ, + ENET_PKTSTATE_APP_WITH_DRIVER); + + /// ���������� ������� � ������� + EnetDma_submitRxPktQ(dma_handle_, &rxFreeQ); + } +} + +bool free_rtos::EthRxFlow::open(uint32_t id, int32_t enetDmaRxChId) +{ + EnetApp_GetDmaHandleInArgs rxInArgs; + EnetApp_GetRxDmaHandleOutArgs rxChInfo; + + EnetAppUtils_print("rx_flow %u: opening flow...\r\n", id); + + rx_pkt_counter_ = 0; + + if (open_) { + EnetAppUtils_print("rx_flow %u: rx flow is already open. Do nothing.\r\n", id_); + return true; + } + + if (!rx_task.Create("rx_task", Task::TaskPriorityHiest - 2, rxTaskHandler, this, RX_TASK_STACK_SIZE)) + { + EnetAppUtils_print("rx_flow %u: failed to create rx task.\r\n", id_); + return false; + } + + id_ = id; + + /// ������������ ���������� �� ������ ������ + rxInArgs.notifyCb = rxIsrHandler; /// ������� ���������� + rxInArgs.cbArg = this; /// �������� ������ + + EnetApp_getRxDmaHandle(enetDmaRxChId, &rxInArgs, &rxChInfo); + + /// ��������� ������ + rx_start_flow_idx_ = rxChInfo.rxFlowStartIdx; + rx_flow_idx_ = rxChInfo.rxFlowIdx; + dma_handle_ = rxChInfo.hRxCh; + + if (rxChInfo.macAddressValid) + { + EnetUtils_copyMacAddr(mac_addr_.bytes, rxChInfo.macAddr); + mac_addr_.addr&= ETH_FRAME_MAC_ADDR_MASK; + + eth_stack_.set_mac_address(mac_addr_.addr); + } + + /// �������� ������ + EnetAppUtils_assert(rxChInfo.useGlobalEvt == true); + EnetAppUtils_assert(rxChInfo.sizeThreshEn == 0U); + EnetAppUtils_assert(rxChInfo.maxNumRxPkts >= (ENET_SYSCFG_TOTAL_NUM_RX_PKT/2U)); + EnetAppUtils_assert(rxChInfo.chIdx == id_); + EnetAppUtils_assert(rxChInfo.useDefaultFlow == true); + + if (dma_handle_ == nullptr) + { + EnetAppUtils_print("rx_flow %u: failed to open rx dma flow\r\n", id_); + EnetAppUtils_assert(dma_handle_ != nullptr); + return false; + } + + /// ������������� ������� ������� + eth_initRxReadyPktQ(dma_handle_, this); + + open_ = true; + + EnetAppUtils_print("rx_flow %u: rx flow open successfully\r\n", id); + + return true; +} + + + diff --git a/components/free_rtos/ethernet/eth_rx_flow.hpp b/components/free_rtos/ethernet/eth_rx_flow.hpp new file mode 100644 index 0000000..903486f --- /dev/null +++ b/components/free_rtos/ethernet/eth_rx_flow.hpp @@ -0,0 +1,73 @@ +/* + * eth_rx_dma.hpp + * + * Created on: 6 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_RX_DMA_HPP_ +#define FREE_RTOS_ETHERNET_ETH_RX_DMA_HPP_ + +#include +#include + +#include "handler_store/handler_store.hpp" +#include "semaphore/semaphore.hpp" +#include "task/task.hpp" + +#include "ethernet/eth_frame.h" +#include "ethernet_ip/eth_stack_iface.hpp" + +namespace free_rtos { + +class EthRxFlow { +public: + EthRxFlow(TEthFrameMacAddr& mac_addr, EthStackIface& eth_stack); + + bool open(uint32_t id, int32_t enetDmaRxChId); + + bool is_open() {return open_;} + + void set_passive() { passive_mode_ = true; } + +private: + + friend void rxIsrHandler(void *appData); /// + + friend void rxTaskHandler(void *appData); /// + + void rxProcessPktTask(); /// + +private: + enum SignalsId { + e_signalRxPkt, /// + e_signalTotal + }; + + uint32_t id_; /// + bool open_; /// , dma + + Semaphore sem_[e_signalTotal]; /// + + Task rx_task; /// + + TEthFrameMacAddr& mac_addr_; /// mac + + uint32_t rx_pkt_counter_; + + EthStackIface& eth_stack_; + + ///------------------------------------ + uint32_t rx_start_flow_idx_; + uint32_t rx_flow_idx_; + EnetDma_RxChHandle dma_handle_; + + bool passive_mode_; /// , , +}; + + +} + + + +#endif /* FREE_RTOS_ETHERNET_ETH_RX_DMA_HPP_ */ diff --git a/components/free_rtos/ethernet/eth_ti_enet_inst.c b/components/free_rtos/ethernet/eth_ti_enet_inst.c new file mode 100644 index 0000000..ab21ff7 --- /dev/null +++ b/components/free_rtos/ethernet/eth_ti_enet_inst.c @@ -0,0 +1,160 @@ +/* + * app_enet_open_close.c + * + * Created on: 1 . 2023 . + * Author: sychev + * + * ti_enet_open_close.h ti_enet_open_close. + */ +#include +#include +#include + +#define ETH_TYPES_MAC_PORT_MAX (2u) /// mac- + +/// +#include + +#include + +static void eth_macMode2MacMii(emac_mode macMode, EnetMacPort_Interface *mii); + +static int32_t eth_getSubsPortIdx(Enet_Type enetType, uint32_t instId, uint32_t *subsportIdx); + +/* + * ti_enet_open_close.h + */ +void EnetApp_initLinkArgs(Enet_Type enetType, + uint32_t instId, + EnetPer_PortLinkCfg *portLinkCfg, + Enet_MacPort macPort) +{ + EnetBoard_EthPort ethPort; + const EnetBoard_PhyCfg *boardPhyCfg; + IcssgMacPort_Cfg *icssgMacCfg; + EnetMacPort_LinkCfg *linkCfg = &portLinkCfg->linkCfg; + EnetMacPort_Interface *mii = &portLinkCfg->mii; + EnetPhy_Cfg *phyCfg = &portLinkCfg->phyCfg; + int32_t status = ENET_SOK; + + EnetAppUtils_print("Open mac port %u\r\n", ENET_MACPORT_ID(macPort)); + + /* Setup board for requested Ethernet port */ + ethPort.enetType = enetType; + ethPort.instId = instId; + ethPort.macPort = macPort; + ethPort.boardId = ENETBOARD_AM64X_AM243X_EVM; + eth_macMode2MacMii(RGMII, ðPort.mii); + + status = EnetBoard_setupPorts(ðPort, 1U); + if (status != ENET_SOK) + { + EnetAppUtils_print("Failed to setup MAC port %u\r\n", ENET_MACPORT_ID(macPort)); + EnetAppUtils_assert(false); + } + + icssgMacCfg = portLinkCfg->macCfg; + IcssgMacPort_initCfg(icssgMacCfg); + icssgMacCfg->specialFramePrio = 1U; + + /* Set port link params */ + portLinkCfg->macPort = macPort; + + mii->layerType = ethPort.mii.layerType; + mii->sublayerType = ethPort.mii.sublayerType; + mii->variantType = ENET_MAC_VARIANT_FORCED; + + linkCfg->speed = ENET_SPEED_AUTO; + linkCfg->duplexity = ENET_DUPLEX_AUTO; + + boardPhyCfg = EnetBoard_getPhyCfg(ðPort); + if (boardPhyCfg != NULL) + { + EnetPhy_initCfg(phyCfg); + if ((ENET_ICSSG_DUALMAC == enetType) && (2U == instId)) + { + phyCfg->phyAddr = CONFIG_ENET_ICSS0_PHY1_ADDR; + } + else if ((ENET_ICSSG_DUALMAC == enetType) && (3U == instId)) + { + phyCfg->phyAddr = CONFIG_ENET_ICSS0_PHY2_ADDR; + } + else if ((ENET_ICSSG_SWITCH == enetType) && (1U == instId)) + { + if (macPort == ENET_MAC_PORT_1) + { + phyCfg->phyAddr = CONFIG_ENET_ICSS0_PHY1_ADDR; + } + else + { + phyCfg->phyAddr = CONFIG_ENET_ICSS0_PHY2_ADDR; + } + } + else + { + EnetAppUtils_assert(false); + } + + phyCfg->isStrapped = boardPhyCfg->isStrapped; + phyCfg->loopbackEn = false; + phyCfg->skipExtendedCfg = boardPhyCfg->skipExtendedCfg; + phyCfg->extendedCfgSize = boardPhyCfg->extendedCfgSize; + memcpy(phyCfg->extendedCfg, boardPhyCfg->extendedCfg, phyCfg->extendedCfgSize); + } + else + { + EnetAppUtils_print("No PHY configuration found for mac %u\r\n", ENET_MACPORT_ID(macPort)); + EnetAppUtils_assert(false); + } + +} + +/* + * ti_enet_open_close.h + */ +void EnetApp_updateIcssgInitCfg(Enet_Type enetType, uint32_t instId, Icssg_Cfg *icssgCfg) +{ + EnetRm_ResCfg *resCfg; + uint32_t i; + + /* Prepare init configuration for all peripherals */ + EnetAppUtils_print("\nInit configs EnetType:%u, InstId :%u\r\n", enetType, instId); + EnetAppUtils_print("----------------------------------------------\r\n"); + + resCfg = &icssgCfg->resCfg; + + /* We use software MAC address pool from apputils, but it will give same MAC address. + * Add port index to make them unique */ + for (i = 0U; i < ETH_TYPES_MAC_PORT_MAX; ++i) + { + resCfg->macList.macAddress[i][ENET_MAC_ADDR_LEN - 1] += i; + } + + resCfg->macList.numMacAddress = ETH_TYPES_MAC_PORT_MAX; +} + +static void eth_macMode2MacMii(emac_mode macMode, + EnetMacPort_Interface *mii) +{ + switch (macMode) + { + case RMII: + mii->layerType = ENET_MAC_LAYER_MII; + mii->sublayerType = ENET_MAC_SUBLAYER_REDUCED; + mii->variantType = ENET_MAC_VARIANT_NONE; + break; + + case RGMII: + mii->layerType = ENET_MAC_LAYER_GMII; + mii->sublayerType = ENET_MAC_SUBLAYER_REDUCED; + mii->variantType = ENET_MAC_VARIANT_FORCED; + break; + default: + EnetAppUtils_print("Invalid MAC mode: %u\r\n", macMode); + EnetAppUtils_assert(false); + break; + } +} + + + diff --git a/components/free_rtos/ethernet/eth_tx_flow.cpp b/components/free_rtos/ethernet/eth_tx_flow.cpp new file mode 100644 index 0000000..1a7777e --- /dev/null +++ b/components/free_rtos/ethernet/eth_tx_flow.cpp @@ -0,0 +1,227 @@ +/* + * eth_tx_flow.cpp + * + * Created on: 7 . 2023 . + * Author: sychev + */ +#include "ethernet/eth_tx_flow.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------------*/ +/** + * sysconfig. + * /syscfg + */ +#include "ti_enet_config.h" +/*----------------------------------------------------------------------*/ + +/** + * p_packet_queue + */ +static void eth_initTxFreePktQ(void * appPriv, EnetDma_PktQ * p_packet_queue) +{ + EnetDma_Pkt *pPktInfo; + uint32_t i; + + /// + int i_max = (ENET_SYSCFG_TOTAL_NUM_TX_PKT/2); + + /* Initialize TX EthPkts and queue them to txFreePktInfoQ */ + for (i = 0U; i < i_max; i++) + { + /// + pPktInfo = EnetMem_allocEthPkt(appPriv, + ENET_MEM_LARGE_POOL_PKT_SIZE, + ENETDMA_CACHELINE_ALIGNMENT); + EnetAppUtils_assert(pPktInfo != NULL); + /// + ENET_UTILS_SET_PKT_APP_STATE(&pPktInfo->pktState, ENET_PKTSTATE_APP_WITH_FREEQ); + /// p_packet_queue + EnetQueue_enq(p_packet_queue, &pPktInfo->node); + } + + EnetAppUtils_print("initQs() txFreePktInfoQ initialized with %d pkts\r\n", + EnetQueue_getQCount(p_packet_queue)); +} + +static uint32_t eth_retrieveFreeTxPkts(EnetDma_TxChHandle * p_handle, EnetDma_PktQ * p_queque) +{ + EnetDma_PktQ txFreeQ; + EnetDma_Pkt *pktInfo; + uint32_t txFreeQCnt = 0U; + int32_t status; + + EnetQueue_initQ(&txFreeQ); + + /// + status = EnetDma_retrieveTxPktQ(*p_handle, &txFreeQ); + if (status == ENET_SOK) + { + /// + txFreeQCnt = EnetQueue_getQCount(&txFreeQ); + + pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&txFreeQ); + while (NULL != pktInfo) + { + EnetDma_checkPktState(&pktInfo->pktState, + ENET_PKTSTATE_MODULE_APP, + ENET_PKTSTATE_APP_WITH_DRIVER, + ENET_PKTSTATE_APP_WITH_FREEQ); + + /// txFreePktInfoQ + EnetQueue_enq(p_queque, &pktInfo->node); + pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&txFreeQ); /// + } + } + else + { + EnetAppUtils_print("retrieveFreeTxPkts() failed to retrieve pkts: %d\r\n", status); + } + + return txFreeQCnt; /// +} + +free_rtos::EthTxFlow::EthTxFlow() : + id_{0}, + open_{false}, + tx_ch_num_{0} +{ + EnetQueue_initQ(&tx_free_pktq_); +} + +bool free_rtos::EthTxFlow::open(uint32_t id, int32_t enetDmaTxChId) +{ + if (id >= e_ethMacTotal) { + return false; + } + + EnetApp_GetDmaHandleInArgs txInArgs; + EnetApp_GetTxDmaHandleOutArgs txChInfo; + + EnetAppUtils_print("tx_flow %u: opening flow...\r\n", id); + + port_data_[id].tx_pkt_counter = 0; + + if (open_) { + EnetAppUtils_print("tx_flow %u: tx flow is already open. Do nothing.\r\n", id_); + return true; + } + + /* Open the TX channel */ + txInArgs.notifyCb = nullptr; + txInArgs.cbArg = nullptr; + + EnetApp_getTxDmaHandle(enetDmaTxChId, &txInArgs, &txChInfo); + + tx_ch_num_ = txChInfo.txChNum; + dma_handle_ = txChInfo.hTxCh; + + EnetAppUtils_assert(txChInfo.useGlobalEvt == true); + EnetAppUtils_assert(txChInfo.maxNumTxPkts >= (ENET_SYSCFG_TOTAL_NUM_TX_PKT/2U)); + + if (dma_handle_ == nullptr) + { + EnetAppUtils_print("tx_flow %u: failed to open tx dma flow\r\n", id_); + EnetAppUtils_assert(dma_handle_ != nullptr); + return false; + } + + eth_initTxFreePktQ(this, &tx_free_pktq_); + + open_= true; + + EnetAppUtils_print("tx_flow %u: tx flow open successfully\r\n", id_); + + return true; +} + +void free_rtos::EthTxFlow::enable(TEthMacPorts port_id) { + if (port_id >= e_ethMacTotal) { + return; + } + + port_data_[port_id].tx_enable = true; +} + +void free_rtos::EthTxFlow::disable(TEthMacPorts port_id) { + if (port_id >= e_ethMacTotal) { + return; + } + + port_data_[port_id].tx_enable = false; +} + +bool free_rtos::EthTxFlow::send(TEthMacPorts port_id, uint8_t * p_data, uint32_t len) +{ + if (port_id >= e_ethMacTotal) { + return false; + } + + if (!port_data_[port_id].tx_enable) { + return false; + } + + EnetDma_PktQ txSubmitQ; + EnetDma_Pkt *txPktInfo; + int32_t status; + + /* + * enet txFreePktInfoQ + */ + eth_retrieveFreeTxPkts(&dma_handle_, &tx_free_pktq_); + + /// txSubmitQ + EnetQueue_initQ(&txSubmitQ); + + /* TX Eth */ + txPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&tx_free_pktq_); + if (txPktInfo != NULL) + { + /// + memcpy(txPktInfo->sgList.list[0].bufPtr, p_data, len); + + txPktInfo->sgList.list[0].segmentFilledLen = len; + txPktInfo->sgList.numScatterSegments = 1; + txPktInfo->chkSumInfo = 0U; + txPktInfo->appPriv = nullptr; + txPktInfo->tsInfo.txPktSeqId = 0; + txPktInfo->txPktTc = 0; /// Traffic class IPv6 + txPktInfo->tsInfo.enableHostTxTs = false; + txPktInfo->txPortNum = (Enet_MacPort)port_id; + + EnetDma_checkPktState(&txPktInfo->pktState, + ENET_PKTSTATE_MODULE_APP, + ENET_PKTSTATE_APP_WITH_FREEQ, + ENET_PKTSTATE_APP_WITH_DRIVER); + + /// txPktInfo txSubmitQ + EnetQueue_enq(&txSubmitQ, &txPktInfo->node); + } + else + { + EnetAppUtils_print("tx_flow %u: Drop due to TX pkt not available\r\n", id_); + return false; + } + + /// DMA + status = EnetDma_submitTxPktQ(dma_handle_, &txSubmitQ); + if (status != ENET_SOK) + { + EnetAppUtils_print("tx_flow %u: Failed to submit TX pkt queue: %d\r\n", id_, status); + return false; + } + + ++port_data_[port_id].tx_pkt_counter; /// + + return true; +} + + diff --git a/components/free_rtos/ethernet/eth_tx_flow.hpp b/components/free_rtos/ethernet/eth_tx_flow.hpp new file mode 100644 index 0000000..6186cec --- /dev/null +++ b/components/free_rtos/ethernet/eth_tx_flow.hpp @@ -0,0 +1,52 @@ +/* + * eth_tx_flow.hpp + * + * Created on: 7 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_TX_FLOW_HPP_ +#define FREE_RTOS_ETHERNET_ETH_TX_FLOW_HPP_ + +#include +#include + +#include "ethernet/eth_tx_flow_iface.hpp" + +namespace free_rtos { + +class EthTxFlow : public EthTxFlowIface { +public: + EthTxFlow(); + + bool open(uint32_t id, int32_t enetDmaTxChId); + + bool is_open() {return open_;} + + void enable(TEthMacPorts port_id); + + void disable(TEthMacPorts port_id); + + virtual bool send(TEthMacPorts port_id, uint8_t * p_data, uint32_t len) override; + +private: + struct PortData { + bool tx_enable; + uint32_t tx_pkt_counter; + }; + + uint32_t id_; + bool open_; + + //------------------------------------------------- + uint32_t tx_ch_num_; + EnetDma_TxChHandle dma_handle_; /// DMA + EnetDma_PktQ tx_free_pktq_; /// + + PortData port_data_[e_ethMacTotal]; +}; + + +} + +#endif /* FREE_RTOS_ETHERNET_ETH_TX_FLOW_HPP_ */ diff --git a/components/free_rtos/ethernet/eth_tx_flow_iface.hpp b/components/free_rtos/ethernet/eth_tx_flow_iface.hpp new file mode 100644 index 0000000..88f6e92 --- /dev/null +++ b/components/free_rtos/ethernet/eth_tx_flow_iface.hpp @@ -0,0 +1,22 @@ +/* + * eth_tx_iface.hpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_TX_FLOW_IFACE_HPP_ +#define FREE_RTOS_ETHERNET_ETH_TX_FLOW_IFACE_HPP_ + +#include +#include "ethernet/eth_types.h" + +class EthTxFlowIface { +public: + virtual bool send(TEthMacPorts port_id, uint8_t * p_data, uint32_t len) = 0; + virtual ~EthTxFlowIface(){} +}; + + + +#endif /* FREE_RTOS_ETHERNET_ETH_TX_FLOW_IFACE_HPP_ */ diff --git a/components/free_rtos/ethernet/eth_types.h b/components/free_rtos/ethernet/eth_types.h new file mode 100644 index 0000000..7f08846 --- /dev/null +++ b/components/free_rtos/ethernet/eth_types.h @@ -0,0 +1,17 @@ +/* + * eth_types.hpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_TYPES_HPP_ +#define FREE_RTOS_ETHERNET_ETH_TYPES_HPP_ + +typedef enum { + e_ethMac0, + e_ethMac1, + e_ethMacTotal +}TEthMacPorts; + +#endif /* FREE_RTOS_ETHERNET_ETH_TYPES_HPP_ */ diff --git a/components/free_rtos/ethernet/eth_vlan.c b/components/free_rtos/ethernet/eth_vlan.c new file mode 100644 index 0000000..a9328c9 --- /dev/null +++ b/components/free_rtos/ethernet/eth_vlan.c @@ -0,0 +1,300 @@ +/* + * eth_vlan.c + * + * Created on: 9 . 2023 . + * Author: sychev + */ +#include "ethernet/eth_vlan.h" + +#include +#include + +//using namespace free_rtos; + +/* Bit#0 Indicates host ownership (indicates Host egress) */ +#define FDB_ENTRY_HOST_BIT (0) + +/* Bit#1 Indicates that MAC ID is connected to Physical Port 1 */ +#define FDB_ENTRY_PORT1_BIT (1) + +/* Bit#2 Indicates that MAC ID is connected to Physical Port 2 */ +#define FDB_ENTRY_PORT2_BIT (2) + +/* Bit#3 This is set to 1 for all learnt entries. 0 for static entries. */ +#define FDB_ENTRY_LEARNT_ENTRY_BIT (3) + +/* Bit#4 If set for SA then packet is dropped (can be used to implement a blacklist). + * If set for DA then packet is determined to be a special packet */ +#define FDB_ENTRY_BLOCK_BIT (4) + +/* Bit#5 If set for DA then the SA from the packet is not learnt */ + +/* Bit#6 if set, it means packet has been seen recently with source address + + * FID matching MAC address/FID of entry. */ +#define FDB_ENTRY_TOUCH_BIT (6) + +/* Bit#7 set if entry is valid */ +#define FDB_ENTRY_VALID_BIT (7) + +int32_t eth_vlan_setPriorityRegMapping(Enet_Handle handle, + uint32_t core_id, + Enet_MacPort macPort, + uint32_t *prioRegenMap) +{ + EnetMacPort_SetPriorityRegenMapInArgs regenMap; + Enet_IoctlPrms prms; + int32_t status = ENET_SOK; + int32_t i; + + regenMap.macPort = macPort; + + for (i = 0; i < ENET_PRI_NUM; i++) + { + regenMap.priorityRegenMap.priorityMap[i] = prioRegenMap[i]; + } + + ENET_IOCTL_SET_IN_ARGS(&prms, ®enMap); + + ENET_IOCTL(handle, core_id, ENET_MACPORT_IOCTL_SET_PRI_REGEN_MAP, &prms, status); + if (status != ENET_SOK) + { + EnetAppUtils_print("ERROR: IOCTL command for priority regeneration for PORT = %u\r\n", macPort); + status = ENET_EFAIL; + } + + return status; +} + +int32_t eth_vlan_setPriorityMapping(Enet_Handle handle, + uint32_t core_id, + Enet_MacPort macPort, + uint32_t *prioMap) +{ + EnetMacPort_SetEgressPriorityMapInArgs priMap; + Enet_IoctlPrms prms; + int32_t status = ENET_SOK; + int32_t i; + + priMap.macPort = macPort; + + for (i = 0; i < ENET_PRI_NUM; i++) + { + priMap.priorityMap.priorityMap[i] = prioMap[i]; + } + + ENET_IOCTL_SET_IN_ARGS(&prms, &priMap); + ENET_IOCTL(handle, core_id, ENET_MACPORT_IOCTL_SET_EGRESS_QOS_PRI_MAP, &prms, status); + + if (status != ENET_SOK) + { + EnetAppUtils_print("ERROR: IOCTL command for priority mapping for PORT = %u\r\n", macPort); + status = ENET_EFAIL; + } + + return status; +} + +int32_t eth_vlan_addDefaultHostVid(Enet_Handle handle, + uint32_t core_id, + uint8_t pcp, + uint16_t vlan_id) +{ + Enet_IoctlPrms prms; + EnetPort_VlanCfg vlanDefaultEntry; + int32_t status = ENET_SOK; + + vlanDefaultEntry.portVID = vlan_id; + vlanDefaultEntry.portPri = pcp; + + ENET_IOCTL_SET_IN_ARGS(&prms, &vlanDefaultEntry); + ENET_IOCTL(handle, core_id, ICSSG_PER_IOCTL_VLAN_SET_HOSTPORT_DFLT_VID, &prms, status); + + if (status != ENET_SOK) + { + EnetAppUtils_print("Failed to set default VID"); + } + + return status; +} + +int32_t eth_vlan_addDefaultPortVid(Enet_Handle handle, + uint32_t core_id, + Enet_MacPort macPort, + uint8_t pcp, + uint16_t vlanId) +{ + int32_t status = ENET_SOK; + Enet_IoctlPrms prms; + Icssg_MacPortDfltVlanCfgInArgs vlanDefaultEntry; + + vlanDefaultEntry.macPort = macPort; + vlanDefaultEntry.vlanCfg.portVID = vlanId; + vlanDefaultEntry.vlanCfg.portPri = pcp; + + ENET_IOCTL_SET_IN_ARGS(&prms, &vlanDefaultEntry); + ENET_IOCTL(handle, core_id, ICSSG_PER_IOCTL_VLAN_SET_MACPORT_DFLT_VID, &prms, status); + + if (status != ENET_SOK) + { + EnetAppUtils_print("Failed to set default VID"); + } + + return status; +} + +int32_t eth_vlan_init(Enet_Handle handle, + uint32_t core_id, + uint16_t vlanId, + Enet_Type enetType) +{ + int32_t status = ENET_SOK; + Enet_IoctlPrms prms; + uint32_t i; + uint32_t prioRegenMap[ENET_PRI_NUM]; + uint32_t prioMap[ENET_PRI_NUM]; + Icssg_VlanFidEntry vlanEntry; + Icssg_VlanFidParams vlanParams = { + .fid = 0, + .hostMember = 1, + .p1Member = 1, + .p2Member = 1, + .hostTagged = 0, + .p1Tagged = 0, + .p2Tagged = 0, + .streamVid = 0, + .floodToHost = 0 + }; + Icssg_VlanFidParams vlanParamsForPrioTag = { + .fid = 0, + .hostMember = 1, + .p1Member = 1, + .p2Member = 1, + .hostTagged = 0, + .p1Tagged = 1, + .p2Tagged = 1, + .streamVid = 0, + .floodToHost = 0 + }; + + vlanParams.fid = vlanId; + + for (i = 0; i < ENET_PRI_NUM; i++) + { + prioRegenMap[i] = (uint32_t)(ENET_PRI_NUM-1-i); + prioMap[i] = 0U; + } + + /* IOCTL, PORT1 , PORT2 . */ + eth_vlan_setPriorityRegMapping(handle, core_id, ENET_MAC_PORT_1, prioRegenMap); + eth_vlan_setPriorityMapping(handle, core_id, ENET_MAC_PORT_1, prioMap); + + if (enetType == ENET_ICSSG_SWITCH) + { + eth_vlan_setPriorityRegMapping(handle, core_id, ENET_MAC_PORT_2, prioRegenMap); + eth_vlan_setPriorityMapping(handle, core_id, ENET_MAC_PORT_2, prioMap); + } + + /* Make an entry for common vlan id + * Update table for default entry */ + vlanEntry.vlanFidParams = vlanParams; + vlanEntry.vlanId = (uint16_t)vlanId; + + ENET_IOCTL_SET_IN_ARGS(&prms, &vlanEntry); + ENET_IOCTL(handle, core_id, ICSSG_PER_IOCTL_VLAN_SET_ENTRY, &prms, status); + + if (status != ENET_SOK) + { + EnetAppUtils_print("FID VLAN entry for HOST is FAILED = %u : FAILED\r\n", status); + return status; + } + + /* -----------------Make an entry for Priority tag----------------- */ + + vlanEntry.vlanFidParams = vlanParamsForPrioTag; + vlanEntry.vlanId = (uint16_t)0; + + ENET_IOCTL_SET_IN_ARGS(&prms, &vlanEntry); + ENET_IOCTL(handle, core_id, ICSSG_PER_IOCTL_VLAN_SET_ENTRY, &prms, status); + + if (status != ENET_SOK) + { + EnetAppUtils_print("FID VLAN entry for VID = 0: FAILED = %u : FAILED\r\n", status); + return status; + } + + /* -----------------Make a default entry for Host port----------------- */ + status = eth_vlan_addDefaultHostVid(handle, core_id, 0, vlanId); + if (status != ENET_SOK) + { + EnetAppUtils_print("\n ERROR: In updating default VLAN for Host : %d\r\n", status); + } + + /* -----------------Make a default entry for P1 port----------------- */ + status = eth_vlan_addDefaultPortVid(handle, core_id, ENET_MAC_PORT_1, 1, vlanId); + if (status != ENET_SOK) + { + EnetAppUtils_print("\n ERROR: In updating default VLAN for P1 \r\n\r"); + return status; + } + + if (enetType == ENET_ICSSG_SWITCH) + { + /* -----------------Make a default entry for P2 port----------------- */ + status = eth_vlan_addDefaultPortVid(handle, core_id, ENET_MAC_PORT_2, 2, vlanId); + if (status != ENET_SOK) + { + EnetAppUtils_print("\n ERROR: In updating default VLAN for P2 \r\n\r"); + return status; + } + } + + return status; +} + +/*int32_t eth_vlan_addMacFdbEntry(Enet_Handle handle, + uint32_t core_id, + Semaphore& ioctl_sem, + Icssg_MacAddr mac, + int16_t vlanId, + uint8_t fdbEntryPort) +{ + int32_t status = ENET_EFAIL; + int32_t semStatus; + Enet_IoctlPrms prms; + Icssg_FdbEntry fdbEntry; + int i = 0; + + // Now make an entry in FDB for the HOST MAC address using Asynchronous IOCTL + for (i = 0; i < ENET_MAC_ADDR_LEN; i++) + { + fdbEntry.macAddr[i] = mac.macAddr[i]; + } + + fdbEntry.vlanId = vlanId; + fdbEntry.fdbEntry[0] = fdbEntryPort; + fdbEntry.fdbEntry[1] = fdbEntryPort; + + ENET_IOCTL_SET_IN_ARGS(&prms, &fdbEntry); + ENET_IOCTL(handle, core_id, ICSSG_FDB_IOCTL_ADD_ENTRY, &prms, status); + + if (status == ENET_SINPROGRESS) + { + EnetAppUtils_print("Success: IOCTL command sent for making MAC entry in FDB \r\n"); + + // Wait for asyc ioctl to complete + do + { + Enet_poll(handle, ENET_EVT_ASYNC_CMD_RESP, NULL, 0U); + semStatus = ioctl_sem.pend(1U); + } while (semStatus != SystemP_SUCCESS); + + status = ENET_SOK; + } + else + { + EnetAppUtils_print("ERROR: IOCTL command sent for making MAC entry in FDB failed as vlanId out of range \r\n"); + EnetAppUtils_print("ERROR: IOCTL command sent for making MAC entry in FDB \r\n"); + } + + return status; +}*/ diff --git a/components/free_rtos/ethernet/eth_vlan.h b/components/free_rtos/ethernet/eth_vlan.h new file mode 100644 index 0000000..1dc39a2 --- /dev/null +++ b/components/free_rtos/ethernet/eth_vlan.h @@ -0,0 +1,62 @@ +/* + * eth_vlan.hpp + * + * Created on: 9 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_VLAN_HPP_ +#define FREE_RTOS_ETHERNET_ETH_VLAN_HPP_ + +//#include "semaphore/semaphore.hpp" + +#include +//#include + +#include + +//namespace free_rtos { +#ifdef __cplusplus +extern "C" { +#endif + +int32_t eth_vlan_setPriorityRegMapping(Enet_Handle handle, + uint32_t core_id, + Enet_MacPort macPort, + uint32_t *prioRegenMap); + +int32_t eth_vlan_setPriorityMapping(Enet_Handle handle, + uint32_t core_id, + Enet_MacPort macPort, + uint32_t *prioMap); + +int32_t eth_vlan_addDefaultHostVid(Enet_Handle handle, + uint32_t core_id, + uint8_t pcp, + uint16_t vlan_id); + +int32_t eth_vlan_addDefaultPortVid(Enet_Handle handle, + uint32_t core_id, + Enet_MacPort macPort, + uint8_t pcp, + uint16_t vlanId); + +int32_t eth_vlan_init(Enet_Handle handle, + uint32_t core_id, + uint16_t vlanId, + Enet_Type enetType); + +/*int32_t eth_vlan_addMacFdbEntry(Enet_Handle handle, + uint32_t core_id, + Semaphore& ioctl_sem, + Icssg_MacAddr mac, + int16_t vlanId, + uint8_t fdbEntryPort); + +}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* FREE_RTOS_ETHERNET_ETH_VLAN_HPP_ */ diff --git a/components/free_rtos/ethernet_industry/eth_ecat.cpp b/components/free_rtos/ethernet_industry/eth_ecat.cpp new file mode 100644 index 0000000..6f3580f --- /dev/null +++ b/components/free_rtos/ethernet_industry/eth_ecat.cpp @@ -0,0 +1,211 @@ +/* + * 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); +} + +int32_t EthEcat::Process(uint8_t * p_data, uint32_t len) { + p_pkt_next_->length = len + sizeof(TEthFrameHeader); + + memcpy(p_pkt_next_->data, p_data - sizeof(TEthFrameHeader), p_pkt_next_->length); + + ++stat_.rx_pkt; + + rx_sem_.post(); + + return 0; +} + +std::vector EthEcat::receive_datagram() { + rx_sem_.pend(); + + return std::vector(p_pkt_next_->data + sizeof(TEthFrameHeader), p_pkt_next_->data + p_pkt_next_->length); +} + +void EthEcat::send_datagram(const std::vector& datagram) { + TEthFrameHeader *p_eth_hdr = reinterpret_cast(p_pkt_->data); + uint8_t *p_eth_data = reinterpret_cast(p_pkt_->data + sizeof(TEthFrameHeader)); + + uint8_t mac_dest[ETH_FRAME_MAC_ADDR_LEN_BYTES] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint8_t mac_src[ETH_FRAME_MAC_ADDR_LEN_BYTES] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + + memcpy(p_eth_hdr->mac_dest, mac_dest, sizeof(mac_dest)); + memcpy(p_eth_hdr->mac_src, mac_src, sizeof(mac_src)); + p_eth_hdr->prot_id = ETH_PROT_ECAT_LE; + + memcpy(p_eth_data, datagram.data(), datagram.size()); + + p_pkt_->length = sizeof(TEthFrameHeader) + datagram.size(); + + bool stat = tx_flow_.send(port_id_, p_pkt_->data, p_pkt_->length); + + if (stat) + { + ++stat_.tx_pkt; + } +} + +void EthEcat::set_slaves_to_default() { +/* deact loop manual */ + uint8_t a_data_out{0x00}; + datagram::EcatDatagram a{ {{0x0000, ECT_REG_DLPORT}}, a_data_out }; + +/* set IRQ mask */ + uint16_t b_data_out{0x0C04}; + datagram::EcatDatagram b{ {{0x0000, ECT_REG_IRQMASK}}, b_data_out }; + +/* reset CRC counters */ + std::array c_data_out; + datagram::EcatDatagram> c{ {{0x0000, ECT_REG_RXERR}}, c_data_out }; + +/* reset FMMU's */ + std::array d_data_out; + std::array d_data_in; + datagram::EcatDatagram> d{ {{0x0000, ECT_REG_FMMU0}}, d_data_out }; + +/* reset SyncM */ + std::array e_data_out; + datagram::EcatDatagram> e{ {{0x0000, ECT_REG_SM0}}, e_data_out }; + +/* reset activation register */ + uint8_t f_data_out{0x00}; + datagram::EcatDatagram f{ {{0x0000, ECT_REG_DCSYNCACT}}, f_data_out }; + +/* reset system time+ofs */ + std::array g_data_out; + datagram::EcatDatagram> g{ {{0x0000, ECT_REG_DCSYSTIME}}, g_data_out }; + +/* DC speedstart */ + uint16_t h_data_out{0x1000}; + datagram::EcatDatagram h{ {{0x0000, ECT_REG_DCSPEEDCNT}}, h_data_out }; + +/* DC filt expr */ + uint16_t i_data_out{0x0C00}; + datagram::EcatDatagram i{ {{0x0000, ECT_REG_DCTIMEFILT}}, i_data_out }; + +/* Ignore Alias register */ + uint8_t j_data_out{0x00}; + datagram::EcatDatagram j{ {{0x0000, ECT_REG_DLALIAS}}, j_data_out }; + +/* Reset all slaves to Init */ + uint8_t k_data_out{0x00}; + datagram::EcatDatagram k{ {{0x0000, ECT_REG_ALCTL}}, k_data_out }; + +/* force Eeprom from PDI */ + uint8_t l_data_out{0x02}; + datagram::EcatDatagram l{ {{0x0000, ECT_REG_EEPCFG}}, l_data_out }; + +/* set Eeprom to master */ + uint8_t m_data_out{0x00}; + datagram::EcatDatagram m{ {{0x0000, ECT_REG_EEPCFG}}, m_data_out }; + + a + b + c + d + e + f + g + h + i + j + k + l + m; + telegram_.transfer(a); + + 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() { + uint16_t data_out{0x0000}; + datagram::EcatDatagram datagram{ {{0x0000, ECT_REG_TYPE}}, data_out }; + + telegram_.transfer(datagram); + + return datagram.get_wkc(); +} + +void EthEcat::set_addresses_of_slaves(uint16_t address_base) { + std::array, max_number_of_slaves> datagrams; + + for(uint16_t i = 0; i < number_of_slaves_; i++) { + slaves_[i].set_slave_address(static_cast(address_base + i)); + slaves_[i].set_slave_address(static_cast(-i)); + + datagrams[i] = { {{address::Position{static_cast(-i)}, ECT_REG_STADR}}, slaves_[i].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::array, max_number_of_slaves> datagrams; + + for(uint16_t i = 0; i < number_of_slaves_; i++) { + slaves_[i].set_slave_address(static_cast(-i)); + + datagrams[i] = { {{address::Position{static_cast(-i)}, ECT_REG_STADR}}, slaves_[i].get_slave_address() }; + } + + for(uint16_t i = 1; i < number_of_slaves_; i++) { + datagrams[i - 1] + datagrams[i]; + } + + telegram_.transfer(datagrams[0]); + + for(uint16_t i = 0; i < number_of_slaves_; i++) { + DebugP_log("Slave %d address = %d\r\n", i, slaves_[i].get_slave_address()); + } +} + +uint16_t EthEcat::config_init() { + DebugP_log("Initializing slaves...\r\n"); + + set_slaves_to_default(); + number_of_slaves_ = slaves_detecting(); + DebugP_log("number_of_slaves = %d\r\n", number_of_slaves_); + + set_addresses_of_slaves(0x1000); + get_addresses_of_slaves(); + + address::Node node = 4096; + + BufferProperties mbx_write_adr_len; + eeprom_.read(node, ECT_SII_RXMBXADR, mbx_write_adr_len); + + BufferProperties mbx_read_adr_len; + eeprom_.read(node, ECT_SII_TXMBXADR, mbx_read_adr_len); + + DebugP_log("response = 0x%04x\r\n", mbx_write_adr_len); + DebugP_log("response = 0x%04x\r\n", mbx_read_adr_len); + + return number_of_slaves_; +} + +} diff --git a/components/free_rtos/ethernet_industry/eth_ecat.hpp b/components/free_rtos/ethernet_industry/eth_ecat.hpp new file mode 100644 index 0000000..3a0961e --- /dev/null +++ b/components/free_rtos/ethernet_industry/eth_ecat.hpp @@ -0,0 +1,141 @@ +/* + * eth_ecat.hpp + * + * Created on: 16 ���. 2023 �. + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_HPP_ +#define FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_HPP_ + +#include +#include + +#include "handler_store/handler.hpp" +#include "ethernet/eth_frame.h" +#include "mutex/mutex.hpp" +#include "semaphore/semaphore.hpp" +#include "ethernet/eth.hpp" +#include "ethernet_industry/ethercattype.hpp" +#include "ethernet_industry/eth_ecat_types.h" +#include "ethernet_industry/eth_ecat_command.hpp" +#include "ethernet_industry/eth_ecat_eeprom.hpp" + +namespace free_rtos { + +struct BufferProperties { + uint16_t address; + uint16_t length; +}; + +class EcatSlave { +public: + EcatSlave() { + + } + + template + void set_slave_address(typename TypeT::TSlaveAddress&& slave_address) { + std::get(TypeT::type)>(slave_addresses_) = slave_address; + } + + template + typename TypeT::TSlaveAddress& get_slave_address() { + return std::get(TypeT::type)>(slave_addresses_); + } + +private: + address::SlaveTypes slave_addresses_; + + BufferProperties mbx_write_; + BufferProperties mbx_read_; + + BufferProperties pdo_output_; + BufferProperties mbx_input_; +}; + +class EthEcat : public Handler { +public: + struct Statistic { + uint32_t rx_pkt; + uint32_t tx_pkt; + }; + + EthEcat(Eth& eth); + + void Init(TEthMacPorts port_id); + + std::vector receive_datagram(); + void send_datagram(const std::vector& datagram); + + void set_slaves_to_default(); + uint16_t slaves_detecting(); + void set_addresses_of_slaves(uint16_t address_base); + void get_addresses_of_slaves(); + + /* + * Тип адресации slave_address зависит от типа команды CommandT + * Может иметь тип Position, Broadcast, Node + * Logical не поддерживается + */ + template + void simple_send_datagram(typename TypeT::TSlaveAddress& slave_address, uint16_t offset, EcatDgDataT& data) { + using TCommand = command::EcatCommand; + datagram::EcatDatagram datagram{ {{slave_address, offset}}, data }; + + telegram_.transfer(datagram); + } + + datagram::EcatTelegram& get_telegram() { + return telegram_; + } + + eeprom::EEPROM& get_eeprom() { + return eeprom_; + } + + uint16_t config_init(); + + bool is_ready() { return ready_; } + + Statistic getStat() { return stat_;} + + virtual int32_t Process(uint8_t * p_data, uint32_t len) override; /// ��������� �� ������ ecat +private: + enum { + e_pktFirst, + e_pktSecond, + e_pktTotal + }; + + static constexpr uint16_t max_number_of_slaves = 32; + + TEthPkt * p_pkt_; + TEthPkt * p_pkt_next_; + + TEthPkt pkt_[e_pktTotal]; + + Mutex mut_; + + free_rtos::Semaphore rx_sem_; + + Eth& eth_; + EthTxFlowIface& tx_flow_; + + datagram::EcatTelegram telegram_; + eeprom::EEPROM eeprom_; + + TEthMacPorts port_id_; /// ���� ���� ����� ���������� ������ + + bool ready_; + + Statistic stat_; + + std::array slaves_; + + uint16_t number_of_slaves_ = 0; +}; + +} + +#endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_HPP_ */ diff --git a/components/free_rtos/ethernet_industry/eth_ecat_command.hpp b/components/free_rtos/ethernet_industry/eth_ecat_command.hpp new file mode 100644 index 0000000..56645f7 --- /dev/null +++ b/components/free_rtos/ethernet_industry/eth_ecat_command.hpp @@ -0,0 +1,230 @@ +/* + * eth_ecat_commands.hpp + * + * Created on: May 2, 2023 + * Author: algin + */ + +#ifndef FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_COMMAND_HPP_ +#define FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_COMMAND_HPP_ + +#include +#include +#include +#include + +#include "ethernet_industry/ethercattype.hpp" +#include "ethernet_industry/eth_ecat_types.h" + +namespace free_rtos { + +namespace address { + +// Slave addressing types +using Position = int16_t; +using Broadcast = uint16_t; +using Node = uint16_t; +using Logical = uint32_t; + +/* +struct Position { + Position(int16_t val): val_{val} { } + Position() { } + + int16_t val_; +}; + +struct Broadcast { + Broadcast(uint16_t val): val_{val} { } + Broadcast() { } + + uint16_t val_; +}; + +struct Node { + Node(uint16_t val): val_{val} { } + Node() { } + + uint16_t val_; +}; + +struct Logical { + Logical(uint32_t val): val_{val} { } + Logical() { } + + uint32_t val_; +}; +*/ +using SlaveTypes = std::tuple; + +// Register offset +using Offset = uint16_t; + +using PositionAddress = std::tuple; +using BroadcastAddress = std::tuple; +using NodeAddress = std::tuple; +using LogicalAddress = std::tuple; + +using Types = std::tuple; + +} // namespace address + +namespace command { + +enum class DIR_INDEX : uint16_t { + RD = 0, + WR, + RW, + RMW, + NO = RMW +}; + +enum class TYPE_INDEX : uint16_t { + AP = 0, + B, + FP, + L +}; + + +struct DirBase { + +}; + +template +struct Dir : public DirBase { + static constexpr DIR_INDEX dir = dir_index; +}; + +using RD = Dir; +using WR = Dir; +using RW = Dir; +using RMW = Dir; +using NO = Dir; + +struct TypeBase { + +}; + +template +struct Type : public TypeBase { + using TAddress = typename std::tuple_element(type_index), address::Types>::type; + using TSlaveAddress = typename std::tuple_element<0, TAddress>::type; + + static constexpr TYPE_INDEX type = type_index; + + static constexpr ec_cmdtype get_cmd(DIR_INDEX dir) { + std::array, 4> commands = {{ + {{EC_CMD_APRD, EC_CMD_APWR, EC_CMD_APRW, EC_CMD_ARMW}}, + {{EC_CMD_BRD, EC_CMD_BWR, EC_CMD_BRW, EC_CMD_NOP}}, + {{EC_CMD_FPRD, EC_CMD_FPWR, EC_CMD_FPRW, EC_CMD_FRMW}}, + {{EC_CMD_LRD, EC_CMD_LWR, EC_CMD_LRW, EC_CMD_NOP}} + }}; + + return commands[static_cast(type)][static_cast(dir)]; + } +}; + +using AP = Type; +using B = Type; +using FP = Type; +using L = Type; + +class EcatCommandBase { +public: + EcatCommandBase(ec_cmdtype cmd) + : cmd_{cmd} { } + + EcatCommandBase() + : cmd_{ec_cmdtype::EC_CMD_NOP} { } + + uint8_t get_cmd() { + return cmd_; + } + +private: + ec_cmdtype cmd_; +}; + +template +class EcatCommand : public EcatCommandBase { + static_assert(std::is_base_of::value == true, "TypeT should be derived from CMD::TypeBase"); + static_assert(std::is_base_of::value == true, "DirT should be derived from CMD::DirBase"); + +public: + EcatCommand(typename TypeT::TAddress fields) + : EcatCommandBase{TypeT::get_cmd(DirT::dir)} + , address_{fields} { } + + EcatCommand() { } + + uint32_t get_address() { + return address_.dword_; + } + +private: + template + union Address + { + Address(FieldsT fields) + : fields_{fields} { } + + Address() { } + + Address& operator=(const Address& other) { + fields_ = other.fields_; + + return *this; + } + + FieldsT fields_; + uint32_t dword_; + }; + + Address address_; +}; + +/* + * Position addressing + * arg0: Each slave increments Position. Slave is addressed if Position = 0. + * arg1: Local register or memory address of the ESC + */ +using APRD = EcatCommand; +using APWR = EcatCommand; +using APRW = EcatCommand; +using ARMW = EcatCommand; + +/* + * Broadcast addressing + * arg0: Each slave increments Position (not used for addressing) + * arg1: Local register or memory address of the ESC + */ +using NOP = EcatCommand; +using BRD = EcatCommand; +using BRW = EcatCommand; +using BWR = EcatCommand; + +// Node addressing shortcuts + +/* + * arg0: Slave is addressed if Address matches Configured Station Address or Configured Station Alias (if enabled). + * arg1: Local register or memory address of the ESC + */ +using FPRD = EcatCommand; +using FPRW = EcatCommand; +using FPWR = EcatCommand; +using FPMW = EcatCommand; + +/* + * Logical addressing + * arg0: Logical Address (configured by FMMUs) Slave is addressed if FMMU configuration matches Address. + */ +using LRD = EcatCommand; +using LRW = EcatCommand; +using LWR = EcatCommand; + +} // namespace command + +} + +#endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_COMMAND_HPP_ */ diff --git a/components/free_rtos/ethernet_industry/eth_ecat_datagram.cpp b/components/free_rtos/ethernet_industry/eth_ecat_datagram.cpp new file mode 100644 index 0000000..b85e845 --- /dev/null +++ b/components/free_rtos/ethernet_industry/eth_ecat_datagram.cpp @@ -0,0 +1,70 @@ +/* + * eth_ecat_datagram.cpp + * + * Created on: May 2, 2023 + * Author: algin + */ + +#include + +namespace free_rtos { + +namespace datagram { + +int32_t EcatTelegram::Process(uint8_t *p_data, uint32_t len) { + buffer_in_.length = len + sizeof(TEthFrameHeader); + + memcpy(buffer_in_.data, p_data - sizeof(TEthFrameHeader), buffer_in_.length); + + rx_sem_.post(); + + return 0; +} + +void EcatTelegram::pack(IEcatDatagram& first) { + TEthFrameHeader *p_eth_hdr = new(buffer_out_.data) TEthFrameHeader{ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + ETH_PROT_ECAT_LE}; + TEcatFrameHeader *p_hdr = new(buffer_out_.data + sizeof(TEthFrameHeader)) TEcatFrameHeader{ .bits.length = 0, + .bits.type = static_cast(ec_network::PROTOCOL_TYPE)}; + uint8_t *p_datagram_first = buffer_out_.data + sizeof(TEthFrameHeader) + sizeof(TEcatFrameHeader); + uint8_t *p_datagram_last = p_datagram_first; + IEcatDatagram *next = &first; + + while(next != nullptr) { + p_datagram_last = next->pack(p_datagram_last); + next = next->get_next(); + } + + p_hdr->bits.length = p_datagram_last - p_datagram_first; + buffer_out_.length = sizeof(TEthFrameHeader) + sizeof(TEcatFrameHeader) + p_hdr->bits.length; +} + +void EcatTelegram::unpack(IEcatDatagram& first) { + TEthFrameHeader *p_eth_hdr = reinterpret_cast(buffer_in_.data); + TEcatFrameHeader *p_hdr = reinterpret_cast(buffer_in_.data + sizeof(TEthFrameHeader)); + uint8_t *p_datagram_first = buffer_in_.data + sizeof(TEthFrameHeader) + sizeof(TEcatFrameHeader); + uint8_t *p_datagram_last = p_datagram_first; + IEcatDatagram *next = &first; + + while(next != nullptr) { + p_datagram_last = next->unpack(p_datagram_last); + next = next->get_next(); + } +} + +void EcatTelegram::transfer(IEcatDatagram& first) { + pack(first); + bool stat = tx_flow_.send(port_id_, buffer_out_.data, buffer_out_.length); + + if(stat == false) { + return; + } + + rx_sem_.pend(); + unpack(first); +} + +} + +} diff --git a/components/free_rtos/ethernet_industry/eth_ecat_datagram.hpp b/components/free_rtos/ethernet_industry/eth_ecat_datagram.hpp new file mode 100644 index 0000000..37443dd --- /dev/null +++ b/components/free_rtos/ethernet_industry/eth_ecat_datagram.hpp @@ -0,0 +1,205 @@ +/* + * eth_ecat_datagram.hpp + * + * Created on: May 2, 2023 + * Author: algin + */ + +#ifndef FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_DATAGRAM_HPP_ +#define FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_DATAGRAM_HPP_ + +#include + +#include "ethernet/eth.hpp" +#include "ethernet_industry/ethercattype.hpp" +#include "ethernet_industry/eth_ecat_types.h" +#include "ethernet_industry/eth_ecat_command.hpp" + +namespace free_rtos { + +namespace datagram { + +using TEcatWkc = uint16_t; + +template +struct EcatDg { +public: + EcatDg(uint8_t cmd, uint32_t address, EcatDgDataT& data, ec_moredatagrams more = ec_moredatagrams::EC_MOREDATAGRAMS_LAST, uint8_t idx = 0, uint16_t irq = 0) + : header_{ + cmd, + idx, + address, + {.bits = { + .len = sizeof(EcatDgDataT), + .c = static_cast(ec_circframe::EC_CIRCFRAME_NOT), + .m = static_cast(more)}}, + irq} + , data_{data} + , wkc_{0} { } + + EcatDg(uint8_t cmd, uint32_t address, ec_moredatagrams more = ec_moredatagrams::EC_MOREDATAGRAMS_LAST, uint8_t idx = 0, uint16_t irq = 0) + : header_{ + cmd, + idx, + address, + {.bits = { + .len = sizeof(EcatDgDataT), + .c = static_cast(ec_circframe::EC_CIRCFRAME_NOT), + .m = static_cast(more)}}, + irq} + , wkc_{0} { } + + EcatDg() { } + + TEcatDgHeader& get_header() { + return header_; + } + + EcatDgDataT& get_data() { + return data_; + } + + TEcatWkc get_wkc() { + return wkc_; + } + +private: + TEcatDgHeader header_; + EcatDgDataT data_; + TEcatWkc wkc_; + +} __attribute__ ((packed)); + +class IEcatDatagram { +public: + IEcatDatagram(ec_moredatagrams more, TEcatWkc wkc) + : more_{more} + , wkc_{wkc} + { } + + IEcatDatagram() { } + + IEcatDatagram& operator+(IEcatDatagram &next) { + more_ = ec_moredatagrams::EC_MOREDATAGRAMS_MORE; + next_ = &next; + + return next; + } + + IEcatDatagram* get_next() { + return next_; + } + + IEcatDatagram& set_next(IEcatDatagram &next) { + + return operator+(next); + } + + virtual uint8_t* pack(uint8_t *raw) = 0; + virtual uint8_t* unpack(uint8_t *raw) = 0; + + TEcatWkc get_wkc() { + return wkc_; + } + +protected: + ec_moredatagrams more_; + TEcatWkc wkc_; + +private: + IEcatDatagram *next_{nullptr}; +}; + +template +class EcatDatagram : public IEcatDatagram { + static_assert(std::is_base_of::value == true, "CommandT should be derived from ECatCommandBase"); + +public: + EcatDatagram(CommandT command, EcatDgDataT &data_out, EcatDgDataT &data_in) + : IEcatDatagram{ec_moredatagrams::EC_MOREDATAGRAMS_LAST, 0x0000} + , command_{command} + , data_out_{&data_out} + , data_in_{&data_in} { } + + EcatDatagram(CommandT command, EcatDgDataT &data) + : IEcatDatagram{ec_moredatagrams::EC_MOREDATAGRAMS_LAST, 0x0000} + , command_{command} + , data_out_{&data} + , data_in_{&data} { } + + EcatDatagram(CommandT command) + : IEcatDatagram{ec_moredatagrams::EC_MOREDATAGRAMS_LAST, 0x0000} + , command_{command} { } + + EcatDatagram() { } + + virtual uint8_t* pack(uint8_t *raw) override { + EcatDg *p_dg; + + if(data_out_ != nullptr) { + p_dg = new(raw) EcatDg {command_.get_cmd(), command_.get_address(), *data_out_, more_}; + }else{ + p_dg = new(raw) EcatDg {command_.get_cmd(), command_.get_address(), more_}; + } + + (void)p_dg; + + return (raw + sizeof(EcatDg)); + } + + virtual uint8_t* unpack(uint8_t *raw) override { + EcatDg *p_dg = reinterpret_cast*>(raw); + + if(data_in_ != nullptr) { + *data_in_ = p_dg->get_data(); + } + + wkc_ = p_dg->get_wkc(); + + return (raw + sizeof(EcatDg)); + } + +private: + CommandT command_; + EcatDgDataT *data_out_{nullptr}; + EcatDgDataT *data_in_{nullptr}; +}; + +class EcatTelegram : public Handler { +public: + EcatTelegram(Eth& eth) + : eth_{eth} + , tx_flow_{*eth.getTxFlowPtr()} { + eth_.getEthStackPtr()->Register(ETH_PROT_ECAT_LE, this); + } + + virtual int32_t Process(uint8_t *p_data, uint32_t len) override; + + void init(TEthMacPorts port_id) { + port_id_ = port_id; + } + + void transfer(IEcatDatagram& first); + +private: + Eth& eth_; + EthTxFlowIface& tx_flow_; + TEthMacPorts port_id_; + + free_rtos::Semaphore rx_sem_; + + TEthPkt buffer_out_; + TEthPkt buffer_in_; + + void pack(IEcatDatagram& first); + void unpack(IEcatDatagram& first); +}; + +} + + +} + + + +#endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_DATAGRAM_HPP_ */ diff --git a/components/free_rtos/ethernet_industry/eth_ecat_eeprom.hpp b/components/free_rtos/ethernet_industry/eth_ecat_eeprom.hpp new file mode 100644 index 0000000..8f78aad --- /dev/null +++ b/components/free_rtos/ethernet_industry/eth_ecat_eeprom.hpp @@ -0,0 +1,82 @@ +/* + * eth_ecat_eeprom.hpp + * + * Created on: May 2, 2023 + * Author: algin + */ + +#ifndef FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_EEPROM_HPP_ +#define FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_EEPROM_HPP_ + +#include + +namespace free_rtos { + +namespace eeprom { + +class EEPROM { +public: + EEPROM(datagram::EcatTelegram& telegram) + : telegram_{telegram} { } + + template + void wait_busy(typename TypeT::TSlaveAddress& slave_address) { + using TCommand = command::EcatCommand; + volatile uint16_t stat; + datagram::EcatDatagram datagram{ {{slave_address, ECT_REG_EEPSTAT}}, stat }; + + do { + telegram_.transfer(datagram); + }while((stat & EC_ESTAT_BUSY) != 0); + } + + template + void control_register(typename TypeT::TSlaveAddress& slave_address, ec_ecmdtype eeprom_cmd, uint16_t eeprom_address) { + using TCommand = command::EcatCommand; + std::array request{eeprom_cmd, eeprom_address}; + datagram::EcatDatagram> datagram{ {{slave_address, ECT_REG_EEPCTL}}, request }; + + telegram_.transfer(datagram); + } + + template + void data_register(typename TypeT::TSlaveAddress& slave_address, EcatDgDataT& data) { + using TCommand = command::EcatCommand; + datagram::EcatDatagram datagram{ {{slave_address, ECT_REG_EEPDAT}}, data }; + + telegram_.transfer(datagram); + } + + template + void read(typename TypeT::TSlaveAddress& slave_address, uint16_t eeprom_address, EcatDgDataT& data) { + wait_busy(slave_address); + + control_register(slave_address, EC_ECMD_READ, eeprom_address); + + wait_busy(slave_address); + + data_register(slave_address, data); + } + + template + void write(typename TypeT::TSlaveAddress& slave_address, uint16_t eeprom_address, EcatDgDataT& data) { + wait_busy(slave_address); + + data_register(slave_address, data); + + wait_busy(slave_address); + + control_register(slave_address, EC_ECMD_WRITE, eeprom_address); + } + +private: + datagram::EcatTelegram& telegram_; +}; + +} + +} + + + +#endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_EEPROM_HPP_ */ diff --git a/components/free_rtos/ethernet_industry/eth_ecat_types.h b/components/free_rtos/ethernet_industry/eth_ecat_types.h new file mode 100644 index 0000000..2db7505 --- /dev/null +++ b/components/free_rtos/ethernet_industry/eth_ecat_types.h @@ -0,0 +1,60 @@ +/* + * eth_ecat_types.h + * + * Created on: 16 ���. 2023 �. + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_TYPES_H_ +#define FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_TYPES_H_ + +#include + +#define ETH_PROT_ECAT_LE 0xa488 /// ETHERCAT +#define ETH_PROT_ECAT_BE 0x88a4 /// ETHERCAT + +/// ����������� ��������( ������� ��� ������� ��� be) +typedef struct +{ + uint16_t length : 11; /// ������� 11 + uint16_t reserved : 1; + uint16_t type : 4; +}TEcatFrameHeaderBits; + +/** + * ��������� ��������� ������ ethercat + */ +typedef union +{ + uint16_t all; + TEcatFrameHeaderBits bits; +}TEcatFrameHeader; + + +typedef struct { + uint16_t len : 11; + uint16_t reserved : 3; + uint16_t c : 1; /// Circulating Datagram + uint16_t m : 1; /// More EtherCAT Datagrams following +}TEcatDgLenBits; + +typedef union { + uint16_t all; + TEcatDgLenBits bits; +}TEcatDgLen; + +/** + * ��������� ��������� ���������� ethercat + * ����������� ��������( ������� ����� ������� ��� be), + * �� ��� �� ��������� ��� ����� ����� ������� 8 ���. + */ +typedef struct +{ + uint8_t cmd; + uint8_t idx; + uint32_t address; + TEcatDgLen len; + uint16_t irq; +} __attribute__ ((packed)) TEcatDgHeader; /// Ethercat datagram header + +#endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_TYPES_H_ */ diff --git a/components/free_rtos/ethernet_industry/ethercattype.hpp b/components/free_rtos/ethernet_industry/ethercattype.hpp new file mode 100644 index 0000000..8266542 --- /dev/null +++ b/components/free_rtos/ethernet_industry/ethercattype.hpp @@ -0,0 +1,300 @@ +/** \file + * \brief + * Типы данных и константы, используемые для работы с EtherCAT сетью. + */ +#ifndef ETHERCAT_MASTER_ETHERCATTYPE_HPP +#define ETHERCAT_MASTER_ETHERCATTYPE_HPP + +#include + +#include +#include +#include + +namespace free_rtos { + + const std::uint16_t COUNTER_INIT = 0u; + const std::uint16_t MIN_DATA_VECTOR_SIZE = 2u; + const std::uint16_t ONE_BYTE_SHIFT = 8u; + const std::uint16_t TWO_BYTE_SHIFT = 16u; + const std::uint16_t THREE_BYTE_SHIFT = 24u; + + + const std::uint16_t RESERVED_VALUE = 0; + + /*! + * Constants used to add_slaves Ethernet network when working with EtherCAT. + */ + enum class ec_network : std::uint16_t { + /** Port used to send EtherCAT datagrams */ + PROTOCOL_TYPE = 1u, + ETHERCAT_PORT = 34980u + + }; + + enum class sync_manager : std::uint16_t { + SYNC_M0 = 0, + SYNC_M1, + SYNC_M2, + SYNC_M3 + }; + enum class fmmu : std::uint16_t { + FMMU0 = 0, + FMMU1, + FMMU2, + FMMU3 + }; + + enum class DataDirection : std::uint8_t { + READ = 0x1, + WRITE = 0x2 + }; + + + /** + * Структура данных описывающая базовые настройки буффера данных, обрабатывающего меилбоксы. + */ + struct MbxBufferProperties { + /** Адрес в памяти подчиненного устройства для доступа на запись запросов */ + std::uint16_t mbx_write_adr; + /** Размер буфера данных, обрабатывающего меилбоксы */ + std::uint16_t mbx_write_len; + /** Адрес в памяти подчиненного устройства для доступа на чтение ответов */ + std::uint16_t mbx_read_adr; + /** Размер буфера данных, обрабатывающего меилбоксы */ + std::uint16_t mbx_read_len; + /** Адрес в памяти подчиненного устройства для доступа на чтение ответов */ + std::uint16_t pdo_output_adr; + /** Адрес в памяти подчиненного устройства для доступа на чтение ответов */ + std::uint16_t pdo_input_adr; + }; + + /*! + * EtherCAT commands types + */ + enum ec_cmdtype : std::uint16_t { + /** No operation */ + EC_CMD_NOP = 0x0, + /** Auto Increment Read */ + EC_CMD_APRD, + /** Auto Increment Write */ + EC_CMD_APWR, + /** Auto Increment Read Write */ + EC_CMD_APRW, + /** Configured Address Read */ + EC_CMD_FPRD, + /** Configured Address Write */ + EC_CMD_FPWR, + /** Configured Address Read Write */ + EC_CMD_FPRW, + /** Broadcast Read */ + EC_CMD_BRD, + /** Broadcast Write */ + EC_CMD_BWR, + /** Broadcast Read Write */ + EC_CMD_BRW, + /** Logical Memory Read */ + EC_CMD_LRD, + /** Logical Memory Write */ + EC_CMD_LWR, + /** Logical Memory Read Write */ + EC_CMD_LRW, + /** Auto Increment Read Multiple Write */ + EC_CMD_ARMW, + /** Configured Read Multiple Write */ + EC_CMD_FRMW + /** Reserved */ + } ; + + /** Ethercat registers */ + enum ec_reg_offset : std::uint16_t + { + ECT_REG_TYPE = 0x0000, + ECT_REG_PORTDES = 0x0007, + ECT_REG_ESCSUP = 0x0008, + ECT_REG_STADR = 0x0010, + ECT_REG_ALIAS = 0x0012, + ECT_REG_DLCTL = 0x0100, + ECT_REG_DLPORT = 0x0101, + ECT_REG_DLALIAS = 0x0103, + ECT_REG_DLSTAT = 0x0110, + ECT_REG_ALCTL = 0x0120, + ECT_REG_ALSTAT = 0x0130, + ECT_REG_ALSTATCODE = 0x0134, + ECT_REG_PDICTL = 0x0140, + ECT_REG_IRQMASK = 0x0200, + ECT_REG_RXERR = 0x0300, + ECT_REG_FRXERR = 0x0308, + ECT_REG_EPUECNT = 0x030C, + ECT_REG_PECNT = 0x030D, + ECT_REG_PECODE = 0x030E, + ECT_REG_LLCNT = 0x0310, + ECT_REG_WD_DIV = 0x0400, + ECT_REG_WD_TIME_PDI = 0x0410, + ECT_REG_WD_TIME_PD = 0x0420, + ECT_REG_WDCNT = 0x0442, + ECT_REG_EEPCFG = 0x0500, + ECT_REG_EEPCTL = 0x0502, + ECT_REG_EEPSTAT = 0x0502, + ECT_REG_EEPADR = 0x0504, + ECT_REG_EEPDAT = 0x0508, + ECT_REG_FMMU0 = 0x0600, + ECT_REG_FMMU1 = ECT_REG_FMMU0 + 0x10, + ECT_REG_FMMU2 = ECT_REG_FMMU1 + 0x10, + ECT_REG_FMMU3 = ECT_REG_FMMU2 + 0x10, + ECT_REG_SM0 = 0x0800, + ECT_REG_SM1 = ECT_REG_SM0 + 0x08, + ECT_REG_SM2 = ECT_REG_SM1 + 0x08, + ECT_REG_SM3 = ECT_REG_SM2 + 0x08, + ECT_REG_SM0STAT = ECT_REG_SM0 + 0x05, + ECT_REG_SM1STAT = ECT_REG_SM1 + 0x05, + ECT_REG_SM1ACT = ECT_REG_SM1 + 0x06, + ECT_REG_SM1CONTR = ECT_REG_SM1 + 0x07, + ECT_REG_DCTIME0 = 0x0900, + ECT_REG_DCTIME1 = 0x0904, + ECT_REG_DCTIME2 = 0x0908, + ECT_REG_DCTIME3 = 0x090C, + ECT_REG_DCSYSTIME = 0x0910, + ECT_REG_DCSOF = 0x0918, + ECT_REG_DCSYSOFFSET = 0x0920, + ECT_REG_DCSYSDELAY = 0x0928, + ECT_REG_DCSYSDIFF = 0x092C, + ECT_REG_DCSPEEDCNT = 0x0930, + ECT_REG_DCTIMEFILT = 0x0934, + ECT_REG_DCCUC = 0x0980, + ECT_REG_DCSYNCACT = 0x0981, + ECT_REG_DCSTART0 = 0x0990, + ECT_REG_DCCYCLE0 = 0x09A0, + ECT_REG_DCCYCLE1 = 0x09A4 + }; + + /** Ethercat registers */ + enum ec_pdo_assigment : std::uint16_t { + rx = 0x1C12, + tx = 0X1c13 + }; + + enum MailboxesRegs { + WRITE = 0, + READ, + EMPTY, + AVAILABLE + }; + + /** Possible EtherCAT slave states */ + typedef enum + { + /** No valid state. */ + EC_STATE_NONE = 0x00, + /** Init state*/ + EC_STATE_INIT = 0x01, + /** Pre-operational. */ + EC_STATE_PRE_OP = 0x02, + /** Boot state*/ + EC_STATE_BOOT = 0x03, + /** Safe-operational. */ + EC_STATE_SAFE_OP = 0x04, + /** Operational */ + EC_STATE_OPERATIONAL = 0x08, + /** Error or ACK error */ + EC_STATE_ACK = 0x10, + EC_STATE_ERROR = 0x10 + } ec_state; + + /** EEprom state machine read size */ + constexpr std::uint32_t EC_ESTAT_R64 = 0x0040; + /** EEprom state machine busy flag */ + constexpr std::uint32_t EC_ESTAT_BUSY = 0x8000; + /** EEprom state machine error flag mask */ + constexpr std::uint32_t EC_ESTAT_EMASK = 0x7800; + /** EEprom state machine error acknowledge */ + constexpr std::uint32_t EC_ESTAT_NACK = 0x2000; + + /** Ethercat EEprom command types */ + typedef enum + { + /** No operation */ + EC_ECMD_NOP = 0x0000, + /** Read */ + EC_ECMD_READ = 0x0100, + /** Write */ + EC_ECMD_WRITE = 0x0201, + /** Reload */ + EC_ECMD_RELOAD = 0x0300 + } ec_ecmdtype; + + /** Item offsets in SII general section */ + enum + { + ECT_SII_MANUF = 0x0008, + ECT_SII_ID = 0x000a, + ECT_SII_REV = 0x000c, + ECT_SII_BOOTRXMBX = 0x0014, + ECT_SII_BOOTTXMBX = 0x0016, + ECT_SII_MBXSIZE = 0x0019, + ECT_SII_TXMBXADR = 0x001a, + ECT_SII_RXMBXADR = 0x0018, + ECT_SII_MBXPROTO = 0x001c, + ECT_PDOOUTPUTADR = 0x0078, + ECT_PDOINPUTADR = 0x007c + + }; + + /*! + * Circulating frames bit + */ + enum class ec_circframe : std::uint16_t { + /** Frame is not circulating */ + EC_CIRCFRAME_NOT = 0u, + /** Frame has circulated once */ + EC_CIRCFRAME_ONCE, + } ; + + /** standard SM0 flags configuration for mailbox slaves */ + constexpr std::uint32_t EC_DEFAULTMBXSM0 = 0x00010026; + /** standard SM1 flags configuration for mailbox slaves */ + constexpr std::uint32_t EC_DEFAULTMBXSM1 = 0x00010022; + /** standard SM2 flags configuration for mailbox slaves */ + constexpr std::uint32_t EC_DEFAULTMBXSM2 = 0x00010074; + /** standard SM3 flags configuration for mailbox slaves */ + constexpr std::uint32_t EC_DEFAULTMBXSM3 = 0x00010030; + + + + + /*! + * More EtherCAT datagrams bit + */ + enum ec_moredatagrams : std::uint16_t { + /** Last EtherCAT datagram */ + EC_MOREDATAGRAMS_LAST = 0u, + /** More EtherCAT datagrams will follow */ + EC_MOREDATAGRAMS_MORE, + } ; + + + /** EtherCAT Frame Header : + *
Length - 11 bit : Length of the EtherCAT datagrams (excl. FCS) + *
Reserved - 1 bit: Reserved, 0 + *
Type - 4 bit : Protocol type. Only EtherCAT commands (Type = 0x1) are supported by ESCs. + */ + struct EthercatFrameHeader { + enum EthercatFrameHeaderSizes : std::uint16_t { + RESERVED = 1u, + TYPE = 4u, + LENGHT = 11u + }; + + + std::uint16_t lenght : EthercatFrameHeaderSizes::LENGHT; + std::uint16_t res : EthercatFrameHeaderSizes::RESERVED; + std::uint16_t type : EthercatFrameHeaderSizes::TYPE; + }; + + constexpr static std::uint16_t write_synch_manager_buffer_size = 256; + constexpr static std::uint16_t read_synch_manager_buffer_size = 256; + +} // namespace ethercat + + +#endif //ETHERCAT_MASTER_ETHERCATTYPE_HPP diff --git a/components/free_rtos/ethernet_ip/eth_arp.cpp b/components/free_rtos/ethernet_ip/eth_arp.cpp new file mode 100644 index 0000000..eafa70f --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_arp.cpp @@ -0,0 +1,206 @@ +/* + * eth_arp.cpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ +#include "ethernet_ip/eth_arp.hpp" +#include "ethernet/eth_frame.h" +#include "ethernet_ip/eth_prots_id.h" +#include "ethernet_ip/eth_ip_types.h" + +#include + +#define ARP_ETH_TYPE_BE 0x1000 + +void free_rtos::clock_timeout(ClockP_Object * obj, void * arg) +{ + EthArp * p_arp = ( EthArp *)arg; + + /// ip + if (p_arp->tmrGratuitous_.tick(100)) + { + if (p_arp->table_mac_.empty()) { + p_arp->request(p_arp->self_ip_); + } + } + + for (auto& item : p_arp->table_ip_) + { + auto& ip_data = item.second; + if (ip_data.tmr.tick(100)) + { + if (++ip_data.attemps >= p_arp->max_attemps_) + { + ip_data.tmr.stop(); + ip_data.attemps = 0; + } + else + { + p_arp->request(item.first); /// mac ip + } + } + } +} + +free_rtos::EthArp::EthArp(EthStackIface& eth_stack) : + eth_stack_{eth_stack} +{ + +} + +bool free_rtos::EthArp::init(TEthMacPorts eth_port_id, uint64_t self_mac, uint32_t self_ip) +{ + self_mac_ = self_mac; + self_ip_ = self_ip; + + eth_port_id_ = eth_port_id; + + init_request_pkt(self_mac_, self_ip_); + + clock_.init(100, free_rtos::clock_timeout, this); /// 100 + + tmrGratuitous_.start(1000); /// 1 + + clock_.start(); + + return true; +} + +void free_rtos::EthArp::init_request_pkt(uint64_t self_mac, uint32_t self_ip) +{ + TArpHeader * arp_hdr = (TArpHeader *)(request_pkt_.data + sizeof(TEthFrameHeader)); + + /// ARP + memcpy(arp_hdr->ar_sha, &self_mac_, ETH_FRAME_MAC_ADDR_LEN_BYTES); + memset(arp_hdr->ar_tha, 0, ETH_FRAME_MAC_ADDR_LEN_BYTES); + memcpy(arp_hdr->ar_spa, &self_ip_, ETH_IP_ADDR_LEN); + + arp_hdr->ar_op = arp_opr_be_[e_oprRequest]; + arp_hdr->ar_hrd = ARP_ETH_TYPE_BE; + arp_hdr->ar_pro = ETH_PROT_IP_BE; + + arp_hdr->ar_hln = ETH_FRAME_MAC_ADDR_LEN_BYTES; + + arp_hdr->ar_pln = ETH_IP_ADDR_LEN; +} + +bool free_rtos::EthArp::request(uint32_t ip) +{ + TArpHeader * arp_hdr = (TArpHeader *)(request_pkt_.data + sizeof(TEthFrameHeader)); + + /// ip- + memcpy(arp_hdr->ar_tpa, &ip, ETH_IP_ADDR_LEN); + + request_pkt_.length = sizeof(TArpHeader); + + /// + return eth_stack_.send_pkt(eth_port_id_, ETH_FRAME_MAC_ADDR_BROADCAST, ETH_PROT_ARP_BE, request_pkt_); +} + +bool free_rtos::EthArp::try_request(uint32_t ip) +{ + ArpIpReqData * p_ip_req_data = nullptr; + auto item = table_ip_.find(ip); + + if (item == table_ip_.end()) + { + p_ip_req_data = &table_ip_[ip]; /// + } + else + { + p_ip_req_data = &item->second; + if (p_ip_req_data->mac != 0) { + return true; /// + } + else if (p_ip_req_data->tmr.is_started()) { + return true; /// + + } + } + + p_ip_req_data->attemps = 0; + p_ip_req_data->tmr.start(1000); /// 1 + + return request(ip); +} + +void free_rtos::EthArp::add(uint64_t mac, uint32_t ip) { + table_mac_[mac] = ip; + + auto& item = table_ip_[ip]; + + item.mac = mac; + item.attemps = 0; + item.tmr.stop(); +} + +bool free_rtos::EthArp::getIpAddr(uint64_t mac, uint32_t& ip) { + auto item = table_mac_.find(mac); + + if (item == table_mac_.end()) { + return false; + } + + ip = item->second; + + return true; +} + +bool free_rtos::EthArp::getMacAddr(uint32_t ip, uint64_t& mac) { + auto item = table_ip_.find(ip); + + if (item == table_ip_.end()) { + try_request(ip); + return false; + } + + mac = item->second.mac; + + return true; +} + +int32_t free_rtos::EthArp::Process(uint8_t * p_data, uint32_t len) +{ + TArpHeader * arp_hdr = (TArpHeader *)(p_data); + uint16_t type = arp_hdr->ar_op; + + uint64_t mac_sender = 0; + uint32_t ip_sender = 0; + + memcpy(&mac_sender, arp_hdr->ar_sha, ETH_FRAME_MAC_ADDR_LEN_BYTES); + memcpy(&ip_sender, arp_hdr->ar_spa, ETH_IP_ADDR_LEN); + + /** + * ip == 0, "Who has....". + * . + */ + if (ip_sender == 0) { + return 0; + } + /// arp- + add(mac_sender, ip_sender); + + if ( type == arp_opr_be_[e_oprRequest]) + { + uint32_t ip_target; + memcpy(&ip_target, arp_hdr->ar_tpa, ETH_IP_ADDR_LEN); + + if (ip_target == self_ip_) + { + /// - + arp_hdr->ar_op = arp_opr_be_[e_oprReply]; + /// mac + memcpy(arp_hdr->ar_tha, arp_hdr->ar_sha, ETH_FRAME_MAC_ADDR_LEN_BYTES); + memcpy(arp_hdr->ar_sha, &self_mac_, ETH_FRAME_MAC_ADDR_LEN_BYTES); + /// ip + memcpy(arp_hdr->ar_tpa, arp_hdr->ar_spa, ETH_IP_ADDR_LEN); + memcpy(arp_hdr->ar_spa, &self_ip_, ETH_IP_ADDR_LEN); + + /// + return len; + } + } + + return 0; +} diff --git a/components/free_rtos/ethernet_ip/eth_arp.hpp b/components/free_rtos/ethernet_ip/eth_arp.hpp new file mode 100644 index 0000000..a8c3081 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_arp.hpp @@ -0,0 +1,79 @@ +/* + * eth_arp.hpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_ARP_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_ARP_HPP_ + +#include +#include +#include "ethernet_ip/eth_arp_iface.hpp" +#include "ethernet_ip/eth_stack_iface.hpp" +#include "handler_store/handler.hpp" +#include "clock/clock.hpp" +#include "timer_sw/timer_sw.hpp" + + +namespace free_rtos { + +class EthArp : public Handler, public EthArpIface { +public: + EthArp(EthStackIface& eth_stack); + + bool init(TEthMacPorts eth_port_id, uint64_t self_mac, uint32_t self_ip); + + bool getIpAddr(uint64_t mac, uint32_t& ip); + + virtual bool getMacAddr(uint32_t ip, uint64_t& mac) override; + + bool try_request(uint32_t ip); + + virtual int32_t Process(uint8_t * p_data, uint32_t len) override; +private: + bool request(uint32_t ip); + + void add(uint64_t mac, uint32_t ip); + + void init_request_pkt(uint64_t self_mac, uint32_t self_ip); + + friend void clock_timeout(ClockP_Object * obj, void * arg); +private: + enum Operations { + e_oprRequest, + e_oprReply, + e_oprTotal + }; + + struct ArpIpReqData { + uint64_t mac = 0; /// - + uint32_t attemps = 0; /// + TimerSw tmr; /// + }; + + static const uint32_t pkt_len = 42; + const uint16_t arp_opr_be_[e_oprTotal] = {0x0100, 0x0200}; + const uint32_t max_attemps_ = 8; + + TEthPkt request_pkt_; + + std::map table_mac_; /// mac, ip + std::map table_ip_; /// ip, + + uint64_t self_mac_; + uint32_t self_ip_; + + TEthMacPorts eth_port_id_; + + EthStackIface& eth_stack_; + + Clock clock_; + + TimerSw tmrGratuitous_; +}; + +} + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_ARP_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_arp_iface.hpp b/components/free_rtos/ethernet_ip/eth_arp_iface.hpp new file mode 100644 index 0000000..51020c4 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_arp_iface.hpp @@ -0,0 +1,24 @@ +/* + * eth_arp_iface.hpp + * + * Created on: 14 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_ARP_IFACE_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_ARP_IFACE_HPP_ + +namespace free_rtos { + +class EthArpIface { +public: + virtual bool getMacAddr(uint32_t ip, uint64_t& mac) = 0; + + virtual ~EthArpIface() {}; +}; + +} + + + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_ARP_IFACE_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_checksum.c b/components/free_rtos/ethernet_ip/eth_checksum.c new file mode 100644 index 0000000..05ee2fd --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_checksum.c @@ -0,0 +1,27 @@ +/* + * eth_checksum.c + * + * Created on: 13 . 2023 . + * Author: sychev + */ +#include "ethernet_ip/eth_checksum.h" + +uint16_t eth_calcChksum(uint32_t sum, uint8_t * const data, uint16_t len) +{ + uint16_t i; + uint16_t size = len - 1; + + if ( !len ) + return 0; + + for ( i = 0; i < size; i+=2 ) + sum += ((uint16_t)data[i] << 8) + data[i+1]; + + if (len & 0x01) + sum += (uint16_t)data[i] << 8; + + while ( sum >> 16 ) + sum = (sum & 0xFFFF) + (sum >> 16); + + return ~sum; +} diff --git a/components/free_rtos/ethernet_ip/eth_checksum.h b/components/free_rtos/ethernet_ip/eth_checksum.h new file mode 100644 index 0000000..f1887bb --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_checksum.h @@ -0,0 +1,23 @@ +/* + * eth_checksum.h + * + * Created on: 13 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_CHECKSUM_H_ +#define FREE_RTOS_ETHERNET_ETH_CHECKSUM_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint16_t eth_calcChksum(uint32_t sum, uint8_t * const data, uint16_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* FREE_RTOS_ETHERNET_ETH_CHECKSUM_H_ */ diff --git a/components/free_rtos/ethernet_ip/eth_icmp.cpp b/components/free_rtos/ethernet_ip/eth_icmp.cpp new file mode 100644 index 0000000..fd9f525 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_icmp.cpp @@ -0,0 +1,42 @@ +/* + * eth_icmp.cpp + * + * Created on: 14 . 2023 . + * Author: sychev + */ +#include "ethernet_ip/eth_icmp.hpp" +#include "ethernet_ip/eth_icmp_types.h" +#include "ethernet_ip/eth_ip_checksum.h" +#include "base/swap.h" + +int32_t free_rtos::EthIcmp::Process(uint8_t * p_data, uint32_t len) +{ + TIcmpEchoHeader * hdr = (TIcmpEchoHeader*)p_data; + uint32_t ul_icmp_len = len; + + if (hdr->type != ICMP_ECHO_REQUEST) { + return 0; + } + + hdr->type = ICMP_ECHO_REPLY; + hdr->code = 0; + hdr->cksum = 0; + + /* Checksum of the ICMP message */ + if (ul_icmp_len % 2) + { + *(((uint8_t *) hdr) + ul_icmp_len) = 0; + ++ul_icmp_len; + } + + ul_icmp_len = ul_icmp_len / 2; + + uint16_t chsum = eth_ip_calcChecksum((uint16_t *)hdr, ul_icmp_len); + + hdr->cksum = BASE_SWAP16(chsum); + + ++rx_cnt_; + + return len; +} + diff --git a/components/free_rtos/ethernet_ip/eth_icmp.hpp b/components/free_rtos/ethernet_ip/eth_icmp.hpp new file mode 100644 index 0000000..93eea99 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_icmp.hpp @@ -0,0 +1,28 @@ +/* + * eth_icmp.hpp + * + * Created on: 14 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_ICMP_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_ICMP_HPP_ + +#include "handler_store/handler.hpp" + +#include + +namespace free_rtos { + +class EthIcmp : public Handler { +public: + virtual int32_t Process(uint8_t * p_data, uint32_t len) override; + + uint32_t getStat() {return rx_cnt_;}; +private: + uint32_t rx_cnt_ = 0; +}; + +} + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_ICMP_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_icmp_types.h b/components/free_rtos/ethernet_ip/eth_icmp_types.h new file mode 100644 index 0000000..ed730cf --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_icmp_types.h @@ -0,0 +1,57 @@ +/* + * eth_icmp_types.h + * + * Created on: 14 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_ICMP_TYPES_H_ +#define FREE_RTOS_ETHERNET_IP_ETH_ICMP_TYPES_H_ + +#include + +/** ICMP types */ +/* http://www.iana.org/assignments/icmp-parameters */ +#define ICMP_ECHO_REPLY 0x00 /**< Echo reply (used to ping) */ +/* 1 and 2 Reserved */ +#define ICMP_DEST_UNREACHABLE 0x03 /**< Destination Unreachable */ +#define ICMP_SOURCE_QUENCH 0x04 /**< Source Quench */ +#define ICMP_REDIR_MESSAGE 0x05 /**< Redirect Message */ +#define ICMP_ALT_HOST_ADD 0x06 /**< Alternate Host Address */ +/* 0x07 Reserved */ +#define ICMP_ECHO_REQUEST 0x08 /**< Echo Request */ +#define ICMP_ROUTER_ADV 0x09 /**< Router Advertisement */ +#define ICMP_ROUTER_SOL 0x0A /**< Router Solicitation */ +#define ICMP_TIME_EXC 0x0B /**< Time Exceeded */ +#define ICMP_PARAM_PB 0x0C /**< Parameter Problem: Bad IP header */ +#define ICMP_TIMESTAMP 0x0D /**< Timestamp */ +#define ICMP_TIMESTAMP_REP 0x0E /**< Timestamp Reply */ +#define ICMP_INFO_REQ 0x0F /**< Information Request */ +#define ICMP_INFO_REPLY 0x10 /**< Information Reply */ +#define ICMP_ADD_MASK_REQ 0x11 /**< Address Mask Request */ +#define ICMP_ADD_MASK_REP 0x12 /**< Address Mask Reply */ +/* 0x13 Reserved for security */ +/* 0X14 through 0x1D Reserved for robustness experiment */ +#define ICMP_TRACEROUTE 0x1E /**< Traceroute */ +#define ICMP_DAT_CONV_ERROR 0x1F /**< Datagram Conversion Error */ +#define ICMP_MOB_HOST_RED 0x20 /**< Mobile Host Redirect */ +#define ICMP_W_A_Y 0x21 /**< Where-Are-You (originally meant for IPv6) */ +#define ICMP_H_I_A 0x22 /**< Here-I-Am (originally meant for IPv6) */ +#define ICMP_MOB_REG_REQ 0x23 /**< Mobile Registration Request */ +#define ICMP_MOB_REG_REP 0x24 /**< Mobile Registration Reply */ +#define ICMP_DOM_NAME_REQ 0x25 /**< Domain Name Request */ +#define ICMP_DOM_NAME_REP 0x26 /**< Domain Name Reply */ +#define ICMP_SKIP_ALGO_PROT 0x27 /**< SKIP Algorithm Discovery Protocol, Simple Key-Management for Internet Protocol */ +#define ICMP_PHOTURIS 0x28 /**< Photuris, Security failures */ +#define ICMP_EXP_MOBIL 0x29 /**< ICMP for experimental mobility protocols such as Seamoby [RFC4065] */ + +/** ICMP echo header structure */ +typedef struct { + uint8_t type; /**< Type of message */ + uint8_t code; /**< Type subcode */ + uint16_t cksum; /**< 1's complement cksum of struct */ + uint16_t id; /**< Identifier */ + uint16_t seq; /**< Sequence number */ +} __attribute__ ((packed)) TIcmpEchoHeader; /* GCC */ + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_ICMP_TYPES_H_ */ diff --git a/components/free_rtos/ethernet_ip/eth_ip.cpp b/components/free_rtos/ethernet_ip/eth_ip.cpp new file mode 100644 index 0000000..64ed112 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_ip.cpp @@ -0,0 +1,129 @@ +/* + * eth_ip.cpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ +#include "ethernet_ip/eth_ip.hpp" +#include "ethernet_ip/eth_ip_types.h" +#include "ethernet_ip/eth_checksum.h" + +#include "ethernet/eth_frame.h" +#include "base/swap.h" + + +#include + +#define IP_TIME_TO_LIVE 64 +#define IP_VER 4 +#define IP_HEADER_WORD_SIZE 5 + +static void ip_swap_ip ( uint8_t * const dest_ip, uint8_t * const source_ip ) +{ + uint8_t i = 0; + + for (i = 0; i < ETH_IP_ADDR_LEN; i++) + { + uint8_t tmp = dest_ip[i]; + dest_ip[i] = source_ip[i]; + source_ip[i] = tmp; + } +} + +free_rtos::EthIp::EthIp(EthStackIface& eth_stack, EthArpIface& arp) : + eth_stack_{eth_stack}, + arp_{arp} +{ + +} + +int32_t free_rtos::EthIp::Process(uint8_t * p_data, uint32_t len) +{ + TIpHeader * ip_hdr = (TIpHeader *)p_data; + uint32_t ip_addr; + + memcpy(&ip_addr, ip_hdr->ip_dst, ETH_IP_ADDR_LEN); + + if (ip_addr != self_ip_) { + return 0; + } + + int32_t reply = handlers_.Process(ip_hdr->ip_p, p_data + sizeof(TIpHeader), len - sizeof(TIpHeader)); + + if (reply > 0) { + uint16_t cksum; + uint16_t len; + /* Swap the IP destination address and the IP source address */ + ip_swap_ip(ip_hdr->ip_dst, ip_hdr->ip_src); + reply += sizeof(TIpHeader); + ip_hdr->ip_len = BASE_SWAP16(reply); + ip_hdr->ip_id = BASE_SWAP16(ip_indet_); + //------------------------------------------------------- + ip_hdr->ip_sum = 0; + len = (ip_hdr->ip_hl_v & 0x0F) * 4; + cksum = eth_calcChksum(0,(uint8_t *)ip_hdr, len); + ip_hdr->ip_sum = BASE_SWAP16(cksum); + //------------------------------------------------------- + ++ip_indet_; + } + + return reply; +} + +bool free_rtos::EthIp::send(TEthMacPorts port_id, uint32_t dest_ip, uint8_t prot_id, TEthPkt& pkt) +{ + uint64_t mac_dst; + + /// mac- arp + if (!arp_.getMacAddr(dest_ip, mac_dst)) { + /* + * arp- , arp- + * ( getMacAddr) + */ + return false; + } + + uint16_t cksum = 0; + uint16_t len = 0; + + TIpHeader * ip_header = (TIpHeader *)(pkt.data + sizeof(TEthFrameHeader)); + + memcpy(ip_header->ip_src, &self_ip_, ETH_IP_ADDR_LEN); + + memcpy(ip_header->ip_dst, &dest_ip, ETH_IP_ADDR_LEN); + + ip_header->ip_hl_v = (IP_VER << 4) | IP_HEADER_WORD_SIZE; + + ip_header->ip_tos = 0; + + ip_header->ip_id = BASE_SWAP16(ip_indet_); + + ++ip_indet_; + + ip_header->ip_off = 0; + + ip_header->ip_ttl = IP_TIME_TO_LIVE; + + ip_header->ip_p = prot_id; + + len = (ip_header->ip_hl_v & 0x0F) * 4; + + pkt.length += len; + + ip_header->ip_len = BASE_SWAP16(pkt.length); + + ip_header->ip_sum = 0; + + cksum = eth_calcChksum(0,(uint8_t *)ip_header, len); + + ip_header->ip_sum = BASE_SWAP16(cksum); + + /// + return eth_stack_.send_pkt(port_id, mac_dst, ETH_PROT_IP_BE, pkt); +} + +bool free_rtos::EthIp::Register(uint8_t prot_id, Handler * p_handler) +{ + return handlers_.Register(prot_id, p_handler); +} + diff --git a/components/free_rtos/ethernet_ip/eth_ip.hpp b/components/free_rtos/ethernet_ip/eth_ip.hpp new file mode 100644 index 0000000..08a4a25 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_ip.hpp @@ -0,0 +1,50 @@ +/* + * eth_ip.hpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_IP_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_IP_HPP_ + +#include "handler_store/handler_store.hpp" +#include "ethernet_ip/eth_stack_iface.hpp" +#include "ethernet/eth_frame.h" +#include "ethernet_ip/eth_arp_iface.hpp" +#include "ethernet_ip/eth_ip_iface.hpp" + +#include + +namespace free_rtos { + +class EthIp : public Handler, public EthIpIface { +public: + EthIp(EthStackIface& eth_stack, EthArpIface& arp); + + void setSelfIpAddr(uint32_t ip) {self_ip_ = ip;}; + + virtual uint32_t getSelfIpAddr() override {return self_ip_;}; + + virtual int32_t Process(uint8_t * p_data, uint32_t len) override; + + virtual bool send(TEthMacPorts port_id, uint32_t dest_ip, uint8_t prot_id, TEthPkt& pkt) override; + + bool Register(uint8_t prot_id, Handler * p_handler); + +private: + HandlerStore handlers_; + + EthStackIface& eth_stack_; + EthArpIface& arp_; + + uint16_t ip_indet_; /// ip_id + + uint32_t self_ip_; /// ip- +}; + +} + + + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_IP_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_ip_checksum.c b/components/free_rtos/ethernet_ip/eth_ip_checksum.c new file mode 100644 index 0000000..8e12615 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_ip_checksum.c @@ -0,0 +1,22 @@ +/* + * eth_ip_checksum.c + * + * Created on: 14 . 2023 . + * Author: sychev + */ +#include "eth_ip_checksum.h" +#include "base/swap.h" + +uint16_t eth_ip_calcChecksum(uint16_t * const data, uint32_t length) +{ + uint32_t i, crc = 0; + + for (i = 0 ; i < length; ++i ) { + crc += BASE_SWAP16(data[i]); + } + + crc = (crc & 0xffff) + (crc >> 16); + + return (uint16_t) (~crc); +} + diff --git a/components/free_rtos/ethernet_ip/eth_ip_checksum.h b/components/free_rtos/ethernet_ip/eth_ip_checksum.h new file mode 100644 index 0000000..b454635 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_ip_checksum.h @@ -0,0 +1,23 @@ +/* + * eth_ip_checksum.h + * + * Created on: 14 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_IP_CHECKSUM_H_ +#define FREE_RTOS_ETHERNET_IP_ETH_IP_CHECKSUM_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint16_t eth_ip_calcChecksum(uint16_t * const data, uint32_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_IP_CHECKSUM_H_ */ diff --git a/components/free_rtos/ethernet_ip/eth_ip_iface.hpp b/components/free_rtos/ethernet_ip/eth_ip_iface.hpp new file mode 100644 index 0000000..9de2b2c --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_ip_iface.hpp @@ -0,0 +1,27 @@ +/* + * eth_ip_iface.hpp + * + * Created on: 15 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_IP_IFACE_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_IP_IFACE_HPP_ + +#include +#include "ethernet/eth_types.h" +#include "ethernet/eth_frame.h" + +class EthIpIface { +public: + /** + * + */ + virtual bool send(TEthMacPorts port_id, uint32_t dest_ip, uint8_t prot_id, TEthPkt& pkt) = 0; + + virtual uint32_t getSelfIpAddr() = 0; + + virtual ~EthIpIface() {}; +}; + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_IP_IFACE_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_ip_prots_id.h b/components/free_rtos/ethernet_ip/eth_ip_prots_id.h new file mode 100644 index 0000000..d57fa14 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_ip_prots_id.h @@ -0,0 +1,16 @@ +/* + * eth_ip_prots_id.h + * + * Created on: 14 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_IP_PROTS_ID_H_ +#define FREE_RTOS_ETHERNET_IP_ETH_IP_PROTS_ID_H_ + +#define IP_PROT_ICMP 1 +#define IP_PROT_IP 4 +#define IP_PROT_TCP 6 +#define IP_PROT_UDP 17 + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_IP_PROTS_ID_H_ */ diff --git a/components/free_rtos/ethernet_ip/eth_ip_types.h b/components/free_rtos/ethernet_ip/eth_ip_types.h new file mode 100644 index 0000000..8d5bfda --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_ip_types.h @@ -0,0 +1,51 @@ +/* + * eth_ip_types.h + * + * Created on: 13 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_IP_TYPES_H_ +#define FREE_RTOS_ETHERNET_IP_ETH_IP_TYPES_H_ + +#include + +#define ETH_IP_ADDR_LEN (4u) + +#define ETH_PROT_IP_LE 0x0800 /**< 2048 (0x0800) IPv4 */ +#define ETH_PROT_IP_BE 0x0008 /**< 2048 (0x0800) IPv4 */ + +typedef union { + uint8_t bytes[4]; + uint32_t addr; +}TEthIpAddr; + +/** ARP header structure */ +typedef struct { + uint16_t ar_hrd; /**< Format of hardware address */ + uint16_t ar_pro; /**< Format of protocol address */ + uint8_t ar_hln; /**< Length of hardware address */ + uint8_t ar_pln; /**< Length of protocol address */ + uint16_t ar_op; /**< Operation */ + uint8_t ar_sha[6]; /**< Sender hardware address */ + uint8_t ar_spa[4]; /**< Sender protocol address */ + uint8_t ar_tha[6]; /**< Target hardware address */ + uint8_t ar_tpa[4]; /**< Target protocol address */ +} __attribute__ ((packed)) TArpHeader; + +/** IP Header structure */ +typedef struct { + uint8_t ip_hl_v; /**< Header length and version */ + uint8_t ip_tos; /**< Type of service */ + uint16_t ip_len; /**< Total length */ + uint16_t ip_id; /**< Identification */ + uint16_t ip_off; /**< Fragment offset field */ + uint8_t ip_ttl; /**< Time to live */ + uint8_t ip_p; /**< Protocol */ + uint16_t ip_sum; /**< Checksum */ + uint8_t ip_src[4]; /**< Source IP address */ + uint8_t ip_dst[4]; /**< Destination IP address */ +} __attribute__ ((packed)) TIpHeader; /* GCC */ + + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_IP_TYPES_H_ */ diff --git a/components/free_rtos/ethernet_ip/eth_prots_id.h b/components/free_rtos/ethernet_ip/eth_prots_id.h new file mode 100644 index 0000000..482ef34 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_prots_id.h @@ -0,0 +1,19 @@ +/* + * eth_prot.h + * + * Created on: 13 . 2023 . + * Author: sychev + * Ethernet + */ + +#ifndef FREE_RTOS_ETHERNET_ETH_PROTS_ID_H_ +#define FREE_RTOS_ETHERNET_ETH_PROTS_ID_H_ + + +#define ETH_PROT_ARP_LE 0x0806 /// ARP +#define ETH_PROT_ARP_BE 0x0608 /// ARP + +#define ETH_PROT_IP_LE 0x0800 /// IPv4 +#define ETH_PROT_IP_BE 0x0008 /// IPv4 + +#endif /* FREE_RTOS_ETHERNET_ETH_PROTS_ID_H_ */ diff --git a/components/free_rtos/ethernet_ip/eth_stack.cpp b/components/free_rtos/ethernet_ip/eth_stack.cpp new file mode 100644 index 0000000..d7568e8 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_stack.cpp @@ -0,0 +1,101 @@ +/* + * eth_stack.cpp + * + * Created on: 14 . 2023 . + * Author: sychev + */ +#include "ethernet_ip/eth_stack.hpp" +#include "ethernet_ip/eth_prots_id.h" +#include "ethernet/eth_frame.h" + +#include "ethernet_ip/eth_ip_prots_id.h" + +#include + +free_rtos::EthStack::EthStack(EthTxFlowIface& tx_flow) : + tx_flow_{tx_flow}, + arp_{*this}, + ip_{*this, arp_}, + udp_{ip_} +{ + +} + +bool free_rtos::EthStack::init(Settings& sett) { + + eth_.self_mac_ = sett.mac_addr_be; + eth_.mac_port_ = sett.mac_port; + eth_.self_ip_ = sett.ip_addr_be; + + rx_pkt_handler_.Register(ETH_PROT_ARP_BE, &arp_); + rx_pkt_handler_.Register(ETH_PROT_IP_BE, &ip_); + + udp_.setPortId(eth_.mac_port_); + + ip_.setSelfIpAddr(eth_.self_ip_); + + ip_.Register(IP_PROT_ICMP, &icmp_); + ip_.Register(IP_PROT_UDP, &udp_); + + return true; +} + +bool free_rtos::EthStack::Register(uint32_t prot_id, Handler * p_handler) { + return rx_pkt_handler_.Register(prot_id, p_handler); +} + +void free_rtos::EthStack::set_mac_address(uint64_t mac_be) { + eth_.self_mac_ = mac_be; + arp_.init(eth_.mac_port_, eth_.self_mac_, eth_.self_ip_); +} + +bool free_rtos::EthStack::send_pkt(TEthMacPorts port_id, uint64_t mac_dst, uint16_t prot_id, TEthPkt& pkt) +{ + TEthFrameHeader * p_eth_hdr = (TEthFrameHeader *)pkt.data; + p_eth_hdr->prot_id = prot_id; + memcpy(p_eth_hdr->mac_src, ð_.self_mac_, ETH_FRAME_MAC_ADDR_LEN_BYTES); + memcpy(p_eth_hdr->mac_dest, &mac_dst, ETH_FRAME_MAC_ADDR_LEN_BYTES); + + pkt.length+= sizeof(TEthFrameHeader); + + return tx_flow_.send(eth_.mac_port_, pkt.data, pkt.length); +} + +void free_rtos::EthStack::rx_handler(uint8_t * p_data, uint32_t len) +{ + /// eth- = 60 + if ( len < ETH_FRAME_MIN_LEN) { + return; + } + + /// + uint64_t dest_addr = *((uint64_t*)p_data); + dest_addr &= ETH_FRAME_MAC_ADDR_MASK; /// 6 + + /// + if ((ETH_FRAME_MAC_ADDR_BROADCAST != dest_addr) && + (eth_.self_mac_ != dest_addr)) { + return; + } + + TEthFrameHeader * p_eth_hdr = (TEthFrameHeader *)p_data; + + /// + int32_t reply_len = rx_pkt_handler_.Process(p_eth_hdr->prot_id, + p_data + sizeof(TEthFrameHeader), + len - sizeof(TEthFrameHeader)); + + /// + if (reply_len > 0) { + /// mac- + memcpy(p_eth_hdr->mac_dest, p_eth_hdr->mac_src, ETH_FRAME_MAC_ADDR_LEN_BYTES); + /// mac- + memcpy(p_eth_hdr->mac_src, ð_.self_mac_, ETH_FRAME_MAC_ADDR_LEN_BYTES); + + reply_len+=sizeof(TEthFrameHeader); + + /// + tx_flow_.send(eth_.mac_port_, p_data, reply_len); + } +} + diff --git a/components/free_rtos/ethernet_ip/eth_stack.hpp b/components/free_rtos/ethernet_ip/eth_stack.hpp new file mode 100644 index 0000000..d32573c --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_stack.hpp @@ -0,0 +1,71 @@ +/* + * eth_stack.hpp + * + * Created on: 14 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_STACK_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_STACK_HPP_ + +#include "ethernet_ip/eth_arp.hpp" +#include "ethernet_ip/eth_ip.hpp" +#include "ethernet_ip/eth_icmp.hpp" +#include "ethernet_ip/eth_udp_server.hpp" + +#include "ethernet_ip/eth_stack_iface.hpp" +#include "handler_store/handler_store.hpp" + +#include "ethernet/eth_types.h" + +#include "ethernet/eth_tx_flow_iface.hpp" + +namespace free_rtos { + +class EthStack : public EthStackIface { +public: + struct Settings { + uint64_t mac_addr_be; /// big endian + uint32_t ip_addr_be; /// big endian + TEthMacPorts mac_port; + }; + + EthStack(EthTxFlowIface& tx_flow); + + bool init(Settings& sett); + + virtual void set_mac_address(uint64_t mac_be) override; + + virtual void rx_handler(uint8_t * p_data, uint32_t len) override; + + virtual bool send_pkt(TEthMacPorts port_id, uint64_t mac_dst, uint16_t prot_id, TEthPkt& pkt) override; + + EthUdpServerIface * getUdpServerPtr() {return &udp_;} + + /* + * ethernet + */ + virtual bool Register(uint32_t prot_id, Handler * p_handler) override; + +private: + struct EthData { + uint64_t self_mac_; /// + TEthMacPorts mac_port_; + uint32_t self_ip_; + }; + + EthTxFlowIface& tx_flow_; + HandlerStore rx_pkt_handler_; + + EthData eth_; + EthArp arp_; + EthIp ip_; + EthIcmp icmp_; + EthUdpServer udp_; +}; + +} + + + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_STACK_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_stack_iface.hpp b/components/free_rtos/ethernet_ip/eth_stack_iface.hpp new file mode 100644 index 0000000..fec9157 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_stack_iface.hpp @@ -0,0 +1,43 @@ +/* + * eth_stack_iface.hpp + * + * Created on: 14 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_STACK_IFACE_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_STACK_IFACE_HPP_ + +#include +#include "ethernet/eth_types.h" +#include "ethernet/eth_frame.h" +#include "handler_store/handler.hpp" + +class EthStackIface { +public: + /** + * mac- + */ + virtual void set_mac_address(uint64_t mac_addr_be) = 0; + + /** + * eth + */ + virtual void rx_handler(uint8_t * p_data, uint32_t len) = 0; + + /** + * + */ + virtual bool send_pkt(TEthMacPorts port_id, uint64_t mac_dst, uint16_t prot_id, TEthPkt& pkt) = 0; + + /** + * eth- + */ + virtual bool Register(uint32_t prot_id, Handler * p_handler) = 0; + + virtual ~EthStackIface() {}; +}; + + + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_STACK_IFACE_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_udp_client.cpp b/components/free_rtos/ethernet_ip/eth_udp_client.cpp new file mode 100644 index 0000000..659b4de --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_udp_client.cpp @@ -0,0 +1,129 @@ +/* + * eth_udp_client.cpp + * + * Created on: 15 . 2023 . + * Author: sychev + */ +#include "ethernet_ip/eth_udp_client.hpp" +#include "base/swap.h" +#include "ethernet_ip/eth_udp_types.h" +#include "ethernet_ip/eth_ip_types.h" +#include "ethernet_ip/eth_checksum.h" +#include "ethernet_ip/eth_ip_prots_id.h" + +#include +#include + + +free_rtos::EthUpdClient::EthUpdClient(EthIpIface& ip_iface, TEthMacPorts port_id, + uint16_t port_dst_be, uint16_t port_src_be, + bool use_chksum) : + port_dst_be_{port_dst_be}, + port_src_be_{port_src_be}, + use_checksum_{use_chksum}, + ip_iface_{ip_iface}, + port_id_{port_id} +{ +} + +void free_rtos::EthUpdClient::put_data(uint32_t src_ip, uint8_t * p_data, uint32_t len) +{ + if ((p_data == nullptr) || (len == 0)) { + return; + } + + /// + { + LockGuard lock(rx_mut_); /// + + /// + if (buff_.size() < max_buf_size) { + buff_.insert(buff_.end(), p_data, p_data + len); + } + } + + src_ip_ = src_ip; + + rx_sem_.post(); +} + +int32_t free_rtos::EthUpdClient::read(uint8_t * p_data, uint32_t len) +{ + if ((p_data == nullptr) || (len == 0)) { + return 0; + } + + /// , + if (buff_.empty()) { + rx_sem_.pend(); + } + + uint32_t size = buff_.size(); + + if (size > len) { + size = len; + } + + { + LockGuard lock(rx_mut_); /// + auto item_begin = buff_.begin(); + auto item_end = item_begin + size; + + /// + std::copy(item_begin, item_end, p_data); + /// + buff_.erase(item_begin, item_end); + } + + return size; +} + +void free_rtos::EthUpdClient::clear() +{ + LockGuard lock(rx_mut_); + buff_.clear(); +} + +int32_t free_rtos::EthUpdClient::write(uint32_t ip_dst_be, uint8_t * p_data, uint32_t len) +{ + TUdpHeader * hdr = (TUdpHeader *)(eth_pkt_.data + sizeof(TIpHeader) + sizeof(TEthFrameHeader)); + uint8_t * p_udp_data = (uint8_t *)(eth_pkt_.data + sizeof(TIpHeader) + sizeof(TEthFrameHeader) + sizeof(TUdpHeader)); + + if (ip_dst_be == 0) { + ip_dst_be = src_ip_; + } + + eth_pkt_.length = len + sizeof(TUdpHeader); + + hdr->Src_port = port_src_be_; + hdr->Dst_port = port_dst_be_; + hdr->Length = BASE_SWAP16(eth_pkt_.length); + hdr->Chk_sum = 0; + + /// + memcpy(p_udp_data, p_data, len); + + /// + if (use_checksum_) { + uint32_t self_ip = ip_iface_.getSelfIpAddr(); + uint32_t chk_sum32 = 0; + + uint8_t * const dst_ip = (uint8_t *)&ip_dst_be; + uint8_t * const src_ip = (uint8_t *)&self_ip; + + for (int j = 0; j < ETH_IP_ADDR_LEN; j += 2) + { + chk_sum32 += ((uint16_t)dst_ip[j] << 8) + dst_ip[j+1]; + chk_sum32 += ((uint16_t)src_ip[j] << 8) + src_ip[j+1]; + } + + chk_sum32 += IP_PROT_UDP + eth_pkt_.length; + + uint16_t chk_sum16 = eth_calcChksum(chk_sum32, (uint8_t *)hdr, eth_pkt_.length); + + hdr->Chk_sum = BASE_SWAP16(chk_sum16); + } + + return ip_iface_.send(port_id_, ip_dst_be, IP_PROT_UDP, eth_pkt_); +} + diff --git a/components/free_rtos/ethernet_ip/eth_udp_client.hpp b/components/free_rtos/ethernet_ip/eth_udp_client.hpp new file mode 100644 index 0000000..900374d --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_udp_client.hpp @@ -0,0 +1,62 @@ +/* + * eth_udp_client.hpp + * + * Created on: 15 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_UDP_CLIENT_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_UDP_CLIENT_HPP_ + +#include "semaphore/semaphore.hpp" +#include "mutex/mutex.hpp" +#include "ethernet/eth_frame.h" +#include "ethernet_ip/eth_ip_iface.hpp" +#include "ethernet/eth_types.h" + +#include +#include + +namespace free_rtos { + +class EthUpdClient { + friend class EthUdpServer; + +public: + EthUpdClient(EthIpIface& ip_iface, TEthMacPorts port_id, + uint16_t port_dst_be, uint16_t port_src_be, + bool use_chksum); + + int32_t read(uint8_t * p_data, uint32_t len); + + int32_t write(uint32_t ip_dst_be, uint8_t * p_data, uint32_t len); + + void clear(); /// + +private: + void put_data(uint32_t src_ip, uint8_t * p_data, uint32_t len); + +private: + const uint32_t max_buf_size = 0x100000; // 1Mb + + Semaphore rx_sem_; + Mutex rx_mut_; + + const uint16_t port_dst_be_; /// big endian + const uint16_t port_src_be_; /// big endian + const bool use_checksum_; + + std::vector buff_; + + TEthPkt eth_pkt_; + + EthIpIface& ip_iface_; + + const TEthMacPorts port_id_; + + uint32_t src_ip_; /// Ip UDP +}; + +} + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_UDP_CLIENT_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_udp_server.cpp b/components/free_rtos/ethernet_ip/eth_udp_server.cpp new file mode 100644 index 0000000..edc4961 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_udp_server.cpp @@ -0,0 +1,75 @@ +/* + * eth_udp.cpp + * + * Created on: 15 . 2023 . + * Author: sychev + */ +#include "ethernet_ip/eth_udp_server.hpp" +#include "ethernet_ip/eth_udp_types.h" +#include "ethernet_ip/eth_ip_types.h" +#include "base/swap.h" + + +free_rtos::EthUdpServer::EthUdpServer(EthIpIface& ip_iface) : + ip_iface_{ip_iface} +{ + +} + +std::shared_ptr free_rtos::EthUdpServer::createClient(uint16_t port_dst, + uint16_t port_src, + bool use_chksum) +{ + port_dst = BASE_SWAP16(port_dst); + port_src = BASE_SWAP16(port_src); + + /// + if (connections_.count(port_dst)) { + return nullptr; + } + + std::shared_ptr p_client = std::make_shared(ip_iface_, port_id_, + port_dst, port_src, use_chksum); + + if (p_client == nullptr) { + return nullptr; + } + + connections_[port_dst] = p_client; + + return p_client; +} + +int32_t free_rtos::EthUdpServer::Process(uint8_t * p_data, uint32_t len) +{ + if (len <= sizeof(TUdpHeader)) { + return 0; + } + + TUdpHeader * hdr = (TUdpHeader *)p_data; + + uint16_t port = hdr->Dst_port; + + auto item = connections_.find(port); + + /// + if (item == connections_.end()) { + return 0; + } + + auto& client = item->second; + + TIpHeader * p_ip_hdr = (TIpHeader*)(p_data - sizeof(TIpHeader)); + + uint32_t src_ip; + + memcpy(&src_ip, p_ip_hdr->ip_src, ETH_IP_ADDR_LEN); + + /// udp + client->put_data(src_ip, p_data + sizeof(TUdpHeader), len - sizeof(TUdpHeader)); + + return 0; +} + + + diff --git a/components/free_rtos/ethernet_ip/eth_udp_server.hpp b/components/free_rtos/ethernet_ip/eth_udp_server.hpp new file mode 100644 index 0000000..fa1c641 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_udp_server.hpp @@ -0,0 +1,44 @@ +/* + * eth_udp.hpp + * + * Created on: 15 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_UDP_SERVER_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_UDP_SERVER_HPP_ + +#include "handler_store/handler_store.hpp" +#include "ethernet_ip/eth_udp_server_iface.hpp" +#include "ethernet_ip/eth_ip_iface.hpp" +#include "ethernet/eth_types.h" +#include + +namespace free_rtos { + +class EthUdpServer : public Handler, public EthUdpServerIface { +public: + EthUdpServer(EthIpIface& ip_iface); + + void setPortId(TEthMacPorts port_id) { port_id_ = port_id;}; + + virtual std::shared_ptr createClient(uint16_t port_dst, + uint16_t port_src, + bool use_chksum) override; + + virtual int32_t Process(uint8_t * p_data, uint32_t len) override; + +private: + EthIpIface& ip_iface_; + + TEthMacPorts port_id_; + + std::map> connections_; /// - + + + ///HandlerStore handlers_; /// udp- +}; + +} + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_UDP_SERVER_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_udp_server_iface.hpp b/components/free_rtos/ethernet_ip/eth_udp_server_iface.hpp new file mode 100644 index 0000000..02506ed --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_udp_server_iface.hpp @@ -0,0 +1,28 @@ +/* + * eth_udp_server_iface.hpp + * + * Created on: 15 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_UDP_SERVER_IFACE_HPP_ +#define FREE_RTOS_ETHERNET_IP_ETH_UDP_SERVER_IFACE_HPP_ + +#include "ethernet_ip/eth_udp_client.hpp" + +#include + +#include + +namespace free_rtos { + +class EthUdpServerIface { +public: + virtual std::shared_ptr createClient(uint16_t port_dst, uint16_t port_src, bool use_chksum) = 0; + + virtual ~EthUdpServerIface() {}; +}; + +} + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_UDP_SERVER_IFACE_HPP_ */ diff --git a/components/free_rtos/ethernet_ip/eth_udp_types.h b/components/free_rtos/ethernet_ip/eth_udp_types.h new file mode 100644 index 0000000..bf49753 --- /dev/null +++ b/components/free_rtos/ethernet_ip/eth_udp_types.h @@ -0,0 +1,21 @@ +/* + * eth_udp_types.h + * + * Created on: 15 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_ETHERNET_IP_ETH_UDP_TYPES_H_ +#define FREE_RTOS_ETHERNET_IP_ETH_UDP_TYPES_H_ + +#include + +typedef struct +{ + uint16_t Src_port; + uint16_t Dst_port; + uint16_t Length; + uint16_t Chk_sum; +} __attribute__ ((packed)) TUdpHeader; + +#endif /* FREE_RTOS_ETHERNET_IP_ETH_UDP_TYPES_H_ */ diff --git a/components/free_rtos/gpio/gpio.cpp b/components/free_rtos/gpio/gpio.cpp new file mode 100644 index 0000000..acd4017 --- /dev/null +++ b/components/free_rtos/gpio/gpio.cpp @@ -0,0 +1,54 @@ +/* + * gpio.cpp + * + * Created on: 6 . 2023 . + * Author: sychev + */ + +#include "gpio/gpio.hpp" +#include + +free_rtos::Gpio::Gpio(uint32_t num, Dir dir, uint32_t base_address) : + num_{num}, + dir_{dir}, + base_addr_{base_address} +{ + uint32_t gpio_dir = GPIO_DIRECTION_INPUT; + if (dir_ == e_gpioDirOutput) { + gpio_dir = GPIO_DIRECTION_OUTPUT; + } + + GPIO_setDirMode(base_addr_, num_, gpio_dir); +} + +void free_rtos::Gpio::set() { + GPIO_pinWriteHigh(base_addr_, num_); +} + +void free_rtos::Gpio::clr() { + GPIO_pinWriteLow(base_addr_, num_); +} + +void free_rtos::Gpio::toggle() { + bool state = get(); + + if (state) { + clr(); + } + else { + set(); + } +} + +bool free_rtos::Gpio::get() { + bool out = false; + + if (dir_ == e_gpioDirInput) { + out = GPIO_pinRead(base_addr_, num_); + } + else if (dir_ == e_gpioDirOutput) { + out = GPIO_pinOutValueRead(base_addr_, num_); + } + + return out; +} diff --git a/components/free_rtos/gpio/gpio.hpp b/components/free_rtos/gpio/gpio.hpp new file mode 100644 index 0000000..cb569d2 --- /dev/null +++ b/components/free_rtos/gpio/gpio.hpp @@ -0,0 +1,45 @@ +/* + * gpio.hpp + * + * Created on: 6 . 2023 . + * Author: sychev + * SysConfig GPIO + */ + +#ifndef FREE_RTOS_GPIO_GPIO_HPP_ +#define FREE_RTOS_GPIO_GPIO_HPP_ + +#include + +namespace free_rtos { + +class Gpio { +public: + enum Dir { + e_gpioDirOutput = 0, + e_gpioDirInput + }; + /* + * num - + * Dir - / + */ + Gpio(uint32_t num, Dir dir, uint32_t base_address); + + void set(); + + void clr(); + + bool get(); + + void toggle(); + +private: + const uint32_t num_; + const Dir dir_; + const uint32_t base_addr_; +}; + +} + + +#endif /* FREE_RTOS_GPIO_GPIO_HPP_ */ diff --git a/components/free_rtos/handler_store/handler.hpp b/components/free_rtos/handler_store/handler.hpp new file mode 100644 index 0000000..43a1c77 --- /dev/null +++ b/components/free_rtos/handler_store/handler.hpp @@ -0,0 +1,22 @@ +/* + * handler_obj.hpp + * + * Created on: 6 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_HANDLER_STORE_HANDLER_HPP_ +#define FREE_RTOS_HANDLER_STORE_HANDLER_HPP_ + +#include + +class Handler { +public: + virtual int32_t Process(uint8_t * p_data, uint32_t len) = 0; + + ~Handler() {}; +}; + + + +#endif /* FREE_RTOS_HANDLER_STORE_HANDLER_HPP_ */ diff --git a/components/free_rtos/handler_store/handler_store.cpp b/components/free_rtos/handler_store/handler_store.cpp new file mode 100644 index 0000000..850965f --- /dev/null +++ b/components/free_rtos/handler_store/handler_store.cpp @@ -0,0 +1,46 @@ +/* + * handler_store.cpp + * + * Created on: 6 . 2023 . + * Author: sychev + */ +#include "handler_store/handler_store.hpp" + +bool HandlerStore::Register(uint32_t prot_id, Handler * p_handler) { + if (p_handler == nullptr) { + return false; + } + + if (handlers_.count(prot_id)) { + return false; /// + } + + /// + handlers_[prot_id] = p_handler; + + return true; +} + +int32_t HandlerStore::Process(uint32_t prot_id, uint8_t * p_data, uint32_t len) +{ + if ((p_data == nullptr) || (len == 0)) { + return 0; + } + + if (handlers_.empty()) { + return 0; + } + + auto item = handlers_.find(prot_id); + + /// + if (item == handlers_.end()) { + return 0; + } + + /// + return handlers_.at(prot_id)->Process(p_data, len); +} + + + diff --git a/components/free_rtos/handler_store/handler_store.hpp b/components/free_rtos/handler_store/handler_store.hpp new file mode 100644 index 0000000..84da306 --- /dev/null +++ b/components/free_rtos/handler_store/handler_store.hpp @@ -0,0 +1,32 @@ +/* + * handler_store.hpp + * + * Created on: 6 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_HANDLER_STORE_HANDLER_STORE_HPP_ +#define FREE_RTOS_HANDLER_STORE_HANDLER_STORE_HPP_ + + +#include +#include + +#include "handler_store/handler.hpp" + +class HandlerStore { +public: + /*** + * + */ + bool Register(uint32_t prot_id, Handler * p_handler); + /*** + * + */ + int32_t Process(uint32_t prot_id, uint8_t * p_data, uint32_t len); +private: + std::map handlers_; /// Ethernet +}; + + +#endif /* FREE_RTOS_HANDLER_STORE_HANDLER_STORE_HPP_ */ diff --git a/components/free_rtos/mutex/mutex.cpp b/components/free_rtos/mutex/mutex.cpp new file mode 100644 index 0000000..dc9ad22 --- /dev/null +++ b/components/free_rtos/mutex/mutex.cpp @@ -0,0 +1,35 @@ +/* + * mutex.cpp + * + * Created on: 26 . 2022 . + * Author: sychev + */ +#include "mutex/mutex.hpp" +#include + +free_rtos::Mutex::Mutex() { + handle_ = xSemaphoreCreateMutex(); + DebugP_assert(nullptr != handle_); +} + +BaseType_t free_rtos::Mutex::lock(TickType_t wait) { + return xSemaphoreTake( handle_, wait ); +} + +void free_rtos::Mutex::unlock(void) { + xSemaphoreGive(handle_); +} + +free_rtos::Mutex::~Mutex() { + vSemaphoreDelete(handle_); +} + +free_rtos::LockGuard::LockGuard(Mutex& mutex) : mutex_{mutex} { + mutex_.lock(); +} + +free_rtos::LockGuard::~LockGuard() { + mutex_.unlock(); +} + + diff --git a/components/free_rtos/mutex/mutex.hpp b/components/free_rtos/mutex/mutex.hpp new file mode 100644 index 0000000..58fa736 --- /dev/null +++ b/components/free_rtos/mutex/mutex.hpp @@ -0,0 +1,57 @@ +/* + * mutex.hpp + * + * Created on: 26 . 2022 . + * Author: sychev + */ + +#ifndef SRC_MUTEX_MUTEX_HPP_ +#define SRC_MUTEX_MUTEX_HPP_ + +#include +#include + +namespace free_rtos { + +/** + * @brief ++ ti rtos + * + */ +class Mutex { +public: + Mutex(); + + /** + * wait - , + * portMAX_DELAY - , 0 - + * pdTRUE + */ + BaseType_t lock(TickType_t wait = portMAX_DELAY); + + void unlock(void); + + ~Mutex(); + +private: + SemaphoreHandle_t handle_; +}; + +/** + * @brief LockGuard + * + */ +class LockGuard { +public: + LockGuard(Mutex& mutex); + + ~LockGuard(); + +private: + Mutex& mutex_; +}; + +} + + + +#endif /* SRC_MUTEX_MUTEX_HPP_ */ diff --git a/components/free_rtos/semaphore/semaphore.hpp b/components/free_rtos/semaphore/semaphore.hpp new file mode 100644 index 0000000..b0f4ca1 --- /dev/null +++ b/components/free_rtos/semaphore/semaphore.hpp @@ -0,0 +1,57 @@ +#ifndef SRC_APP_SEMAPHORE_SEMAPHORE_HPP_ +#define SRC_APP_SEMAPHORE_SEMAPHORE_HPP_ + +#include +#include + +namespace free_rtos { + +/** + * @brief ++ free rtos + * + */ +class Semaphore { +public: + enum Type { + e_semTypeBinary, + e_semTypeCounting + }; + + Semaphore() { + int32_t status = SystemP_FAILURE; + status = SemaphoreP_constructBinary(&sem_, 0); + DebugP_assert(SystemP_SUCCESS == status); + } + + Semaphore(Semaphore::Type type, uint32_t init_val, uint32_t max_val) { + int32_t status = SystemP_FAILURE; + + if (type == Semaphore::e_semTypeBinary) { + status = SemaphoreP_constructBinary(&sem_, init_val); + } + else if (type == Semaphore::e_semTypeCounting) { + status = SemaphoreP_constructCounting(&sem_, init_val, max_val); + } + + DebugP_assert(SystemP_SUCCESS == status); + } + + void post() { + SemaphoreP_post(&sem_); + } + + int32_t pend(uint32_t ticks = SystemP_WAIT_FOREVER) { + return SemaphoreP_pend(&sem_, ticks); + } + + ~Semaphore() { + SemaphoreP_destruct(&sem_); + } + +private: + SemaphoreP_Object sem_; +}; + +} + +#endif diff --git a/components/free_rtos/task/task.cpp b/components/free_rtos/task/task.cpp new file mode 100644 index 0000000..7ee1cce --- /dev/null +++ b/components/free_rtos/task/task.cpp @@ -0,0 +1,41 @@ +/* + * task.cpp + * + * Created on: 6 . 2023 . + * Author: sychev + */ +#include "task/task.hpp" + +bool free_rtos::Task::Create(std::string name, uint32_t priority, TaskFunction task_fun, + void * taskArg, int32_t stack_size_bytes) +{ + if ( (priority > TaskPriorityHiest) || (task_fun == nullptr) ) { + return false; + } + + if (stack_size_bytes < 0) + { + stack_size_bytes = defStackSize_; + } + + /// 32 + if (stack_size_bytes % 32) { + return false; + } + + auto ret = xTaskCreate(task_fun, + name.c_str(), + stack_size_bytes / sizeof(configSTACK_DEPTH_TYPE), + taskArg, + priority, + &taskHandle_); + + if (pdPASS != ret) { + return false; + } + + return true; +} + + + diff --git a/components/free_rtos/task/task.hpp b/components/free_rtos/task/task.hpp new file mode 100644 index 0000000..faa3e8e --- /dev/null +++ b/components/free_rtos/task/task.hpp @@ -0,0 +1,52 @@ +/* + * task.hpp + * + * Created on: 6 . 2023 . + * Author: sychev + * FreeRtos : + * xTaskCreate - + * xTaskCreateStatic - + * xTaskCreate + */ + +#ifndef FREE_RTOS_TASK_TASK_HPP_ +#define FREE_RTOS_TASK_TASK_HPP_ + +#include +#include + +#include "FreeRTOS.h" +#include "task.h" + +namespace free_rtos { +/** + * @brief free_rtos. + */ +class Task { +public: + /** + * @brief + * + */ + using TaskFunction = TaskFunction_t; + + static const uint32_t TaskPriorityHiest = configMAX_PRIORITIES - 1; // 31 + static const uint32_t TaskPriorityLowest = 0; // 0 + + bool Create(std::string name, uint32_t priority, TaskFunction task_fun, + void * taskArg, int32_t stack_size_bytes = -1); + + ~Task() { + vTaskDelete(taskHandle_); + } + +private: + static const uint32_t defStackSize_ = 8192; /// - + + TaskHandle_t taskHandle_; +}; + +} + + +#endif /* FREE_RTOS_TASK_TASK_HPP_ */ diff --git a/components/free_rtos/timer/timer.cpp b/components/free_rtos/timer/timer.cpp new file mode 100644 index 0000000..5eaf112 --- /dev/null +++ b/components/free_rtos/timer/timer.cpp @@ -0,0 +1,77 @@ +/* + * timer.cpp + * + * Created on: 10 . 2023 . + * Author: sychev + */ +#include "timer/timer.hpp" +#include +#include +#include + +using namespace free_rtos; + +void free_rtos::timer_isr_callback(void * arg) +{ + Timer * const p_timer = (Timer * const)arg; + + p_timer->sem_.post(); + + TimerP_clearOverflowInt(p_timer->base_addr_); + HwiP_clearInt(p_timer->int_num_); +} + +bool free_rtos::Timer::Init(Settings& sett) +{ + TimerP_Params timerParams; + HwiP_Params timerHwiParams; + int32_t status; + + /* set timer clock source */ + SOC_controlModuleUnlockMMR(SOC_DOMAIN_ID_MAIN, 2); + *(volatile uint32_t*)AddrTranslateP_getLocalAddr(sett.clock_src_mux_addr) = 0; /// CLOCK_SRC_MCU_HFOSC0 + SOC_controlModuleLockMMR(SOC_DOMAIN_ID_MAIN, 2); + + base_addr_ = (uint32_t)AddrTranslateP_getLocalAddr(sett.base_address); + + TimerP_Params_init(&timerParams); + timerParams.inputPreScaler = 1; + timerParams.inputClkHz = sett.input_clk_Hz; + timerParams.periodInNsec = sett.period_us * 1000; + timerParams.oneshotMode = 0; + timerParams.enableOverflowInt = 1; + timerParams.enableDmaTrigger = 0; + + TimerP_setup(base_addr_, &timerParams); + + int_num_ = sett.int_num; + + HwiP_Params_init(&timerHwiParams); + + timerHwiParams.intNum = int_num_; + timerHwiParams.callback = free_rtos::timer_isr_callback; + timerHwiParams.args = (void*)this; + timerHwiParams.isPulse = 0; + timerHwiParams.priority = sett.int_priority; + + status = HwiP_construct(&hwi_obj_, &timerHwiParams); + + return (status == SystemP_SUCCESS); +} + +void free_rtos::Timer::Wait() { + sem_.pend(); +} + +void free_rtos::Timer::Start() { + TimerP_start(base_addr_); +} + +void free_rtos::Timer::Stop() { + TimerP_stop(base_addr_); +} + + + + + diff --git a/components/free_rtos/timer/timer.hpp b/components/free_rtos/timer/timer.hpp new file mode 100644 index 0000000..5fe3328 --- /dev/null +++ b/components/free_rtos/timer/timer.hpp @@ -0,0 +1,56 @@ +/* + * timer.hpp + * + * Created on: 10 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_TIMER_TIMER_HPP_ +#define FREE_RTOS_TIMER_TIMER_HPP_ + +#include +#include +#include + + + +namespace free_rtos { + +class Timer { +public: + struct Settings { + uint32_t input_clk_Hz; /// + uint32_t base_address; /// + uint32_t clock_src_mux_addr; /// + uint32_t int_num; /// + uint32_t int_priority; /// + uint32_t period_us; /// + }; + + /** + * + */ + bool Init(Settings& sett); + + /** + * . . + */ + void Wait(); + + void Start(); + + void Stop(); +private: + friend void timer_isr_callback(void * arg); + +private: + uint32_t base_addr_; /// + uint32_t int_num_; /// + HwiP_Object hwi_obj_; /// + + Semaphore sem_; +}; + +} + +#endif /* FREE_RTOS_TIMER_TIMER_HPP_ */ diff --git a/components/free_rtos/timer_sw/timer_sw.cpp b/components/free_rtos/timer_sw/timer_sw.cpp new file mode 100644 index 0000000..40333f4 --- /dev/null +++ b/components/free_rtos/timer_sw/timer_sw.cpp @@ -0,0 +1,33 @@ +/* + * timer_sw.cpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ +#include "timer_sw/timer_sw.hpp" + +void TimerSw::start(uint32_t period) { + enable_ = true; + cnt_ = 0; + prd_ = period; +} + +void TimerSw::stop() { + enable_ = false; +} + +bool TimerSw::tick(uint32_t ticks) { + + if (!enable_) { + return false; + } + + cnt_+=ticks; + + if (cnt_ >= prd_) { + cnt_ = 0; + return true; + } + + return false; +} diff --git a/components/free_rtos/timer_sw/timer_sw.hpp b/components/free_rtos/timer_sw/timer_sw.hpp new file mode 100644 index 0000000..0eb88b1 --- /dev/null +++ b/components/free_rtos/timer_sw/timer_sw.hpp @@ -0,0 +1,31 @@ +/* + * timer_sw.hpp + * + * Created on: 13 . 2023 . + * Author: sychev + */ + +#ifndef FREE_RTOS_TIMER_SW_TIMER_SW_HPP_ +#define FREE_RTOS_TIMER_SW_TIMER_SW_HPP_ + +#include + +class TimerSw { +public: + void start(uint32_t period); + + void stop(); + + bool tick(uint32_t ticks); + + bool is_started() { return enable_; } + +private: + bool enable_ = false; + uint32_t cnt_ = 0; + uint32_t prd_ = 0; +}; + + + +#endif /* FREE_RTOS_TIMER_SW_TIMER_SW_HPP_ */