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