Ejemplo n.º 1
0
 def closeSockets(self):
     """Allows you to manually close any sockets that may have been opened."""
     try:
         self._socket.close()
         chipsLog.debug("Socket closed successfully.")
     except:
         chipsLog.warn("Error closing socket!")
Ejemplo n.º 2
0
    def queueWrite(self, name, dataU32, addrOffset = 0):
        """Create a register write (RMW-bits) transaction element and add it to the transaction queue.
        
        This works in the same way as a normal write(), except that many can be queued
        into a packet and dispatched all at once rather than individually.  Run the
        queued transactions with queueRun().
        
        Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        if len(self._queuedRequests) < ChipsBus.MAX_QUEUED_REQUESTS:
        
            dataU32 = dataU32 & 0xffffffff # Ignore oversize input.
            chipsLog.debug("Write queued: dataU32 = 0x" + uInt32HexStr(dataU32) + " to register '"
                           + name + "' with addrOffset = 0x" + uInt32HexStr(addrOffset))
        
            addrTableItem = self.addrTable.getItem(name) # Get the details of the relevant item from the addr table.
        
            if not addrTableItem.getWriteFlag():
                raise ChipsException("Write transaction creation error: write is not allowed on register '" +  addrTableItem.getName() + "'.")       
        
            self._queuedRequests.append(self._createRMWBitsTransactionElement(addrTableItem, dataU32, addrOffset))
            self._queuedAddrTableItems.append(addrTableItem)
            self._queuedIsARead.append(False)
            
        else:
            chipsLog.warning("Warning: transaction not added to queue as transaction queue has reached its maximum length!\n" +
                             "\tPlease either run or clear the transaction queue before continuing.\n")
Ejemplo n.º 3
0
    def _makeAndRunTransaction(self, requestsList):
        """Constructs, runs and then returns a completed transaction from the given requestsList

        requestsList: a list of TransactionElements (i.e. requests from client to the hardware).

        Notes:  _makeAndRunTransaction will automatically prepend one byte-order transaction.
        """

        # Construct the transaction and serialise it - we prepend four byte-order transactions in
        # order to ensure we meet minimum Ethernet payload requirements, else funny stuff happens.
        transaction = Transaction.constructClientTransaction(requestsList, self._hostAddr)
        transaction.serialiseRequests()

        chipsLog.debug("Sending packet now.");
        try:
            # Send the transaction
            self._socketSend(transaction)
        except socket.error as socketError:
            raise ChipsException("A socket error occurred whilst sending the IPbus transaction request packet:\n\t" + str(socketError))

        try:
            # Get response
            transaction.serialResponses = self._socket.recv(ChipsBus.SOCKET_BUFFER_SIZE)
        except socket.error as socketError:
            raise ChipsException("A socket error occurred whilst getting the IPbus transaction response packet:\n\t" + str(socketError))
        chipsLog.debug("Received response packet.");

        transaction.deserialiseResponses()

        transaction.doTransactionChecks() # Generic transaction checks

        self._transactionId = 1   # TEMPORARY IPBUS V2.x HACK!   Reset the transaction ID to 1 for each packet.
        return transaction
Ejemplo n.º 4
0
    def queueWrite(self, name, dataU32, addrOffset = 0):
        """Create a register write (RMW-bits) transaction element and add it to the transaction queue.

        This works in the same way as a normal write(), except that many can be queued
        into a packet and dispatched all at once rather than individually.  Run the
        queued transactions with queueRun().

        Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        if len(self._queuedRequests) < ChipsBus.MAX_QUEUED_REQUESTS:

            dataU32 = dataU32 & 0xffffffff # Ignore oversize input.
            chipsLog.debug("Write queued: dataU32 = 0x" + uInt32HexStr(dataU32) + " to register '"
                           + name + "' with addrOffset = 0x" + uInt32HexStr(addrOffset))

            addrTableItem = self.addrTable.getItem(name) # Get the details of the relevant item from the addr table.

            if not addrTableItem.getWriteFlag():
                raise ChipsException("Write transaction creation error: write is not allowed on register '" +  addrTableItem.getName() + "'.")

            # self._queuedRequests.append(self._createRMWBitsTransactionElement(addrTableItem, dataU32, addrOffset))
            # self._queuedAddrTableItems.append(addrTableItem)
            # self._queuedIsARead.append(False)

            self._queuedRequests.append(self._createWriteTransactionElement(addrTableItem, [dataU32], addrOffset))
            self._queuedAddrTableItems.append(addrTableItem)
            self._queuedIsARead.append(False)

        else:
            chipsLog.warning("Warning: transaction not added to queue as transaction queue has reached its maximum length!\n" +
                             "\tPlease either run or clear the transaction queue before continuing.\n")
Ejemplo n.º 5
0
 def _handleGetReservedAddrInfoRequest(self, request):
     chipsLog.debug("Reserved Address Info transaction requested")
     # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE
     responseHeader = IPbusHeader.updateInfoCode(request.getHeader(), IPbusHeader.INFO_CODE_RESPONSE)
     responseHeader = IPbusHeader.updateWords(responseHeader, 2)
     # Returning zeros for the response body, as no real idea what else it should be.
     return TransactionElement.makeFromHeaderAndBody(responseHeader, [0,0])
Ejemplo n.º 6
0
    def _blockOrFifoWrite(self, name, dataList, addrOffset, isFifo = False):
        """Common code for either a block write or a FIFO write."""

        depth = len(dataList)

        addrTableItem = self.addrTable.getItem(name) # Get the details of the relevant item from the addr table.

        if addrTableItem.getMask() != 0xffffffff:
            raise ChipsException("Block/FIFO write error: cannot perform block or FIFO write on a masked register address!")

        if depth == 0:
            chipsLog.warn("Ignoring block/FIFO write to register '" + name + "': dataList is empty!");
            return
        elif depth > ChipsBus.MAX_BLOCK_TRANSFER_DEPTH:
            return self._oversizeBlockOrFifoWrite(name, dataList, addrOffset, isFifo)

        try:
            if not addrTableItem.getWriteFlag(): raise ChipsException("Write transaction creation error: write is not allowed on register '" +  addrTableItem.getName() + "'.")
            # create and run the transaction and get the response
            self._makeAndRunTransaction( [self._createWriteTransactionElement(addrTableItem, dataList, addrOffset, isFifo)] )
        except ChipsException as err:
            raise ChipsException("Block/FIFO write error on register '" + name + "':\n\t" + str(err))

        chipsLog.debug("Block/FIFO write success! " + str(depth) + " 32-bit words were written to '"
                        + name + "' (addrOffset=0x" + uInt32HexStr(addrOffset) + ")")
Ejemplo n.º 7
0
 def closeSockets(self):
     """Allows you to manually close any sockets that may have been opened."""
     try:
         self._socket.close()
         chipsLog.debug("Socket closed successfully.")
     except:
         chipsLog.warn("Error closing socket!")
