from enum import Enum
# --------------- Enumerations --------------------------
[docs]
class Device(Enum):
"""Device enumeration"""
FPGA_1 = 1
FPGA_2 = 2
FPGA_3 = 4
FPGA_4 = 8
FPGA_5 = 16
FPGA_6 = 32
FPGA_7 = 64
FPGA_8 = 128
Board = 65536
[docs]
class BoardMake(Enum):
"""BoardMake enumeration"""
TpmBoard = 1
RoachBoard = 2
Roach2Board = 3
UniboardBoard = 4
[docs]
class Status(Enum):
"""Status enumeration"""
OK = 0
LoadingFirmware = -1
ConfigError = -2
BoardError = -3
NotConnected = -4
NetworkError = -5
FirmwareError = -6
LoadingFirmwareError = -7
[docs]
class RegisterType(Enum):
"""RegisterType enumeration"""
Sensor = 1
BoardRegister = 2
FirmwareRegister = 3
SPIDevice = 4
Component = 5
FifoRegister = 6
[docs]
class Permission(Enum):
"""Permission enumeration"""
Read = 1
Write = 2
ReadWrite = 3
# String representation of device names
DeviceNames = {
Device.Board: "Board",
Device.FPGA_1: "FPGA 1",
Device.FPGA_2: "FPGA 2",
Device.FPGA_3: "FPGA 3",
Device.FPGA_4: "FPGA 4",
Device.FPGA_5: "FPGA 5",
Device.FPGA_6: "FPGA 6",
Device.FPGA_7: "FPGA 7",
Device.FPGA_8: "FPGA 8",
}
# --------------- Structures --------------------------
[docs]
class Values:
"""Class representing VALUES struct"""
[docs]
def __init__(self, values, error):
self.values = values
self.error = error
[docs]
class RegisterInfo:
"""Class representing REGISTER_INFO struct"""
[docs]
def __init__(
self,
name,
address,
reg_type,
device,
permission,
bitmask,
bits,
shift,
value,
size,
desc,
):
self.name = name
self.address = address
self.type = reg_type
self.device = device
self.permission = permission
self.bitmask = bitmask
self.bits = bits
self.shift = shift
self.value = value
self.size = size
self.desc = desc
def __repr__(self):
return "Register {} at address {}".format(self.name, hex(self.address))
[docs]
class SPIDeviceInfo:
"""Class representing SPI_DEVICE_INFO struct"""
[docs]
def __init__(self, name, spi_sclk, spi_en):
self.name = name
self.spi_sclk = spi_sclk
self.spi_en = spi_en
# -------------------- Classes -------------------------
[docs]
class PluginList(list):
def __getattr__(self, item):
if len(self) == 1:
return self[0].__getattribute__(item)
elif len(self) > 1:
raise LibraryError(
"Cannot directly access methods of a plugin list with multiple entries"
)
# ------------------- Exceptions -----------------------
[docs]
class BoardError(Exception):
"""Define an exception which occurs when an operation occuring
on an FPGA boards returns an error"""
pass
[docs]
class LibraryError(Exception):
"""Define an exception which occurs when an operation occuring
within the library returns an error"""
pass
[docs]
class InstrumentError(Exception):
"""Define an exception which occurs when an operation occuring
within the instrument returns an error"""
pass
[docs]
class PluginError(Exception):
"""Define an exception which occurs when an operation occuring
within a plugin returns an error"""
pass
# ----------- Board Compatibility Decorator --------------
[docs]
def compatibleboards(*args):
"""
Add board compatability to funtion.
:param args: Compatible boards
:return: Decorated class
"""
def decorator(func):
# Check if any boards were declared
if len(args) > 0 and all(type(x) == BoardMake for x in args):
# Add board make to class metadata
func.__dict__["_compatible_boards"] = args
# All done, return
return func
return decorator
# ------------- Friendly Name Decorator ----------------
[docs]
def friendlyname(*args):
"""
Add board compatability to funtion.
:param args: Compatible boards
:return: Decorated class
"""
def decorator(func):
# Add friendly name to class metadata
arg = args
if len(args) > 0:
arg = args[0]
if type(arg) is str:
func.__dict__["_friendly_name"] = arg
else:
raise PluginError("Invalid friendly name in plugin friendlyname decorator")
# All done, return
return func
return decorator
# ------------- Max Instances Decorator ----------------
[docs]
def maxinstances(*args):
"""
Maximum number of instances the plugin can be loaded.
:param args: Number of instances
:return: Decorated class
"""
def decorator(func):
# Add max number of instances to call metadata
arg = args
if len(args) > 0:
arg = args[0]
if type(arg) is int:
func.__dict__["_max_instances"] = arg
else:
raise PluginError(
"Invalid maximum number of instances in plugin maxinstance decorator"
)
# All done, return
return func
return decorator
# ------------- Firmware association Decorator ----------------
[docs]
def firmware(*args):
"""
A plugin can be associated with a particular firmware.
:param args: Design name string or dictionary containing design and verion
:return: Decorated class
"""
def decorator(func):
arg = args
if len(arg) > 1:
arg = args[0]
# Extract first item of tuple...
if type(arg) is tuple:
arg = arg[0]
# If string, assume it refers to design name
if type(arg) is str:
func.__dict__["_design"] = arg
# If dict, it should contain design name and may contain major and minor version numbers
elif type(arg) is dict:
if arg.get("design", None) is None:
raise PluginError(
"Design name must be specified in plugin firmware decorator"
)
func.__dict__["_design"] = arg["design"]
if arg.get("major", None) is not None:
func.__dict__["_major"] = arg["major"]
if arg.get("minor", None) is not None:
func.__dict__["_minor"] = arg["minor"]
else:
raise PluginError("Invalid firmware association for plugin")
# All done, return
return func
return decorator