sitara_depot/components/free_rtos/ethernet_industry/eth_ecat_command.hpp

203 lines
5.4 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 <type_traits>
#include "free_rtos/ethernet_industry/ethercattype.hpp"
#include "free_rtos/ethernet_industry/eth_ecat_types.h"
#include "free_rtos/ethernet_industry/eth_ecat_custom_tuple.hpp"
#include "free_rtos/ethernet_industry/eth_ecat_packer.hpp"
namespace free_rtos {
namespace address {
// Slave addressing types
using Position = int16_t;
using Broadcast = uint16_t;
using Station = uint16_t;
using Logical = uint32_t;
using SlaveAddresses = custom_tuple<Position, Broadcast, Station, Logical>;
// Register offset
using Offset = uint16_t;
using PositionAddress = custom_tuple<Position, Offset>;
using BroadcastAddress = custom_tuple<Broadcast, Offset>;
using StationAddress = custom_tuple<Station, Offset>;
using LogicalAddress = custom_tuple<Logical>;
using Addresses = custom_tuple<PositionAddress, BroadcastAddress, StationAddress, 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 custom_tuple_element<static_cast<size_t>(type_index), address::Addresses>::type;
using TSlaveAddress = typename custom_tuple_element<0, TAddress>::type;
static constexpr TYPE_INDEX type = type_index;
};
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:
private:
};
template<typename TypeT, typename DirT>
class EcatCommand : public EcatCommandBase {
static_assert(std::is_base_of<TypeBase, TypeT>::value == true, "TypeT should be derived from command::TypeBase");
static_assert(std::is_base_of<DirBase, DirT>::value == true, "DirT should be derived from command::DirBase");
public:
EcatCommand(typename TypeT::TAddress&& address)
: address_{address} { }
EcatCommand() { }
using TType = TypeT;
using TDir = DirT;
static constexpr uint8_t get_cmd() {
std::array<std::array<uint8_t, 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>(TypeT::type)][static_cast<uint16_t>(DirT::dir)];
}
static constexpr bool get_skip_pack() {
std::array<std::array<bool, 4>, 4> commands = {{
{{true, false, false, false}},
{{false, false, false, true}},
{{true, false, false, false}},
{{true, false, false, true}}
}};
return commands[static_cast<uint16_t>(TypeT::type)][static_cast<uint16_t>(DirT::dir)];
}
static constexpr bool get_skip_unpack() {
std::array<std::array<bool, 4>, 4> commands = {{
{{false, true, false, false}},
{{false, false, false, true}},
{{false, true, false, false}},
{{false, true, false, true}}
}};
return commands[static_cast<uint16_t>(TypeT::type)][static_cast<uint16_t>(DirT::dir)];
}
uint32_t get_address() {
uint32_t address{0x00000000};
PackFunctor functor{reinterpret_cast<uint8_t*>(&address)};
for_each(address_, functor);
return address;
}
private:
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>;
/*
* 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_ */