10.02_devices/2_src/uda.cpp
//
// GetNextCommand():
//  Attempts to pull the next command from the command ring, if any
//  are available.
//  If successful, returns a pointer to a Message struct; this pointer
//  is owned by the caller.
//  On failure, nullptr is returned.  This indicates that the ring is
//  empty or that an attempt to access non-existent memory occurred.
//  The error pointer is set to true if an error occurred during the 
//  operation -- due to non-existent memory or invalid data.  
//  (In this case nullptr will also be returned.)
//
Attempts to pull the next command from the command ring, if any
are available.
If successful, returns a pointer to a Message struct; this pointer
is owned by the caller.
On failure, nullptr is returned.  This indicates that the ring is
empty or that an attempt to access non-existent memory occurred.
The error pointer is set to true if an error occurred during the
operation -- due to non-existent memory or invalid data.
(In this case nullptr will also be returned.)
Attempts to pull the next command from the command ring if any are available . If successful returns a pointer to a Message struct ; this pointer is owned by the caller . On failure nullptr is returned . This indicates that the ring is empty or that an attempt to access non - existent memory occurred . The error pointer is set to true if an error occurred during the operation -- due to non - existent memory or invalid data . ( In this case nullptr will also be returned . )
Message*
uda_c::GetNextCommand(bool* error) 
{
    timeout_c timer;
    *error = false;
    uint32_t descriptorAddress = 
        GetCommandDescriptorAddress(_commandRingPointer);
    DEBUG("Next descriptor (ring ptr 0x%x) address is o%o", 
        _commandRingPointer, 
        descriptorAddress);
    std::unique_ptr<Descriptor> cmdDescriptor(
        reinterpret_cast<Descriptor*>(
            DMARead(
                descriptorAddress,
                sizeof(Descriptor),
                sizeof(Descriptor))));
    if (!cmdDescriptor)
    {
        PortError(PORT_ERROR_PACKET_READ);
        *error = true;
        return nullptr;
    }
    if (cmdDescriptor->Word1.Fields.Ownership)
    {
        bool doInterrupt = false;
        uint32_t messageAddress =
            cmdDescriptor->Word0.EnvelopeLow |
            (cmdDescriptor->Word1.Fields.EnvelopeHigh << 16);
        DEBUG("Next message address is o%o, flag %d", 
            messageAddress, cmdDescriptor->Word1.Fields.Flag);
         Grab the message length; this is at messageAddress - 4
        bool success = false;
        uint16_t messageLength = 
            DMAReadWord(
                messageAddress - 4,
                success);
        if (!success || messageLength <= 0 || messageLength >= MAX_MESSAGE_LENGTH)
        {
            PortError(PORT_ERROR_RING_READ);
            *error = true;
            return nullptr;
        }     
        std::unique_ptr<Message> cmdMessage(
            reinterpret_cast<Message*>(
                DMARead(
                    messageAddress - 4,
                    messageLength + 4, 
                    sizeof(Message)))); 
        if (!cmdMessage)
        {
            PortError(PORT_ERROR_RING_READ);
            *error = true;
            return nullptr;
        }
         Handle Ring Transitions (from full to not-full) and associated
         interrupts.
         If the previous entry in the ring is owned by the Port then that indicates
         that the ring was previously full (i.e. the descriptor we're now returning
         is the first free entry.)
        if (cmdDescriptor->Word1.Fields.Flag)
        {
             Flag is set, host is requesting a transition interrupt.
             Check the previous entry in the ring.            
            if (_commandRingLength == 1)
            {
                 Degenerate case:  If the ring is of size 1 we always interrupt.
                doInterrupt = true;
            }
            else
            {
                uint32_t previousDescriptorAddress =
                    GetCommandDescriptorAddress(
                        (_commandRingPointer - 1) % _commandRingLength);
                std::unique_ptr<Descriptor> previousDescriptor(
                    reinterpret_cast<Descriptor*>(
                        DMARead(
                            previousDescriptorAddress,
                            sizeof(Descriptor),
                            sizeof(Descriptor))));
                if (!previousDescriptor)
                {
                    PortError(PORT_ERROR_RING_READ);
                    *error = true;
                    return nullptr;
                }
                if (previousDescriptor->Word1.Fields.Ownership)
                {
                     We own the previous descriptor, so the ring was previously
                     full.
                    doInterrupt = true;
                }
            }            
        }
         Message retrieved; reset the Owner bit of the command descriptor,
         set the Flag bit (to indicate that we've processed it)
         and return a pointer to the message.
        cmdDescriptor->Word1.Fields.Ownership = 0;
        cmdDescriptor->Word1.Fields.Flag = 1;
        if (!DMAWrite(
            descriptorAddress,
            sizeof(Descriptor),
            reinterpret_cast<uint8_t*>(cmdDescriptor.get())))
        {
            PortError(PORT_ERROR_RING_WRITE);
            *error = true;
            return nullptr;
        }
         Move to the next descriptor in the ring for next time.
        _commandRingPointer = (_commandRingPointer + 1) % _commandRingLength;
         Post an interrupt as necessary.
        if (doInterrupt)
        {
             Set ring base - 4 to non-zero to indicate a transition.
            DMAWriteWord(_ringBase - 4, 0x1);
            Interrupt();
        }
        return cmdMessage.release();
    }
    DEBUG("No descriptor found.  0x%x 0x%x", cmdDescriptor->Word0.Word0, cmdDescriptor->Word1.Word1);  
     No descriptor available.
    return nullptr;
}
Message * uda_c :: GetNextCommand ( bool * error ) { timeout_c timer ; * error = false ; uint32_t descriptorAddress = GetCommandDescriptorAddress ( _commandRingPointer ) ; DEBUG ( " " , _commandRingPointer , descriptorAddress ) ; std :: unique_ptr < Descriptor > cmdDescriptor ( reinterpret_cast < Descriptor * > ( DMARead ( descriptorAddress , sizeof ( Descriptor ) , sizeof ( Descriptor ) ) ) ) ; if ( ! cmdDescriptor ) { PortError ( PORT_ERROR_PACKET_READ ) ; * error = true ; return nullptr ; } if ( cmdDescriptor -> Word1 . Fields . Ownership ) { bool doInterrupt = false ; uint32_t messageAddress = cmdDescriptor -> Word0 . EnvelopeLow | ( cmdDescriptor -> Word1 . Fields . EnvelopeHigh << 16 ) ; DEBUG ( " " , messageAddress , cmdDescriptor -> Word1 . Fields . Flag ) ; bool success = false ; uint16_t messageLength = DMAReadWord ( messageAddress - 4 , success ) ; if ( ! success || messageLength <= 0 || messageLength >= MAX_MESSAGE_LENGTH ) { PortError ( PORT_ERROR_RING_READ ) ; * error = true ; return nullptr ; } std :: unique_ptr < Message > cmdMessage ( reinterpret_cast < Message * > ( DMARead ( messageAddress - 4 , messageLength + 4 , sizeof ( Message ) ) ) ) ; if ( ! cmdMessage ) { PortError ( PORT_ERROR_RING_READ ) ; * error = true ; return nullptr ; } if ( cmdDescriptor -> Word1 . Fields . Flag ) { if ( _commandRingLength == 1 ) { doInterrupt = true ; } else { uint32_t previousDescriptorAddress = GetCommandDescriptorAddress ( ( _commandRingPointer - 1 ) % _commandRingLength ) ; std :: unique_ptr < Descriptor > previousDescriptor ( reinterpret_cast < Descriptor * > ( DMARead ( previousDescriptorAddress , sizeof ( Descriptor ) , sizeof ( Descriptor ) ) ) ) ; if ( ! previousDescriptor ) { PortError ( PORT_ERROR_RING_READ ) ; * error = true ; return nullptr ; } if ( previousDescriptor -> Word1 . Fields . Ownership ) { doInterrupt = true ; } } } cmdDescriptor -> Word1 . Fields . Ownership = 0 ; cmdDescriptor -> Word1 . Fields . Flag = 1 ; if ( ! DMAWrite ( descriptorAddress , sizeof ( Descriptor ) , reinterpret_cast < uint8_t * > ( cmdDescriptor . get ( ) ) ) ) { PortError ( PORT_ERROR_RING_WRITE ) ; * error = true ; return nullptr ; } _commandRingPointer = ( _commandRingPointer + 1 ) % _commandRingLength ; if ( doInterrupt ) { DMAWriteWord ( _ringBase - 4 , 0x1 ) ; Interrupt ( ) ; } return cmdMessage . release ( ) ; } DEBUG ( " " , cmdDescriptor -> Word0 . Word0 , cmdDescriptor -> Word1 . Word1 ) ; return nullptr ; }
GetNextCommand():
Attempts to pull the next command from the command ring, if any
are available.
GetNextCommand () : Attempts to pull the next command from the command ring if any are available .
// Grab the next descriptor being pointed to     // A null command descriptor indicates an NXM condition; we set SA to the appropriate // error code and reset the port. // Check owner bit: if set, ownership has been passed to us, in which case // we can attempt to pull the actual message from memory. // // Grab the message length; this is at messageAddress - 4 // // // Handle Ring Transitions (from full to not-full) and associated // interrupts. // If the previous entry in the ring is owned by the Port then that indicates // that the ring was previously full (i.e. the descriptor we're now returning // is the first free entry.) // // // Flag is set, host is requesting a transition interrupt. // Check the previous entry in the ring.             //             // Degenerate case:  If the ring is of size 1 we always interrupt. // We own the previous descriptor, so the ring was previously // full. // // Message retrieved; reset the Owner bit of the command descriptor, // set the Flag bit (to indicate that we've processed it) // and return a pointer to the message. // // // Move to the next descriptor in the ring for next time. // Post an interrupt as necessary. // // Set ring base - 4 to non-zero to indicate a transition. // // No descriptor available.