Ejemplo n.º 8
0
    def queueWrite(self, name, dataU32, addrOffset = 0):
        """Create a register write (RMW-bits) transaction element and add it to the transaction queue.
        
        This works in the same way as a normal write(), except that many can be queued
        into a packet and dispatched all at once rather than individually.  Run the
        queued transactions with queueRun().
        
        Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        if len(self._transactionQueue) <= 50:
        
            dataU32 = dataU32 & 0xffffffff # Ignore oversize input.
            chipsLog.debug("Write queued: dataU32 = 0x" + uInt32HexStr(dataU32) + " to register '"
                           + name + "' with addrOffset = 0x" + uInt32HexStr(addrOffset))
        
            item = self.addrTable.getItem(name) # Get the details of the relevant item from the addr table.
        
            try:
                self._checkRWFlag(item, 0, 1)
            except ChipsException, err:
                raise ChipsException("Write error on register '" + name + "':\n\t" + str(err))
        
            self._transactionQueue.append(self._createRMWBitsTransactionElement(item, dataU32, addrOffset))
            self._transactionItemQueue.append(item)
            self._transactionRWFlagQueue.append(0)
Ejemplo n.º 9
0
    def _oversizeBlockOrFifoWrite(self, name, dataList, addrOffset, isFifo):
        """Handling for a block write which is too big for the hardware to handle in one go"""

        chipsLog.debug(
            "Write depth too large for single packet... will automatically split write over many packets"
        )

        depth = len(dataList)
        remainingTransactions = depth

        offsetMultiplier = 1
        if isFifo: offsetMultiplier = 0

        while remainingTransactions > ChipsBus.MAX_BLOCK_TRANSFER_DEPTH:
            self._blockOrFifoWrite(
                name, dataList[(
                    depth -
                    remainingTransactions):(depth - remainingTransactions) +
                               ChipsBus.MAX_BLOCK_TRANSFER_DEPTH], addrOffset +
                ((depth - remainingTransactions) * offsetMultiplier), isFifo)
            remainingTransactions -= ChipsBus.MAX_BLOCK_TRANSFER_DEPTH

        self._blockOrFifoWrite(
            name, dataList[(depth - remainingTransactions):],
            addrOffset + ((depth - remainingTransactions) * offsetMultiplier),
            isFifo)
Ejemplo n.º 10
0
    def _oversizeBlockOrFifoRead(self, name, depth, addrOffset, isFifo):
        """Handles a block or FIFO read that's too big to be handled by a single UDP packet"""

        chipsLog.debug(
            "Read depth too large for single packet... will automatically split read over many packets"
        )

        remainingTransactions = depth
        result = []

        offsetMultiplier = 1
        if isFifo: offsetMultiplier = 0

        while remainingTransactions > ChipsBus.MAX_BLOCK_TRANSFER_DEPTH:

            print "REMAINING=", remainingTransactions
            result.extend(
                self._blockOrFifoRead(
                    name, ChipsBus.MAX_BLOCK_TRANSFER_DEPTH, addrOffset +
                    ((depth - remainingTransactions) * offsetMultiplier),
                    isFifo))
            remainingTransactions -= ChipsBus.MAX_BLOCK_TRANSFER_DEPTH

        print "REMAINING: rest=", remainingTransactions
        result.extend(
            self._blockOrFifoRead(
                name, remainingTransactions, addrOffset +
                ((depth - remainingTransactions) * offsetMultiplier), isFifo))

        return result
Ejemplo n.º 11
0
    def serveForever(self):
        """The only function any user of this class needs to run!
        
        Receives, acts on, and responds to UDP control packets as the Mini-T (or similar hardware) would.
        Packets are received by the main thread and queued for action and response by a second thread.
        """
        chipsLog.info("Dummy Hardware UDP Server starting")
        # This starts the packet "act and respond" handler thread
        self.start()

        while not self.stopServing:
            try:
                data, addr = self._socket.recvfrom(DummyHardware.SOCKET_BUFFER_SIZE)
            except KeyboardInterrupt:
                chipsLog.warning("\nKeyboard interrupt (ctrl-c) received whilst waiting for incoming UDP packet")
                self._stopServingAndJoinThreads()
                return
            except:
                chipsLog.warning("\nException caught whilst waiting for incoming UDP packet")
                self._stopServingAndJoinThreads()
                return

            if not data:
                chipsLog.warning("Socket received an empty packet from " + repr(addr) + \
                                 ".  Assuming socket now closed.\nTerminating dummy hardware server...")
                self._stopServingAndJoinThreads()
                return
            else:
                chipsLog.debug("\nReceived packet from " + repr(addr))
                transaction = Transaction.constructHostTransaction(data, addr)
                self._transaction_queue.put(transaction)
Ejemplo n.º 12
0
    def _handleReadRequest(self, request):
        requestHeader = request.getHeader()
        words = IPbusHeader.getWords(requestHeader)
        baseAddr = request.getBody()[0]
        chipsLog.debug("Read requested on Addr=0x" + uInt32HexStr(baseAddr))

        # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE
        responseHeader = IPbusHeader.updateInfoCode(
            requestHeader, IPbusHeader.INFO_CODE_RESPONSE)

        # The (baseAddr & 0xffffffff) forces baseAddr to be in unsigned form (i.e. 0xfffffffc, say, rather than -4)
        if (
                baseAddr & 0xffffffff
        ) == 0xffffffff:  # A read on this register is a Dummy Hardware Reset Request.
            chipsLog.info(
                "** Dummy Hardware reset request received! Zeroing all registers. **"
            )
            self._registers.clear()

        responseBody = []
        appendToResponseBody = responseBody.append  # This is for a speed optimisation

        for offset in range(words):
            currentReg = baseAddr + offset
            # Create these registers if they don't already exist.
            if currentReg not in self._registers:
                self._registers[currentReg] = 0
            appendToResponseBody(self._registers[currentReg])
        return TransactionElement.makeFromHeaderAndBody(
            responseHeader, responseBody)
Ejemplo n.º 13
0
 def queueRead(self, name, addrOffset = 0):
     """Create a read transaction element and add it to the transaction queue.
     
     This works in the same way as a normal read(), except that many can be queued
     into a packet and dispatched all at once rather than individually.  Run the
     queued transactions with queueRun().
     
     Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
     be queued.
     """
     
     if len(self._transactionQueue) <= 50:
     
         chipsLog.debug("Read queued: register '" + name + "' with addrOffset = 0x" + uInt32HexStr(addrOffset))
     
         item = self.addrTable.getItem(name) # Get the details of the relevant item from the addr table.
     
         try:
             self._checkRWFlag(item)
         except ChipsException, err:
             raise ChipsException("Read error on register '" + name + "':\n\t" + str(err))
     
         self._transactionQueue.append(self._createReadTransactionElement(item, 1, addrOffset))
         self._transactionItemQueue.append(item)
         self._transactionRWFlagQueue.append(1)
Ejemplo n.º 14
0
    def _blockOrFifoRead(self, name, depth, addrOffset, isFifo = False):
        """Common code for either a block read or a FIFO read."""

        if depth <= 0:
            chipsLog.warn("Ignoring read with depth = 0 from register '" + name + "'!")
            return

        if depth > ChipsBus.MAX_BLOCK_TRANSFER_DEPTH:
            return self._oversizeBlockOrFifoRead(name, depth, addrOffset, isFifo)

        addrTableItem = self.addrTable.getItem(name) # Get the details of the relevant item from the addr table.

        if addrTableItem.getMask() != 0xffffffff:
            raise ChipsException("Block/FIFO read error: cannot perform block or FIFO read on a masked register address!")

        try:
            if not addrTableItem.getReadFlag(): raise ChipsException("Read transaction creation error: read is not allowed on register '" + addrTableItem.getName() + "'.")
            # create and run the transaction and get the response
            transaction = self._makeAndRunTransaction( [self._createReadTransactionElement(addrTableItem, depth, addrOffset, isFifo)] )
        except ChipsException as err:
            raise ChipsException("Block/FIFO read error on register '" + name + "':\n\t" + str(err))

        blockReadResponse = transaction.responses[-1] # Block read response will be last in list

        chipsLog.debug("Block/FIFO read success! Register '" + name + "' (addrOffset=0x"
                       + uInt32HexStr(addrOffset) + ") was read successfully." )

        return blockReadResponse.getBody().tolist()
Ejemplo n.º 15
0
 def queueClear(self):
     """Clears the current queue of transactions"""
     
     chipsLog.debug("Clearing transaction queue")
     
     self._transactionQueue = []
     self._transactionItemQueue = []
     self._transactionRWFlagQueue =[]
Ejemplo n.º 16
0
 def _handleGetReservedAddrInfoRequest(self, request):
     chipsLog.debug("Reserved Address Info transaction requested")
     # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE
     responseHeader = IPbusHeader.updateInfoCode(
         request.getHeader(), IPbusHeader.INFO_CODE_RESPONSE)
     responseHeader = IPbusHeader.updateWords(responseHeader, 2)
     # Returning zeros for the response body, as no real idea what else it should be.
     return TransactionElement.makeFromHeaderAndBody(responseHeader, [0, 0])
Ejemplo n.º 17
0
    def queueClear(self):
        """Clears the current queue of transactions"""

        chipsLog.debug("Clearing transaction queue")

        self._queuedRequests = []
        self._queuedAddrTableItems = []
        self._queuedIsARead =[]
