feat: First commit

Adds sitara_depot/free_rtos

Original one is on server_gorbunov/SmartForce4.0/sitara_depot
This commit is contained in:
algin 2023-05-03 14:01:32 +03:00
parent 52f8c89ec4
commit ae3cac8a7d
65 changed files with 5111 additions and 0 deletions

View File

@ -1,2 +1,3 @@
# sitara_depot
Хранилище программных модулей для процессора Sitara AM64x

View File

@ -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_ */

View File

@ -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_);
}

View File

@ -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 <kernel/dpl/ClockP.h>
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_ */

View File

@ -0,0 +1,301 @@
/*
* eth.cpp
*
* Created on: 9 <EFBFBD><EFBFBD><EFBFBD>. 2023 <EFBFBD>.
* Author: sychev
*/
#include "ethernet/eth.hpp"
#include "ethernet/eth_vlan.h"
#include "ethernet/eth_ioctl.h"
#include <networking/enet/core/include/core/enet_ioctl.h>
#include <kernel/dpl/DebugP.h>
#include <kernel/dpl/ClockP.h>
#include <cstring>
/*----------------------------------------------------------------------*/
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> sysconfig.
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <build_name>/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 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 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;
}
/// <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD> 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(); /// <20><><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
tx_flow_.enable((TEthMacPorts)i);
}
else {
tx_flow_.disable((TEthMacPorts)i);
}
linkUp_[i] = linkUp;
}
}
ClockP_usleep(100000); // 100ms /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 10<31><30> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
}
}
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;
}

View File

@ -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 <networking/enet/core/include/core/enet_per.h>
#include <networking/enet/utils/include/enet_apputils.h>
#include <networking/enet/core/include/per/icssg.h>
#include <cstdint>
#include <string>
#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 &eth_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_ */

View File

@ -0,0 +1,40 @@
/*
* eth_frame.h
*
* Created on: 7 <EFBFBD><EFBFBD><EFBFBD>. 2023 <EFBFBD>.
* Author: sychev
*/
#ifndef FREE_RTOS_ETHERNET_ETH_FRAME_H_
#define FREE_RTOS_ETHERNET_ETH_FRAME_H_
#include <stdint.h>
#define ETH_FRAME_MAC_ADDR_LEN_BYTES (6u)
#define ETH_FRAME_MAC_ADDR_MASK (0xFFFFFFFFFFFFul) /// 6 <20><><EFBFBD><EFBFBD>
#define ETH_FRAME_MAC_ADDR_BROADCAST (0xFFFFFFFFFFFFul) /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
#define ETH_FRAME_MIN_LEN (14u) /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#define ETH_FRAME_MAX_LEN (1518u) /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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_ */

View File

@ -0,0 +1,41 @@
/*
* eth_ioctl.c
*
* Created on: 10 ìàð. 2023 ã.
* Author: sychev
*/
#include "ethernet/eth_ioctl.h"
#include <networking/enet/core/include/per/icssg.h>
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;
}

View File

@ -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 <networking/enet/core/include/core/enet_base.h>
#include <networking/enet/core/include/core/enet_ioctl.h>
#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_ */

View File

