from enum import Enum
from ._ingenialink import ffi, lib
from ingenialink.utils._utils import *
from abc import ABC
# CANOPEN DTYPES
IL_REG_DTYPE_DOMAIN = 15
[docs]class REG_DTYPE(Enum):
"""Data Type."""
U8 = lib.IL_REG_DTYPE_U8
"""Unsigned 8-bit integer."""
S8 = lib.IL_REG_DTYPE_S8
"""Signed 8-bit integer."""
U16 = lib.IL_REG_DTYPE_U16
"""Unsigned 16-bit integer."""
S16 = lib.IL_REG_DTYPE_S16
"""Signed 16-bit integer."""
U32 = lib.IL_REG_DTYPE_U32
"""Unsigned 32-bit integer."""
S32 = lib.IL_REG_DTYPE_S32
"""Signed 32-bit integer."""
U64 = lib.IL_REG_DTYPE_U64
"""Unsigned 64-bit integer."""
S64 = lib.IL_REG_DTYPE_S64
"""Signed 64-bit integer."""
FLOAT = lib.IL_REG_DTYPE_FLOAT
"""Float."""
STR = lib.IL_REG_DTYPE_STR
"""String."""
DOMAIN = IL_REG_DTYPE_DOMAIN
"""Domain."""
[docs]class REG_ACCESS(Enum):
"""Access Type."""
RW = lib.IL_REG_ACCESS_RW
"""Read/Write."""
RO = lib.IL_REG_ACCESS_RO
"""Read-only."""
WO = lib.IL_REG_ACCESS_WO
"""Write-only."""
[docs]class REG_PHY(Enum):
"""Physical Units."""
NONE = lib.IL_REG_PHY_NONE
"""None."""
TORQUE = lib.IL_REG_PHY_TORQUE
"""Torque."""
POS = lib.IL_REG_PHY_POS
"""Position."""
VEL = lib.IL_REG_PHY_VEL
"""Velocity."""
ACC = lib.IL_REG_PHY_ACC
"""Acceleration."""
VOLT_REL = lib.IL_REG_PHY_VOLT_REL
"""Relative voltage (DC)."""
RAD = lib.IL_REG_PHY_RAD
"""Radians."""
dtypes_ranges = {
REG_DTYPE.U8: {"max": 255, "min": 0},
REG_DTYPE.S8: {"max": 127, "min": -128},
REG_DTYPE.U16: {"max": 65535, "min": 0},
REG_DTYPE.S16: {"max": 32767, "min": -32767 - 1},
REG_DTYPE.U32: {"max": 4294967295, "min": 0},
REG_DTYPE.S32: {"max": 2147483647, "min": -2147483647 - 1},
REG_DTYPE.U64: {"max": 18446744073709551615, "min": 0},
REG_DTYPE.S64: {"max": 9223372036854775807, "min": 9223372036854775807 - 1},
REG_DTYPE.FLOAT: {"max": 2147483647, "min": -2147483647 - 1}
}
def dtype_size(dtype):
sizes = {
REG_DTYPE.U8: 1,
REG_DTYPE.S8: 1,
REG_DTYPE.U16: 2,
REG_DTYPE.S16: 2,
REG_DTYPE.U32: 4,
REG_DTYPE.S32: 4,
REG_DTYPE.U64: 8,
REG_DTYPE.S64: 8,
REG_DTYPE.FLOAT: 4
}
return sizes[dtype]
def _get_reg_id(reg):
"""Obtain Register and ID.
Args:
reg (str, Register): Register.
"""
if isinstance(reg, str):
return ffi.NULL, cstr(reg)
elif isinstance(reg, Register):
return reg._reg, ffi.NULL
raise TypeError('Unexpected register type')
[docs]class Register(ABC):
"""Register.
Args:
identifier (str): Identifier.
units (str): Units.
cyclic (str): Cyclic typed register.
dtype (REG_DTYPE): Data type.
access (REG_ACCESS): Access type.
phy (REG_PHY, optional): Physical units.
subnode (int): Subnode
storage (any, optional): Storage.
reg_range (tuple, optional): Range (min, max).
labels (dict, optional): Register labels.
enums (dict, optional): Enumeration values.
cat_id (str, optional): Category ID.
scat_id (str, optional): Sub-category ID.
internal_use (int, optional): Internal use.
Raises:
TypeError: If any of the parameters has invalid type.
"""
def __init__(self, identifier, units, cyclic, dtype, access,
phy=REG_PHY.NONE, subnode=1, storage=None, reg_range=None,
labels=None, enums=None, enums_count=0, cat_id=None, scat_id=None,
internal_use=0):
if labels is None:
labels = {}
if enums is None:
enums = []
if not isinstance(dtype, REG_DTYPE):
raise TypeError('Invalid data type')
if not isinstance(access, REG_ACCESS):
raise TypeError('Invalid access type')
if not isinstance(phy, REG_PHY):
raise TypeError('Invalid physical units type')
self._identifier = identifier
self._units = units
self._subnode = subnode
self._cyclic = cyclic
self._dtype = dtype.value
self._access = access.value
self._phy = phy.value
self._storage = storage
self._storage_valid = 0 if not storage else 1
self._internal_use = internal_use
self._range = (None, None) if not reg_range else reg_range
self._labels = labels
self._enums = enums
self._enums_count = enums_count
self._cat_id = cat_id
self._scat_id = scat_id
@property
def identifier(self):
"""str: Register identifier."""
return self._identifier
@property
def units(self):
"""str: Units of the register."""
return self._units
@property
def subnode(self):
"""int: Target subnode of the register."""
return self._subnode
@property
def cyclic(self):
"""str: Defines if the register is cyclic."""
return self._cyclic
@property
def dtype(self):
"""REG_DTYPE: Data type of the register."""
return REG_DTYPE(self._dtype)
@property
def access(self):
"""REG_ACCESS: Access type of the register."""
return REG_ACCESS(self._access)
@property
def phy(self):
"""REG_PHY: Physical units of the register."""
return REG_PHY(self._phy)
@property
def storage(self):
"""any: Defines if the register needs to be stored."""
return self._storage
@storage.setter
def storage(self, value):
self._storage = value
@property
def storage_valid(self):
"""bool: Defines if the register storage is valid."""
return self._storage_valid
@storage_valid.setter
def storage_valid(self, value):
self._storage_valid = value
@property
def range(self):
"""tuple: Containing the minimum and the maximum values of the register."""
return self._range
@property
def labels(self):
"""dict: Containing the labels of the register."""
return self._labels
@property
def enums(self):
"""dict: Containing all the enums for the register."""
return self._enums
@property
def enums_count(self):
"""int: The number of the enums in the register."""
return self._enums_count
@property
def cat_id(self):
"""str: Category ID"""
return self._cat_id
@property
def scat_id(self):
"""str: Sub-Category ID"""
return self._scat_id
@property
def internal_use(self):
"""int: Defines if the register is only for internal uses."""
return self._internal_use