Ejemplo n.º 18
0
 def queueClear(self):
     """Clears the current queue of transactions"""
     
     chipsLog.debug("Clearing transaction queue")
     
     self._queuedRequests = []
     self._queuedAddrTableItems = []
     self._queuedIsARead =[]
Ejemplo n.º 19
0
 def closeSockets(self):
     """Allows you to manually close any sockets that may have been opened."""
     if self._connectedSocket != None:
         try:
             self._connectedSocket.close()
             chipsLog.debug("Connected TCP socket closed successfully.")
         except:
             chipsLog.debug("Error closing connected TCP socket!")
     DummyHardwareBase.closeSockets(self)
Ejemplo n.º 20
0
 def closeSockets(self):
     """Allows you to manually close any sockets that may have been opened."""
     if self._connectedSocket != None:
         try:
             self._connectedSocket.close()
             chipsLog.debug("Connected TCP socket closed successfully.")
         except:
             chipsLog.debug("Error closing connected TCP socket!")
     DummyHardwareBase.closeSockets(self)
Ejemplo n.º 21
0
    def _handleWriteRequest(self, request):
        requestHeader = request.getHeader()
        words = IPbusHeader.getWords(requestHeader)
        requestBody = request.getBody()
        baseAddr = requestBody[0]
        chipsLog.debug("Write requested on Addr=0x" + uInt32HexStr(baseAddr))

        # Response header is the request header with direction bit changed
        responseHeader = IPbusHeader.updateDirection(requestHeader, 1)

        for offset in range(words):
            currentReg = baseAddr + offset  
            self._registers[currentReg] = requestBody[offset + 1]
        return TransactionElement.makeFromHeaderAndBody(responseHeader)
Ejemplo n.º 22
0
 def serialise(self, transactionElementList):
     '''Serialises a list of transaction elements into an ASCII string for transmission'''
 
     if chipsLog.level <= logging.DEBUG:
         msg = "\nSerialising the following packet content:\n"
         msg += reprTransactionElementList(transactionElementList)
         chipsLog.debug(msg)
 
     allTransactionsArray = array('I', [0x200000f0])   # TEMPORARY IPBUS V2.x HACK!   Add a packet header of [0x200000f0] to the beginning of each packet.
     extendFunc = allTransactionsArray.extend
     for element in transactionElementList:
         extendFunc(element.getAll())
     if self._doByteReorder: allTransactionsArray.byteswap()
     return allTransactionsArray.tostring()
Ejemplo n.º 23
0
    def _handleWriteRequest(self, request):
        requestHeader = request.getHeader()
        words = IPbusHeader.getWords(requestHeader)
        requestBody = request.getBody()
        baseAddr = requestBody[0]
        chipsLog.debug("Write requested on Addr=0x" + uInt32HexStr(baseAddr))

        # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE
        responseHeader = IPbusHeader.updateInfoCode(requestHeader, IPbusHeader.INFO_CODE_RESPONSE)

        for offset in range(words):
            currentReg = baseAddr + offset  
            self._registers[currentReg] = requestBody[offset + 1]
        return TransactionElement.makeFromHeaderAndBody(responseHeader)
Ejemplo n.º 24
0
 def serialise(self, transactionElementList):
     '''Serialises a list of transaction elements into an ASCII string for transmission'''
 
     if chipsLog.level <= logging.DEBUG:
         msg = "\nSerialising the following packet content:\n"
         msg += reprTransactionElementList(transactionElementList)
         chipsLog.debug(msg)
 
     allTransactionsArray = array('I')
     extendFunc = allTransactionsArray.extend
     for element in transactionElementList:
         extendFunc(element.getAll())
     if self._doByteReorder: allTransactionsArray.byteswap()
     return allTransactionsArray.tostring()
Ejemplo n.º 25
0
 def serialise(self, transactionElementList):
     '''Serialises a list of transaction elements into an ASCII string for transmission'''
 
     if chipsLog.level <= logging.DEBUG:
         msg = "\nSerialising the following packet content:\n"
         msg += reprTransactionElementList(transactionElementList)
         chipsLog.debug(msg)
 
     allTransactionsArray = array('I', [0x200000f0])   # TEMPORARY IPBUS V2.x HACK!   Add a packet header of [0x200000f0] to the beginning of each packet.
     extendFunc = allTransactionsArray.extend
     for element in transactionElementList:
         extendFunc(element.getAll())
     if self._doByteReorder: allTransactionsArray.byteswap()
     return allTransactionsArray.tostring()
Ejemplo n.º 26
0
    def _handleFifoWriteRequest(self, request):
        requestHeader = request.getHeader()
        requestBody = request.getBody()
        fifoAddr = requestBody[0]
        chipsLog.debug("FIFO write requested on Addr=0x" + uInt32HexStr(fifoAddr))

        # Response header is the request header with direction bit changed
        responseHeader = IPbusHeader.updateDirection(requestHeader, 1)

        # Obviously we don't really have a FIFO, we just have a single register at the address of the supposed
        # FIFO.  So, whatever the last value written into the FIFO is, this will be the value this register will
        # take.  We ignore all the previous "writes" to the FIFO.
        self._registers[fifoAddr] = requestBody[-1]

        return TransactionElement.makeFromHeaderAndBody(responseHeader)
Ejemplo n.º 27
0
    def _handleWriteRequest(self, request):
        requestHeader = request.getHeader()
        words = IPbusHeader.getWords(requestHeader)
        requestBody = request.getBody()
        baseAddr = requestBody[0]
        chipsLog.debug("Write requested on Addr=0x" + uInt32HexStr(baseAddr))

        # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE
        responseHeader = IPbusHeader.updateInfoCode(
            requestHeader, IPbusHeader.INFO_CODE_RESPONSE)

        for offset in range(words):
            currentReg = baseAddr + offset
            self._registers[currentReg] = requestBody[offset + 1]
        return TransactionElement.makeFromHeaderAndBody(responseHeader)
Ejemplo n.º 28
0
    def _handleReadModifyWriteSumRequest(self, request):
        requestBody = request.getBody()
        addr = requestBody[0]
        addend = requestBody[1]  # The value we add to the existing value
        chipsLog.debug("Read/Modify/Write-sum requested on Addr=0x" + uInt32HexStr(addr))
        
        # Create the register if it doesn't already exist.
        if addr not in self._registers: self._registers[addr] = 0
        
        updatedValue = (self._registers[addr] + addend) & 0xffffffff
        self._registers[addr] = updatedValue

        # Response header is the request header with direction bit changed
        responseHeader = IPbusHeader.updateDirection(request.getHeader(), 1)

        return TransactionElement.makeFromHeaderAndBody(responseHeader, [updatedValue])
Ejemplo n.º 29
0
    def _oversizeBlockOrFifoWrite(self, name, dataList, addrOffset, isFifo):
        """Handling for a block write which is too big for the hardware to handle in one go"""
        
        chipsLog.debug("Write depth too large for single packet... will automatically split write over many packets")

        depth = len(dataList)
        remainingTransactions = depth

        offsetMultiplier = 1
        if isFifo: offsetMultiplier = 0
                
        while remainingTransactions > ChipsBus.MAX_BLOCK_TRANSFER_DEPTH:
            self._blockOrFifoWrite(name, dataList[(depth - remainingTransactions):(depth - remainingTransactions) + ChipsBus.MAX_BLOCK_TRANSFER_DEPTH],
                                   addrOffset + ((depth - remainingTransactions) * offsetMultiplier), isFifo)
            remainingTransactions -= ChipsBus.MAX_BLOCK_TRANSFER_DEPTH
            
        self._blockOrFifoWrite(name, dataList[(depth - remainingTransactions):], addrOffset + ((depth - remainingTransactions) * offsetMultiplier), isFifo)