@ -0,0 +1,227 @@
/*
* eth_rx_flow.cpp
*
* Created on: 7 <EFBFBD><EFBFBD><EFBFBD>. 2023 <EFBFBD>.
* Author: sychev
*/
#include "ethernet/eth_rx_flow.hpp"
#include <networking/enet/core/include/core/enet_soc.h>
#include <networking/enet/core/include/core/enet_queue.h>
#include <networking/enet/utils/include/enet_board.h>
#include <networking/enet/utils/include/enet_appmemutils.h>
#include <networking/enet/utils/include/enet_appmemutils_cfg.h>
#include <networking/enet/utils/include/enet_apputils.h>
/*----------------------------------------------------------------------*/
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> sysconfig.
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <build_name>/syscfg
*/
#include "ti_enet_config.h"
/*----------------------------------------------------------------------*/
using namespace free_rtos;
#define RX_TASK_STACK_SIZE (10U * 1024U) /// 10<31><30>
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
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; /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
EnetDma_PktQ rxFreeQ; /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
EnetDma_Pkt* rxPktInfo; /// <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int32_t status;
while(1)
{
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
sem_[e_signalRxPkt].pend();
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
EnetQueue_initQ(&rxReadyQ);
EnetQueue_initQ(&rxFreeQ);
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> rxReadyQ
status = EnetDma_retrieveRxPktQ(dma_handle_, &rxReadyQ);
EnetAppUtils_assert(status == ENET_SOK);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
rxPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rxReadyQ);
while(rxPktInfo != nullptr)
{
/// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (!passive_mode_)
{
/// <20> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
for (int j = 0 ; j < rxPktInfo->sgList.numScatterSegments; ++j)
{
eth_stack_.rx_handler(rxPktInfo->sgList.list[j].bufPtr, rxPktInfo->sgList.list[j].segmentFilledLen);
}
}
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
EnetDma_checkPktState(&rxPktInfo->pktState,
ENET_PKTSTATE_MODULE_APP,
ENET_PKTSTATE_APP_WITH_DRIVER,
ENET_PKTSTATE_APP_WITH_FREEQ);
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
EnetQueue_enq(&rxFreeQ, &rxPktInfo->node);
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
rxPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rxReadyQ);
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
++rx_pkt_counter_;
}
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ENET_PKTSTATE_APP_WITH_FREEQ)
* <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> ENET_PKTSTATE_APP_WITH_DRIVER. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> EnetDma_checkPktState.
*/
EnetAppUtils_validatePacketState(&rxFreeQ,
ENET_PKTSTATE_APP_WITH_FREEQ,
ENET_PKTSTATE_APP_WITH_DRIVER);
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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;
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
rxInArgs.notifyCb = rxIsrHandler; /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
rxInArgs.cbArg = this; /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
EnetApp_getRxDmaHandle(enetDmaRxChId, &rxInArgs, &rxChInfo);
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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);
}
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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;
}
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
eth_initRxReadyPktQ(dma_handle_, this);
open_ = true;
EnetAppUtils_print("rx_flow %u: rx flow open successfully\r\n", id);
return true;
}

View File

@ -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 <cstdint>
#include <networking/enet/core/include/dma/udma/enet_udma.h>
#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_ */

View File

@ -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 <utils/include/enet_board.h>
#include <networking/enet/core/include/per/icssg.h>
#include <networking/enet/utils/include/enet_apputils.h>
#define ETH_TYPES_MAC_PORT_MAX (2u) /// Êîëè÷åñòâî mac-ïîðòîâ
/// Ñãåíåðåííûå ôàéëû
#include <ti_board_config.h>
#include <stddef.h>
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, &ethPort.mii);
status = EnetBoard_setupPorts(&ethPort, 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(&ethPort);
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;
}
}

View File

@ -0,0 +1,227 @@
/*
* eth_tx_flow.cpp
*
* Created on: 7 ìàð. 2023 ã.
* Author: sychev
*/
#include "ethernet/eth_tx_flow.hpp"
#include <cstring>
#include <networking/enet/core/include/core/enet_soc.h>
#include <networking/enet/core/include/core/enet_queue.h>
#include <networking/enet/utils/include/enet_board.h>
#include <networking/enet/utils/include/enet_appmemutils.h>
#include <networking/enet/utils/include/enet_appmemutils_cfg.h>
#include <networking/enet/utils/include/enet_apputils.h>
/*----------------------------------------------------------------------*/
/**
* Ôàéëû ãåíåðèðóåìûå sysconfig.
* Ãåíåðèðóþòñÿ ïåðåä ñáîðêîé è ïîìåùàþòñÿ â ïàïêó <build_name>/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;
}

View File

@ -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 <cstdint>
#include <networking/enet/core/include/core/enet_dma.h>
#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_ */

View File

@ -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 <cstdint>
#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_ */

View File

@ -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_ */

View File

@ -0,0 +1,300 @@
/*
* eth_vlan.c
*
* Created on: 9 ìàð. 2023 ã.
* Author: sychev
*/
#include "ethernet/eth_vlan.h"
#include <networking/enet/utils/include/enet_apputils.h>
#include <networking/enet/core/include/core/enet_ioctl.h>
//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, &regenMap);
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;
}*/

