OpenCores
URL https://opencores.org/ocsvn/rio/rio/trunk

Subversion Repositories rio

[/] [rio/] [trunk/] [sw/] [stack/] [riostack.c] - Rev 49

Compare with Previous | Blame | View Log

/*******************************************************************************
 * 
 * RapidIO IP Library Core
 * 
 * This file is part of the RapidIO IP library project
 * http://www.opencores.org/cores/rio/
 * 
 * Description:
 * This file contains a software implementation of a RapidIO stack according to 
 * the 2.2 version, part 6, of the standard. Only short control symbols are 
 * supported.
 *
 * Symbols are in four flavors, idle, control, data and error. They are abstract 
 * and should be serialized by any implementation to be sent on a transmission 
 * channel. Error symbols are never generated by the stack and are used if the 
 * symbol decoder encounters an error that the stack should be notified of.
 * 
 * Symbols are inserted into the stack from the lower-half by calling 
 * RIOSTACK_portAddSymbol() and symbols to transmit are fetched from the stack
 * using RIOSTACK_portGetSymbol(). These two functions are the low-level interface 
 * towards a physical transmission channel.
 * The function RIOSTACK_portSetStatus() is used to indicate to the stack that initial
 * training of the symbol codec has been completed and that the transmission port
 * is ready to accept other symbols than idle. The procedure is to set the port
 * status to initialized once idle symbols are successfully received.
 *
 * On the upper-half interface are the RIOSTACK_setOutboundPacket() function used to 
 * insert packets into the outbound transmission queue and RIOSTACK_getInboundPacket() 
 * is used to get packet from the inbound reception queue. The 
 * RIOSTACK_getInboundQueueLength() function is used to check if any packet is available
 * for reading in the inbound reception queue.
 * 
 * -----------------
 * |  OS dependent |
 * |  (your code)  |
 * -----------------
 *        |
 * -----------------
 * |   RioStack    |
 * -----------------
 *        |
 * -----------------
 * | Symbol Codec  |
 * |  (your code)  |
 * -----------------
 *        |
 * -----------------
 * |  Port driver  |
 * -----------------
 *        |
 * -----------------
 * | Physical port |
 * -----------------
 *
 * The symbol codec maps a RapidIO symbol to the physical transmission media.
 * 
 * Some typical patterns to handle this stack are:
 * Initialization:
 *   RIOSTACK_open(...);
 *   RIOSTACK_portSetTimeout(...);
 *   ...
 *   <Symbol transcoder is successfully decoding symbols from the link>
 *   RIOSTACK_portSetStatus(1);
 *
 * Bottom-half traffic handling:
 *   RIOSTACK_portSetTime(...);
 *   <get symbol from decoder>
 *   RIOSTACK_portAddSymbol(...);
 *   s = RIOSTACK_portGetSymbol(...);
 *   <send symbol to encoder>
 *
 * Receiving packets:
 *   if(RIOSTACK_getInboundQueueLength(...) > 0)
 *   {
 *     RIOSTACK_getInboundPacket(...);
 *     <process the new packet>
 *   }
 *
 * Transmitting packets:
 *   <create a new packet>
 *   if(RIOSTACK_getOutboundQueueAvailable(...) > 0)
 *   {
 *     RIOSTACK_setOutboundPacket(...);
 *   }
 *
 * More details about the usage can be found in the module tests in test_riostack.c.
 * 
 * To Do:
 * - Optimize the packing of stype0 and stype1 into control symbols.
 * 
 * Author(s): 
 * - Magnus Rosenius, magro732@opencores.org 
 * 
 *******************************************************************************
 * 
 * Copyright (C) 2015 Authors and OPENCORES.ORG 
 * 
 * This source file may be used and distributed without 
 * restriction provided that this copyright statement is not 
 * removed from the file and that any derivative work contains 
 * the original copyright notice and the associated disclaimer. 
 * 
 * This source file is free software; you can redistribute it 
 * and/or modify it under the terms of the GNU Lesser General 
 * Public License as published by the Free Software Foundation; 
 * either version 2.1 of the License, or (at your option) any 
 * later version. 
 * 
 * This source is distributed in the hope that it will be 
 * useful, but WITHOUT ANY WARRANTY; without even the implied 
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
 * PURPOSE. See the GNU Lesser General Public License for more 
 * details. 
 * 
 * You should have received a copy of the GNU Lesser General 
 * Public License along with this source; if not, download it 
 * from http://www.opencores.org/lgpl.shtml 
 * 
 *******************************************************************************/
 
 
/** 
 * \file riostack.c
 */
 
/*******************************************************************************
 * Includes
 *******************************************************************************/
 
#include "riostack.h"
 
 
/*lint -e961 Allow function like macros. */
/*lint -e621 Long identifier names allowed to increase readability. */
/*lint -w2 */
 
 
/*lint --estring(960,17.4) It is not possible to implement a rio stack without some
 * pointer arithmetic */
 
 
/*******************************************************************************
 * Local macro definitions
 *******************************************************************************/
 
/* Macro to update 5-bit ackId counters. */
#define ACKID_INC(ackId) (((ackId)+1)&0x1f)
 
/* Macros to get entries from a control symbol. */
#define STYPE0_GET(data) ((uint8_t) (((data) >> 21) & 0x00000007u))
#define PARAMETER0_GET(data) ((uint8_t) (((data) >> 16) & 0x00000001fu))
#define PARAMETER1_GET(data) ((uint8_t) (((data) >> 11) & 0x00000001fu))
#define STYPE1_GET(data) ((uint8_t) (((data) >> 8) & 0x00000007u))
#define CMD_GET(data) ((uint8_t) (((data) >> 5) & 0x00000007u))
#define CRC5_GET(data) ((uint8_t) (((data) >> 0) & 0x0000001fu))
 
/* Macros to get entries from a packet in a buffer. */
#define FTYPE_GET(p) (((p)[0] >> 16) & 0xf)
#define DESTID_GET(p) ((p)[0] & 0xffff)
#define SRCID_GET(p) (((p)[1] >> 16) & 0xffff)
#define TRANSACTION_GET(p) (((p)[1] >> 12) & 0xf)
#define MSGLEN_GET(p) TRANSACTION_GET(p)
#define SSIZE_GET(p) (((p)[1] >> 8) & 0xf)
#define LETTER_GET(p) (((p)[1] >> 6) & 0x3)
#define MBOX_GET(p) (((p)[1] >> 4) & 0x3)
#define MSGSEG_GET(p) ((p)[1] & 0xf)
#define XMBOX_GET(p) MSGSEG_GET(p)
#define RDSIZE_GET(p) SSIZE_GET(p)
#define WRSIZE_GET(p) SSIZE_GET(p)
#define TID_GET(p) ((p)[1] & 0xff)
#define HOP_GET(p) (((p)[2] >> 24) & 0xff)
#define CONFIG_OFFSET_GET(p) ((p)[2] & 0x00fffffcul)
#define INFO_GET(p) (((p)[2] >> 16) & 0xffff)
#define ADDRESS_GET(p) ((p)[2] & 0xfffffff8ul)
#define WDPTR_GET(p) (((p)[2] >> 2) & 0x1)
#define XAMBS_GET(p) ((p)[2] & 0x3)
#define DOUBLE_WORD_MSB_GET(p, i) (p)[3+(2*i+0)]
#define DOUBLE_WORD_LSB_GET(p, i) (p)[3+(2*i+1)]
 
/* Transmitter frame states. */
#define TX_FRAME_START                  ((uint8_t)0u)
#define TX_FRAME_BODY                   ((uint8_t)1u)
 
/* Control symbol constants. */
#define STYPE0_PACKET_ACCEPTED          ((uint8_t)0x00u)
#define STYPE0_PACKET_RETRY             ((uint8_t)0x01u)
#define STYPE0_PACKET_NOT_ACCEPTED      ((uint8_t)0x02u)
#define STYPE0_RESERVED                 ((uint8_t)0x03u)
#define STYPE0_STATUS                   ((uint8_t)0x04u)
#define STYPE0_VC_STATUS                ((uint8_t)0x05u)
#define STYPE0_LINK_RESPONSE            ((uint8_t)0x06u)
#define STYPE0_IMPLEMENTATION_DEFINED   ((uint8_t)0x07u)
#define STYPE1_START_OF_PACKET          ((uint8_t)0x00u)
#define STYPE1_STOMP                    ((uint8_t)0x01u)
#define STYPE1_END_OF_PACKET            ((uint8_t)0x02u)
#define STYPE1_RESTART_FROM_RETRY       ((uint8_t)0x03u)
#define STYPE1_LINK_REQUEST             ((uint8_t)0x04u)
#define STYPE1_MULTICAST_EVENT          ((uint8_t)0x05u)
#define STYPE1_RESERVED                 ((uint8_t)0x06u)
#define STYPE1_NOP                      ((uint8_t)0x07u)
 