Ejemplo n.º 30
0
    def _handleReadModifyWriteBitsRequest(self, request):
        requestBody = request.getBody()
        addr = requestBody[0]
        andTerm = requestBody[1]  # The and term is the bitwise complement of the register mask (i.e. mask = ~andTerm)
        orTerm = requestBody[2]
        chipsLog.debug("Read/Modify/Write-bits requested on Addr=0x" + uInt32HexStr(addr))
        
        # Create the register if it doesn't already exist.
        if addr not in self._registers: self._registers[addr] = 0
        
        updatedValue = (self._registers[addr] & andTerm) | (orTerm)
        self._registers[addr] = updatedValue

        # Response header is the request header with direction bit changed
        responseHeader = IPbusHeader.updateDirection(request.getHeader(), 1)

        return TransactionElement.makeFromHeaderAndBody(responseHeader, [updatedValue])
Ejemplo n.º 31
0
    def _handleFifoWriteRequest(self, request):
        requestHeader = request.getHeader()
        requestBody = request.getBody()
        fifoAddr = requestBody[0]
        chipsLog.debug("FIFO write requested on Addr=0x" +
                       uInt32HexStr(fifoAddr))

        # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE
        responseHeader = IPbusHeader.updateInfoCode(
            requestHeader, IPbusHeader.INFO_CODE_RESPONSE)

        # Obviously we don't really have a FIFO, we just have a single register at the address of the supposed
        # FIFO.  So, whatever the last value written into the FIFO is, this will be the value this register will
        # take.  We ignore all the previous "writes" to the FIFO.
        self._registers[fifoAddr] = requestBody[-1]

        return TransactionElement.makeFromHeaderAndBody(responseHeader)
Ejemplo n.º 32
0
    def blockRead(self, name, depth=1, addrOffset=0):
        """Block read (not for masked registers!).  Returns a list of the read results (32-bit numbers).

        The blockRead() transaction runs straight away - it cannot be queued.

        name: the register name of the register you want to read from.
        depth: the number of 32-bit reads deep you want to go from the start address.
            (i.e. depth=3 will return a list with three 32-bit values).
        addrOffset: optional - provide a 32-bit word offset if you wish.

        Notes: Use the depth and addrOffset at your own risk!  No checking is done to
            see if these values are remotely sensible!
        """

        chipsLog.debug("Block read requested: register '" + name + "' with addrOffset = 0x"
                       + uInt32HexStr(addrOffset) + " and depth = " + str(depth))

        return self._blockOrFifoRead(name, depth, addrOffset, False)
Ejemplo n.º 33
0
    def _handleFifoReadRequest(self, request):
        requestHeader = request.getHeader()
        words = IPbusHeader.getWords(requestHeader)
        fifoAddr = request.getBody()[0]
        chipsLog.debug("FIFO read requested on Addr=0x" + uInt32HexStr(fifoAddr))

        # Response header is the request header with direction bit changed
        responseHeader = IPbusHeader.updateDirection(requestHeader, 1)

        # Create the register if they don't already exist in our memory space
        if fifoAddr not in self._registers:
            self._registers[fifoAddr] = 0

        # Obviously we don't really have a FIFO, so we'll just have to return the value stored
        # at the FIFO's address many times...
        value = self._registers[fifoAddr]
        responseBody = [value for iReads in range(words)]
        return TransactionElement.makeFromHeaderAndBody(responseHeader, responseBody)
Ejemplo n.º 34
0
    def blockRead(self, name, depth=1, addrOffset=0):
        """Block read (not for masked registers!).  Returns a list of the read results (32-bit numbers).
        
        The blockRead() transaction runs straight away - it cannot be queued.

        name: the register name of the register you want to read from.
        depth: the number of 32-bit reads deep you want to go from the start address.
            (i.e. depth=3 will return a list with three 32-bit values). 
        addrOffset: optional - provide a 32-bit word offset if you wish.
        
        Notes: Use the depth and addrOffset at your own risk!  No checking is done to
            see if these values are remotely sensible!
        """

        chipsLog.debug("Block read requested: register '" + name + "' with addrOffset = 0x"
                       + uInt32HexStr(addrOffset) + " and depth = " + str(depth))

        return self._blockOrFifoRead(name, depth, addrOffset, False)
Ejemplo n.º 35
0
    def blockWrite(self, name, dataList, addrOffset=0):
        """Block write (not for masked registers!).

        The blockWrite() transaction runs straight away - it cannot be queued.

        name: the register name of the register you want to read from.
        dataList: the list of 32-bit values you want writing.  The size of the list
            determines how deep the block write goes.
        addrOffset: optional - provide a 32-bit word offset if you wish.

        Notes:  Use this at your own risk!  No checking is currently done to see if
            you will be stomping on any other registers if the dataList or addrOffset
            is inappropriate in size!
        """

        chipsLog.debug("Block write requested: register '" + name + "' with addrOffset = 0x"
                       + uInt32HexStr(addrOffset) + " and depth = " + str(len(dataList)))

        return self._blockOrFifoWrite(name, dataList, addrOffset, False)
Ejemplo n.º 36
0
 def _oversizeBlockOrFifoRead(self, name, depth, addrOffset, isFifo):
     """Handles a block or FIFO read that's too big to be handled by a single UDP packet"""
     
     chipsLog.debug("Read depth too large for single packet... will automatically split read over many packets")
     
     remainingTransactions = depth
     result =[]
     
     offsetMultiplier = 1
     if isFifo: offsetMultiplier = 0
     
     while remainingTransactions > ChipsBus.MAX_BLOCK_TRANSFER_DEPTH:
         
         result.extend(self._blockOrFifoRead(name, ChipsBus.MAX_BLOCK_TRANSFER_DEPTH, addrOffset + ((depth - remainingTransactions) * offsetMultiplier), isFifo))
         remainingTransactions -= ChipsBus.MAX_BLOCK_TRANSFER_DEPTH
         
     result.extend(self._blockOrFifoRead(name, remainingTransactions, addrOffset + ((depth - remainingTransactions) * offsetMultiplier), isFifo))
     
     return result
Ejemplo n.º 37
0
    def _handleReadModifyWriteSumRequest(self, request):
        requestBody = request.getBody()
        addr = requestBody[0]
        addend = requestBody[1]  # The value we add to the existing value
        chipsLog.debug("Read/Modify/Write-sum requested on Addr=0x" +
                       uInt32HexStr(addr))

        # Create the register if it doesn't already exist.
        if addr not in self._registers: self._registers[addr] = 0

        updatedValue = (self._registers[addr] + addend) & 0xffffffff
        self._registers[addr] = updatedValue

        # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE
        responseHeader = IPbusHeader.updateInfoCode(
            request.getHeader(), IPbusHeader.INFO_CODE_RESPONSE)

        return TransactionElement.makeFromHeaderAndBody(
            responseHeader, [updatedValue])
Ejemplo n.º 38
0
    def _makeAndRunTransaction(self, requestsList):
        """Constructs, runs and then returns a completed transaction from the given requestsList

        requestsList: a list of TransactionElements (i.e. requests from client to the hardware).
        
        Notes:  _makeAndRunTransaction will automatically prepend one byte-order transaction.
        """

        # Construct the transaction and serialise it - we prepend four byte-order transactions in
        # order to ensure we meet minimum Ethernet payload requirements, else funny stuff happens.
        transaction = Transaction.constructClientTransaction(requestsList, self._hostAddr)
        transaction.serialiseRequests()
        
        chipsLog.debug("Sending packet now.");
        try:
            # Send the transaction
            self._socketSend(transaction)
        except socket.error, socketError:
            raise ChipsException("A socket error occurred whilst sending the IPbus transaction request packet:\n\t" + str(socketError))
Ejemplo n.º 39
0
    def blockWrite(self, name, dataList, addrOffset=0):
        """Block write (not for masked registers!).
        
        The blockWrite() transaction runs straight away - it cannot be queued.

        name: the register name of the register you want to read from.
        dataList: the list of 32-bit values you want writing.  The size of the list
            determines how deep the block write goes.  
        addrOffset: optional - provide a 32-bit word offset if you wish.
        
        Notes:  Use this at your own risk!  No checking is currently done to see if
            you will be stomping on any other registers if the dataList or addrOffset
            is inappropriate in size!
        """

        chipsLog.debug("Block write requested: register '" + name + "' with addrOffset = 0x"
                       + uInt32HexStr(addrOffset) + " and depth = " + str(len(dataList)))

        return self._blockOrFifoWrite(name, dataList, addrOffset, False)