View File

@ -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 <networking/enet/core/include/core/enet_base.h>
//#include <networking/enet/core/include/per/icssg.h>
#include <stdint.h>
//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_ */

View File

@ -0,0 +1,211 @@
/*
* eth_ecat.cpp
*
* Created on: 16 <EFBFBD><EFBFBD><EFBFBD>. 2023 <EFBFBD>.
* Author: sychev
*/
#include "ethernet_industry/eth_ecat.hpp"
#include <cstring>
#include <kernel/dpl/ClockP.h>
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<uint8_t> EthEcat::receive_datagram() {
rx_sem_.pend();
return std::vector<uint8_t>(p_pkt_next_->data + sizeof(TEthFrameHeader), p_pkt_next_->data + p_pkt_next_->length);
}
void EthEcat::send_datagram(const std::vector<uint8_t>& datagram) {
TEthFrameHeader *p_eth_hdr = reinterpret_cast<TEthFrameHeader*>(p_pkt_->data);
uint8_t *p_eth_data = reinterpret_cast<uint8_t*>(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<command::BWR, uint8_t> a{ {{0x0000, ECT_REG_DLPORT}}, a_data_out };
/* set IRQ mask */
uint16_t b_data_out{0x0C04};
datagram::EcatDatagram<command::BWR, uint16_t> b{ {{0x0000, ECT_REG_IRQMASK}}, b_data_out };
/* reset CRC counters */
std::array<uint8_t, 8> c_data_out;
datagram::EcatDatagram<command::BWR, std::array<uint8_t, 8>> c{ {{0x0000, ECT_REG_RXERR}}, c_data_out };
/* reset FMMU's */
std::array<uint8_t, 16*3> d_data_out;
std::array<uint8_t, 16*3> d_data_in;
datagram::EcatDatagram<command::BWR, std::array<uint8_t, 16*3>> d{ {{0x0000, ECT_REG_FMMU0}}, d_data_out };
/* reset SyncM */
std::array<uint8_t, 8*4> e_data_out;
datagram::EcatDatagram<command::BWR, std::array<uint8_t, 8*4>> e{ {{0x0000, ECT_REG_SM0}}, e_data_out };
/* reset activation register */
uint8_t f_data_out{0x00};
datagram::EcatDatagram<command::BWR, uint8_t> f{ {{0x0000, ECT_REG_DCSYNCACT}}, f_data_out };
/* reset system time+ofs */
std::array<uint8_t, 4> g_data_out;
datagram::EcatDatagram<command::BWR, std::array<uint8_t, 4>> g{ {{0x0000, ECT_REG_DCSYSTIME}}, g_data_out };
/* DC speedstart */
uint16_t h_data_out{0x1000};
datagram::EcatDatagram<command::BWR, uint16_t> h{ {{0x0000, ECT_REG_DCSPEEDCNT}}, h_data_out };
/* DC filt expr */
uint16_t i_data_out{0x0C00};
datagram::EcatDatagram<command::BWR, uint16_t> i{ {{0x0000, ECT_REG_DCTIMEFILT}}, i_data_out };
/* Ignore Alias register */
uint8_t j_data_out{0x00};
datagram::EcatDatagram<command::BWR, uint8_t> j{ {{0x0000, ECT_REG_DLALIAS}}, j_data_out };
/* Reset all slaves to Init */
uint8_t k_data_out{0x00};
datagram::EcatDatagram<command::BWR, uint8_t> k{ {{0x0000, ECT_REG_ALCTL}}, k_data_out };
/* force Eeprom from PDI */
uint8_t l_data_out{0x02};
datagram::EcatDatagram<command::BWR, uint8_t> l{ {{0x0000, ECT_REG_EEPCFG}}, l_data_out };
/* set Eeprom to master */
uint8_t m_data_out{0x00};
datagram::EcatDatagram<command::BWR, uint8_t> 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<command::BRD, uint16_t> 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<datagram::EcatDatagram<command::APWR, address::Node>, max_number_of_slaves> datagrams;
for(uint16_t i = 0; i < number_of_slaves_; i++) {
slaves_[i].set_slave_address<command::FP>(static_cast<address::Node>(address_base + i));
slaves_[i].set_slave_address<command::AP>(static_cast<address::Position>(-i));
datagrams[i] = { {{address::Position{static_cast<int16_t>(-i)}, ECT_REG_STADR}}, slaves_[i].get_slave_address<command::FP>() };
}
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<datagram::EcatDatagram<command::APRD, address::Node>, max_number_of_slaves> datagrams;
for(uint16_t i = 0; i < number_of_slaves_; i++) {
slaves_[i].set_slave_address<command::AP>(static_cast<address::Position>(-i));
datagrams[i] = { {{address::Position{static_cast<int16_t>(-i)}, ECT_REG_STADR}}, slaves_[i].get_slave_address<command::FP>() };
}
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<command::FP>());
}
}
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<command::FP>(node, ECT_SII_RXMBXADR, mbx_write_adr_len);
BufferProperties mbx_read_adr_len;
eeprom_.read<command::FP>(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_;
}
}

