1 /*
2  * Copyright (c) 2021-2023, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== RCL_Buffer.c ========
34  */
35 
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <stdbool.h>
39 
40 #include <ti/drivers/rcl/RCL_Command.h>
41 #include <ti/drivers/rcl/RCL_Scheduler.h>
42 #include <ti/drivers/rcl/RCL_Buffer.h>
43 #include <ti/drivers/rcl/RCL_Debug.h>
44 
45 #include <ti/log/Log.h>
46 
47 #include <ti/devices/DeviceFamily.h>
48 #include DeviceFamily_constructPath(inc/hw_ints.h)
49 
50 #include <ti/log/Log.h>
51 
52 static bool RxEntry_isAtEnd(RCL_MultiBuffer *multiBuffer, uint16_t curIndex);
53 static void List_consumeAndStore(List_List *list, List_List *consumedBuffers);
54 
55 /*
56  *  ======== RCL_TxBuffer_put ========
57  */
RCL_TxBuffer_put(List_List * list,RCL_Buffer_TxBuffer * elem)58 void RCL_TxBuffer_put(List_List *list, RCL_Buffer_TxBuffer *elem)
59 {
60 
61     List_put(list, (List_Elem *)elem);
62     /* Notify running command */
63     RCL_Scheduler_postEvent(rclSchedulerState.currCmd, RCL_EventTxBufferUpdate);
64 }
65 
66 /*
67  *  ======== RCL_TxBuffer_init ========
68  */
RCL_TxBuffer_init(RCL_Buffer_TxBuffer * buffer,uint32_t numPad,uint32_t hdrLen,uint32_t dataLen)69 uint8_t *RCL_TxBuffer_init(RCL_Buffer_TxBuffer *buffer, uint32_t numPad, uint32_t hdrLen,
70                            uint32_t dataLen)
71 {
72     if (buffer == NULL)
73     {
74         return NULL;
75     }
76     else
77     {
78         buffer->state = RCL_BufferStatePending;
79         buffer->length = sizeof(buffer->numPad) + numPad + hdrLen + dataLen;
80         buffer->numPad = numPad;
81         /* Start writing at pad0, then continue into data field */
82         uint8_t *data = &buffer->pad0;
83         while (numPad > 0)
84         {
85             --numPad;
86             *data++ = numPad;
87         }
88         return data;
89     }
90 }
91 
92 /*
93  *  ======== RCL_MultiBuffer_clear ========
94  */
RCL_MultiBuffer_clear(RCL_MultiBuffer * buffer)95 void RCL_MultiBuffer_clear(RCL_MultiBuffer *buffer)
96 {
97     buffer->state = RCL_BufferStatePending;
98     buffer->headIndex = 0;
99     buffer->tailIndex = 0;
100 }
101 
102 /*
103  *  ======== RCL_MultiBuffer_init ========
104  */
RCL_MultiBuffer_init(RCL_MultiBuffer * buffer,size_t size)105 void RCL_MultiBuffer_init(RCL_MultiBuffer *buffer, size_t size)
106 {
107     size -= offsetof(RCL_MultiBuffer, data);
108     RCL_Debug_assert(size > 0 && size <= 0xFFFF);
109     buffer->length = size;
110     RCL_MultiBuffer_clear(buffer);
111 
112 }
113 
114 /*
115  *  ======== RCL_MultiBuffer_put ========
116  */
RCL_MultiBuffer_put(List_List * list,RCL_MultiBuffer * elem)117 void RCL_MultiBuffer_put(List_List *list, RCL_MultiBuffer *elem)
118 {
119     List_put(list, (List_Elem *)elem);
120     /* Notify running command */
121     RCL_Scheduler_postEvent(rclSchedulerState.currCmd, RCL_EventRxBufferUpdate);
122 }
123 
124 /*
125  *  ======== RCL_MultiBuffer_RxEntry_get ========
126  */
RCL_MultiBuffer_RxEntry_get(List_List * list,List_List * consumedBuffers)127 RCL_Buffer_DataEntry *RCL_MultiBuffer_RxEntry_get(List_List *list, List_List *consumedBuffers)
128 {
129     RCL_Buffer_DataEntry *rxEntry = NULL;
130     RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *)list->head;
131     if (multiBuffer != NULL)
132     {
133         int32_t headIndex = multiBuffer->headIndex;
134         int32_t tailIndex = multiBuffer->tailIndex;
135 
136         RCL_Debug_assert(headIndex <= tailIndex);
137 
138         if (headIndex >= tailIndex)
139         {
140             if (multiBuffer->state == RCL_BufferStateFinished)
141             {
142                 List_consumeAndStore(list, consumedBuffers);
143                 multiBuffer = (RCL_MultiBuffer *) List_head(list);
144                 headIndex = 0;
145                 tailIndex = multiBuffer->tailIndex;
146                 RCL_Debug_assert(multiBuffer->headIndex == 0);
147 
148             }
149         }
150 
151         if (headIndex < tailIndex)
152         {
153             rxEntry = (RCL_Buffer_DataEntry *) &multiBuffer->data[headIndex];
154             headIndex += RCL_Buffer_DataEntry_paddedLen(rxEntry->length);
155             RCL_Debug_assert(headIndex <= tailIndex);
156             multiBuffer->headIndex = headIndex;
157             if (headIndex >= tailIndex)
158             {
159                 if (multiBuffer->state == RCL_BufferStateFinished)
160                 {
161                     List_consumeAndStore(list, consumedBuffers);
162                 }
163             }
164         }
165     }
166     return rxEntry;
167 }
168 
169 /*
170  *  ======== RCL_MultiBuffer_RxEntry_isEmpty ========
171  */
RCL_MultiBuffer_RxEntry_isEmpty(List_List * list)172 bool RCL_MultiBuffer_RxEntry_isEmpty(List_List *list)
173 {
174     RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *)list->head;
175 
176     if (multiBuffer != NULL)
177     {
178         return RxEntry_isAtEnd(multiBuffer, multiBuffer->headIndex);
179     }
180     else {
181         return true;
182     }
183 }
184 
185 /*
186  *  ======== RCL_MultiBuffer_ListInfo_init ========
187  */
RCL_MultiBuffer_ListInfo_init(RCL_MultiBuffer_ListInfo * listInfo,List_List * list)188 void RCL_MultiBuffer_ListInfo_init(RCL_MultiBuffer_ListInfo *listInfo, List_List *list)
189 {
190     RCL_Debug_assert(listInfo != NULL);
191     RCL_Debug_assert(list != NULL);
192 
193     listInfo->multiBuffers = list;
194     listInfo->nextBuffer = (RCL_MultiBuffer *) List_head(list);
195     if (listInfo->nextBuffer != NULL)
196     {
197         listInfo->nextIndex = listInfo->nextBuffer->headIndex;
198     }
199     else
200     {
201         listInfo->nextIndex = 0;
202     }
203 }
204 
205 /*
206  *  ======== RCL_MultiBuffer_RxEntry_next ========
207  */
RCL_MultiBuffer_RxEntry_next(RCL_MultiBuffer_ListInfo * listInfo)208 RCL_Buffer_DataEntry *RCL_MultiBuffer_RxEntry_next(RCL_MultiBuffer_ListInfo *listInfo)
209 {
210     RCL_Buffer_DataEntry *rxEntry = NULL;
211 
212     RCL_Debug_assert(listInfo != NULL);
213     RCL_MultiBuffer *nextBuffer = listInfo->nextBuffer;
214 
215     if (nextBuffer == NULL)
216     {
217         RCL_Debug_assert(listInfo->multiBuffers != NULL);
218         nextBuffer = RCL_MultiBuffer_head(listInfo->multiBuffers);
219     }
220 
221     if (nextBuffer != NULL)
222     {
223         int32_t nextIndex = listInfo->nextIndex;
224         int32_t tailIndex = nextBuffer->tailIndex;
225         if (nextIndex >= tailIndex)
226         {
227             if (nextBuffer->state == RCL_BufferStateFinished)
228             {
229                 nextBuffer = (RCL_MultiBuffer *) List_next((List_Elem *) nextBuffer);
230                 nextIndex = 0;
231                 tailIndex = nextBuffer->tailIndex;
232             }
233         }
234 
235         if (nextIndex < tailIndex)
236         {
237             rxEntry = (RCL_Buffer_DataEntry *) &nextBuffer->data[nextIndex];
238             nextIndex += RCL_Buffer_DataEntry_paddedLen(rxEntry->length);
239             RCL_Debug_assert(nextIndex <= tailIndex);
240             if (nextIndex >= tailIndex)
241             {
242                 if (nextBuffer->state == RCL_BufferStateFinished)
243                 {
244                     nextBuffer = (RCL_MultiBuffer *) List_next((List_Elem *) nextBuffer);
245                     nextIndex = 0;
246                 }
247             }
248         }
249         listInfo->nextBuffer = nextBuffer;
250         listInfo->nextIndex = nextIndex;
251     }
252     return rxEntry;
253 }
254 
255 /*
256  *  ======== RCL_MultiBuffer_RxEntry_isLast ========
257  */
RCL_MultiBuffer_RxEntry_isLast(RCL_MultiBuffer_ListInfo * listInfo)258 bool RCL_MultiBuffer_RxEntry_isLast(RCL_MultiBuffer_ListInfo *listInfo)
259 {
260     RCL_Debug_assert(listInfo != NULL);
261 
262     RCL_MultiBuffer *nextBuffer = listInfo->nextBuffer;
263 
264     if (nextBuffer != NULL)
265     {
266         return RxEntry_isAtEnd(nextBuffer, listInfo->nextIndex);
267     }
268     else {
269         RCL_Debug_assert(listInfo->multiBuffers != NULL);
270         return RxEntry_isAtEnd((RCL_MultiBuffer *)List_head(listInfo->multiBuffers), 0);
271     }
272 }
273 
274 /*
275  *  ======== RCL_MultiBuffer_RxEntry_consume ========
276  */
RCL_MultiBuffer_RxEntry_consume(RCL_MultiBuffer_ListInfo * listInfo,List_List * consumedBuffers)277 void RCL_MultiBuffer_RxEntry_consume(RCL_MultiBuffer_ListInfo *listInfo, List_List *consumedBuffers)
278 {
279     RCL_Debug_assert(listInfo != NULL);
280 
281     List_List *multiBuffers = listInfo->multiBuffers;
282     RCL_Debug_assert(multiBuffers != NULL);
283 
284     RCL_MultiBuffer *nextBuffer = listInfo->nextBuffer;
285     RCL_MultiBuffer *head = RCL_MultiBuffer_head(multiBuffers);
286     if (head != NULL)
287     {
288         while (head != nextBuffer)
289         {
290             RCL_Debug_assert(head != NULL);
291             List_consumeAndStore(multiBuffers, consumedBuffers);
292             head = (RCL_MultiBuffer *) List_next((List_Elem *) head);
293         }
294     }
295 }
296 
297 /*
298  *  ======== RCL_MultiBuffer_findFirstWritableBuffer ========
299  */
RCL_MultiBuffer_findFirstWritableBuffer(RCL_MultiBuffer * head)300 RCL_MultiBuffer *RCL_MultiBuffer_findFirstWritableBuffer(RCL_MultiBuffer *head)
301 {
302     RCL_MultiBuffer *curBuffer = head;
303     while (curBuffer != NULL && curBuffer->state == RCL_BufferStateFinished)
304     {
305         curBuffer = (RCL_MultiBuffer *) List_next((List_Elem *)curBuffer);
306     }
307     return curBuffer;
308 }
309 
310 /*
311  *  ======== RCL_MultiBuffer_getBuffer ========
312  */
RCL_MultiBuffer_getBuffer(RCL_MultiBuffer * curBuffer,uint32_t minLength)313 RCL_MultiBuffer *RCL_MultiBuffer_getBuffer(RCL_MultiBuffer *curBuffer,
314                                            uint32_t minLength)
315 {
316     /* Try to find a buffer with enough space */
317     if (curBuffer != NULL)
318     {
319         /* Check if first buffer in queue needs initialization */
320         if (curBuffer->state != RCL_BufferStateInUse)
321         {
322             /* Initialize buffer for use */
323             curBuffer->state = RCL_BufferStateInUse;
324             /* Initialize indeces */
325             curBuffer->headIndex = 0;
326             curBuffer->tailIndex = 0;
327         }
328         if (minLength + curBuffer->tailIndex > curBuffer->length)
329         {
330             /* Not room in this buffer. Need to go to next buffer - unless buffer is empty */
331             if (curBuffer->tailIndex == 0)
332             {
333                 /* New buffer already - give up, as buffer is too small */
334                 curBuffer = NULL;
335             }
336             else
337             {
338                 curBuffer->state = RCL_BufferStateFinished;
339                 curBuffer = (RCL_MultiBuffer *) List_next((List_Elem *)curBuffer);
340                 /* Check that buffer is available */
341                 if (curBuffer != NULL) {
342                     /* Make sure that length is enough */
343                     if (minLength > curBuffer->length)
344                     {
345                         /* Buffer too short */
346                         curBuffer = NULL;
347                     }
348                     else
349                     {
350                         /* Initialize buffer for use */
351                         curBuffer->state = RCL_BufferStateInUse;
352                         /* Initialize indeces */
353                         curBuffer->headIndex = 0;
354                         curBuffer->tailIndex = 0;
355                     }
356                 }
357             }
358         }
359     }
360 
361     return curBuffer;
362 }
363 
364 /*
365  *  ======== RCL_MultiBuffer_findAvailableRxSpace ========
366  */
RCL_MultiBuffer_findAvailableRxSpace(const RCL_MultiBuffer * curBuffer)367 uint32_t RCL_MultiBuffer_findAvailableRxSpace(const RCL_MultiBuffer *curBuffer)
368 {
369     uint32_t space = 0;
370 
371     if (curBuffer != NULL)
372     {
373         /* Find available space in current buffer */
374         if (curBuffer->state == RCL_BufferStateInUse)
375         {
376             const RCL_MultiBuffer *nextBuffer;
377             nextBuffer = (RCL_MultiBuffer *) List_next((List_Elem *)curBuffer);
378             /* Check if there is another buffer available */
379             if (nextBuffer == NULL)
380             {
381                 /* No - use remaining space in this buffer */
382                 space = curBuffer->length - curBuffer->tailIndex;
383             }
384             else
385             {
386                 /* Yes - use space in next buffer */
387                 space = nextBuffer->length;
388             }
389         }
390         else
391         {
392             space = curBuffer->length;
393         }
394     }
395     return space;
396 }
397 
398 /*
399  *  ======== RxEntry_isAtEnd ========
400  */
RxEntry_isAtEnd(RCL_MultiBuffer * multiBuffer,uint16_t curIndex)401 static bool RxEntry_isAtEnd(RCL_MultiBuffer *multiBuffer, uint16_t curIndex)
402 {
403     bool isAtEnd = true;
404 
405     if (multiBuffer != NULL)
406     {
407         if (curIndex < multiBuffer->tailIndex)
408         {
409             isAtEnd = false;
410         }
411         else
412         {
413             if (multiBuffer->state == RCL_BufferStateFinished)
414             {
415                 /* Look in next MultiBuffer to see if there is data there */
416                 multiBuffer = (RCL_MultiBuffer *) List_next((List_Elem *)multiBuffer);
417                 if (multiBuffer != NULL && multiBuffer->tailIndex > 0)
418                 {
419                     isAtEnd = false;
420                 }
421             }
422         }
423     }
424 
425     return isAtEnd;
426 }
427 
428 /*
429  *  ======== List_consumeAndStore ========
430  */
List_consumeAndStore(List_List * list,List_List * consumedBuffers)431 static void List_consumeAndStore(List_List *list, List_List *consumedBuffers)
432 {
433     List_Elem *consumedBuffer = List_get(list);
434 
435     if (consumedBuffers != NULL)
436     {
437         List_put(consumedBuffers, consumedBuffer);
438     }
439 }
440