am_hal_queue.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. //*****************************************************************************
  2. //
  3. // am_hal_queue.c
  4. //! @file
  5. //!
  6. //! @brief Functions for implementing a queue system.
  7. //!
  8. //! @addtogroup Miscellaneous2 Software Features (MISC)
  9. //! @ingroup apollo2hal
  10. //! @{
  11. //
  12. //*****************************************************************************
  13. //*****************************************************************************
  14. //
  15. // Copyright (c) 2017, Ambiq Micro
  16. // All rights reserved.
  17. //
  18. // Redistribution and use in source and binary forms, with or without
  19. // modification, are permitted provided that the following conditions are met:
  20. //
  21. // 1. Redistributions of source code must retain the above copyright notice,
  22. // this list of conditions and the following disclaimer.
  23. //
  24. // 2. Redistributions in binary form must reproduce the above copyright
  25. // notice, this list of conditions and the following disclaimer in the
  26. // documentation and/or other materials provided with the distribution.
  27. //
  28. // 3. Neither the name of the copyright holder nor the names of its
  29. // contributors may be used to endorse or promote products derived from this
  30. // software without specific prior written permission.
  31. //
  32. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  33. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  34. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  35. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  36. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  37. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  38. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  39. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  40. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  42. // POSSIBILITY OF SUCH DAMAGE.
  43. //
  44. // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
  45. //
  46. //*****************************************************************************
  47. #include <stdint.h>
  48. #include <stdbool.h>
  49. #include "am_mcu_apollo.h"
  50. //*****************************************************************************
  51. //
  52. //! @brief Initializes a queue.
  53. //!
  54. //! @param psQueue - Pointer to a queue structure.
  55. //! @param pvData - Pointer to a memory location to be used for data storage.
  56. //! @param ui32ItemSize - Number of bytes per item in the queue.
  57. //! @param ui32ArraySize - Number of bytes in the data array.
  58. //!
  59. //! This function initializes the members of a queue structure and attaches it
  60. //! to an array of memory that it can use for storage. This function should be
  61. //! called before the queue is used.
  62. //!
  63. //! In this example, we are creating a queue that can hold 1024 32-bit
  64. //! integers. The integers themselves will be stored in the array named
  65. //! pui32WorkingSpace, while information about the queue itself will be stored
  66. //! in sDataQueue.
  67. //!
  68. //! @note The caller should not modify any of the members of am_hal_queue_t
  69. //! structures. The queue API will handle these members in a thread-safe way.
  70. //!
  71. //! @note The queue will remember what size data is in it. Other queue API
  72. //! functions will perform transfers in units of "items" where one "item" is
  73. //! the number of bytes you specify in the \e ui32ItemSize argument upon
  74. //! initialization.
  75. //!
  76. //! Example usage:
  77. //!
  78. //! @code
  79. //!
  80. //! //
  81. //! // Declare a queue structure and an array of bytes we can use to store
  82. //! // data.
  83. //! //
  84. //! am_hal_queue_t sDataQueue;
  85. //! uint32_t pui32WorkingSpace[1024];
  86. //!
  87. //! //
  88. //! // Attach the queue structure to the working memory.
  89. //! //
  90. //! am_hal_queue_init(&sDataQueue, pui8WorkingSpace, sizeof(uint32_t)
  91. //! sizeof(pui32WorkingSpace));
  92. //!
  93. //! @endcode
  94. //!
  95. //! The am_hal_queue_from_array macro is a convenient shorthand for this
  96. //! operation. The code below does the same thing as the code above.
  97. //!
  98. //! @code
  99. //!
  100. //! //
  101. //! // Declare a queue structure and an array of bytes we can use to store
  102. //! // data.
  103. //! //
  104. //! am_hal_queue_t sDataQueue;
  105. //! uint32_t pui32WorkingSpace[1024];
  106. //!
  107. //! //
  108. //! // Attach the queue structure to the working memory.
  109. //! //
  110. //! am_hal_queue_from_array(&sDataQueue, pui8WorkingSpace);
  111. //!
  112. //! @endcode
  113. //
  114. //*****************************************************************************
  115. void
  116. am_hal_queue_init(am_hal_queue_t *psQueue, void *pvData, uint32_t ui32ItemSize,
  117. uint32_t ui32ArraySize)
  118. {
  119. psQueue->ui32WriteIndex = 0;
  120. psQueue->ui32ReadIndex = 0;
  121. psQueue->ui32Length = 0;
  122. psQueue->ui32Capacity = ui32ArraySize;
  123. psQueue->ui32ItemSize = ui32ItemSize;
  124. psQueue->pui8Data = (uint8_t *) pvData;
  125. }
  126. //*****************************************************************************
  127. //
  128. //! @brief Adds an item to the Queue
  129. //!
  130. //! @param psQueue - Pointer to a queue structure.
  131. //! @param pvSource - Pointer to the data to be added.
  132. //! @param ui32NumItems - Number of items to be added.
  133. //!
  134. //! This function will copy the data pointed to by pvSource into the queue. The
  135. //! \e ui32NumItems term specifies the number of items to be copied from \e
  136. //! pvSource. The size of an "item" depends on how the queue was initialized.
  137. //! Please see am_hal_queue_init() for more information on this.
  138. //!
  139. //! @return true if the add operation was successful, or false if the queue
  140. //! didn't have enough space.
  141. //
  142. //*****************************************************************************
  143. bool
  144. am_hal_queue_item_add(am_hal_queue_t *psQueue, const void *pvSource, uint32_t ui32NumItems)
  145. {
  146. uint32_t i;
  147. uint8_t *pui8Source;
  148. uint32_t ui32Bytes = ui32NumItems * psQueue->ui32ItemSize;
  149. bool bSuccess = false;
  150. uint32_t ui32Primask;
  151. pui8Source = (uint8_t *) pvSource;
  152. ui32Primask = am_hal_interrupt_master_disable();
  153. //
  154. // Check to make sure that the buffer isn't already full
  155. //
  156. if ( am_hal_queue_space_left(psQueue) >= ui32Bytes )
  157. {
  158. //
  159. // Loop over the bytes in the source array.
  160. //
  161. for ( i = 0; i < ui32Bytes; i++ )
  162. {
  163. //
  164. // Write the value to the buffer.
  165. //
  166. psQueue->pui8Data[psQueue->ui32WriteIndex] = pui8Source[i];
  167. //
  168. // Advance the write index, making sure to wrap if necessary.
  169. //
  170. psQueue->ui32WriteIndex = ((psQueue->ui32WriteIndex + 1) %
  171. psQueue->ui32Capacity);
  172. }
  173. //
  174. // Update the length value appropriately.
  175. //
  176. psQueue->ui32Length += ui32Bytes;
  177. //
  178. // Report a success.
  179. //
  180. bSuccess = true;
  181. }
  182. else
  183. {
  184. //
  185. // The buffer can't fit the amount of data requested. Return a
  186. // failure.
  187. //
  188. bSuccess = false;
  189. }
  190. am_hal_interrupt_master_set(ui32Primask);
  191. return bSuccess;
  192. }
  193. //*****************************************************************************
  194. //
  195. //! @brief Removes an item from the Queue
  196. //!
  197. //! @param psQueue - Pointer to a queue structure.
  198. //! @param pvDest - Pointer to the data to be added.
  199. //! @param ui32NumItems - Number of items to be added.
  200. //!
  201. //! This function will copy the data from the queue into the memory pointed to
  202. //! by pvDest. The \e ui32NumItems term specifies the number of items to be
  203. //! copied from the queue. The size of an "item" depends on how the queue was
  204. //! initialized. Please see am_hal_queue_init() for more information on this.
  205. //!
  206. //! @return true if we were able to pull the requested number of items from the
  207. //! queue, or false if the queue didn't have that many items to pull.
  208. //
  209. //*****************************************************************************
  210. bool
  211. am_hal_queue_item_get(am_hal_queue_t *psQueue, void *pvDest, uint32_t ui32NumItems)
  212. {
  213. uint32_t i;
  214. uint8_t *pui8Dest;
  215. uint32_t ui32Bytes = ui32NumItems * psQueue->ui32ItemSize;
  216. bool bSuccess = false;
  217. uint32_t ui32Primask;
  218. pui8Dest = (uint8_t *) pvDest;
  219. ui32Primask = am_hal_interrupt_master_disable();
  220. //
  221. // Check to make sure that the buffer isn't empty
  222. //
  223. if ( am_hal_queue_data_left(psQueue) >= ui32Bytes )
  224. {
  225. //
  226. // Loop over the bytes in the destination array.
  227. //
  228. for ( i = 0; i < ui32Bytes; i++ )
  229. {
  230. //
  231. // Grab the next value from the buffer.
  232. //
  233. pui8Dest[i] = psQueue->pui8Data[psQueue->ui32ReadIndex];
  234. //
  235. // Advance the read index, wrapping if needed.
  236. //
  237. psQueue->ui32ReadIndex = ((psQueue->ui32ReadIndex + 1) %
  238. psQueue->ui32Capacity);
  239. }
  240. //
  241. // Adjust the length value to reflect the change.
  242. //
  243. psQueue->ui32Length -= ui32Bytes;
  244. //
  245. // Report a success.
  246. //
  247. bSuccess = true;
  248. }
  249. else
  250. {
  251. //
  252. // If the buffer didn't have enough data, just return false.
  253. //
  254. bSuccess = false;
  255. }
  256. am_hal_interrupt_master_set(ui32Primask);
  257. return bSuccess;
  258. }
  259. //*****************************************************************************
  260. //
  261. // End Doxygen group.
  262. //! @}
  263. //
  264. //*****************************************************************************