View File

@ -0,0 +1,141 @@
/*
* eth_ecat.hpp
*
* Created on: 16 <EFBFBD><EFBFBD><EFBFBD>. 2023 <EFBFBD>.
* Author: sychev
*/
#ifndef FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_HPP_
#define FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_HPP_
#include <ethernet_industry/eth_ecat_datagram.hpp>
#include <cstdint>
#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<typename TypeT>
void set_slave_address(typename TypeT::TSlaveAddress&& slave_address) {
std::get<static_cast<size_t>(TypeT::type)>(slave_addresses_) = slave_address;
}
template<typename TypeT>
typename TypeT::TSlaveAddress& get_slave_address() {
return std::get<static_cast<size_t>(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<uint8_t> receive_datagram();
void send_datagram(const std::vector<std::uint8_t>& 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<typename TypeT, typename DirT, typename EcatDgDataT>
void simple_send_datagram(typename TypeT::TSlaveAddress& slave_address, uint16_t offset, EcatDgDataT& data) {
using TCommand = command::EcatCommand<TypeT, DirT>;
datagram::EcatDatagram<TCommand, EcatDgDataT> datagram{ {{slave_address, offset}}, data };
telegram_.transfer(datagram);
}
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; /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 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_; /// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
bool ready_;
Statistic stat_;
std::array<EcatSlave, max_number_of_slaves> slaves_;
uint16_t number_of_slaves_ = 0;
};
}
#endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_HPP_ */

View File

@ -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 <cstdint>
#include <array>
#include <tuple>
#include <type_traits>
#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<Position, Broadcast, Node, Logical>;
// Register offset
using Offset = uint16_t;
using PositionAddress = std::tuple<Position, Offset>;
using BroadcastAddress = std::tuple<Broadcast, Offset>;
using NodeAddress = std::tuple<Node, Offset>;
using LogicalAddress = std::tuple<Logical>;
using Types = std::tuple<PositionAddress, BroadcastAddress, NodeAddress, LogicalAddress>;
} // 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<DIR_INDEX dir_index>
struct Dir : public DirBase {
static constexpr DIR_INDEX dir = dir_index;
};
using RD = Dir<DIR_INDEX::RD>;
using WR = Dir<DIR_INDEX::WR>;
using RW = Dir<DIR_INDEX::RW>;
using RMW = Dir<DIR_INDEX::RMW>;
using NO = Dir<DIR_INDEX::NO>;
struct TypeBase {
};
template<TYPE_INDEX type_index>
struct Type : public TypeBase {
using TAddress = typename std::tuple_element<static_cast<size_t>(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<std::array<ec_cmdtype, 4>, 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<uint16_t>(type)][static_cast<uint16_t>(dir)];
}
};
using AP = Type<TYPE_INDEX::AP>;
using B = Type<TYPE_INDEX::B>;
using FP = Type<TYPE_INDEX::FP>;
using L = Type<TYPE_INDEX::L>;
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<typename TypeT, typename DirT>
class EcatCommand : public EcatCommandBase {
static_assert(std::is_base_of<TypeBase, TypeT>::value == true, "TypeT should be derived from CMD::TypeBase");
static_assert(std::is_base_of<DirBase, DirT>::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<typename FieldsT>
union Address
{
Address(FieldsT fields)
: fields_{fields} { }
Address() { }
Address& operator=(const Address& other) {
fields_ = other.fields_;
return *this;
}
FieldsT fields_;
uint32_t dword_;
};
Address<typename TypeT::TAddress> 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<AP, RD>;
using APWR = EcatCommand<AP, WR>;
using APRW = EcatCommand<AP, RW>;
using ARMW = EcatCommand<AP, RMW>;
/*
* Broadcast addressing
* arg0: Each slave increments Position (not used for addressing)
* arg1: Local register or memory address of the ESC
*/
using NOP = EcatCommand<B, NO>;
using BRD = EcatCommand<B, RD>;
using BRW = EcatCommand<B, RW>;
using BWR = EcatCommand<B, WR>;
// 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<FP, RD>;
using FPRW = EcatCommand<FP, RW>;
using FPWR = EcatCommand<FP, WR>;
using FPMW = EcatCommand<FP, RMW>;
/*
* Logical addressing
* arg0: Logical Address (configured by FMMUs) Slave is addressed if FMMU configuration matches Address.
*/
using LRD = EcatCommand<L, RD>;
using LRW = EcatCommand<L, RW>;
using LWR = EcatCommand<L, WR>;
} // namespace command
}
#endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_COMMAND_HPP_ */