Ejemplo n.º 40
0
    def queueRun(self):
        """Runs the current queue of single register read or write transactions and returns two lists. The
        first contains the values read and the second contains the values written.
        
        Note: Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        chipsLog.debug("Running all queued transactions")
        
        requestQueueLength = len(self._queuedRequests)
        readResponse = []
        writeResponse = []
        
        try:
            transaction = self._makeAndRunTransaction(self._queuedRequests)
        except ChipsException, err:
            self.queueClear()
            raise ChipsException("Error while running queued transactions:\n\t" + str(err))
Ejemplo n.º 41
0
    def fifoRead(self, name, depth=1, addrOffset=0):
        """Non-incrementing block read (not for masked registers!). Returns list of the read results.
        
        Reads from the same address the number of times specified by depth

        The fifoRead() transaction runs straight away - it cannot be queued.
        
        name: the register name of the register you want to read from.
        depth: the number of 32-bit reads you want to perform on the FIFO
            (i.e. depth=3 will return a list with three 32-bit values). 
        addrOffset: optional - provide a 32-bit word offset if you wish.
        
        Notes: Use the depth and addrOffset at your own risk!  No checking is done to
            see if these values are remotely sensible!
        """        

        chipsLog.debug("FIFO read (non-incrementing block read) requested: register '" + name + "' with addrOffset = 0x"
                       + uInt32HexStr(addrOffset) + " and depth = " + str(depth))

        return self._blockOrFifoRead(name, depth, addrOffset, True)
Ejemplo n.º 42
0
    def queueRun(self):
        """Runs the current queue of single register read or write transactions and returns two lists. The
        first contains the values read and the second contains the values written.
        
        Note: Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        chipsLog.debug("Running all queued transactions")

        requestQueueLength = len(self._queuedRequests)
        readResponse = []
        writeResponse = []

        try:
            transaction = self._makeAndRunTransaction(self._queuedRequests)
        except ChipsException, err:
            self.queueClear()
            raise ChipsException(
                "Error while running queued transactions:\n\t" + str(err))
Ejemplo n.º 43
0
    def fifoRead(self, name, depth=1, addrOffset=0):
        """Non-incrementing block read (not for masked registers!). Returns list of the read results.

        Reads from the same address the number of times specified by depth

        The fifoRead() transaction runs straight away - it cannot be queued.

        name: the register name of the register you want to read from.
        depth: the number of 32-bit reads you want to perform on the FIFO
            (i.e. depth=3 will return a list with three 32-bit values).
        addrOffset: optional - provide a 32-bit word offset if you wish.

        Notes: Use the depth and addrOffset at your own risk!  No checking is done to
            see if these values are remotely sensible!
        """

        chipsLog.debug("FIFO read (non-incrementing block read) requested: register '" + name + "' with addrOffset = 0x"
                       + uInt32HexStr(addrOffset) + " and depth = " + str(depth))

        return self._blockOrFifoRead(name, depth, addrOffset, True)
Ejemplo n.º 44
0
    def _handleReadModifyWriteBitsRequest(self, request):
        requestBody = request.getBody()
        addr = requestBody[0]
        andTerm = requestBody[
            1]  # The and term is the bitwise complement of the register mask (i.e. mask = ~andTerm)
        orTerm = requestBody[2]
        chipsLog.debug("Read/Modify/Write-bits requested on Addr=0x" +
                       uInt32HexStr(addr))

        # Create the register if it doesn't already exist.
        if addr not in self._registers: self._registers[addr] = 0

        updatedValue = (self._registers[addr] & andTerm) | (orTerm)
        self._registers[addr] = updatedValue

        # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE
        responseHeader = IPbusHeader.updateInfoCode(
            request.getHeader(), IPbusHeader.INFO_CODE_RESPONSE)

        return TransactionElement.makeFromHeaderAndBody(
            responseHeader, [updatedValue])
Ejemplo n.º 45
0
    def _handleFifoReadRequest(self, request):
        requestHeader = request.getHeader()
        words = IPbusHeader.getWords(requestHeader)
        fifoAddr = request.getBody()[0]
        chipsLog.debug("FIFO read requested on Addr=0x" +
                       uInt32HexStr(fifoAddr))

        # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE
        responseHeader = IPbusHeader.updateInfoCode(
            requestHeader, IPbusHeader.INFO_CODE_RESPONSE)

        # Create the register if they don't already exist in our memory space
        if fifoAddr not in self._registers:
            self._registers[fifoAddr] = 0

        # Obviously we don't really have a FIFO, so we'll just have to return the value stored
        # at the FIFO's address many times...
        value = self._registers[fifoAddr]
        responseBody = [value for iReads in range(words)]
        return TransactionElement.makeFromHeaderAndBody(
            responseHeader, responseBody)
Ejemplo n.º 46
0
    def _makeAndRunTransaction(self, requestsList):
        """Constructs, runs and then returns a completed transaction from the given requestsList

        requestsList: a list of TransactionElements (i.e. requests from client to the hardware).

        Notes:  _makeAndRunTransaction will automatically prepend one byte-order transaction.
        """

        # Construct the transaction and serialise it - we prepend four byte-order transactions in
        # order to ensure we meet minimum Ethernet payload requirements, else funny stuff happens.
        transaction = Transaction.constructClientTransaction(
            requestsList, self._hostAddr)
        transaction.serialiseRequests()

        chipsLog.debug("Sending packet now.")
        try:
            # Send the transaction
            self._socketSend(transaction)
        except socket.error, socketError:
            raise ChipsException(
                "A socket error occurred whilst sending the IPbus transaction request packet:\n\t"
                + str(socketError))
Ejemplo n.º 47
0
 def deserialise(self, packetPayloadString):
     '''Deserialises a packet payload ASCII string into list of transaction elements'''
 
     # 1) Unpack the string into unsigned integers
     try:
         rawU32Array = array('I', packetPayloadString)  # Unpack string to an unsigned 32-bit array
     except Exception as err:
         raise ChipsException("Deserialisation error:\n\t" + str(err))
 
     # 2) Debug output of the raw packet
     if chipsLog.level <= logging.DEBUG:
         msg = "\nRaw received packet content is:\n"
         for u32 in rawU32Array: msg += "  0x" + uInt32HexStr(u32) + "\n"
         chipsLog.debug(msg)
 
     # 3) Detect if we need to do a byte-reorder
     firstWord = rawU32Array[0]
     firstWordMasked = firstWord & 0xf00000f0  # This selects only the bits relevant for detecting the byte ordering
     if firstWordMasked == 0x200000f0:
         chipsLog.debug("Packet header detected: no byte-reorder is required.")
     elif firstWordMasked == 0xf0000020:
         chipsLog.debug("Packet header detected: a byte-reorder will be performed.")
         self._doByteReorder = True
     else:
         chipsLog.warn("Warning: No packet header (or unknown protocol version)! First word = 0x" + uInt32HexStr(firstWord) + ". Will hope for the best!...")
     
     # 4) Do the byte-reorder if necessary
     if self._doByteReorder:  rawU32Array.byteswap()
    
     # 5) Now deserialise into a list of TransactionElements
     transactionElementList = []  # The list all the deserialised transaction elements will go into
     appendToTransactionElementList = transactionElementList.append  # This is needed for a speed optimisation
     iU32 = 1  # Index for moving through the rawU32Array          # TEMPORARY IPBUS V2.x HACK! Skip the first word which is now a packet ID
     rawU32ArraySize = len(rawU32Array)
     while iU32 < rawU32ArraySize:
         expectedBodySize = getExpectedBodySize(rawU32Array[iU32])
         if rawU32ArraySize - iU32 - 1 - expectedBodySize < 0:
             raise ChipsException("Deserialisation error: packet not correctly formatted " \
                                  "or does not contain the expected amount of data!")
         appendToTransactionElementList(TransactionElement(rawU32Array[iU32: iU32 + 1 + expectedBodySize]))
         iU32 += (1 + expectedBodySize)
     
     # 6) Debug output of deserialised packet content
     if chipsLog.level <= logging.DEBUG:
         msg = "\nDeserialised packet content is:\n" \
               + reprTransactionElementList(transactionElementList)
         chipsLog.debug(msg)
         
     return transactionElementList