/* Packet ftype constants. */
#define FTYPE_REQUEST 0x2
#define FTYPE_WRITE 0x5
#define FTYPE_MAINTENANCE 0x8
#define FTYPE_DOORBELL 0xa
#define FTYPE_MESSAGE 0xb
#define FTYPE_RESPONSE 0xd
 
/* Transaction constants. */
#define TRANSACTION_MAINT_READ_REQUEST 0
#define TRANSACTION_MAINT_WRITE_REQUEST 1
#define TRANSACTION_MAINT_READ_RESPONSE 2
#define TRANSACTION_MAINT_WRITE_RESPONSE 3
#define TRANSACTION_WRITE_NWRITE 4
#define TRANSACTION_WRITE_NWRITER 5
#define TRANSACTION_REQUEST_NREAD 4
#define TRANSACTION_RESPONSE_NO_PAYLOAD 0
#define TRANSACTION_RESPONSE_MESSAGE_RESPONSE 1
#define TRANSACTION_RESPONSE_WITH_PAYLOAD 8
 
/* Maintenance transaction lengths. */
#define MAINTENANCE_TRANSACTION_READ_REQUEST_SIZE ((uint32_t) 4ul)
#define MAINTENANCE_TRANSACTION_WRITE_REQUEST_SIZE ((uint32_t) 6ul)
#define MAINTENANCE_TRANSACTION_READ_RESPONSE_SIZE ((uint32_t) 6ul)
#define MAINTENANCE_TRANSACTION_WRITE_RESPONSE_SIZE ((uint32_t) 4ul)
 
/* Constants used to forward different errors to the link partner. */
#define PACKET_NOT_ACCEPTED_CAUSE_RESERVED 0u
#define PACKET_NOT_ACCEPTED_CAUSE_UNEXPECTED_ACKID 1u
#define PACKET_NOT_ACCEPTED_CAUSE_CONTROL_CRC 2u
#define PACKET_NOT_ACCEPTED_CAUSE_NON_MAINTENANCE 3u
#define PACKET_NOT_ACCEPTED_CAUSE_PACKET_CRC 4u
#define PACKET_NOT_ACCEPTED_CAUSE_ILLEGAL_CHARACTER 5u
#define PACKET_NOT_ACCEPTED_CAUSE_NO_RESOURCE 6u
#define PACKET_NOT_ACCEPTED_CAUSE_DESCRAMBLER 7u
#define PACKET_NOT_ACCEPTED_CAUSE_GENERAL 31u
 
/* Constants used to request link-responses. */
#define LINK_REQUEST_RESET_DEVICE 3u
#define LINK_REQUEST_INPUT_STATUS 4u
 
/* Constants used to forward a port status in a link-resonse. */
#define LINK_RESPONSE_PORT_STATUS_ERROR 2u
#define LINK_RESPONSE_PORT_STATUS_RETRY_STOPPED 4u
#define LINK_RESPONSE_PORT_STATUS_ERROR_STOPPED 5u
#define LINK_RESPONSE_PORT_STATUS_OK 16u
 
 
 
/*******************************************************************************
 * Local typedefs
 *******************************************************************************/
 
 
 
/*******************************************************************************
 * Global declarations
 *******************************************************************************/
 
 
 
/*******************************************************************************
 * Local declarations
 *******************************************************************************/
 
 
 
/*******************************************************************************
 * Local function prototypes
 *******************************************************************************/
 
/* Helper functions for protocol events. */
static void handleStatus(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus);
static void handlePacketAccepted(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus);
static void handlePacketRetry(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus);
static void handlePacketNotAccepted(RioStack_t *stack, const uint8_t arbitrary, const uint8_t cause);
static void handleLinkResponse(RioStack_t *stack, const uint8_t ackId, const uint8_t portStatus);
static void handleStartOfPacket(RioStack_t *stack);
static void handleEndOfPacket(RioStack_t *stack);
static void handleLinkRequest(RioStack_t *stack, uint8_t cmd);
static void handleNewPacketStart(RioStack_t *stack);
static void handleNewPacketEnd(RioStack_t *stack);
 
/**
 * \brief Create a control symbol.
 *
 * \param[in] stype0 The stype0 value.
 * \param[in] parameter0 The parameter0 value.
 * \param[in] parameter1 The parameter1 value.
 * \param[in] stype1 The stype1 value.
 * \param[in] cmd The cmd value.
 * \return The control symbol that were created from the input parameters.
 *
 * This function creates a control symbol with the specified arguments and
 * calculates a CRC-5 checksum according to the standard specification.
 */
static RioSymbol_t CreateControlSymbol(const uint8_t stype0,
                                       const uint8_t parameter0, const uint8_t parameter1,
                                       const uint8_t stype1, const uint8_t cmd);
 
/**
 * \brief Function to calculate ITU-CRC5, polynom=0x15.
 *
 * \param[in] data The data of a control symbol.
 * \param[in] crc The crc to initiate the result with.
 * \return A new CRC-5 value.
 */
static uint8_t Crc5(const uint32_t data, const uint8_t crc);
 
/**
 * \brief Create a queue with a specified size and a buffer attached to it.
 *
 * \param[in] size The number of entries in the queue.
 * \param[in] buffer A pointer to the buffer to store the content in.
 * \return A queue with the specified size and where new data will be stored 
 * to the specified buffer.
 */
static Queue_t QueueCreate(const uint8_t size, uint32_t *buffer);
 
/**
 * \brief Get number of available elements.
 *
 * \param[in] q The queue to operate on.
 * \return The number of free packet buffers in the queue.
 */
static uint8_t QueueAvailable(const Queue_t q );
 
/**
 * \brief Get if the queue is empty or not.
 *
 * \param[in] q The queue to operate on.
 * \return Non-zero if the queue is empty.
 */
static int QueueEmpty(const Queue_t q);
 
/**
 * \brief Get the length of a queue.
 *
 * \param[in] q The queue to operate on.
 * \return The number of elements in the queue.
 */
static uint8_t QueueLength(const Queue_t q);
 
/**
 * \brief Add a new element to the queue.
 *
 * \param[in] q The queue to operate on.
 * \return A queue with one added element.
 */
static Queue_t QueueEnqueue(Queue_t q);
 
/**
 * \brief Remove an element from the queue.
 *
 * \param[in] q The queue to operate on.
 * \return A queue with on removed element.
 */
static Queue_t QueueDequeue(Queue_t q);
 
/**
 * \brief Check if the readout window is empty.
 *
 * \param[in] q The queue to operate on.
 * \return If the readout window is empty.
 */
static int QueueWindowEmpty(const Queue_t q);
 
/**
 * \brief Reset the window to none.
 *
 * \param[in] q The queue to operate on.
 * \return The updated Queue_t structure.
 */
static Queue_t QueueWindowReset(Queue_t q);
 
/**
 * \brief Increase the window to the next pending element.
 *
 * \param[in] q The queue to operate on.
 * \return The updated Queue_t structure.
 */
static Queue_t QueueWindowNext(Queue_t q);
 
/**
 * \brief Set actual size of the newest element.
 *
 * \param[in] q The queue to operate on.
 * \param[in] size The size to set the newest content size to.
 */
static void QueueSetSize(Queue_t q, const uint32_t size);
 
/**
 * \brief Set content at a specified index in the newest element.
 *
 * \param[in] q The queue to operate on.
 * \param[in] index posititon into the element
 * \param[in] content The content to set at the specified index in the newest queue element.
 */
static void QueueSetContent(Queue_t q, const uint32_t index, const uint32_t content);
 
/**
 * \brief Get a pointer to the buffer of the newest element.
 *
 * \param[in] q The queue to operate on.
 * \return A pointer to the content.
 */
static uint32_t *QueueGetBackBuffer(Queue_t q );
 
/**
 * \brief Get the size of the oldest element.
 * \param[in] q The queue to operate on.
 * \return The size of the element.
 */
static uint32_t QueueGetSize(Queue_t q );
 
/**
 * \brief Get the content of the oldest element at specified index.
 * \param[in] q The queue to operate on.
 * \param[in] index The index into the element to get the content from.
 * \return content of element at index position.
 */
static uint32_t QueueGetFrontContent(Queue_t q, const uint32_t index);
 
/**
 * \brief Get a pointer to the buffer of the oldest element.
 *
 * \param[in] q The queue to operate on.
 * \return A pointer to the content.
 */
static uint32_t *QueueGetFrontBuffer(Queue_t q );
 
 
 
/*******************************************************************************
 * Global functions
 *******************************************************************************/
 
