Creating a Custom Pyrogue Device

class AxiVersion(pr.Device):

# Last comment added by rherbst for demonstration.
def __init__(
        self,
        name             = 'AxiVersion',
        description      = 'AXI-Lite Version Module',
        numUserConstants = 0,
        **kwargs):

    super().__init__(
        name        = name,
        description = description,
        **kwargs)

    ##############################
    # Variables
    ##############################

    self.add(pr.RemoteVariable(
        name         = 'FpgaVersion',
        description  = 'FPGA Firmware Version Number',
        offset       = 0x00,
        bitSize      = 32,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RO',
        disp         = '{:#08x}',
    ))

    self.add(pr.RemoteVariable(
        name         = 'ScratchPad',
        description  = 'Register to test reads and writes',
        offset       = 0x04,
        bitSize      = 32,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RW',
        units        = 'Test',
        disp         = '{:#08x}'
    ))

    self.add(pr.RemoteVariable(
        name         = 'UpTimeCnt',
        description  = 'Number of seconds since last reset',
        hidden       = True,
        offset       = 0x08,
        bitSize      = 32,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RO',
        disp         = '{:d}',
        units        = 'seconds',
        pollInterval = 1
    ))

    self.add(pr.LinkVariable(
        name = 'UpTime',
        mode = 'RO',
        dependencies = [self.UpTimeCnt],
        linkedGet = lambda: str(datetime.timedelta(seconds=self.UpTimeCnt.value()))
    ))

    self.add(pr.RemoteVariable(
        name         = 'FpgaReloadHalt',
        description  = 'Used to halt automatic reloads via AxiVersion',
        offset       = 0x100,
        bitSize      = 1,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RW',
    ))


    self.add(pr.RemoteCommand(
        name         = 'FpgaReload',
        description  = 'Optional Reload the FPGA from the attached PROM',
        offset       = 0x104,
        bitSize      = 1,
        bitOffset    = 0x00,
        base         = pr.UInt,
        function     = lambda cmd: cmd.post(1)
    ))

    self.add(pr.RemoteVariable(
        name         = 'FpgaReloadAddress',
        description  = 'Reload start address',
        offset       = 0x108,
        bitSize      = 32,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RW',
    ))

    @self.command(hidden=True)
    def FpgaReloadAtAddress(arg):
        self.FpgaReloadAddress.set(arg)
        self.FpgaReload()

    self.add(pr.RemoteVariable(
        name         = 'UserReset',
        description  = 'Optional User Reset',
        offset       = 0x10C,
        bitSize      = 1,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RW',
    ))

    self.add(pr.RemoteVariable(
        name         = 'FdSerial',
        description  = 'Board ID value read from DS2411 chip',
        offset       = 0x300,
        bitSize      = 64,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RO',
    ))

    self.addRemoteVariables(
        name         = 'UserConstants',
        description  = 'Optional user input values',
        offset       = 0x400,
        bitSize      = 32,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RO',
        number       = numUserConstants,
        stride       = 4,
        hidden       = True,
    )


    self.add(pr.RemoteVariable(
        name         = 'DeviceId',
        description  = 'Device Identification  (configured by generic)',
        offset       = 0x500,
        bitSize      = 32,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RO',
    ))

    self.add(pr.RemoteVariable(
        name         = 'GitHash',
        description  = 'GIT SHA-1 Hash',
        offset       = 0x600,
        bitSize      = 160,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RO',
        hidden       = True,
    ))

    self.add(pr.LinkVariable(
        name = 'GitHashShort',
        dependencies = [self.GitHash],
        disp = '{:07x}',
        linkedGet = lambda: self.GitHash.value() >> 132
    ))


    self.add(pr.RemoteVariable(
        name         = 'DeviceDna',
        description  = 'Xilinx Device DNA value burned into FPGA',
        offset       = 0x700,
        bitSize      = 128,
        bitOffset    = 0x00,
        base         = pr.UInt,
        mode         = 'RO',
    ))

    self.add(pr.RemoteVariable(
        name         = 'TestEnum',
        description  = 'ENUM Test Field',
        offset       = 0x900,
        bitSize      = 3,
        bitOffset    = 0x00,
        enum         = {0: 'Test0',
                        1: 'Test1',
                        2: 'Test2',
                        3: 'Test3',
                        4: 'Test4'},
        base         = pr.UInt,
        mode         = 'RW',
        hidden       = True,
    ))

    #self.add(pr.LocalVariable(name = 'TestArray[2]',value=0))

    for i in range(4):
        for j in range(4):
            for k in range(4):
                self.add(pr.LocalVariable(name = f'TestArray[{i}][{j}][{k}]',
                                          guiGroup='TestArray',
                                          value=0))

    self.add(pr.LocalVariable(name = 'TestArray[4][5]',
                              guiGroup='TestArray',
                              value=0))
    self.add(pr.LocalVariable(name = 'TestArray[6]',
                              guiGroup='TestArray',
                              value=0))

    #self.add(pr.LocalVariable(name = 'TestArray[2]',value=0))

    for i in range(2):
        self.add(pr.LocalVariable(name = f'TestArray2[{i}]',
                                  guiGroup='TestArray',
                                  value=0))

    self.add(pr.RemoteVariable(
        name         = 'TestSpareArray[5][5]',
        description  = 'Array Test Field',
        offset       = 0x2000,
        bitSize      = 32,
        bitOffset    = 0,
        base         = pr.UInt,
        mode         = 'RW',
    ))

    self.add(pr.RemoteVariable(
        name         = 'TestSpareArray[8][8]',
        description  = 'Array Test Field',
        offset       = 0x2004,
        bitSize      = 32,
        bitOffset    = 0,
        base         = pr.UInt,
        mode         = 'RW',
    ))

    self.add(pr.RemoteVariable(
        name         = 'Test10Bit',
        description  = 'Test 10 bits',
        offset       = 0x2008,
        bitSize      = 10,
        bitOffset    = 0,
        base         = pr.UInt,
        mode         = 'RW',
    ))

    self.add(pr.RemoteVariable(
        name         = 'AlarmTest',
        description  = 'Alarm Test Field',
        offset       = 0x8000,
        bitSize      = 32,
        bitOffset    = 0,
        base         = pr.UInt,
        mode         = 'RW',
        minimum      = 100,
        maximum      = 1000,
        lowAlarm     = 200,
        lowWarning   = 300,
        highWarning  = 800,
        highAlarm    = 900,
        value        = 100,
        disp         = '{}',
        hidden       = False,
        groups       = ['NoConfig','NoAlarm'],
    ))

    self.add(pr.LocalVariable(
        name = 'TestRealArray',
        mode = 'RW',
        value = np.array([1,2,3,4])))

    self.add(pr.LocalVariable(
        name = 'TestReal2dArray',
        mode = 'RW',
        value = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]],np.float32)))

    self.add(pr.LocalVariable(
        name = 'TestListA',
        mode = 'RW',
        value = np.array([1,2,3,4,5,6,7,8,9,10],np.int32)))

    self.add(pr.LocalVariable(
        name = 'TestList2',
        mode = 'RW',
        value = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]))

    self.add(pr.LocalVariable(
        name = 'TestListB',
        mode = 'RW',
        value = np.array([11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0])))

    self.add(pr.LocalVariable(
        name = 'TestBool',
        mode = 'RW',
        value = False))

    self.add(pr.LocalVariable(
        name = 'TestBoolArray',
        mode = 'RW',
        value = [False] * 10))

    #self.add(pr.LocalVariable(
    #    name = 'TestBadArray[x]',
    #    mode = 'RW',
    #    value = ''))

    @self.command(hidden=False,value='',retValue='')
    def TestCommand(arg):
        print('Got {}'.format(arg))
        return 'Got {}'.format(arg)

    @self.command(hidden=False,value='',retValue='')
    def TestMemoryException(arg):
        raise pr.MemoryError(name='blah',address=0)

    @self.command(hidden=False,value='',retValue='')
    def TestErrorLog(arg):
        self._log.error("Test error message")

    @self.command(hidden=False,value='',retValue='')
    def TestOtherLog(arg):
        self._log.log(93,"Test log level 39 message")

    @self.command(hidden=False,value='',retValue='')
    def TestGeneralException(arg):
        return rogue.hardware.axi.AxiStreamDma('/dev/not_a_device',0,True)

    @self.command(hidden=False,value='',retValue='')
    def TestOtherError(arg):
        return rogue.hardware.axi.AxiStreamDma('/dev/not_a_device',0)

    @self.command(hidden=False,value='blah blah',retValue='')
    def TestCmdString(arg):
        print("Send command string: {}".format(arg))

    @self.command(hidden=False, value=1, retValue='', enum={1:'One',2:'Two',3:'Three'})
    def TestCmdEnum(arg):
        print("Send command Enum: {}".format(arg))

def hardReset(self):
    print('AxiVersion hard reset called')

def softReset(self):
    print('AxiVersion soft reset called')

def countReset(self):
    print('AxiVersion count reset called')