Ejemplo n.º 48
0
    def queueRun(self):
        """Runs the current queue of single register read or write transactions and returns two lists. The
        first contains the values read and the second contains the values written.
        
        Note: Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        chipsLog.debug("Running all queued transactions")
        # A check is performed to ensure the lists containing the transaction
        # queue information are of equal length
        if len(self._transactionQueue) != len(self._transactionItemQueue) or len(self._transactionQueue) != len(self._transactionRWFlagQueue):
            raise ChipsException("Error while running queued transactions: elements missing from transaction list!")
        
        transactionQueueLength = len(self._transactionQueue)
        readResponse = []
        writeResponse = []
        
        try:
            transaction = self._makeAndRunTransaction(self._transactionQueue)
        except ChipsException, err:
            self.queueClear()
            raise ChipsException("Error while running queued transactions:\n\t" + str(err))
Ejemplo n.º 49
0
    def _handleReadRequest(self, request):
        requestHeader = request.getHeader()
        words = IPbusHeader.getWords(requestHeader)
        baseAddr = request.getBody()[0]
        chipsLog.debug("Read requested on Addr=0x" + uInt32HexStr(baseAddr))

        # Response header is the request header with direction bit changed
        responseHeader = IPbusHeader.updateDirection(requestHeader, 1)

        # The (baseAddr & 0xffffffff) forces baseAddr to be in unsigned form (i.e. 0xfffffffc, say, rather than -4)
        if (baseAddr & 0xffffffff) == 0xffffffff:  # A read on this register is a Dummy Hardware Reset Request.
            chipsLog.info("** Dummy Hardware reset request received! Zeroing all registers. **")
            self._registers.clear()
        
        responseBody = []
        appendToResponseBody = responseBody.append  # This is for a speed optimisation  
        
        for offset in range(words):
            currentReg = baseAddr + offset  
            # Create these registers if they don't already exist.
            if currentReg not in self._registers:
                self._registers[currentReg] = 0
            appendToResponseBody(self._registers[currentReg])
        return TransactionElement.makeFromHeaderAndBody(responseHeader, responseBody)
Ejemplo n.º 50
0
    def serveForever(self):
        """The only function any user of this class needs to run!
        
        Receives, acts on, and responds to UDP control packets as the Mini-T (or similar hardware) would.
        Packets are received by the main thread and queued for action and response by a second thread.
        """
        chipsLog.info("Dummy Hardware UDP Server starting")
        # This starts the packet "act and respond" handler thread
        self.start()

        while not self.stopServing:
            try:
                data, addr = self._socket.recvfrom(
                    DummyHardware.SOCKET_BUFFER_SIZE)
            except KeyboardInterrupt:
                chipsLog.warning(
                    "\nKeyboard interrupt (ctrl-c) received whilst waiting for incoming UDP packet"
                )
                self._stopServingAndJoinThreads()
                return
            except:
                chipsLog.warning(
                    "\nException caught whilst waiting for incoming UDP packet"
                )
                self._stopServingAndJoinThreads()
                return

            if not data:
                chipsLog.warning("Socket received an empty packet from " + repr(addr) + \
                                 ".  Assuming socket now closed.\nTerminating dummy hardware server...")
                self._stopServingAndJoinThreads()
                return
            else:
                chipsLog.debug("\nReceived packet from " + repr(addr))
                transaction = Transaction.constructHostTransaction(data, addr)
                self._transaction_queue.put(transaction)
Ejemplo n.º 51
0
 def _actAndRespond(self, transaction):
     """Performs the required action and returns the response for a given transaction"""
     self._transactionCounter += 1
     chipsLog.debug("*** Performing transaction #" + str(self._transactionCounter) + " ***")
     try:
         transaction.deserialiseRequests()
 
         for request in transaction.requests:
             transaction.appendResponse(self._requestTypeHandlerMap[IPbusHeader.getTypeId(request.getHeader())](request))
         
         transaction.serialiseResponses()
         chipsLog.debug("Sending response packet")
         self._socketSend(transaction)
         chipsLog.debug("Response packet sent!")
         chipsLog.debug("*** Transaction #" + str(self._transactionCounter) + " completed! ***\n")
     except ChipsException, err:
         chipsLog.error("ERROR! Transaction #" + str(self._transactionCounter) + 
                        " could not be successfully processed:\n\t" + str(err))
Ejemplo n.º 52
0
    def _actAndRespond(self, transaction):
        """Performs the required action and returns the response for a given transaction"""
        self._transactionCounter += 1
        chipsLog.debug("*** Performing transaction #" +
                       str(self._transactionCounter) + " ***")
        try:
            transaction.deserialiseRequests()

            for request in transaction.requests:
                transaction.appendResponse(
                    self._requestTypeHandlerMap[IPbusHeader.getTypeId(
                        request.getHeader())](request))

            transaction.serialiseResponses()
            chipsLog.debug("Sending response packet")
            self._socketSend(transaction)
            chipsLog.debug("Response packet sent!")
            chipsLog.debug("*** Transaction #" +
                           str(self._transactionCounter) + " completed! ***\n")
        except ChipsException, err:
            chipsLog.error("ERROR! Transaction #" +
                           str(self._transactionCounter) +
                           " could not be successfully processed:\n\t" +
                           str(err))
Ejemplo n.º 53
0
    def queueRun(self):
        """Runs the current queue of single register read or write transactions and returns two lists. The
        first contains the values read and the second contains the values written.

        Note: Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        chipsLog.debug("Running all queued transactions")

        requestQueueLength = len(self._queuedRequests)

        readResponse = []
        writeResponse = []

        try:
            transaction = self._makeAndRunTransaction(self._queuedRequests)
        except ChipsException as err:
            self.queueClear()
            raise ChipsException("Error while running queued transactions:\n\t" + str(err))

        for i in range(requestQueueLength):
            addrTableItem = self._queuedAddrTableItems[i]

            if len(transaction.responses[0].getBody()) > 0:
                transactionResponse = transaction.responses[i - requestQueueLength].getBody()[0] & 0xffffffff
                transactionResponse = addrTableItem.shiftDataFromMask(transactionResponse)
            else:
                transactionResponse = 0

            if self._queuedIsARead[i]:
                readResponse.append(transactionResponse)
                chipsLog.debug("Read success! Register '" + addrTableItem.getName() + "' returned: 0x" + uInt32HexStr(transactionResponse))
            else:
                writeResponse.append(transactionResponse)
                chipsLog.debug("Write success! Register '" + addrTableItem.getName() + "' assigned: 0x" + uInt32HexStr(transactionResponse))

        self.queueClear()

        response = [readResponse, writeResponse]

        return response
Ejemplo n.º 54
0
        transaction = Transaction.constructClientTransaction(requestsList, self._hostAddr)
        transaction.serialiseRequests()
        
        chipsLog.debug("Sending packet now.");
        try:
            # Send the transaction
            self._socketSend(transaction)
        except socket.error, socketError:
            raise ChipsException("A socket error occurred whilst sending the IPbus transaction request packet:\n\t" + str(socketError))
          
        try:
            # Get response
            transaction.serialResponses = self._socket.recv(ChipsBus.SOCKET_BUFFER_SIZE)
        except socket.error, socketError:
            raise ChipsException("A socket error occurred whilst getting the IPbus transaction response packet:\n\t" + str(socketError))
        chipsLog.debug("Received response packet.");

        transaction.deserialiseResponses()

        transaction.doTransactionChecks() # Generic transaction checks

        self._transactionId = 1   # TEMPORARY IPBUS V2.x HACK!   Reset the transaction ID to 1 for each packet.
        return transaction


    def _initSocketCommon(self, localPort):
        """Performs common socket initialisation (i.e. common to UDP + TCP)"""
        if localPort != None:
            localAddr = ("", localPort)
            self._socket.bind(localAddr)
        self._socket.settimeout(1)