View File

@ -0,0 +1,70 @@
/*
* eth_ecat_datagram.cpp
*
* Created on: May 2, 2023
* Author: algin
*/
#include <ethernet_industry/eth_ecat_datagram.hpp>
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<uint16_t>(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<TEthFrameHeader*>(buffer_in_.data);
TEcatFrameHeader *p_hdr = reinterpret_cast<TEcatFrameHeader*>(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);
}
}
}

View File

@ -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 <cstdint>
#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<typename EcatDgDataT>
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<uint16_t>(ec_circframe::EC_CIRCFRAME_NOT),
.m = static_cast<uint16_t>(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<uint16_t>(ec_circframe::EC_CIRCFRAME_NOT),
.m = static_cast<uint16_t>(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<typename CommandT, typename EcatDgDataT>
class EcatDatagram : public IEcatDatagram {
static_assert(std::is_base_of<command::EcatCommandBase, CommandT>::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<EcatDgDataT> *p_dg;
if(data_out_ != nullptr) {
p_dg = new(raw) EcatDg<EcatDgDataT> {command_.get_cmd(), command_.get_address(), *data_out_, more_};
}else{
p_dg = new(raw) EcatDg<EcatDgDataT> {command_.get_cmd(), command_.get_address(), more_};
}
(void)p_dg;
return (raw + sizeof(EcatDg<EcatDgDataT>));
}
virtual uint8_t* unpack(uint8_t *raw) override {
EcatDg<EcatDgDataT> *p_dg = reinterpret_cast<EcatDg<EcatDgDataT>*>(raw);
if(data_in_ != nullptr) {
*data_in_ = p_dg->get_data();
}
wkc_ = p_dg->get_wkc();
return (raw + sizeof(EcatDg<EcatDgDataT>));
}
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_ */

View File

@ -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 <ethernet_industry/eth_ecat_datagram.hpp>
namespace free_rtos {
namespace eeprom {
class EEPROM {
public:
EEPROM(datagram::EcatTelegram& telegram)
: telegram_{telegram} { }
template<typename TypeT>
void wait_busy(typename TypeT::TSlaveAddress& slave_address) {
using TCommand = command::EcatCommand<TypeT, command::RD>;
volatile uint16_t stat;
datagram::EcatDatagram<TCommand, volatile uint16_t> datagram{ {{slave_address, ECT_REG_EEPSTAT}}, stat };
do {
telegram_.transfer(datagram);
}while((stat & EC_ESTAT_BUSY) != 0);
}
template<typename TypeT, typename DirT>
void control_register(typename TypeT::TSlaveAddress& slave_address, ec_ecmdtype eeprom_cmd, uint16_t eeprom_address) {
using TCommand = command::EcatCommand<TypeT, DirT>;
std::array<uint16_t, 2> request{eeprom_cmd, eeprom_address};
datagram::EcatDatagram<TCommand, std::array<uint16_t, 2>> datagram{ {{slave_address, ECT_REG_EEPCTL}}, request };
telegram_.transfer(datagram);
}
template<typename TypeT, typename DirT, typename EcatDgDataT>
void data_register(typename TypeT::TSlaveAddress& slave_address, EcatDgDataT& data) {
using TCommand = command::EcatCommand<TypeT, DirT>;
datagram::EcatDatagram<TCommand, EcatDgDataT> datagram{ {{slave_address, ECT_REG_EEPDAT}}, data };
telegram_.transfer(datagram);
}
template<typename TypeT, typename EcatDgDataT>
void read(typename TypeT::TSlaveAddress& slave_address, uint16_t eeprom_address, EcatDgDataT& data) {
wait_busy<TypeT>(slave_address);
control_register<TypeT, command::WR>(slave_address, EC_ECMD_READ, eeprom_address);
wait_busy<TypeT>(slave_address);
data_register<TypeT, command::RD, EcatDgDataT>(slave_address, data);
}
template<typename TypeT, typename EcatDgDataT>
void write(typename TypeT::TSlaveAddress& slave_address, uint16_t eeprom_address, EcatDgDataT& data) {
wait_busy<TypeT>(slave_address);
data_register<TypeT, command::WR, EcatDgDataT>(slave_address, data);
wait_busy<TypeT>(slave_address);
control_register<TypeT, command::WR>(slave_address, EC_ECMD_WRITE, eeprom_address);
}
private:
datagram::EcatTelegram& telegram_;
};
}
}
#endif /* FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_EEPROM_HPP_ */

View File

@ -0,0 +1,60 @@
/*
* eth_ecat_types.h
*
* Created on: 16 <EFBFBD><EFBFBD><EFBFBD>. 2023 <EFBFBD>.
* Author: sychev
*/
#ifndef FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_TYPES_H_
#define FREE_RTOS_ETHERNET_INDUSTRY_ETH_ECAT_TYPES_H_
#include <stdint.h>
#define ETH_PROT_ECAT_LE 0xa488 /// ETHERCAT
#define ETH_PROT_ECAT_BE 0x88a4 /// ETHERCAT
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>( <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> be)
typedef struct
{
uint16_t length : 11; /// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 11
uint16_t reserved : 1;
uint16_t type : 4;
}TEcatFrameHeaderBits;
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 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;
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ethercat
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>( <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> be),
* <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 8 <EFBFBD><EFBFBD><EFBFBD>.
*/
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_ */

View File

@ -0,0 +1,300 @@
/** \file
* \brief
* Типы данных и константы, используемые для работы с EtherCAT сетью.
*/
#ifndef ETHERCAT_MASTER_ETHERCATTYPE_HPP
#define ETHERCAT_MASTER_ETHERCATTYPE_HPP
#include <cstdint>
#include <memory>
#include <array>
#include <sys/types.h>
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 :
* <br>Length - 11 bit : Length of the EtherCAT datagrams (excl. FCS)
* <br>Reserved - 1 bit: Reserved, 0
* <br>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

View File

@ -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 <cstring>
#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;
}

View File

@ -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 <map>
#include <cstdint>
#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<uint64_t, uint32_t> table_mac_; /// Êëþ÷ mac, çíà÷åíèå ip
std::map<uint32_t, ArpIpReqData> 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_ */

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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 <stdint.h>
#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_ */

View File

@ -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;
}

View File

@ -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 <cstdint>
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_ */

View File

@ -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 <stdint.h>
/** 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_ */

View File

@ -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 <cstring>
#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);
}