void RIOSTACK_open(RioStack_t *stack, void *private,
                   const uint32_t rxPacketBufferSize, uint32_t *rxPacketBuffer, 
                   const uint32_t txPacketBufferSize, uint32_t *txPacketBuffer)
{
  /* Port time and timeout limit. */
  stack->portTime = 0u;
  stack->portTimeout = 1000u;
 
  /* Setup the receiver. */
  stack->rxState = RX_STATE_UNINITIALIZED;
  stack->rxCounter = 0u;
  stack->rxCrc = 0xffffu;
  stack->rxStatusReceived = 0u;
  stack->rxAckId = 0u;
  stack->rxAckIdAcked = 0u;
  stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_RESERVED;
  stack->rxQueue = QueueCreate((uint8_t) (rxPacketBufferSize/RIOSTACK_BUFFER_SIZE), rxPacketBuffer);
 
  /* Setup the transmitter. */
  stack->txState = TX_STATE_UNINITIALIZED;
  stack->txCounter = 0u;
  stack->txStatusCounter = 0u;
  stack->txFrameState = TX_FRAME_START;
  stack->txAckId = 0u;
  stack->txAckIdWindow = 0u;
  stack->txQueue = QueueCreate((uint8_t) (txPacketBufferSize/RIOSTACK_BUFFER_SIZE), txPacketBuffer);
 
  /* Setup status counters for inbound direction. */
  stack->statusInboundPacketComplete = 0ul;
  stack->statusInboundPacketRetry = 0ul;
  stack->statusInboundErrorControlCrc = 0ul;
  stack->statusInboundErrorPacketAckId = 0ul;
  stack->statusInboundErrorPacketCrc = 0ul;
  stack->statusInboundErrorIllegalCharacter = 0ul;
  stack->statusInboundErrorGeneral = 0ul;
  stack->statusInboundErrorPacketUnsupported = 0ul;
 
  /* Setup status counters for outbound direction. */
  stack->statusOutboundPacketComplete = 0ul;
  stack->statusOutboundLinkLatencyMax = 0ul;
  stack->statusOutboundPacketRetry = 0ul;
  stack->statusOutboundErrorTimeout = 0ul;
  stack->statusOutboundErrorPacketAccepted = 0ul;
  stack->statusOutboundErrorPacketRetry = 0ul;
 
  /* Setup status counters for potential problems on the link-partner. */
  stack->statusPartnerLinkRequest = 0ul;
  stack->statusPartnerErrorControlCrc = 0ul;
  stack->statusPartnerErrorPacketAckId = 0ul;
  stack->statusPartnerErrorPacketCrc = 0ul;
  stack->statusPartnerErrorIllegalCharacter = 0ul;
  stack->statusPartnerErrorGeneral = 0ul;
 
  /* Set pointer to user private data. */
  stack->private = private;
}
 
 
 
/*******************************************************************************************
 * Stack status and queue access functions.
 * Note that status counters are accessed directly in the stack-structure.
 *******************************************************************************************/
 
int RIOSTACK_getStatus(RioStack_t *stack)
{
  return !(((stack->rxState == RX_STATE_UNINITIALIZED) || (stack->rxState == RX_STATE_PORT_INITIALIZED)) &&
           ((stack->txState == TX_STATE_UNINITIALIZED) || (stack->txState == TX_STATE_PORT_INITIALIZED)));
}
 
 
 
void RIOSTACK_clearOutboundQueue(RioStack_t *stack)
{
  while(!QueueEmpty(stack->txQueue))
  {
    stack->txQueue = QueueDequeue(stack->txQueue);
  }
}
 
 
 
uint8_t RIOSTACK_getOutboundQueueLength(RioStack_t *stack)
{
  return QueueLength(stack->txQueue);
}
 
 
 
uint8_t RIOSTACK_getOutboundQueueAvailable(RioStack_t *stack)
{
  return QueueAvailable(stack->txQueue);
}
 
 
 
void RIOSTACK_setOutboundPacket(RioStack_t *stack, RioPacket_t *packet)
{
  uint32_t *src, *dst;
  uint32_t size;
  uint32_t i;
 
 
  ASSERT((QueueAvailable(stack->txQueue) > 0u), 
         "Transmission queue packet overflow.");
 
  src = &packet->payload[0];
  dst = QueueGetBackBuffer(stack->txQueue);
  size = packet->size;
  for(i = 0; i < size; i++)
  {
    dst[i] = src[i];
  }
 
  QueueSetSize(stack->txQueue, size);
  stack->txQueue = QueueEnqueue(stack->txQueue);
}
 
 
 
void RIOSTACK_clearInboundQueue(RioStack_t *stack)
{
  while(!QueueEmpty(stack->rxQueue))
  {
    stack->rxQueue = QueueDequeue(stack->rxQueue);
  }
}
 
 
 
uint8_t RIOSTACK_getInboundQueueLength(RioStack_t *stack)
{
  return QueueLength(stack->rxQueue);
}
 
 
 
uint8_t RIOSTACK_getInboundQueueAvailable(RioStack_t *stack)
{
  return QueueAvailable(stack->rxQueue);
}
 
 
 
void RIOSTACK_getInboundPacket(RioStack_t *stack, RioPacket_t *packet)
{
  uint32_t *src, *dst;
  uint32_t size;
  uint32_t i;
 
 
  ASSERT(!QueueEmpty(stack->rxQueue), "Reading from empty reception queue.");
 
  src = QueueGetFrontBuffer(stack->rxQueue);
  dst = &packet->payload[0];
  size = QueueGetSize(stack->rxQueue);
  for(i = 0; i < size; i++)
  {
    dst[i] = src[i];
  }
 
  packet->size = size;
  stack->rxQueue = QueueDequeue(stack->rxQueue);
}
 
 
 
/*******************************************************************************************
 * Packet port functions.
 *******************************************************************************************/
 
void RIOSTACK_portSetTime(RioStack_t *stack, const uint32_t time)
{
  stack->portTime = time;
}
 
 
 
void RIOSTACK_portSetTimeout(RioStack_t *stack, const uint32_t time)
{
  stack->portTimeout = time;
}
 
 
 
void RIOSTACK_portSetStatus(RioStack_t *stack, const uint8_t initialized)
{
  /* REMARK: Clean the queues here as well??? */
  if (initialized)
  {
    stack->rxState = RX_STATE_PORT_INITIALIZED;
    stack->rxCounter = 0u;
    stack->rxCrc = 0xffffu;
    stack->rxStatusReceived = 0;
    stack->rxAckId = 0u;
    stack->rxAckIdAcked = 0u;
    stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_RESERVED;
 
    stack->txState = TX_STATE_PORT_INITIALIZED;
    stack->txCounter = 0u;
    stack->txStatusCounter = 0u;
    stack->txFrameState = TX_FRAME_START;
    stack->txAckId = 0u;
    stack->txAckIdWindow = 0u;
  }
  else
  {
    stack->rxState = RX_STATE_UNINITIALIZED;
    stack->txState = TX_STATE_UNINITIALIZED;
  }
}
 
 
 
