200 lines
4.8 KiB
C++
200 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 <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 Station = uint16_t;
|
|
using Logical = uint32_t;
|
|
|
|
using SlaveAddresses = std::tuple<Position, Broadcast, Station, Logical>;
|
|
|
|
// Register offset
|
|
using Offset = uint16_t;
|
|
|
|
using PositionAddress = std::tuple<Position, Offset>;
|
|
using BroadcastAddress = std::tuple<Broadcast, Offset>;
|
|
using StationAddress = std::tuple<Station, Offset>;
|
|
using LogicalAddress = std::tuple<Logical>;
|
|
|
|
using Addresses = std::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 std::tuple_element<static_cast<size_t>(type_index), address::Addresses>::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 command::TypeBase");
|
|
static_assert(std::is_base_of<DirBase, DirT>::value == true, "DirT should be derived from command::DirBase");
|
|
|
|
public:
|
|
EcatCommand(typename TypeT::TAddress fields)
|
|
: EcatCommandBase{TypeT::get_cmd(DirT::dir)}
|
|
, address_union_{fields} { }
|
|
|
|
EcatCommand() { }
|
|
|
|
uint32_t get_address() {
|
|
return address_union_.dword_;
|
|
}
|
|
|
|
private:
|
|
template<typename FieldsT>
|
|
union AddressUnion
|
|
{
|
|
AddressUnion(FieldsT fields)
|
|
: fields_{fields} { }
|
|
|
|
AddressUnion() { }
|
|
|
|
AddressUnion& operator=(const AddressUnion& other) {
|
|
fields_ = other.fields_;
|
|
|
|
return *this;
|
|
}
|
|
|
|
FieldsT fields_;
|
|
uint32_t dword_;
|
|
};
|
|
|
|
AddressUnion<typename TypeT::TAddress> address_union_;
|
|
};
|
|
|
|
/*
|
|
* 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_ */
|