View File

@ -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 <cstdint>
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_ */

View File

@ -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);
}

View File

@ -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 <stdint.h>
#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_ */

View File

@ -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 <cstdint>
#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_ */

View File

@ -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_ */

View File

@ -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 <stdint.h>
#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_ */

View File

@ -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_ */

View File

@ -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 <cstring>
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, &eth_.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, &eth_.self_mac_, ETH_FRAME_MAC_ADDR_LEN_BYTES);
reply_len+=sizeof(TEthFrameHeader);
/// Îòïðàâëÿåì äàííûå
tx_flow_.send(eth_.mac_port_, p_data, reply_len);
}
}

View File

@ -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_ */

View File

@ -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 <cstdint>
#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_ */

View File

@ -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 <algorithm>
#include <cstring>
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_);
}

View File

@ -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 <vector>
#include <cstdint>
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<uint8_t> 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_ */

View File

@ -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::EthUpdClient> 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<EthUpdClient> p_client = std::make_shared<EthUpdClient>(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;
}

View File

@ -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 <map>
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<EthUpdClient> 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<uint16_t, std::shared_ptr<EthUpdClient>> connections_; /// Êëþ÷ - ïîðò íàçíà÷åíèÿ
///HandlerStore handlers_; /// Îáðàáîò÷èêè udp-äàííûõ
};
}
#endif /* FREE_RTOS_ETHERNET_IP_ETH_UDP_SERVER_HPP_ */

