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