sitara_depot/components/free_rtos/ethernet_industry/eth_ecat_command.hpp
algin ae3cac8a7d feat: First commit
Adds sitara_depot/free_rtos

Original one is on server_gorbunov/SmartForce4.0/sitara_depot
2023-05-03 14:01:32 +03:00

231 lines
5.2 KiB
C++

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