Ejemplo n.º 55
0
            # Send the transaction
            self._socketSend(transaction)
        except socket.error, socketError:
            raise ChipsException(
                "A socket error occurred whilst sending the IPbus transaction request packet:\n\t"
                + str(socketError))

        try:
            # Get response
            transaction.serialResponses = self._socket.recv(
                ChipsBus.SOCKET_BUFFER_SIZE)
        except socket.error, socketError:
            raise ChipsException(
                "A socket error occurred whilst getting the IPbus transaction response packet:\n\t"
                + str(socketError))
        chipsLog.debug("Received response packet.")

        transaction.deserialiseResponses()

        transaction.doTransactionChecks()  # Generic transaction checks

        self._transactionId = 1  # TEMPORARY IPBUS V2.x HACK!   Reset the transaction ID to 1 for each packet.
        return transaction

    def _initSocketCommon(self, localPort):
        """Performs common socket initialisation (i.e. common to UDP + TCP)"""
        if localPort != None:
            localAddr = ("", localPort)
            self._socket.bind(localAddr)
        self._socket.settimeout(1)
Ejemplo n.º 56
0
class SerDes(object):
    '''Class for serialising/deserialising IPbus transaction data
    
    Can serialise a list of TransactionElements into a string, or deserialise
    a string into a list of TransactionElements.  The deserialisation stage
    checks the byte-ordering by looking for a byte-order header, and deals
    with the byte-reordering as appropriate.  If a byte-reorder was required
    on the deserialisation stage, then the serialisation stage will also
    perform a reorder in order to respond correctly.
    
    Byte-reordering is off by default, as it's obviously a waste of CPU.
    '''
    def __init__(self):
        '''Constructor - no arguments'''
        object.__init__(self)
        self._doByteReorder = False

    def serialise(self, transactionElementList):
        '''Serialises a list of transaction elements into an ASCII string for transmission'''

        if chipsLog.level <= logging.DEBUG:
            msg = "\nSerialising the following packet content:\n"
            msg += reprTransactionElementList(transactionElementList)
            chipsLog.debug(msg)

        allTransactionsArray = array(
            'I', [0x200000f0]
        )  # TEMPORARY IPBUS V2.x HACK!   Add a packet header of [0x200000f0] to the beginning of each packet.
        extendFunc = allTransactionsArray.extend
        for element in transactionElementList:
            extendFunc(element.getAll())
        if self._doByteReorder: allTransactionsArray.byteswap()
        return allTransactionsArray.tostring()

    def deserialise(self, packetPayloadString):
        '''Deserialises a packet payload ASCII string into list of transaction elements'''

        # 1) Unpack the string into unsigned integers
        try:
            rawU32Array = array('I', packetPayloadString
                                )  # Unpack string to an unsigned 32-bit array
        except Exception, err:
            raise ChipsException("Deserialisation error:\n\t" + str(err))

        # 2) Debug output of the raw packet
        if chipsLog.level <= logging.DEBUG:
            msg = "\nRaw received packet content is:\n"
            for u32 in rawU32Array:
                msg += "  0x" + uInt32HexStr(u32) + "\n"
            chipsLog.debug(msg)

        # 3) Detect if we need to do a byte-reorder
        firstWord = rawU32Array[0]
        firstWordMasked = firstWord & 0xf00000f0  # This selects only the bits relevant for detecting the byte ordering
        if firstWordMasked == 0x200000f0:
            chipsLog.debug(
                "Packet header detected: no byte-reorder is required.")
        elif firstWordMasked == 0xf0000020:
            chipsLog.debug(
                "Packet header detected: a byte-reorder will be performed.")
            self._doByteReorder = True
        else:
            chipsLog.warn(
                "Warning: No packet header (or unknown protocol version)! First word = 0x"
                + uInt32HexStr(firstWord) + ". Will hope for the best!...")

        # 4) Do the byte-reorder if necessary
        if self._doByteReorder: rawU32Array.byteswap()

        # 5) Now deserialise into a list of TransactionElements
        transactionElementList = [
        ]  # The list all the deserialised transaction elements will go into
        appendToTransactionElementList = transactionElementList.append  # This is needed for a speed optimisation
        iU32 = 1  # Index for moving through the rawU32Array          # TEMPORARY IPBUS V2.x HACK! Skip the first word which is now a packet ID
        rawU32ArraySize = len(rawU32Array)
        while iU32 < rawU32ArraySize:
            expectedBodySize = getExpectedBodySize(rawU32Array[iU32])
            if rawU32ArraySize - iU32 - 1 - expectedBodySize < 0:
                raise ChipsException("Deserialisation error: packet not correctly formatted " \
                                     "or does not contain the expected amount of data!")
            appendToTransactionElementList(
                TransactionElement(rawU32Array[iU32:iU32 + 1 +
                                               expectedBodySize]))
            iU32 += (1 + expectedBodySize)

        # 6) Debug output of deserialised packet content
        if chipsLog.level <= logging.DEBUG:
            msg = "\nDeserialised packet content is:\n" \
                  + reprTransactionElementList(transactionElementList)
            chipsLog.debug(msg)

        return transactionElementList
Ejemplo n.º 57
0
    def serveForever(self):
        """The only function any user of this class needs to run!
        
        Receives, acts on, and responds to TCP control packets as the Mini-T (or similar hardware) would.
        Packets are received by the main thread and queued for action and response by a second thread.
        """
        chipsLog.info("Dummy Hardware TCP Server starting")
        # This starts the packet "act and respond" handler thread
        self.start()

        try:
            chipsLog.debug("Awaiting connection...")
            self._connectedSocket, addr = self._socket.accept()  # TCP
            chipsLog.debug("Client connection accepted.")            
        except KeyboardInterrupt:
            chipsLog.warning("\nKeyboard interrupt (ctrl-c) received whilst waiting for a TCP connection")
            self._stopServingAndJoinThreads()
            return            

        while not self.stopServing:
            try:
                data = self._connectedSocket.recv(DummyHardware.SOCKET_BUFFER_SIZE)  # TCP
            except KeyboardInterrupt:
                chipsLog.warning("\nKeyboard interrupt (ctrl-c) received whilst waiting for incoming TCP packet")
                self._stopServingAndJoinThreads()
                return
            except:
                chipsLog.warning("\nException caught whilst waiting for incoming TCP packet")
                self._stopServingAndJoinThreads()
                return

            if not data:
                chipsLog.debug("TCP socket received an empty packet from " + repr(addr) + ": assuming connection closed.")
                try:
                    chipsLog.debug("Awaiting new connection...")
                    self._connectedSocket, addr = self._socket.accept()  # TCP
                    chipsLog.debug("Client connection accepted.")            
                    continue
                except KeyboardInterrupt:
                    chipsLog.warning("\nKeyboard interrupt (ctrl-c) received whilst waiting for a TCP connection")
                    self._stopServingAndJoinThreads()
                    return            

            chipsLog.debug("\nReceived TCP packet from " + repr(addr))
            transaction = Transaction.constructHostTransaction(data, addr)
            self._transaction_queue.put(transaction)

        chipsLog.info("Dummy Hardware TCP Server stopping.")
Ejemplo n.º 58
0
 def _handleByteOrderRequest(self, request):
     chipsLog.debug("Byte-order transaction requested")
     # Response header is the request header with direction bit changed
     responseHeader = IPbusHeader.updateDirection(request.getHeader(), 1)
     return TransactionElement.makeFromHeaderAndBody(responseHeader)