void RIOSTACK_portAddSymbol(RioStack_t *stack, const RioSymbol_t s)
{
  uint8_t stype0;
  uint8_t parameter0;
  uint8_t parameter1;
  uint8_t stype1;
 
 
  switch(stack->rxState)
  {
    case RX_STATE_PORT_INITIALIZED:
      /******************************************************************************
       * PORT_INITIALIZED
       * This state is entered to initialize the link. Only status-control-symbols 
       * are accepted in this state. When 7 error-free, i.e. with CRC5 correct, status 
       * control symbols has been received, change state to linkInitialized.
       ******************************************************************************/
 
      /* Check the type of symbol. */
      if(s.type == RIOSTACK_SYMBOL_TYPE_CONTROL)
      {
        /* This is a control symbol. */
 
        /* Check that the control symbol contains no errors. */
        if(Crc5(s.data, 0x1fu) == (s.data & 0x1ful))
        {
          /* Error-free control symbol. */
 
          /* Check if the symbol is a status symbol. */
          stype0 = STYPE0_GET(s.data);
          if(stype0 == STYPE0_STATUS) 
          {
            /* Status symbol received. */
 
            /* Indicate an error-free status has been received. */
            stack->rxStatusReceived = 1;
 
            /* Check if enough status control symbols has been received. */
            if(stack->rxCounter == 7u)
            {
              /* Enough correct status control symbols has been received without 
                 errors in between. */
 
              /* Setup the transmitter with the content of the symbol. */
              stack->txAckId = PARAMETER0_GET(s.data);
              stack->txAckIdWindow = stack->txAckId;
              stack->txBufferStatus = PARAMETER1_GET(s.data);
 
              /* Set the transmitter in its normal operational mode. */
              stack->rxState = RX_STATE_LINK_INITIALIZED;
              stack->rxCounter = 0u;
            }
            else
            {
              /* Count the number of consequitive error-free status control symbols 
                 that has been received. */
              stack->rxCounter++;
            }
          }
          else
          {
            /* The received symbol is not a status symbol. */
            /* Discard it. */
          }
        }
        else
        {
          /* CRC error in control symbol. */
          /* Restart counting error-free status-control-symbols. */
          stack->rxCounter = 0u;
        }
      }
      else
      {
        /* Not a control symbol. */
        /* Discard the symbol. */
      }
 
      break;
 
    case RX_STATE_LINK_INITIALIZED:
      /******************************************************************************
       * LINK_INITIALIZED
       * The normal state. Accept packets and forward them.
       ******************************************************************************/
 
      /* Check the type of symbol. */
      switch(s.type)
      {
        case RIOSTACK_SYMBOL_TYPE_CONTROL:
          /**************************************************************************
           * This is a control symbol.
           **************************************************************************/
 
          /* Check if the CRC is correct. */
          if(Crc5(s.data, 0x1fu) == (s.data & (uint8_t)0x1ful))
          {
            /* The CRC is correct. */
 
            /* Get the content of the control symbol. */
            stype0 = STYPE0_GET(s.data);
            parameter0 = PARAMETER0_GET(s.data);
            parameter1 = PARAMETER1_GET(s.data);
            stype1 = STYPE1_GET(s.data);            
 
            /**********************************************************************************
             * Check the stype0 part of the symbol. 
             * Note that errors in this should trigger OUTPUT_ERROR_STOPPED.
             **********************************************************************************/
            switch(stype0)
            {
              case STYPE0_STATUS:
                /* A status containing the current ackId and the buffer status has been 
                   received. */
                handleStatus(stack, parameter0, parameter1);
                break;
 
              case STYPE0_PACKET_ACCEPTED:
                /* A packet has been accepted by the link partner. */
                handlePacketAccepted(stack, parameter0, parameter1);
                break;
 
              case STYPE0_PACKET_RETRY:
                /* The link partner wants us to initiate a restart of the received ackId. */
                handlePacketRetry(stack, parameter0, parameter1);
                break;
 
              case STYPE0_PACKET_NOT_ACCEPTED:
                /* The link partner indicates that a packet has been rejected. */
                handlePacketNotAccepted(stack, parameter0, parameter1);
                break;
 
              case STYPE0_LINK_RESPONSE:
                /* The link partner has sent a response to a link-request. */
                handleLinkResponse(stack, parameter0, parameter1);
                break;
 
              case STYPE0_VC_STATUS:
              case STYPE0_RESERVED:
              case STYPE0_IMPLEMENTATION_DEFINED:
              default:
                /* Unsupported symbol received. */
                /* Discard them. */
                break;
            }
 
            /**********************************************************************************
             * Check the stype1 part of the symbol.
             * Note that errors in this should trigger INPUT_ERROR_STOPPED.
             **********************************************************************************/
            switch(stype1)
            {
              case STYPE1_START_OF_PACKET:
                /* Start of a new packet. */
                handleStartOfPacket(stack);
                break;
 
              case STYPE1_END_OF_PACKET:
                /* Ending a packet. */
                handleEndOfPacket(stack);
                break;
 
              case STYPE1_STOMP:
                /* Cancel the currently received frame. */
                stack->rxCounter = 0;
                break;
 
              case STYPE1_RESTART_FROM_RETRY:
                /* Cancel the currently received frame when in this state. */
                stack->rxCounter = 0;
                break;
 
              case STYPE1_LINK_REQUEST:
                /* A link-request has been received. */
                handleLinkRequest(stack, CMD_GET(s.data));
                break;
 
              case STYPE1_NOP:
                /* No operation symbol. */
                /* Discard these. */
                break;
 
              case STYPE1_MULTICAST_EVENT:
              case STYPE1_RESERVED:
              default:
                /* Unsupported symbol received. */
                /* Discard them. */
                break;
            }
          }
          else
          {
            /* The control symbol CRC is incorrect. */
            /* Corrupted control symbol. Discard the symbol and enter the input-error-stopped state. */
            stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
            stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
            stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_CONTROL_CRC;
            stack->statusInboundErrorControlCrc++;
          }
          break;
 
        case RIOSTACK_SYMBOL_TYPE_DATA:
          /**************************************************************************
           * This is a data symbol.
           **************************************************************************/
 
          /* Check if a packet has been started and that it is not too long. */
          if ((stack->rxCounter >= 1u) && (stack->rxCounter <= RIOPACKET_SIZE_MAX))
          {
            /* A packet has been started. */
 
            /* Check if the ackId is correct on the first part of the packet. */
            if ((stack->rxCounter > 1u) ||
                ((stack->rxCounter == 1u) && (((uint8_t)(s.data >> 27)) == stack->rxAckId)))
            {
              /* The ackId is the expected one. */
 
              /* Check if this is the first symbol of a packet. */
              if (stack->rxCounter == 1u)
              {
                /* This is the first symbol of the packet. */
                /* Start to calculate the CRC of the packet. */
                /* Note that the ackId should not be included in the CRC calculation. */
                stack->rxCrc = RIOPACKET_Crc32(s.data & (uint32_t)0x03fffffful, 0xffffu);
              }
              else
              {
                /* This is not the first symbol. */
                /* Continue to calculate the CRC of the packet. */
                stack->rxCrc = RIOPACKET_Crc32(s.data, stack->rxCrc);
              }
 
              /* Save the new data in the packet queue and update the reception counter. */
              QueueSetContent(stack->rxQueue, (uint32_t)stack->rxCounter - (uint32_t)1ul, s.data);
              stack->rxCounter++;
            }
            else
            {
              /* The ackId is not correct. */
              /* Packet error. Enter input-error-stopped state. */
              stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
              stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
              stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_UNEXPECTED_ACKID;
              stack->statusInboundErrorPacketAckId++;
            }
          }
          else
          {
            /* No packet has been started or the packet is too long. */
            /* Packet error. Enter input-error-stopped state. */
            stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
            stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
            stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_GENERAL;
            stack->statusInboundErrorGeneral++;
          }
          break;
 
        case RIOSTACK_SYMBOL_TYPE_ERROR:
          /**************************************************************************
           * The decoder has received a erronous symbol.
           **************************************************************************/
 
          /* Idle symbol error. Place the receiver in input-error-stopped state. */
          stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
          stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
          stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_ILLEGAL_CHARACTER;
          stack->statusInboundErrorIllegalCharacter++;
          break;
 
        case RIOSTACK_SYMBOL_TYPE_IDLE:
        default:
          /**************************************************************************
           * Idle symbol or unsupported symbol.
           **************************************************************************/
 
          /* Discard these for now. */
          break;
      }
      break;
 
    case RX_STATE_INPUT_RETRY_STOPPED:
      /******************************************************************************
       * INPUT_RETRY_STOPPED
       * This state is entered when no more buffers was available and a packet was 
       * received. When in this state, all packets should be discarded until a 
       * RESTART-FROM-RETRY symbol is received. See section 5.9.1.4 of the standard. 
       * Note that it is only the input side of the port that are affected, not the 
       * output side. Packets may still be transmitted and acknowledges should be 
       * accepted.
       ******************************************************************************/
 
      /* Check the type of symbol. */
      switch(s.type)
      {
        case RIOSTACK_SYMBOL_TYPE_CONTROL:
          /* This is a control symbol. */
 
          /* Check if the CRC is correct. */
          if(Crc5(s.data, 0x1fu) == (s.data & (uint8_t)0x1ful))
          {
            /* The CRC is correct. */
 
            /* Get the content of the control symbol. */
            stype0 = STYPE0_GET(s.data);
            parameter0 = PARAMETER0_GET(s.data);
            parameter1 = PARAMETER1_GET(s.data);
            stype1 = STYPE1_GET(s.data);
 
            /* Check the stype0 part of the symbol. */
            switch(stype0)
            {
              case STYPE0_STATUS:
                /* A status containing the current ackId and the buffer status has been 
                   received. */
                handleStatus(stack, parameter0, parameter1);
                break;
 
              case STYPE0_PACKET_ACCEPTED:
                /* A packet has been accepted by the link partner. */
                handlePacketAccepted(stack, parameter0, parameter1);
                break;
 
              case STYPE0_PACKET_RETRY:
                /* The link partner wants us to initiate a restart of the received ackId. */
                handlePacketRetry(stack, parameter0, parameter1);
                break;
 
              case STYPE0_PACKET_NOT_ACCEPTED:
                /* The link partner indicates that a packet has been rejected. */
                handlePacketNotAccepted(stack, parameter0, parameter1);
                break;
 
              case STYPE0_LINK_RESPONSE:
                /* The link partner has sent a response to a link-request. */
                handleLinkResponse(stack, parameter0, parameter1);
                break;
 
              case STYPE0_VC_STATUS:
              case STYPE0_RESERVED:
              case STYPE0_IMPLEMENTATION_DEFINED:
              default:
                /* Unsupported symbol received. */
                /* Discard them. */
                break;
            }
 
            /* Check the stype1 part of the symbol. */
            switch(stype1)
            {
              case STYPE1_START_OF_PACKET:
                /* Starting new frames are ignored in this state. */
                break;
 
              case STYPE1_END_OF_PACKET:
                /* Ending new frames are ignored in this state. */
                break;
 
              case STYPE1_STOMP:
                /* Restarting frames are ignored in this state. */
                break;
 
              case STYPE1_RESTART_FROM_RETRY:
                /* The link partner has confirmed our packet-retry-symbol. */
                /* Go back to the normal state and reset the frame reception. */
                stack->rxState = RX_STATE_LINK_INITIALIZED;
                stack->rxCounter = 0u;
                break;
 
              case STYPE1_LINK_REQUEST:
                /* A link-request has been received. */
                handleLinkRequest(stack, CMD_GET(s.data));
                stack->rxState = RX_STATE_LINK_INITIALIZED;
                break;
 
              case STYPE1_NOP:
                /* No operation symbol. */
                /* Discard these. */
                break;
 
              case STYPE1_MULTICAST_EVENT:
              case STYPE1_RESERVED:
              default:
                /* Unsupported symbol received. */
                /* Discard them. */
                break;
            }
          }
          else
          {
            /* The control symbol CRC is incorrect. */
            /* Corrupted control symbol. Discard the symbol and enter the input-error-stopped state. */
            stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
            stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
            stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_CONTROL_CRC;
            stack->statusInboundErrorControlCrc++;
          }
          break;
 
        case RIOSTACK_SYMBOL_TYPE_ERROR:
          /* Idle symbol error. Place the receiver in input-error-stopped state. */
          stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
          stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
          stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_ILLEGAL_CHARACTER;
          stack->statusInboundErrorIllegalCharacter++;
          break;
 
        case RIOSTACK_SYMBOL_TYPE_DATA:
        case RIOSTACK_SYMBOL_TYPE_IDLE:
        default:
          /* Data or idle symbol. */
          /* Discard these in this state. */
          break;
      }
      break;
 
    case RX_STATE_INPUT_ERROR_STOPPED:
      /******************************************************************************
       * INPUT_ERROR_STOPPED
       * This state is entered when an error situation has occurred. When in this 
       * state, all symbols should be discarded until a link-request-symbols has 
       * been received. See section 5.13.2.6 in part 6 of the standard.
       * Note that it is only the input side of the port that are affected, not the 
       * output side. Packets may still be transmitted and acknowledges should be 
       * accepted.
       ******************************************************************************/
 
      /* Check the type of symbol. */
      switch(s.type)
      {
        case RIOSTACK_SYMBOL_TYPE_CONTROL:
          /* This is a control symbol. */
 
          /* Check if the CRC is correct. */
          if(Crc5(s.data, 0x1fu) == (s.data & (uint8_t)0x1ful))
          {
            /* The CRC is correct. */
 
            /* Get the content of the control symbol. */
            stype0 = STYPE0_GET(s.data);
            parameter0 = PARAMETER0_GET(s.data);
            parameter1 = PARAMETER1_GET(s.data);
            stype1 = STYPE1_GET(s.data);
 
            /* Check the stype0 part of the symbol. */
            switch(stype0)
            {
              case STYPE0_STATUS:
                /* A status containing the current ackId and the buffer status has been 
                   received. */
                handleStatus(stack, parameter0, parameter1);
                break;
 
              case STYPE0_PACKET_ACCEPTED:
                /* A packet has been accepted by the link partner. */
                handlePacketAccepted(stack, parameter0, parameter1);
                break;
 
              case STYPE0_PACKET_RETRY:
                /* The link partner wants us to initiate a restart of the received ackId. */
                handlePacketRetry(stack, parameter0, parameter1);
                break;
 
              case STYPE0_PACKET_NOT_ACCEPTED:
                /* The link partner indicates that a packet has been rejected. */
                handlePacketNotAccepted(stack, parameter0, parameter1);
                break;
 
              case STYPE0_LINK_RESPONSE:
                /* The link partner has sent a response to a link-request. */
                handleLinkResponse(stack, parameter0, parameter1);
                break;
 
              case STYPE0_VC_STATUS:
              case STYPE0_RESERVED:
              case STYPE0_IMPLEMENTATION_DEFINED:
              default:
                /* Unsupported symbol received. */
                /* Discard them. */
                break;
            }
 
            /* Check the stype1 part of the symbol. */
            switch(stype1)
            {
              case STYPE1_START_OF_PACKET:
                /* Starting new frames are ignored in this state. */
                break;
 
              case STYPE1_END_OF_PACKET:
                /* Ending new frames are ignored in this state. */
                break;
 
              case STYPE1_STOMP:
                /* Restarting frames are ignored in this state. */
                break;
 
              case STYPE1_RESTART_FROM_RETRY:
                /* Restart-from-retry are ignored in this state.  */
                break;
 
              case STYPE1_LINK_REQUEST:
                /* This is the symbol we have been waiting for. */
                /* Force the transmitter to send a link-response and go back into the normal 
                   operational state. */
                /* The transmitter will always send a status as the first symbol after this. */
                handleLinkRequest(stack, CMD_GET(s.data));
                stack->rxState = RX_STATE_LINK_INITIALIZED;
                break;
 
              case STYPE1_NOP:
                /* No operation symbol. */
                /* Discard these. */
                break;
 
              case STYPE1_MULTICAST_EVENT:
              case STYPE1_RESERVED:
              default:
                /* Unsupported symbol received. */
                /* Discard them. */
                break;
            }
          }
          else
          {
            /* The CRC is incorrect. */
            /* Discard these in this state. */
          }
          break;
 
        case RIOSTACK_SYMBOL_TYPE_DATA:
        case RIOSTACK_SYMBOL_TYPE_IDLE:
        case RIOSTACK_SYMBOL_TYPE_ERROR:
        default:
          /* Data, idle or error symbol. */
          /* Discard these in this state. */
          break;
      }
      break;
 
    case RX_STATE_UNINITIALIZED:
    default:
      /******************************************************************************
       * Wait for the port to be initialized.
       ******************************************************************************/
 
      /* Discard all incoming symbols. */
      break;
  }
}
 
 
 