View File

@ -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 <memory>
#include <cstdint>
namespace free_rtos {
class EthUdpServerIface {
public:
virtual std::shared_ptr<EthUpdClient> 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_ */

View File

@ -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 <stdint.h>
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_ */

View File

@ -0,0 +1,54 @@
/*
* gpio.cpp
*
* Created on: 6 ìàð. 2023 ã.
* Author: sychev
*/
#include "gpio/gpio.hpp"
#include <drivers/gpio.h>
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;
}

View File

@ -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 <cstdint>
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_ */

View File

@ -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 <cstdint>
class Handler {
public:
virtual int32_t Process(uint8_t * p_data, uint32_t len) = 0;
~Handler() {};
};
#endif /* FREE_RTOS_HANDLER_STORE_HANDLER_HPP_ */

View File

@ -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);
}

View File

@ -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 <map>
#include <cstdint>
#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<uint32_t, Handler *> handlers_; /// Îáðàáîò÷èêè ïàêåòîâ Ethernet
};
#endif /* FREE_RTOS_HANDLER_STORE_HANDLER_STORE_HPP_ */

View File

@ -0,0 +1,35 @@
/*
* mutex.cpp
*
* Created on: 26 ñåíò. 2022 ã.
* Author: sychev
*/
#include "mutex/mutex.hpp"
#include <kernel/dpl/DebugP.h>
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();
}

View File

@ -0,0 +1,57 @@
/*
* mutex.hpp
*
* Created on: 26 ñåíò. 2022 ã.
* Author: sychev
*/
#ifndef SRC_MUTEX_MUTEX_HPP_
#define SRC_MUTEX_MUTEX_HPP_
#include <kernel/freertos/FreeRTOS-Kernel/include/FreeRTOS.h>
#include <kernel/freertos/FreeRTOS-Kernel/include/semphr.h>
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_ */

View File

@ -0,0 +1,57 @@
#ifndef SRC_APP_SEMAPHORE_SEMAPHORE_HPP_
#define SRC_APP_SEMAPHORE_SEMAPHORE_HPP_
#include <kernel/dpl/SemaphoreP.h>
#include <kernel/dpl/DebugP.h>
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

View File

@ -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;
}

View File

@ -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 <cstdint>
#include <string>
#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_ */

View File

@ -0,0 +1,77 @@
/*
* timer.cpp
*
* Created on: 10 ìàð. 2023 ã.
* Author: sychev
*/
#include "timer/timer.hpp"
#include <kernel/dpl/TimerP.h>
#include <drivers/soc.h>
#include <kernel/dpl/AddrTranslateP.h>
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_);
}

View File

@ -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 <semaphore/semaphore.hpp>
#include <cstdint>
#include <kernel/dpl/HwiP.h>
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_ */

View File

@ -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;
}

View File

@ -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 <cstdint>
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_ */