Ejemplo n.º 59
0
    def serveForever(self):
        """The only function any user of this class needs to run!
        
        Receives, acts on, and responds to TCP control packets as the Mini-T (or similar hardware) would.
        Packets are received by the main thread and queued for action and response by a second thread.
        """
        chipsLog.info("Dummy Hardware TCP Server starting")
        # This starts the packet "act and respond" handler thread
        self.start()

        try:
            chipsLog.debug("Awaiting connection...")
            self._connectedSocket, addr = self._socket.accept()  # TCP
            chipsLog.debug("Client connection accepted.")
        except KeyboardInterrupt:
            chipsLog.warning(
                "\nKeyboard interrupt (ctrl-c) received whilst waiting for a TCP connection"
            )
            self._stopServingAndJoinThreads()
            return

        while not self.stopServing:
            try:
                data = self._connectedSocket.recv(
                    DummyHardware.SOCKET_BUFFER_SIZE)  # TCP
            except KeyboardInterrupt:
                chipsLog.warning(
                    "\nKeyboard interrupt (ctrl-c) received whilst waiting for incoming TCP packet"
                )
                self._stopServingAndJoinThreads()
                return
            except:
                chipsLog.warning(
                    "\nException caught whilst waiting for incoming TCP packet"
                )
                self._stopServingAndJoinThreads()
                return

            if not data:
                chipsLog.debug("TCP socket received an empty packet from " +
                               repr(addr) + ": assuming connection closed.")
                try:
                    chipsLog.debug("Awaiting new connection...")
                    self._connectedSocket, addr = self._socket.accept()  # TCP
                    chipsLog.debug("Client connection accepted.")
                    continue
                except KeyboardInterrupt:
                    chipsLog.warning(
                        "\nKeyboard interrupt (ctrl-c) received whilst waiting for a TCP connection"
                    )
                    self._stopServingAndJoinThreads()
                    return

            chipsLog.debug("\nReceived TCP packet from " + repr(addr))
            transaction = Transaction.constructHostTransaction(data, addr)
            self._transaction_queue.put(transaction)

        chipsLog.info("Dummy Hardware TCP Server stopping.")
Ejemplo n.º 60
0
class ChipsBusBase(object):
    """Common Hardware Interface Protocol System Bus (CHIPS-Bus) abstract base-class

    Allows you to communicate with and control devices running Jeremy Mans's, et al, IP-based
    uTCA control system firmware.  This base class represents the part of the ChipsBus code
    that is protocol-agnostic.  Protocol-specific concrete classes, using either UDP or TCP,
    derive from this.

    The bus assumes 32-bit word addressing, so in a 32-bit address space up to 2^34 bytes in
    total can be addressed.
    """

    IPBUS_PROTOCOL_VER = 2  # I.e. IPbus Protocol v1.4
    SOCKET_BUFFER_SIZE = 32768  # Max UDP/TCP socket buffer size in bytes for receiving packets.
    MAX_TRANSACTION_ID = 4095  # The maximum value the transaction ID field can go up to.

    # Max depth of a block read or write before bridging the read/write over multiple requests.
    # Note that for UDP the max IPBus packet size cannot exceed 368 32-bit words (1472 bytes), or
    # it'll fail due to reaching the max Ethernet packet payload size (without using Jumbo Frames).
    # If you are Jumbo-Frames capable, then this number should not exceed 2000. Note that the
    # jumbo-frames firmware uses a 8192-byte buffer, so we can't make use of the full 9000 byte
    # Jumbo Frame anyway.
    MAX_BLOCK_TRANSFER_DEPTH = 255  # Temporary hack to get IPbus v2.0 compatible code working

    # The max size of the request queue (note: current API excludes ability to queue block transfer requests)
    MAX_QUEUED_REQUESTS = 80

    def __init__(self, addrTable, hostIp, hostPort, localPort=None):
        """ChipsBus abstract base-class constructor

        addrTable:  An instance of AddressTable for the device you wish to communicate with.
        hostIP:  The IP address of the device you want to control, e.g. the string '192.168.1.100'.
        hostPort:  The network port number of the device you want to control.
        localPort:  If you wish to bind the socket to a particular local port, then specify the
            the local port number here.  The default (None) means that the socket will not bind
            to any specific local port - an available port be found when it comes to sending any
            packets.
        """
        object.__init__(self)
        self._transactionId = 1
        self.addrTable = addrTable
        self._hostAddr = (hostIp, hostPort)
        self._queuedRequests = []  # Request queue
        self._queuedAddrTableItems = [
        ]  # The corresponding address table item for each request in the request queue
        self._queuedIsARead = [
        ]  # This holds a True if the corresponding request in _queuedRequests is a read, or a False if it's a write.

    def queueRead(self, name, addrOffset=0):
        """Create a read transaction element and add it to the transaction queue.

        This works in the same way as a normal read(), except that many can be queued
        into a packet and dispatched all at once rather than individually.  Run the
        queued transactions with queueRun().

        Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        if len(self._queuedRequests) < ChipsBus.MAX_QUEUED_REQUESTS:

            chipsLog.debug("Read queued: register '" + name +
                           "' with addrOffset = 0x" + uInt32HexStr(addrOffset))

            addrTableItem = self.addrTable.getItem(
                name
            )  # Get the details of the relevant item from the addr table.

            if not addrTableItem.getReadFlag():
                raise ChipsException(
                    "Read transaction creation error: read is not allowed on register '"
                    + addrTableItem.getName() + "'.")

            self._queuedRequests.append(
                self._createReadTransactionElement(addrTableItem, 1,
                                                   addrOffset))
            self._queuedAddrTableItems.append(addrTableItem)
            self._queuedIsARead.append(True)

        else:
            chipsLog.warning(
                "Warning: transaction not added to queue as transaction queue has reached its maximum length!\n"
                +
                "\tPlease either run or clear the transaction queue before continuing.\n"
            )

    def queueWrite(self, name, dataU32, addrOffset=0):
        """Create a register write (RMW-bits) transaction element and add it to the transaction queue.

        This works in the same way as a normal write(), except that many can be queued
        into a packet and dispatched all at once rather than individually.  Run the
        queued transactions with queueRun().

        Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        if len(self._queuedRequests) < ChipsBus.MAX_QUEUED_REQUESTS:

            dataU32 = dataU32 & 0xffffffff  # Ignore oversize input.
            chipsLog.debug("Write queued: dataU32 = 0x" +
                           uInt32HexStr(dataU32) + " to register '" + name +
                           "' with addrOffset = 0x" + uInt32HexStr(addrOffset))

            addrTableItem = self.addrTable.getItem(
                name
            )  # Get the details of the relevant item from the addr table.

            if not addrTableItem.getWriteFlag():
                raise ChipsException(
                    "Write transaction creation error: write is not allowed on register '"
                    + addrTableItem.getName() + "'.")

            # self._queuedRequests.append(self._createRMWBitsTransactionElement(addrTableItem, dataU32, addrOffset))
            # self._queuedAddrTableItems.append(addrTableItem)
            # self._queuedIsARead.append(False)

            self._queuedRequests.append(
                self._createWriteTransactionElement(addrTableItem, [dataU32],
                                                    addrOffset))
            self._queuedAddrTableItems.append(addrTableItem)
            self._queuedIsARead.append(False)

        else:
            chipsLog.warning(
                "Warning: transaction not added to queue as transaction queue has reached its maximum length!\n"
                +
                "\tPlease either run or clear the transaction queue before continuing.\n"
            )

    def queueRun(self):
        """Runs the current queue of single register read or write transactions and returns two lists. The
        first contains the values read and the second contains the values written.

        Note: Only single-register reads/writes can be queued.  Block reads/writes, etc, cannot
        be queued.
        """

        chipsLog.debug("Running all queued transactions")

        requestQueueLength = len(self._queuedRequests)

        readResponse = []
        writeResponse = []

        try:
            transaction = self._makeAndRunTransaction(self._queuedRequests)
        except ChipsException, err:
            self.queueClear()
            raise ChipsException(
                "Error while running queued transactions:\n\t" + str(err))

        for i in range(requestQueueLength):
            addrTableItem = self._queuedAddrTableItems[i]

            if len(transaction.responses[0].getBody()) > 0:
                transactionResponse = transaction.responses[
                    i - requestQueueLength].getBody()[0] & 0xffffffff
                transactionResponse = addrTableItem.shiftDataFromMask(
                    transactionResponse)
            else:
                transactionResponse = 0

            if self._queuedIsARead[i]:
                readResponse.append(transactionResponse)
                chipsLog.debug("Read success! Register '" +
                               addrTableItem.getName() + "' returned: 0x" +
                               uInt32HexStr(transactionResponse))
            else:
                writeResponse.append(transactionResponse)
                chipsLog.debug("Write success! Register '" +
                               addrTableItem.getName() + "' assigned: 0x" +
                               uInt32HexStr(transactionResponse))

        self.queueClear()

        response = [readResponse, writeResponse]

        return response