sitara_depot/components/free_rtos/ethernet_industry/eth_ecat_command.hpp

186 lines
4.8 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 "ethernet_industry/ethercattype.hpp"
#include "ethernet_industry/eth_ecat_types.h"
#include "ethernet_industry/eth_ecat_custom_tuple.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 = free_rtos::custom_tuple<Position, Broadcast, Station, Logical>;
// Register offset
using Offset = uint16_t;
using PositionAddress = free_rtos::custom_tuple<Position, Offset>;
using BroadcastAddress = free_rtos::custom_tuple<Broadcast, Offset>;
using StationAddress = free_rtos::custom_tuple<Station, Offset>;
using LogicalAddress = free_rtos::custom_tuple<Logical>;
using Addresses = free_rtos::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 free_rtos::custom_tuple_element<static_cast<size_t>(type_index), address::Addresses>::type;
using TSlaveAddress = typename free_rtos::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:
EcatCommandBase(TYPE_INDEX type, DIR_INDEX dir)
: cmd_{get_cmd_from_table(type, dir)} { }
EcatCommandBase()
: cmd_{ec_cmdtype::EC_CMD_NOP} { }
uint8_t get_cmd() {
return cmd_;
}
private:
ec_cmdtype cmd_;
static constexpr ec_cmdtype get_cmd_from_table(TYPE_INDEX type, 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)];
}
};
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)
: EcatCommandBase{TypeT::type, DirT::dir}
, address_{address} { }
EcatCommand() { }
uint32_t get_address() {
uint32_t address{0x00000000};
address_.pack(reinterpret_cast<uint8_t*>(&address));
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_ */