text: //*****************************************************************************
  //
  //  am_hal_queue.c
  //! @file
  //!
  //! @brief Functions for implementing a queue system.
  //!
  //! @addtogroup Miscellaneous2 Software Features (MISC)
  //! @ingroup apollo2hal
  //! @{
  //
  //*****************************************************************************
  
  //*****************************************************************************
  //
  // Copyright (c) 2017, Ambiq Micro
  // All rights reserved.
  // 
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are met:
  // 
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  // 
  // 2. Redistributions in binary form must reproduce the above copyright
  // notice, this list of conditions and the following disclaimer in the
  // documentation and/or other materials provided with the distribution.
  // 
  // 3. Neither the name of the copyright holder nor the names of its
  // contributors may be used to endorse or promote products derived from this
  // software without specific prior written permission.
  // 
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  // POSSIBILITY OF SUCH DAMAGE.
  //
  // This is part of revision 1.2.9 of the AmbiqSuite Development Package.
  //
  //*****************************************************************************
  
  #include <stdint.h>
  #include <stdbool.h>
  #include "am_mcu_apollo.h"
  
  //*****************************************************************************
  //
  //! @brief Initializes a queue.
  //!
  //! @param psQueue - Pointer to a queue structure.
  //! @param pvData - Pointer to a memory location to be used for data storage.
  //! @param ui32ItemSize - Number of bytes per item in the queue.
  //! @param ui32ArraySize - Number of bytes in the data array.
  //!
  //! This function initializes the members of a queue structure and attaches it
  //! to an array of memory that it can use for storage. This function should be
  //! called before the queue is used.
  //!
  //! In this example, we are creating a queue that can hold 1024 32-bit
  //! integers. The integers themselves will be stored in the array named
  //! pui32WorkingSpace, while information about the queue itself will be stored
  //! in sDataQueue.
  //!
  //! @note The caller should not modify any of the members of am_hal_queue_t
  //! structures. The queue API will handle these members in a thread-safe way.
  //!
  //! @note The queue will remember what size data is in it. Other queue API
  //! functions will perform transfers in units of "items" where one "item" is
  //! the number of bytes you specify in the \e ui32ItemSize argument upon
  //! initialization.
  //!
  //! Example usage:
  //!
  //! @code
  //!
  //! //
  //! // Declare a queue structure and an array of bytes we can use to store
  //! // data.
  //! //
  //! am_hal_queue_t sDataQueue;
  //! uint32_t pui32WorkingSpace[1024];
  //!
  //! //
  //! // Attach the queue structure to the working memory.
  //! //
  //! am_hal_queue_init(&sDataQueue, pui8WorkingSpace, sizeof(uint32_t)
  //!                   sizeof(pui32WorkingSpace));
  //!
  //! @endcode
  //!
  //! The am_hal_queue_from_array macro is a convenient shorthand for this
  //! operation. The code below does the same thing as the code above.
  //!
  //! @code
  //!
  //! //
  //! // Declare a queue structure and an array of bytes we can use to store
  //! // data.
  //! //
  //! am_hal_queue_t sDataQueue;
  //! uint32_t pui32WorkingSpace[1024];
  //!
  //! //
  //! // Attach the queue structure to the working memory.
  //! //
  //! am_hal_queue_from_array(&sDataQueue, pui8WorkingSpace);
  //!
  //! @endcode
  //
  //*****************************************************************************
  void
  am_hal_queue_init(am_hal_queue_t *psQueue, void *pvData, uint32_t ui32ItemSize,
                    uint32_t ui32ArraySize)
  {
      psQueue->ui32WriteIndex = 0;
      psQueue->ui32ReadIndex = 0;
      psQueue->ui32Length = 0;
      psQueue->ui32Capacity = ui32ArraySize;
      psQueue->ui32ItemSize = ui32ItemSize;
      psQueue->pui8Data = (uint8_t *) pvData;
  }
  
  //*****************************************************************************
  //
  //! @brief Adds an item to the Queue
  //!
  //! @param psQueue - Pointer to a queue structure.
  //! @param pvSource - Pointer to the data to be added.
  //! @param ui32NumItems - Number of items to be added.
  //!
  //! This function will copy the data pointed to by pvSource into the queue. The
  //! \e ui32NumItems term specifies the number of items to be copied from \e
  //! pvSource. The size of an "item" depends on how the queue was initialized.
  //! Please see am_hal_queue_init() for more information on this.
  //!
  //! @return true if the add operation was successful, or false if the queue
  //! didn't have enough space.
  //
  //*****************************************************************************
  bool
  am_hal_queue_item_add(am_hal_queue_t *psQueue, const void *pvSource, uint32_t ui32NumItems)
  {
      uint32_t i;
      uint8_t *pui8Source;
      uint32_t ui32Bytes = ui32NumItems * psQueue->ui32ItemSize;
      bool bSuccess = false;
      uint32_t ui32Primask;
  
      pui8Source = (uint8_t *) pvSource;
  
      ui32Primask = am_hal_interrupt_master_disable();
  
      //
      // Check to make sure that the buffer isn't already full
      //
      if ( am_hal_queue_space_left(psQueue) >= ui32Bytes )
      {
          //
          // Loop over the bytes in the source array.
          //
          for ( i = 0; i < ui32Bytes; i++ )
          {
              //
              // Write the value to the buffer.
              //
              psQueue->pui8Data[psQueue->ui32WriteIndex] = pui8Source[i];
  
              //
              // Advance the write index, making sure to wrap if necessary.
              //
              psQueue->ui32WriteIndex = ((psQueue->ui32WriteIndex + 1) %
                                          psQueue->ui32Capacity);
          }
  
          //
          // Update the length value appropriately.
          //
          psQueue->ui32Length += ui32Bytes;
  
          //
          // Report a success.
          //
          bSuccess = true;
      }
      else
      {
          //
          // The buffer can't fit the amount of data requested. Return a
          // failure.
          //
          bSuccess = false;
      }
  
      am_hal_interrupt_master_set(ui32Primask);
  
      return bSuccess;
  }
  
  //*****************************************************************************
  //
  //! @brief Removes an item from the Queue
  //!
  //! @param psQueue - Pointer to a queue structure.
  //! @param pvDest - Pointer to the data to be added.
  //! @param ui32NumItems - Number of items to be added.
  //!
  //! This function will copy the data from the queue into the memory pointed to
  //! by pvDest. The \e ui32NumItems term specifies the number of items to be
  //! copied from the queue. The size of an "item" depends on how the queue was
  //! initialized.  Please see am_hal_queue_init() for more information on this.
  //!
  //! @return true if we were able to pull the requested number of items from the
  //! queue, or false if the queue didn't have that many items to pull.
  //
  //*****************************************************************************
  bool
  am_hal_queue_item_get(am_hal_queue_t *psQueue, void *pvDest, uint32_t ui32NumItems)
  {
      uint32_t i;
      uint8_t *pui8Dest;
      uint32_t ui32Bytes = ui32NumItems * psQueue->ui32ItemSize;
      bool bSuccess = false;
      uint32_t ui32Primask;
  
      pui8Dest = (uint8_t *) pvDest;
  
      ui32Primask = am_hal_interrupt_master_disable();
  
      //
      // Check to make sure that the buffer isn't empty
      //
      if ( am_hal_queue_data_left(psQueue) >= ui32Bytes )
      {
          //
          // Loop over the bytes in the destination array.
          //
          for ( i = 0; i < ui32Bytes; i++ )
          {
              //
              // Grab the next value from the buffer.
              //
              pui8Dest[i] = psQueue->pui8Data[psQueue->ui32ReadIndex];
  
              //
              // Advance the read index, wrapping if needed.
              //
              psQueue->ui32ReadIndex = ((psQueue->ui32ReadIndex + 1) %
                                         psQueue->ui32Capacity);
          }
  
          //
          // Adjust the length value to reflect the change.
          //
          psQueue->ui32Length -= ui32Bytes;
  
          //
          // Report a success.
          //
          bSuccess = true;
      }
      else
      {
          //
          // If the buffer didn't have enough data, just return false.
          //
          bSuccess = false;
      }
  
      am_hal_interrupt_master_set(ui32Primask);
  
      return bSuccess;
  }
  
  //*****************************************************************************
  //
  // End Doxygen group.
  //! @}
  //
  //*****************************************************************************
  