RioSymbol_t RIOSTACK_portGetSymbol(RioStack_t *stack )
{
  RioSymbol_t s;
 
 
  switch(stack->txState)
  {
    case TX_STATE_PORT_INITIALIZED:
      /******************************************************************************
       * PORT_INITIALIZED
       * This state is entered to initialize the link. Send status-control-symbols 
       * once in a while until the receiver has received enough error-free status-
       * control-symbols and we have transmitted enough status-control-symbols. Once 
       * an error-free status-control-symbol has been received, the statuses are
       * transmitted more frequently to decrease the time for the link to be 
       * initialized.
       ******************************************************************************/
 
      /* Check if an idle symbol or a status control symbol should be sent. */
      if(((stack->rxStatusReceived == 0) && (stack->txCounter == 255u)) ||
         ((stack->rxStatusReceived == 1) && (stack->txCounter >= 15u)))
      {
        /* A control symbol should be sent. */
 
        /* Create a new status symbol and reset the transmission counter. */
        stack->txCounter = 0u;
        s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                                STYPE1_NOP, 0u);
 
        /* Check if the receiver has received any error-free status and that we 
           have sent at least 15 status control symbols. */
        if((stack->rxStatusReceived == 1) && (stack->txStatusCounter < 15u))
        {
          /* Has not sent enough status control symbols. */
          stack->txStatusCounter++;
        }
        else
        {
          /* Has sent enough status control symbols. */
          /* Dont do anything. */
        }
      }
      else
      {
        /* Idle symbol should be sent. */
        s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
        stack->txCounter++;
      }
 
      /* Check if we are ready to set the transmitter in a link initialized state. */
      if ((stack->rxState == RX_STATE_LINK_INITIALIZED) && (stack->txStatusCounter == 15u))
      {
        /* Ready to go to link initialized. */
        stack->txState = TX_STATE_LINK_INITIALIZED;
        stack->txFrameState = TX_FRAME_START;
        stack->txStatusCounter = 0u;
      }
      else
      {
        /* Not ready to go to link initialized. */
        /* Dont do anything. */
      }
 
      break;
 
    case TX_STATE_LINK_INITIALIZED:
      /******************************************************************************
       * LINK_INITIALIZED
       * The normal state. Accept packets and forward them. Send acknowledges when 
       * the receiver has received complete packets.
       ******************************************************************************/
 
      /* Check if the receiver wants to acknowledge a packet. */
      if(stack->rxAckId == stack->rxAckIdAcked)
      {
        /* The receiver does not want to acknowledge a packet. */
 
        /* Check if there are any outstanding packets and if it has timed out. */
        if((stack->txAckId == stack->txAckIdWindow) ||
           ((stack->portTime - stack->txFrameTimeout[stack->txAckId]) < stack->portTimeout))
        {
          /* There are no outstanding packets or there has been no timeout. */
 
          /* Check if a packet is ongoing. */
          if(stack->txFrameState == TX_FRAME_BODY)
          {
            /* A packet transmission is ongoing. */
 
            /* Check if the packet has been completly sent. */
            if(stack->txCounter != QueueGetSize(stack->txQueue))
            {
              /* The packet has not been completly sent. */
 
              /* Create a new data symbol to transmit. */
              s.type = RIOSTACK_SYMBOL_TYPE_DATA;
              s.data = QueueGetFrontContent(stack->txQueue, (uint32_t)stack->txCounter);
 
              /* Check if this is the first symbol in a packet. */
              if (stack->txCounter == 0u)
              {
                /* Place the correct ackId in the right place. */
                s.data |= (uint32_t)stack->txAckIdWindow << 27;
              }
              else
              {
                /* Dont do anything. */
              }
 
              /* Update the transmission counter. */
              stack->txCounter++;
 
              /* A status control symbol was not sent. Update the status counter. */
              stack->txStatusCounter++;
            }
            else 
            {
              /* The packet has been sent. */
 
              /* Save the timeout time and update to the next ackId. */
              stack->txFrameTimeout[stack->txAckIdWindow] = stack->portTime;
              stack->txAckIdWindow = ACKID_INC(stack->txAckIdWindow);
              stack->txQueue = QueueWindowNext(stack->txQueue);
 
              /* Check if there are more packets pending to be sent. */
              /* Also check that there are buffer available at the receiver and that not too many 
                 packets are outstanding. */
              if(!QueueWindowEmpty(stack->txQueue) && (stack->txBufferStatus > 0) &&
                 (((stack->txAckIdWindow - stack->txAckId) & 0x1f) != 31))
              {
                /* More pending packets. */
                /* Create a control symbol to signal that the new packet has started. */
                s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                                        STYPE1_START_OF_PACKET, 0u);
 
                /* Restart transmission counter. */
                stack->txCounter = 0;
              }
              else
              {
                /* No more pending packets. */
                /* Create a control symbol to signal that the packet has ended. */
                s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                                        STYPE1_END_OF_PACKET, 0u);
 
                /* Go back to wait for a new frame. */
                stack->txFrameState = TX_FRAME_START;
              }
 
              /* A status control symbol has been sent. Reset the status counter. */
              stack->txStatusCounter = 0u;
            }
          }
          else
          {
            /* No packet is being sent. */
 
            /* Check if there are any pending packets to start sending. */
            /* Also check that there are buffer available at the receiver and that not too many 
               packets are outstanding. */
            if(!QueueWindowEmpty(stack->txQueue) && (stack->txBufferStatus > 0) &&
               (((stack->txAckIdWindow - stack->txAckId) & 0x1f) != 31))
            {
              /* There is a pending packet to send. */
              /* Send a start-of-packet control symbol to start to send the packet. */
              s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                                      STYPE1_START_OF_PACKET, 0u);
              stack->txFrameState = TX_FRAME_BODY;
              stack->txCounter = 0u;
 
              /* A status control symbol has been sent. Reset the status counter. */
              stack->txStatusCounter = 0u;
            }
            else
            {
              /* There are no pending packets to send. */
 
              /* Check if a status control symbol must be transmitted. */
              if(stack->txStatusCounter < 255u)
              {
                /* Not required to send a status control symbol. */
 
                /* Send an idle-symbol. */
                s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
                stack->txStatusCounter++;
              }
              else
              {
                /* Must send a status control symbol. */
 
                /* Create a status control symbol. */
                s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                                        STYPE1_NOP, 0u);
 
                /* A status control symbol has been sent. Reset the status counter. */
                stack->txStatusCounter = 0u;
              }
            }
          }
        }
        else
        {
          /* There has been a timeout. */
          /* A packet has been sent but no packet-accepted has been received. */
          /* Send link-request-symbol (input-status). */
          s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                                  STYPE1_LINK_REQUEST, LINK_REQUEST_INPUT_STATUS);
 
          /* Save the time when this was transmitted. */
          stack->txFrameTimeout[stack->txAckId] = stack->portTime;
 
          /* Remember that this symbol has been transmitted. */
          stack->txCounter = 1;
 
          /* Go into the output error stopped state. */
          stack->txState = TX_STATE_OUTPUT_ERROR_STOPPED;
          stack->statusOutboundErrorTimeout++;
        }
      }
      else
      {
        /* The receiver wants us to send an acknowledgement. */
        s = CreateControlSymbol(STYPE0_PACKET_ACCEPTED, stack->rxAckIdAcked, QueueAvailable(stack->rxQueue), 
                                STYPE1_NOP, 0u);
        stack->rxAckIdAcked = ACKID_INC(stack->rxAckIdAcked);
 
        /* A status control symbol was not sent. Update the status counter. */
        stack->txStatusCounter++;
      }
      break;
 
    case TX_STATE_SEND_PACKET_RETRY:
      /******************************************************************************
       * SEND_PACKET_RETRY
       * This state is set by the receiver to force a packet-retry-symbol to be 
       * transmitted.
       ******************************************************************************/
 
      /* Check if the receiver wants to acknowledge a packet. */
      /* This must be done first or we will get an error for a missmatching 
         ackId in the link-partner. */
      if(stack->rxAckId == stack->rxAckIdAcked)
      {
        /* No pending acknowledge. */
 
        /* Send a packet-retry symbol to tell the link partner to retry the last frame. */
        s = CreateControlSymbol(STYPE0_PACKET_RETRY, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                                STYPE1_NOP, 0u);
 
        /* Proceed with normal transmission. */
        stack->txState = TX_STATE_LINK_INITIALIZED;
 
        /* A status control symbol was not sent. Update the status counter. */
        stack->txStatusCounter++;
      }
      else
      {
 
        /* The receiver wants us to send an acknowledgement. */
        s = CreateControlSymbol(STYPE0_PACKET_ACCEPTED, stack->rxAckIdAcked, QueueAvailable(stack->rxQueue), 
                                STYPE1_NOP, 0u);
        stack->rxAckIdAcked = ACKID_INC(stack->rxAckIdAcked);
 
        /* A status control symbol was not sent. Update the status counter. */
        stack->txStatusCounter++;
      }
      break;
 
    case TX_STATE_SEND_PACKET_NOT_ACCEPTED:
      /******************************************************************************
       * SEND_PACKET_NOT_ACCEPTED
       * This state is set by the receiver to force a packet-not-accepted-symbol to be 
       * transmitted.
       ******************************************************************************/
 
      /* Send a packet-not-accepted symbol to indicate an error on the link. */
      s = CreateControlSymbol(STYPE0_PACKET_NOT_ACCEPTED, 0, stack->rxErrorCause, 
                              STYPE1_NOP, 0u);
 
      /* Proceed with normal transmission. */
      stack->txState = TX_STATE_LINK_INITIALIZED;
 
      /* A status control symbol was not sent. Update the status counter. */
      stack->txStatusCounter++;
      break;
 
    case TX_STATE_SEND_LINK_RESPONSE:
      /******************************************************************************
       * SEND_LINK_RESPONSE
       * This state is set by the receiver to force a link-response-symbol to be 
       * transmitted.
       ******************************************************************************/
 
      /* Check the state of the receiver. */
      /* REMARK: If a link-request gives this response and a link-request also makes the receiver 
         enter the normal operational state, none of these states except the normal state will ever 
         be used... */
      if((stack->rxState == RX_STATE_LINK_INITIALIZED) || (stack->rxState == RX_STATE_PORT_INITIALIZED))
      {
        /* Normal state. */
        s = CreateControlSymbol(STYPE0_LINK_RESPONSE, stack->rxAckId, LINK_RESPONSE_PORT_STATUS_OK, 
                                STYPE1_NOP, 0u);
      }
      else if(stack->rxState == RX_STATE_INPUT_RETRY_STOPPED)
      {
        /* Input-retry-stopped state. */
        s = CreateControlSymbol(STYPE0_LINK_RESPONSE, stack->rxAckId, LINK_RESPONSE_PORT_STATUS_RETRY_STOPPED, 
                                STYPE1_NOP, 0u);
      }
      else if(stack->rxState == RX_STATE_INPUT_ERROR_STOPPED)
      {
        /* Input-error-stopped state. */
        s = CreateControlSymbol(STYPE0_LINK_RESPONSE, stack->rxAckId, LINK_RESPONSE_PORT_STATUS_ERROR_STOPPED, 
                                STYPE1_NOP, 0u);
      }
      else
      {
        /* Not in the defined states. */
        s = CreateControlSymbol(STYPE0_LINK_RESPONSE, stack->rxAckId, LINK_RESPONSE_PORT_STATUS_ERROR, 
                                STYPE1_NOP, 0u);
      }
 
      /* Proceed with normal transmission. */
      stack->txState = TX_STATE_LINK_INITIALIZED;
 
      /* Force a status to be transmitted the next time to comply to the input-error-stopped 
         state rules. */
      stack->txStatusCounter = 255;
      break;
 
    case TX_STATE_OUTPUT_RETRY_STOPPED:
      /******************************************************************************
       * OUTPUT_RETRY_STOPPED
       * This state is entered when the link-partner has transmitted a 
       * packet-retry-symbol. The packet-retry-symbol is acknowledged by sending a 
       * restart-from-retry-symbol.
       * This state follows 5.9.1.5 in part 6. 
       ******************************************************************************/
 
      /* Send a restart-from-retry symbol to acknowledge. */
      s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                              STYPE1_RESTART_FROM_RETRY, 0u);
 
      /* Restart the current frame and proceed with normal operation. */
      stack->txFrameState = TX_FRAME_START;
      stack->txState = TX_STATE_LINK_INITIALIZED;
      stack->txCounter = 0;
 
      /* Discard all packets that has not received a matching packet-accepted. */
      stack->txAckIdWindow = stack->txAckId;
      stack->txQueue = QueueWindowReset(stack->txQueue);
 
      /* A status control symbol was sent. Reset the status counter. */
      stack->txStatusCounter = 0;
      break;
 
    case TX_STATE_OUTPUT_ERROR_STOPPED:
      /******************************************************************************
       * OUTPUT_ERROR_STOPPED
       * This state is entered when the link partner has encountered any problem 
       * which is indicated by sending a packet-not-accepted symbol or if a packet 
       * timeout has expired. The error condition is acknowledged by sending a 
       * link-request-symbol and then wait for a link-response reply.
       * This state follows 5.13.2.7 in part 6. 
       ******************************************************************************/
 
      /* Check if a link-request-symbol has been transmitted. */
      if(stack->txCounter == 0)
      {
        /* A link-request-symbol has not been transmitted. */
 
        /* Send link-request-symbol (input-status). */
        s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                                STYPE1_LINK_REQUEST, LINK_REQUEST_INPUT_STATUS);
 
        /* Save the time when this was transmitted. */
        stack->txFrameTimeout[stack->txAckId] = stack->portTime;
 
        /* Remember that this symbol has been transmitted. */
        stack->txCounter = 1;
      }
      else
      {
        /* A link-request-symbol has been transmitted. */
 
        /* Check if the link partner reply has timed out. */
        if((stack->portTime - stack->txFrameTimeout[stack->txAckId]) < stack->portTimeout)
        {
          /* No timeout. */
 
          /* A link-request-symbol has been transmitted. */
          /* Send only idle-symbols until the link-response is received. */
          s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
        }
        else
        {
          /* Link response timeout. */
 
          /* Check if the link-partner has not responded for too many times. */
          if(stack->txCounter < 5)
          {
            /* Not too many timeouts. */
            /* Retry and send a new link-request. */
 
            /* Send link-request-symbol (input-status). */
            s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue), 
                                    STYPE1_LINK_REQUEST, LINK_REQUEST_INPUT_STATUS);
 
            /* Save the time when this was transmitted. */
            stack->txFrameTimeout[stack->txAckId] = stack->portTime;
 
            /* Increment the number of times we have retransmitted the link-request. */
            stack->txCounter++;
          }
          else
          {
            /* The link partner has not answered for too many times. */
            /* Give up and set the state to uninitialized. */
            stack->txState = TX_STATE_UNINITIALIZED;
            s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
            ASSERT0("No link-response received, giving up.");
          }
        }
      }
      break;
 
    case TX_STATE_UNINITIALIZED:
    default:
      /******************************************************************************
       * Wait for the port to be initialized.
       ******************************************************************************/
 
      /* Send only idle symbols. */
      s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
      break;
  }
 
  /* Return the created symbol. */
  return s;
}
 
 
 
