1 /*
2  * Copyright (c) 2020-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 #ifndef ti_drivers_RCL_Buffers_h__include
34 #define ti_drivers_RCL_Buffers_h__include
35 
36 #include <stdint.h>
37 #include <ti/drivers/utils/List.h>
38 
39 
40 /**
41  *  @brief Buffer state
42  */
43 typedef enum {
44     RCL_BufferStatePending  = 0U, /*!< Buffer is not yet accessed by RCL */
45     RCL_BufferStateInUse    = 1U, /*!< Buffer has been accessed by RCL, and may be accessed again */
46     RCL_BufferStateFinished = 2U  /*!< RCL is finished with the buffer. It may be reused or freed. */
47 } RCL_BufferState;
48 
49 typedef struct RCL_Buffer_TxBuffer_s      RCL_Buffer_TxBuffer;
50 typedef struct RCL_Buffer_DataEntry_s     RCL_Buffer_DataEntry;
51 typedef struct RCL_MultiBuffer_s          RCL_MultiBuffer;
52 typedef struct RCL_MultiBuffer_ListInfo_s RCL_MultiBuffer_ListInfo;
53 
54 /**
55  *  @brief Definition of an RCL Tx Buffer
56  *
57  *  Instances of %RCL_Buffer_TxBuffer shall be allocated by the protocol stacks.
58  */
59 struct RCL_Buffer_TxBuffer_s {
60     List_Elem            __elem__;
61     RCL_BufferState      state;                                  /*!< Buffer state */
62     uint16_t             length   __attribute__ ((aligned (4))); /*!< Number of bytes in buffer after the length field */
63     uint8_t              numPad;                                 /*!< Number of pad bytes before start of the packet */
64     uint8_t              pad0;                                   /*!< First pad byte, or first byte of the packet if numPad == 0 */
65     uint8_t              data[];                                 /*!< Remaining pad bytes and packet */
66 };
67 
68 /**
69  *  @brief Definition of an RCL Rx Buffer Entry
70  *
71  *  Instances of %RCL_Buffer_DataEntry are written by LRF into %RCL_MultiBuffer
72  *  instances allocated by the protocol stacks, or used for a single TX packet
73  */
74 struct RCL_Buffer_DataEntry_s {
75     uint16_t             length  __attribute__ ((aligned (4))); /*!< Number of bytes in buffer after the length field */
76     uint8_t              numPad;                                /*!< Number of pad bytes before start of the packet */
77     uint8_t              pad0;                                  /*!< First pad byte, or first byte of the packet if numPad == 0 */
78     uint8_t              data[];                                /*!< Remaining pad bytes and packet */
79 };
80 
81 /**
82  *  @brief Definition of an RCL Rx MultiBuffer
83  *
84  *  Instances of %RCL_MultiBuffer are allocated by the protocol stacks, and
85  *  provided to RCL
86  */
87 struct RCL_MultiBuffer_s {
88     List_Elem            __elem__;
89     RCL_BufferState      state;       /*!< Buffer state */
90     uint16_t             length;      /*!< Number of bytes in the data field */
91     uint16_t             headIndex;   /*!< Number of bytes consumed */
92     uint16_t             tailIndex;   /*!< Number of bytes written */
93     uint8_t              data[];      /*!< Data buffer consisting of %RCL_Buffer_DataEntry elements */
94 };
95 
96 /**
97  *  @brief Information about an RCL_MultiBuffer list being traversed
98  *
99  *  An instance of %RCL_MultiBuffer_ListInfo is used to hold information
100  *  of an RX queue which is read without consuming directly.
101  */
102 struct RCL_MultiBuffer_ListInfo_s {
103     List_List            *multiBuffers;    /*!< Pointer to list of MultiBuffers */
104     RCL_MultiBuffer      *nextBuffer;      /*!< Pointer to next MultiBuffer to traverse */
105     uint16_t             nextIndex;        /*!< Index of nextBuffer->data for next entry */
106 };
107 
108 /**
109  *  @brief Number of 32-bit words needed to hold a given number of bytes (rounded up)
110  */
111 #define RCL_Buffer_bytesToWords(byteLen) (((byteLen) + sizeof(uint32_t) - 1) / sizeof(uint32_t))
112 
113 /**
114  *  @brief Total length of a data entry in bytes based on length field of the entry
115  */
116 /* Include the data entry's length field and padding to uint32_t boundary */
117 #define RCL_Buffer_DataEntry_paddedLen(len) (RCL_Buffer_bytesToWords((len) + sizeof(uint16_t)) * sizeof(uint32_t))
118 
119 /** @defgroup bufferApiFunctions Buffer APIs
120  *  These functions are useful as part of the API to RCL
121  *  @{
122  */
123 
124 /**
125  *  @brief Total length of a data entry in bytes, including entry length field and padding
126  *
127  *  @param  numPad    Number of padding bytes in front of the packet
128  *
129  *  @param  hdrLen    Number of header bytes to hold
130  *
131  *  @param  dataLen   Number of payload bytes to hold
132  *
133  */
134 #define RCL_Buffer_entryLen(numPad, hdrLen, dataLen) (RCL_Buffer_DataEntry_paddedLen(sizeof(uint8_t) + (numPad) + (hdrLen) + (dataLen)))
135 
136 /**
137  *  @brief Total length of a TX buffer in bytes, including all fields and padding
138  *
139  *  @param  numPad    Number of padding bytes in front of the packet
140  *
141  *  @param  hdrLen    Number of header bytes to hold
142  *
143  *  @param  dataLen   Number of payload bytes to hold
144  *
145  */
146 #define RCL_TxBuffer_len(numPad, hdrLen, dataLen) (offsetof(RCL_Buffer_TxBuffer, length) + RCL_Buffer_entryLen(numPad, hdrLen, dataLen))
147 
148 /**
149  *  @brief Total length of a TX buffer in 32-bit words, including all fields and padding
150  *
151  *  @param  numPad    Number of padding bytes in front of the packet
152  *
153  *  @param  hdrLen    Number of header bytes to hold
154  *
155  *  @param  dataLen   Number of payload bytes to hold
156  *
157  */
158 #define RCL_TxBuffer_len_u32(numPad, hdrLen, dataLen) (RCL_Buffer_bytesToWords(RCL_TxBuffer_len(numPad, hdrLen, dataLen)))
159 
160 /**
161  *  @brief Total length of a multi buffer in bytes, including all fields
162  *
163  *  @param  dataLen   Number of bytes available to store data entries
164  *
165  */
166 #define RCL_MultiBuffer_len(dataLen) (offsetof(RCL_MultiBuffer, data) + (dataLen))
167 
168 /**
169  *  @brief Total length of a multi buffer in 32-bit words, including all fields
170  *
171  *  @param  dataLen   Number of bytes available to store data entries
172  *
173  */
174 #define RCL_MultiBuffer_len_u32(dataLen) (RCL_Buffer_bytesToWords(RCL_MultiBuffer_len(dataLen)))
175 
176 /**
177  *  @brief  Function to atomically get the first elem in a Tx Buffer list
178  *
179  *  @param  list A pointer to a linked list of Tx Buffers
180  *
181  *  @return Pointer the first elem in the linked list or NULL if empty
182  */
RCL_TxBuffer_get(List_List * list)183 static inline RCL_Buffer_TxBuffer *RCL_TxBuffer_get(List_List *list)
184 {
185     return (RCL_Buffer_TxBuffer *)List_get(list);
186 }
187 
188 /**
189  *  @brief  Function to return the head of a TxBuffer list
190  *
191  *  This function does not remove the head, it simply returns a pointer to
192  *  it. This function is typically used when traversing a linked list.
193  *
194  *  @param  list A pointer to the linked list of Tx Buffers
195  *
196  *  @return Pointer to the first elem in the linked list or NULL if empty
197  */
RCL_TxBuffer_head(List_List * list)198 static inline RCL_Buffer_TxBuffer *RCL_TxBuffer_head(List_List *list)
199 {
200     return (RCL_Buffer_TxBuffer *) (list->head);
201 }
202 
203 /**
204  *  @brief  Function to return the next elem in a linked list of Tx Buffers
205  *
206  *  This function does not remove the elem, it simply returns a pointer to
207  *  next one. This function is typically used when traversing a linked list.
208  *
209  *  @param  elem Elem in the TxBuffer list
210  *
211  *  @return Pointer to the next elem in linked list or NULL if at the end
212  */
RCL_TxBuffer_next(RCL_Buffer_TxBuffer * elem)213 static inline RCL_Buffer_TxBuffer *RCL_TxBuffer_next(RCL_Buffer_TxBuffer *elem)
214 {
215     return (RCL_Buffer_TxBuffer *)(((List_Elem *)elem)->next);
216 }
217 
218 /**
219  *  @brief  Function to initialize a TX buffer entry for use by RCL
220  *
221  * Initialize a new TX buffer entry with the correct length and padding
222  *
223  *  @param  buffer    Tx buffer to initialize
224  *
225  *  @param  numPad    Number of padding bytes in front of the packet
226  *
227  *  @param  hdrLen    Number of header bytes to hold
228  *
229  *  @param  dataLen   Number of payload bytes to hold
230  *
231  * @return  Pointer to address where first header byte should be stored (followed by payload)
232 */
233 extern uint8_t *RCL_TxBuffer_init(RCL_Buffer_TxBuffer *buffer, uint32_t numPad, uint32_t hdrLen,
234                                   uint32_t dataLen);
235 
236 /**
237  *  @brief  Function to atomically put an elem onto the end of a Tx Buffer list
238  *
239  * Add an entry to the TX buffer list and notify the running command if there is any
240  *
241  *  @param  list A pointer to the Tx buffer list
242  *
243  *  @param  elem Element to place onto the end of the linked list
244  */
245 extern void RCL_TxBuffer_put(List_List *list, RCL_Buffer_TxBuffer *elem);
246 
247 /**
248  *  @brief  Function to return the head of a MultiBuffer list
249  *
250  *  This function does not remove the head, it simply returns a pointer to
251  *  it. This function is typically used when traversing a linked list.
252  *
253  *  @param  list A pointer to the linked list of Multi Buffers
254  *
255  *  @return Pointer to the first elem in the linked list or NULL if empty
256  */
RCL_MultiBuffer_head(List_List * list)257 static inline RCL_MultiBuffer *RCL_MultiBuffer_head(List_List *list)
258 {
259     return (RCL_MultiBuffer *) (list->head);
260 }
261 
262 /**
263  *  @brief  Function to return the next elem in a linked list of MultiBuffers
264  *
265  *  This function does not remove the elem, it simply returns a pointer to
266  *  next one. This function is typically used when traversing a linked list.
267  *
268  *  @param  elem Elem in the MultiBuffer list
269  *
270  *  @return Pointer to the next elem in linked list or NULL if at the end
271  */
RCL_MultiBuffer_next(RCL_MultiBuffer * elem)272 static inline RCL_MultiBuffer *RCL_MultiBuffer_next(RCL_MultiBuffer *elem)
273 {
274     return (RCL_MultiBuffer *)(((List_Elem *)elem)->next);
275 }
276 
277 /**
278  *  @brief  Function to get the first elem in a MultiBuffer list
279  *
280  *  Returns the first whole MultiBuffer from a list. Note that this
281  *  will be done even if the buffer wasn't finished and that the
282  *  buffer may contain several entries.
283  *
284  *  @param  list A pointer to a linked list of Tx Buffers
285  *
286  *  @return Pointer the first elem in the linked list or NULL if empty
287  */
RCL_MultiBuffer_get(List_List * list)288 static inline RCL_MultiBuffer *RCL_MultiBuffer_get(List_List *list)
289 {
290     return (RCL_MultiBuffer *)List_get(list);
291 }
292 
293 /**
294  *  @brief  Function to clear a multi buffer entry for re-use by RCL
295  *
296  * Clear a new multi buffer entry so that it can be re-used by RCL for
297  * storing received packets
298  *
299  *  @param  buffer Multi buffer to clear
300  */
301 extern void RCL_MultiBuffer_clear(RCL_MultiBuffer *buffer);
302 
303 /**
304  *  @brief  Function to initialize a multi buffer entry for use by RCL
305  *
306  * Initialize a new multi buffer entry so that it can be provided to
307  * RCL for storing received packets
308  *
309  *  @param  buffer Multi buffer to initialize
310  *
311  *  @param  size Size of the buffer in bytes including all fields
312  */
313 extern void RCL_MultiBuffer_init(RCL_MultiBuffer *buffer, size_t size);
314 
315 /**
316  *  @brief  Function to get the first entry in a MultiBuffer list
317  *
318  *  This function gets the first entry in a MultiBuffer list and
319  *  consumes it. If one or two whole %RCL_MultiBuffer are consumed as
320  *  a result of this, they are added to the consumedBuffers list.
321  *
322  *  @param  list A pointer to a linked list of MultiBuffers
323  *
324  *  @param consumedBuffers A pointer to a linked list which will hold
325  *                          the buffers that were consumed and can now
326  *                          be re-used. The list is not initialized,
327  *                          so that it is possible to get consumed
328  *                          entries appended. If this is not desired,
329  *                          the list should be cleared first. If NULL,
330  *                          consumed buffers are not reported
331  *
332  *  @return Pointer the first entry in the linked list or NULL if empty
333  */
334 extern RCL_Buffer_DataEntry *RCL_MultiBuffer_RxEntry_get(List_List *list, List_List *consumedBuffers);
335 
336 /**
337  *  @brief  Function to check if the MultiBuffer List is out of entries
338  *
339  *  This function returns true if there are no more entries to read
340  *  from a list of MultiBuffers
341  *
342  *  @param  list        Pointer to list of multi buffers
343  *
344  *  @return true if there are no more entries to read now; false if
345  *          there are more entries to read
346  */
347 extern bool RCL_MultiBuffer_RxEntry_isEmpty(List_List *list);
348 
349 /**
350  *  @brief  Function to initialize information for traversing a multi buffer list
351  *
352  *  This function prepares a struct for holding information about entries being
353  *  read from a list of multi buffers. It will set up the struct to start by
354  *  traversing the head of the list.
355  *
356  *  @param  listInfo    Pointer to list information which will be set up to start
357  *                      traversing the head of the list
358  *
359  *  @param  list        Pointer to list of multi buffers
360  *
361  */
362 extern void RCL_MultiBuffer_ListInfo_init(RCL_MultiBuffer_ListInfo *listInfo, List_List *list);
363 
364 /**
365  *  @brief  Function to return the next entry in a list of multi buffers
366  *
367  *  This function does not remove the entry, it simply returns a pointer to
368  *  next one. This function is typically used when traversing a linked list of
369  *  multi buffers.
370  *
371  *  @param  listInfo    Struct with information of the next entry to
372  *                      access. Set up using
373  *                      %RCL_MultiBuffer_ListInfo_init before starting.
374  *
375  *  @return Pointer to the entry in the linked list of MultiBuffers or NULL if
376  *          at the end
377  */
378 extern RCL_Buffer_DataEntry *RCL_MultiBuffer_RxEntry_next(RCL_MultiBuffer_ListInfo *listInfo);
379 
380 /**
381  *  @brief  Function to check a traversed entry was the last one
382  *
383  *  This function returns true if the latest entry returned by
384  *  %RCL_MultiBuffer_RxEntry_next was the last one
385  *
386  *  @param  listInfo    Struct with information of the next entry to
387  *                      access
388  *
389  *  @return true if there are no more entries to read now; false if
390  *          there are more entries to read
391  */
392 extern bool RCL_MultiBuffer_RxEntry_isLast(RCL_MultiBuffer_ListInfo *listInfo);
393 
394 /**
395  *  @brief  Function to atomically put an elem onto the end of a multi buffer list
396  *
397  *  Add an entry to the multi buffer list and notify the running command if there is any
398  *
399  *  @param  list A pointer to the multi buffer list
400  *
401  *  @param  elem Multi buffer to place onto the end of the linked list
402  */
403 extern void RCL_MultiBuffer_put(List_List *list, RCL_MultiBuffer *elem);
404 /** @}
405  */
406 
407 /** @defgroup bufferHandlerFunctions Buffer Handler Functions
408  *  These functions are meant mostly to be used by handlers and RCL itself
409  *  @{
410  */
411 /**
412  *  @brief Find the first writable buffer in a list of MultiBuffers
413  *
414  *  @note This function is intended as internal to RCL and its handlers
415  *
416  *  @param head [in] - The head of the list
417  *
418  *  @return Pointer to first non-finished MultiBuffer after head; NULL if none
419  */
420 RCL_MultiBuffer *RCL_MultiBuffer_findFirstWritableBuffer(RCL_MultiBuffer *head);
421 
422 /**
423  *  @brief Returns a buffer with at least `minLength` bytes remaining capacity.
424  *
425  *  Checks current buffer and next buffer against minLength, returns current if enough
426  *  space, otherwise moves to next buffer.
427  *
428  *  If no such buffer is available, NULL is returned.
429  *
430  *  @note This function is intended as internal to RCL and its handlers
431  *
432  *  @note The caller is responsible for issuing the necessary event if the decision is
433  *        made to use the returned buffer and it is != curBuffer, or if the result of a
434  *        NULL return is to stop using curBuffer.
435  *
436  *  @param curBuffer [in] - Buffer to search from
437  *  @param minLength [in] - Minimum amount of bytes needed in buffer
438  *
439  *  @return Suitable %RCL_MultiBuffer or NULL
440  */
441 RCL_MultiBuffer *RCL_MultiBuffer_getBuffer(RCL_MultiBuffer *curBuffer,
442                                            uint32_t minLength);
443 
444 /**
445  *  @brief Find the minumum number of bytes that can be stored in available MultiBuffers
446  *
447  *  Finds the number of bytes that can be guaranteed to be possible to store in available
448  *  MultiBuffers, regardless of packet sizes. This is the size of a free MultiBuffer if that
449  *  is available, or the remaining space in a MultiBuffer.
450  *
451  *  @note This function is intended as internal to RCL and its handlers
452  *
453  *  @param curBuffer [in] - Pointer to the first writable %RCL_MultiBuffer
454  *
455  *  @return Number of available bytes
456  */
457 uint32_t RCL_MultiBuffer_findAvailableRxSpace(const RCL_MultiBuffer *curBuffer);
458 
459 /**
460  *  @brief Find the first byte to write in an %RCL_MultiBuffer
461  *
462  *  @note This function is intended as internal to RCL and its handlers
463  *
464  *  @param curBuffer [in] - Pointer to %RCL_MultiBuffer
465  *
466  *  @return Pointer to first writable byte in curBuffer
467  */
RCL_MultiBuffer_getNextWritableByte(RCL_MultiBuffer * curBuffer)468 static inline uint8_t *RCL_MultiBuffer_getNextWritableByte(RCL_MultiBuffer *curBuffer)
469 {
470     return & curBuffer->data[curBuffer->tailIndex];
471 }
472 
473 /**
474  *  @brief Update number of bytes written to %RCL_MultiBuffer
475  *
476  *  @note This function is intended as internal to RCL and its handlers
477  *
478  *  @note The caller is responsible for ensuring that the buffer can fit the bytes
479  *        to be committed for issuing the necessary event if the decision is
480  *
481  *  @param curBuffer [in] - Pointer to %RCL_MultiBuffer
482  *  @param numBytes [in] - Number of bytes that have been written
483  */
RCL_MultiBuffer_commitBytes(RCL_MultiBuffer * curBuffer,uint32_t numBytes)484 static inline void RCL_MultiBuffer_commitBytes(RCL_MultiBuffer *curBuffer, uint32_t numBytes)
485 {
486     curBuffer->tailIndex += numBytes;
487 }
488 /** @}
489  */
490 
491 #endif
492