/*******************************************************************************
 * Local RapidIO stack helper functions.
 *******************************************************************************/
 
static void handleStatus(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus)
{
  /* Update the buffer status of the link partner. */
  (void) ackId;
  stack->txBufferStatus = bufferStatus;
}
 
 
 
static void handlePacketAccepted(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus)
{
  uint32_t linkLatency;
 
 
  /* Check if an acknowledge is expected and that it is for a transmitted packet. */
  if((stack->txAckId != stack->txAckIdWindow) && (ackId == stack->txAckId))
  {
    /* Acknowledge for a recently transmitted packet received. */
 
    /* Check if the latency of this packet is larger than the largest encountered so far. */
    linkLatency = stack->portTime - stack->txFrameTimeout[ackId];
    if(linkLatency > stack->statusOutboundLinkLatencyMax)
    {
      stack->statusOutboundLinkLatencyMax = linkLatency;
    }
 
    /* Remove the packet from the outbound queue and restart the transmission for
       a new packet. */
    stack->txQueue = QueueDequeue(stack->txQueue);
    stack->txAckId = ACKID_INC(stack->txAckId);
    stack->statusOutboundPacketComplete++;
  }
  else
  {
    /* Acknowledge for an unexpected ackId or not waiting for an acknowledge. */
    /* Link protocol violation. Discard the symbol and enter the output-error-stopped state. */
    stack->txState = TX_STATE_OUTPUT_ERROR_STOPPED;
    stack->txCounter = 0u;
    stack->statusOutboundErrorPacketAccepted++;
  }
 
  /* Update the buffer status of the link partner. */
  stack->txBufferStatus = bufferStatus;
}
 
 
 
static void handlePacketRetry(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus)
{
  /* Check if the retried packet ackId is acceptable. */
  if(ackId == stack->txAckId)
  {
    /* The request for retry is for the current packet. */
    /* Force the transmitter to send a RESTART-FROM-RETRY symbol. */
    stack->txState = TX_STATE_OUTPUT_RETRY_STOPPED;
    stack->statusOutboundPacketRetry++;
  }
  else
  {
    /* Link protocol violation. Discard the symbol and enter the output-error-stopped state. */
    stack->txState = TX_STATE_OUTPUT_ERROR_STOPPED;
    stack->txCounter = 0u;
    stack->statusOutboundErrorPacketRetry++;
  }
 
  /* Update the buffer status of the link partner. */
  stack->txBufferStatus = bufferStatus;
}
 
 
 
static void handlePacketNotAccepted(RioStack_t *stack, const uint8_t arbitrary, const uint8_t cause)
{
  (void) arbitrary;
 
  /* Force the transmitter to enter output-error-stopped state. */
  stack->txState = TX_STATE_OUTPUT_ERROR_STOPPED;
  stack->txCounter = 0u;
 
  /* Record the type of error that caused the packet to not being accepted. */
  switch(cause)
  {
    case PACKET_NOT_ACCEPTED_CAUSE_UNEXPECTED_ACKID:
      stack->statusPartnerErrorPacketAckId++;
      break;
    case PACKET_NOT_ACCEPTED_CAUSE_CONTROL_CRC:
      stack->statusPartnerErrorControlCrc++;
      break;
    case PACKET_NOT_ACCEPTED_CAUSE_PACKET_CRC:
      stack->statusPartnerErrorPacketCrc++;
      break;
    case PACKET_NOT_ACCEPTED_CAUSE_ILLEGAL_CHARACTER:
      stack->statusPartnerErrorIllegalCharacter++;
      break;
    default:
      stack->statusPartnerErrorGeneral++;
      break;
  }
}
 
 
 
static void handleLinkResponse(RioStack_t *stack, const uint8_t ackId, const uint8_t portStatus)
{
  uint8_t window;
  uint8_t windowReceived;
 
 
  (void) portStatus;
 
  /* Check if this symbols is expected. */
  if(stack->txState == TX_STATE_OUTPUT_ERROR_STOPPED)
  {
    /* Calculate the number of packets that has not received an acknowledge on our side and 
       on the link-partner side. */
    window = (stack->txAckIdWindow - stack->txAckId) & 0x1f;
    windowReceived = (ackId - stack->txAckId) & 0x1f;
 
    /* Check if the link-partners response is acceptable. */
    if(windowReceived <= window)
    {
      /* A link-response is expected. */
 
      /* Remove entries in the queue that the link-partner has sent acknowledges for that has been lost. */
      while(stack->txAckId != ackId)
      {
        stack->txQueue = QueueDequeue(stack->txQueue);
        stack->txAckId = ACKID_INC(stack->txAckId);
        stack->statusOutboundPacketComplete++;
      }
 
      /* Set the transmission window to the resend packets that has not been received. */
      stack->txQueue = QueueWindowReset(stack->txQueue);
      stack->txAckIdWindow = ackId;
      stack->txFrameState = TX_FRAME_START;
 
      /* Set the transmitter back into normal operation. */
      stack->txState = TX_STATE_LINK_INITIALIZED;
    }
    else
    {
      /* The link-partner response is unacceptable. */
      /* Recovery is not possible. */
      stack->txState = TX_STATE_UNINITIALIZED;
      ASSERT0("Unrecoverable protocol error.");
    }
  }
  else
  {
    /* Not expecting a link-response. */
    /* Just discard this symbol. */
    /* REMARK: Add status counter here??? */
  }
}
 
 
 
static void handleStartOfPacket(RioStack_t *stack)
{
  /* Check if a packet is already started. */
  if(stack->rxCounter != 0u)
  {
    /* Packet has already started. */
    /* This indicates an implicit end-of-packet symbol and signals the previous packet as ready. */
 
    /* Check the packet crc. */
    if(stack->rxCrc == 0x0000u)
    {
      /* The packet has a correct CRC. */
 
      /* Check if the packet is long enough to contain a complete packet. */
      if(stack->rxCounter > 3u)
      {
        /* Packet long enough to process. */
 
        /* Process the newly received packet and start a new one. */
        handleNewPacketEnd(stack);
        handleNewPacketStart(stack);
      }
      else
      {
        /* The packet has a valid CRC but is too short. */
        /* Packet error. Enter input-error-stopped state. */
        stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
        stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
        stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_GENERAL;
        stack->statusInboundErrorGeneral++;
      }
    }
    else
    {
      /* The packet has an invalid CRC. */
      /* Packet error. Enter input-error-stopped state. */
      stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
      stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
      stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_PACKET_CRC;
      stack->statusInboundErrorPacketCrc++;
    }
  }
  else
  {
    /* Packet has not already started. */
    handleNewPacketStart(stack);
  }
}
 
 
 
static void handleEndOfPacket(RioStack_t *stack)
{
  /* Check if the CRC is correct. */
  if(stack->rxCrc == 0x0000u)
  {
    /* The packet has a correct CRC. */
 
    /* Check if the packet is long enough to contain a complete packet. */
    if(stack->rxCounter > 3u)
    {
      /* Packet long enough to process. */
 
      /* Process the newly received packet. */
      handleNewPacketEnd(stack);
    }
    else
    {
      /* The packet has a valid CRC but is too short. */
      /* Packet error. Enter input-error-stopped state. */
      stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
      stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
      stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_GENERAL;
      stack->statusInboundErrorGeneral++;
    }
  }
  else
  {
    /* The packet has an invalid CRC. */
    /* Packet error. Enter input-error-stopped state. */
    stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
    stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
    stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_PACKET_CRC;
    stack->statusInboundErrorPacketCrc++;
  }
}
 
 
 
static void handleNewPacketStart(RioStack_t *stack)
{
  /* Check if there are buffers available to store the new frame. */
  if (QueueAvailable(stack->rxQueue) > 0u)
  {
    /* There are buffers available to accept the new packet. */
 
    /* Update the reception counter to indicate the frame has started. */
    stack->rxCounter = 1;
  }
  else
  {
    /* There are no buffers available. */
    /* Go to input retry stopped state. */
    stack->statusInboundPacketRetry++;
    stack->txState = TX_STATE_SEND_PACKET_RETRY;
    stack->rxState = RX_STATE_INPUT_RETRY_STOPPED;
  }
}
 
 
 
static void handleNewPacketEnd(RioStack_t *stack)
{
  /* Save the size of the packet. */
  QueueSetSize(stack->rxQueue, (uint32_t)stack->rxCounter - (uint32_t)1ul);
 
  /* Always forward the packet to the top of the stack. */
  stack->rxQueue = QueueEnqueue(stack->rxQueue);
 
  /* Make sure the CRC is reset to an invalid value to avoid a packet 
     accidentally being accepted. */
  stack->rxCrc = 0xffff;
 
  /* Reset the reception counter. */
  stack->rxCounter = 0u;
 
  /* Update the ackId for the receiver. */
  stack->rxAckId = ACKID_INC(stack->rxAckId);
 
  /* Update status counter. */
  stack->statusInboundPacketComplete++;
}
 
 
 
static void handleLinkRequest(RioStack_t *stack, uint8_t cmd)
{
  /* Check the command of the link-request. */
  if(cmd == LINK_REQUEST_INPUT_STATUS)
  {
    /* Input-status requested. */
    /* Return input port status. */
 
    /* Force the transmitter to send a link-response-symbol. */
    stack->txState = TX_STATE_SEND_LINK_RESPONSE;
  }
  else if(cmd == LINK_REQUEST_RESET_DEVICE)
  {
    /* Reset-device requested. */
    /* REMARK: Support this??? */
  }
  else
  {
    /* Unrecognized command. */
    /* Dont do anything. */
  }
 
  /* Always cancel an ongoing frame when a link-request has been received. */
  stack->rxCounter = 0;
 
  /* Receiving this indicates the link partner having encountered a potential problem. */
  /* Count the number of times this happens. */
  stack->statusPartnerLinkRequest++;
}
 
 
 
static RioSymbol_t CreateControlSymbol(const uint8_t stype0,
                                       const uint8_t parameter0, const uint8_t parameter1,
                                       const uint8_t stype1, const uint8_t cmd)
{
  RioSymbol_t s;
 
  s.type = RIOSTACK_SYMBOL_TYPE_CONTROL;
 
  s.data = ((uint32_t)stype0 & (uint32_t)0x07ul) << 21;
  s.data |= ((uint32_t)parameter0 & (uint32_t)0x1ful) << 16;
  s.data |= ((uint32_t)parameter1 & (uint32_t)0x1ful) << 11;
  s.data |= ((uint32_t)stype1 & (uint32_t)0x07ul) << 8;
  s.data |= ((uint32_t)cmd & (uint32_t)0x7ul) << 5;
  s.data |= Crc5(s.data, 0x1fu);
 
  return s;
}
 
 
 
static uint8_t Crc5(const uint32_t data, const uint8_t crc)
{
  static const uint8_t crcTable[] = {
    0x00u, 0x15u, 0x1fu, 0x0au, 0x0bu, 0x1eu, 0x14u, 0x01u,
    0x16u, 0x03u, 0x09u, 0x1cu, 0x1du, 0x08u, 0x02u, 0x17u,
    0x19u, 0x0cu, 0x06u, 0x13u, 0x12u, 0x07u, 0x0du, 0x18u,
    0x0fu, 0x1au, 0x10u, 0x05u, 0x04u, 0x11u, 0x1bu, 0x0eu
  };
 
  uint8_t result;
  uint8_t index;
 
  result = crc;
  index  = (uint8_t)((data >> 19) & (uint32_t)0x1ful) ^ result;
  result = crcTable[index];
  index  = (uint8_t)((data >> 14) & (uint32_t)0x1ful) ^ result;
  result = crcTable[index];
  index  = (uint8_t)((data >> 9) & (uint32_t)0x1ful) ^ result;
  result = crcTable[index];
  index  = (uint8_t)((data >> 4) & (uint32_t)0x1eul) ^ result;
  result = crcTable[index];
 
  return result;
}
 
 
/*******************************************************************************************
 * Internal queue functions.
 *******************************************************************************************/
 
static Queue_t QueueCreate(const uint8_t size, uint32_t *buffer)
{
  Queue_t q;
 
  q.size = size;
  q.available = size;
  q.windowSize = 0u;
  q.windowIndex = 0u;
  q.frontIndex = 0u;
  q.backIndex = 0u;
  q.buffer_p = buffer;
 
  return q;
}
 
 
 
static uint8_t QueueAvailable(const Queue_t q)
{
  return q.available;
}
 
 
 
static int QueueEmpty(const Queue_t q)
{
  return (q.available == q.size);
}
 
 
 
static uint8_t QueueLength(const Queue_t q)
{
  return q.size - q.available;
}
 
 
 
static Queue_t QueueEnqueue(Queue_t q)
{
  q.backIndex++;
  if(q.backIndex == q.size)
  {
    q.backIndex = 0;
  }
  q.available--;
  return q;
}
 
 
 
static Queue_t QueueDequeue(Queue_t q)
{
  q.frontIndex++;
  if(q.frontIndex == q.size)
  {
    q.frontIndex = 0;
  }
  q.available++;
  if(q.windowSize == 0)
  {
    q.windowIndex = q.frontIndex;
  }
  else
  {
    q.windowSize--;
  }
  return q;
}
 
 
 
static int QueueWindowEmpty(const Queue_t q)
{
  return ((q.available + q.windowSize) == q.size);
}
 
 
 
static Queue_t QueueWindowReset(Queue_t q)
{
  q.windowIndex = q.frontIndex;
  q.windowSize = 0;
  return q;
}
 
 
 
static Queue_t QueueWindowNext(Queue_t q)
{
  q.windowIndex++;
  if(q.windowIndex == q.size)
  {
    q.windowIndex = 0;
  }
  q.windowSize++;
  return q;
}
 
 
 
static void QueueSetSize(Queue_t q, const uint32_t size)
{
  (q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.backIndex))[0] = size;
}
 
 
 
static void QueueSetContent(Queue_t q, const uint32_t index, const uint32_t content)
{
  (q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.backIndex))[index+1ul] = content;
}
 
 
 
static uint32_t QueueGetSize(Queue_t q)
{
  return (q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.windowIndex))[0];
}
 
 
 
static uint32_t QueueGetFrontContent(const Queue_t q, const uint32_t index)
{
  return (q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.windowIndex))[index+1ul];
}
 
 
 
static uint32_t *QueueGetFrontBuffer(const Queue_t q )
{
  return &((q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.windowIndex))[1]);
}
 
 
 
static uint32_t *QueueGetBackBuffer(const Queue_t q )
{
  return &((q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.backIndex))[1]);
}
 
/*************************** end of file **************************************/
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.