Open FFBoard
Open source force feedback firmware
tusb_fifo.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 Ha Thach (tinyusb.org)
5 * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 *
25 * This file is part of the TinyUSB stack.
26 */
27
28#include "osal/osal.h"
29#include "tusb_fifo.h"
30
31#define TU_FIFO_DBG 0
32
33// Suppress IAR warning
34// Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
35#if defined(__ICCARM__)
36#pragma diag_suppress = Pa082
37#endif
38
39#if OSAL_MUTEX_REQUIRED
40
41TU_ATTR_ALWAYS_INLINE static inline void _ff_lock(osal_mutex_t mutex)
42{
43 if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER);
44}
45
46TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex)
47{
48 if (mutex) osal_mutex_unlock(mutex);
49}
50
51#else
52
53#define _ff_lock(_mutex)
54#define _ff_unlock(_mutex)
55
56#endif
57
62typedef enum
63{
65#ifdef TUP_MEM_CONST_ADDR
67#endif
69
70bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable)
71{
72 // Limit index space to 2*depth - this allows for a fast "modulo" calculation
73 // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable
74 // only if overflow happens once (important for unsupervised DMA applications)
75 if (depth > 0x8000) return false;
76
79
80 f->buffer = (uint8_t*) buffer;
81 f->depth = depth;
82 f->item_size = (uint16_t) (item_size & 0x7FFF);
83 f->overwritable = overwritable;
84 f->rd_idx = 0;
85 f->wr_idx = 0;
86
89
90 return true;
91}
92
93//--------------------------------------------------------------------+
94// Pull & Push
95//--------------------------------------------------------------------+
96
97#ifdef TUP_MEM_CONST_ADDR
98// Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address
99// Code adapted from dcd_synopsys.c
100// TODO generalize with configurable 1 byte or 4 byte each read
101static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len)
102{
103 volatile const uint32_t * reg_rx = (volatile const uint32_t *) app_buf;
104
105 // Reading full available 32 bit words from const app address
106 uint16_t full_words = len >> 2;
107 while(full_words--)
108 {
109 tu_unaligned_write32(ff_buf, *reg_rx);
110 ff_buf += 4;
111 }
112
113 // Read the remaining 1-3 bytes from const app address
114 uint8_t const bytes_rem = len & 0x03;
115 if ( bytes_rem )
116 {
117 uint32_t tmp32 = *reg_rx;
118 memcpy(ff_buf, &tmp32, bytes_rem);
119 }
120}
121
122// Intended to be used to write to hardware USB FIFO in e.g. STM32
123// where all data is written to a constant address in full word copies
124static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len)
125{
126 volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf;
127
128 // Write full available 32 bit words to const address
129 uint16_t full_words = len >> 2;
130 while(full_words--)
131 {
132 *reg_tx = tu_unaligned_read32(ff_buf);
133 ff_buf += 4;
134 }
135
136 // Write the remaining 1-3 bytes into const address
137 uint8_t const bytes_rem = len & 0x03;
138 if ( bytes_rem )
139 {
140 uint32_t tmp32 = 0;
141 memcpy(&tmp32, ff_buf, bytes_rem);
142
143 *reg_tx = tmp32;
144 }
145}
146#endif
147
148// send one item to fifo WITHOUT updating write pointer
149static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel)
150{
151 memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size);
152}
153
154// send n items to fifo WITHOUT updating write pointer
155static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode)
156{
157 uint16_t const lin_count = f->depth - wr_ptr;
158 uint16_t const wrap_count = n - lin_count;
159
160 uint16_t lin_bytes = lin_count * f->item_size;
161 uint16_t wrap_bytes = wrap_count * f->item_size;
162
163 // current buffer of fifo
164 uint8_t* ff_buf = f->buffer + (wr_ptr * f->item_size);
165
166 switch (copy_mode)
167 {
168 case TU_FIFO_COPY_INC:
169 if(n <= lin_count)
170 {
171 // Linear only
172 memcpy(ff_buf, app_buf, n*f->item_size);
173 }
174 else
175 {
176 // Wrap around
177
178 // Write data to linear part of buffer
179 memcpy(ff_buf, app_buf, lin_bytes);
180
181 // Write data wrapped around
182 // TU_ASSERT(nWrap_bytes <= f->depth, );
183 memcpy(f->buffer, ((uint8_t const*) app_buf) + lin_bytes, wrap_bytes);
184 }
185 break;
186#ifdef TUP_MEM_CONST_ADDR
188 // Intended for hardware buffers from which it can be read word by word only
189 if(n <= lin_count)
190 {
191 // Linear only
192 _ff_push_const_addr(ff_buf, app_buf, n*f->item_size);
193 }
194 else
195 {
196 // Wrap around case
197
198 // Write full words to linear part of buffer
199 uint16_t nLin_4n_bytes = lin_bytes & 0xFFFC;
200 _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes);
201 ff_buf += nLin_4n_bytes;
202
203 // There could be odd 1-3 bytes before the wrap-around boundary
204 uint8_t rem = lin_bytes & 0x03;
205 if (rem > 0)
206 {
207 volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf;
208
209 uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem);
210 wrap_bytes -= remrem;
211
212 uint32_t tmp32 = *rx_fifo;
213 uint8_t * src_u8 = ((uint8_t *) &tmp32);
214
215 // Write 1-3 bytes before wrapped boundary
216 while(rem--) *ff_buf++ = *src_u8++;
217
218 // Read more bytes to beginning to complete a word
219 ff_buf = f->buffer;
220 while(remrem--) *ff_buf++ = *src_u8++;
221 }
222 else
223 {
224 ff_buf = f->buffer; // wrap around to beginning
225 }
226
227 // Write data wrapped part
228 if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes);
229 }
230 break;
231#endif
232 default: break;
233 }
234}
235
236// get one item from fifo WITHOUT updating read pointer
237static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel)
238{
239 memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size);
240}
241
242// get n items from fifo WITHOUT updating read pointer
243static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_copy_mode_t copy_mode)
244{
245 uint16_t const lin_count = f->depth - rd_ptr;
246 uint16_t const wrap_count = n - lin_count; // only used if wrapped
247
248 uint16_t lin_bytes = lin_count * f->item_size;
249 uint16_t wrap_bytes = wrap_count * f->item_size;
250
251 // current buffer of fifo
252 uint8_t* ff_buf = f->buffer + (rd_ptr * f->item_size);
253
254 switch (copy_mode)
255 {
256 case TU_FIFO_COPY_INC:
257 if ( n <= lin_count )
258 {
259 // Linear only
260 memcpy(app_buf, ff_buf, n*f->item_size);
261 }
262 else
263 {
264 // Wrap around
265
266 // Read data from linear part of buffer
267 memcpy(app_buf, ff_buf, lin_bytes);
268
269 // Read data wrapped part
270 memcpy((uint8_t*) app_buf + lin_bytes, f->buffer, wrap_bytes);
271 }
272 break;
273#ifdef TUP_MEM_CONST_ADDR
275 if ( n <= lin_count )
276 {
277 // Linear only
278 _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size);
279 }
280 else
281 {
282 // Wrap around case
283
284 // Read full words from linear part of buffer
285 uint16_t lin_4n_bytes = lin_bytes & 0xFFFC;
286 _ff_pull_const_addr(app_buf, ff_buf, lin_4n_bytes);
287 ff_buf += lin_4n_bytes;
288
289 // There could be odd 1-3 bytes before the wrap-around boundary
290 uint8_t rem = lin_bytes & 0x03;
291 if (rem > 0)
292 {
293 volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf;
294
295 uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem);
296 wrap_bytes -= remrem;
297
298 uint32_t tmp32=0;
299 uint8_t * dst_u8 = (uint8_t *)&tmp32;
300
301 // Read 1-3 bytes before wrapped boundary
302 while(rem--) *dst_u8++ = *ff_buf++;
303
304 // Read more bytes from beginning to complete a word
305 ff_buf = f->buffer;
306 while(remrem--) *dst_u8++ = *ff_buf++;
307
308 *reg_tx = tmp32;
309 }
310 else
311 {
312 ff_buf = f->buffer; // wrap around to beginning
313 }
314
315 // Read data wrapped part
316 if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes);
317 }
318 break;
319#endif
320 default: break;
321 }
322}
323
324//--------------------------------------------------------------------+
325// Helper
326//--------------------------------------------------------------------+
327
328// return only the index difference and as such can be used to determine an overflow i.e overflowable count
329TU_ATTR_ALWAYS_INLINE static inline
330uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx)
331{
332 // In case we have non-power of two depth we need a further modification
333 if (wr_idx >= rd_idx)
334 {
335 return (uint16_t) (wr_idx - rd_idx);
336 } else
337 {
338 return (uint16_t) (2*depth - (rd_idx - wr_idx));
339 }
340}
341
342// return remaining slot in fifo
343TU_ATTR_ALWAYS_INLINE static inline
344uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx)
345{
346 uint16_t const count = _ff_count(depth, wr_idx, rd_idx);
347 return (depth > count) ? (depth - count) : 0;
348}
349
350//--------------------------------------------------------------------+
351// Index Helper
352//--------------------------------------------------------------------+
353
354// Advance an absolute index
355// "absolute" index is only in the range of [0..2*depth)
356static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset)
357{
358 // We limit the index space of p such that a correct wrap around happens
359 // Check for a wrap around or if we are in unused index space - This has to be checked first!!
360 // We are exploiting the wrap around to the correct index
361 uint16_t new_idx = (uint16_t) (idx + offset);
362 if ( (idx > new_idx) || (new_idx >= 2*depth) )
363 {
364 uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1));
365 new_idx = (uint16_t) (new_idx + non_used_index_space);
366 }
367
368 return new_idx;
369}
370
371#if 0 // not used but
372// Backward an absolute index
373static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset)
374{
375 // We limit the index space of p such that a correct wrap around happens
376 // Check for a wrap around or if we are in unused index space - This has to be checked first!!
377 // We are exploiting the wrap around to the correct index
378 uint16_t new_idx = (uint16_t) (idx - offset);
379 if ( (idx < new_idx) || (new_idx >= 2*depth) )
380 {
381 uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1));
382 new_idx = (uint16_t) (new_idx - non_used_index_space);
383 }
384
385 return new_idx;
386}
387#endif
388
389// index to pointer, simply an modulo with minus.
390TU_ATTR_ALWAYS_INLINE static inline
391uint16_t idx2ptr(uint16_t depth, uint16_t idx)
392{
393 // Only run at most 3 times since index is limit in the range of [0..2*depth)
394 while ( idx >= depth ) idx -= depth;
395 return idx;
396}
397
398// Works on local copies of w
399// When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms
400// an full fifo i.e _ff_count() = depth
401TU_ATTR_ALWAYS_INLINE static inline
402uint16_t _ff_correct_read_index(tu_fifo_t* f, uint16_t wr_idx)
403{
404 uint16_t rd_idx;
405 if ( wr_idx >= f->depth )
406 {
407 rd_idx = wr_idx - f->depth;
408 }else
409 {
410 rd_idx = wr_idx + f->depth;
411 }
412
413 f->rd_idx = rd_idx;
414
415 return rd_idx;
416}
417
418// Works on local copies of w and r
419// Must be protected by mutexes since in case of an overflow read pointer gets modified
420static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16_t rd_idx)
421{
422 uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx);
423
424 // nothing to peek
425 if ( cnt == 0 ) return false;
426
427 // Check overflow and correct if required
428 if ( cnt > f->depth )
429 {
430 rd_idx = _ff_correct_read_index(f, wr_idx);
431 cnt = f->depth;
432 }
433
434 uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
435
436 // Peek data
437 _ff_pull(f, p_buffer, rd_ptr);
438
439 return true;
440}
441
442// Works on local copies of w and r
443// Must be protected by mutexes since in case of an overflow read pointer gets modified
444static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode)
445{
446 uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx);
447
448 // nothing to peek
449 if ( cnt == 0 ) return 0;
450
451 // Check overflow and correct if required
452 if ( cnt > f->depth )
453 {
454 rd_idx = _ff_correct_read_index(f, wr_idx);
455 cnt = f->depth;
456 }
457
458 // Check if we can read something at and after offset - if too less is available we read what remains
459 if ( cnt < n ) n = cnt;
460
461 uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
462
463 // Peek data
464 _ff_pull_n(f, p_buffer, n, rd_ptr, copy_mode);
465
466 return n;
467}
468
469static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode)
470{
471 if ( n == 0 ) return 0;
472
473 _ff_lock(f->mutex_wr);
474
475 uint16_t wr_idx = f->wr_idx;
476 uint16_t rd_idx = f->rd_idx;
477
478 uint8_t const* buf8 = (uint8_t const*) data;
479
480 TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ",
481 rd_idx, wr_idx, _ff_count(f->depth, wr_idx, rd_idx), _ff_remaining(f->depth, wr_idx, rd_idx), n);
482
483 if ( !f->overwritable )
484 {
485 // limit up to full
486 uint16_t const remain = _ff_remaining(f->depth, wr_idx, rd_idx);
487 n = tu_min16(n, remain);
488 }
489 else
490 {
491 // In over-writable mode, fifo_write() is allowed even when fifo is full. In such case,
492 // oldest data in fifo i.e at read pointer data will be overwritten
493 // Note: we can modify read buffer contents but we must not modify the read index itself within a write function!
494 // Since it would end up in a race condition with read functions!
495 if ( n >= f->depth )
496 {
497 // Only copy last part
498 if ( copy_mode == TU_FIFO_COPY_INC )
499 {
500 buf8 += (n - f->depth) * f->item_size;
501 }else
502 {
503 // TODO should read from hw fifo to discard data, however reading an odd number could
504 // accidentally discard data.
505 }
506
507 n = f->depth;
508
509 // We start writing at the read pointer's position since we fill the whole buffer
510 wr_idx = rd_idx;
511 }
512 else
513 {
514 uint16_t const overflowable_count = _ff_count(f->depth, wr_idx, rd_idx);
515 if (overflowable_count + n >= 2*f->depth)
516 {
517 // Double overflowed
518 // Index is bigger than the allowed range [0,2*depth)
519 // re-position write index to have a full fifo after pushed
520 wr_idx = advance_index(f->depth, rd_idx, f->depth - n);
521
522 // TODO we should also shift out n bytes from read index since we avoid changing rd index !!
523 // However memmove() is expensive due to actual copying + wrapping consideration.
524 // Also race condition could happen anyway if read() is invoke while moving result in corrupted memory
525 // currently deliberately not implemented --> result in incorrect data read back
526 }else
527 {
528 // normal + single overflowed:
529 // Index is in the range of [0,2*depth) and thus detect and recoverable. Recovering is handled in read()
530 // Therefore we just increase write index
531 // we will correct (re-position) read index later on in fifo_read() function
532 }
533 }
534 }
535
536 if (n)
537 {
538 uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
539
540 TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr);
541
542 // Write data
543 _ff_push_n(f, buf8, n, wr_ptr, copy_mode);
544
545 // Advance index
546 f->wr_idx = advance_index(f->depth, wr_idx, n);
547
548 TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx);
549 }
550
552
553 return n;
554}
555
556static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode)
557{
558 _ff_lock(f->mutex_rd);
559
560 // Peek the data
561 // f->rd_idx might get modified in case of an overflow so we can not use a local variable
562 n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode);
563
564 // Advance read pointer
565 f->rd_idx = advance_index(f->depth, f->rd_idx, n);
566
568 return n;
569}
570
571//--------------------------------------------------------------------+
572// Application API
573//--------------------------------------------------------------------+
574
575/******************************************************************************/
589/******************************************************************************/
591{
592 return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth);
593}
594
595/******************************************************************************/
607/******************************************************************************/
609{
610 return f->wr_idx == f->rd_idx;
611}
612
613/******************************************************************************/
625/******************************************************************************/
627{
628 return _ff_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth;
629}
630
631/******************************************************************************/
643/******************************************************************************/
645{
646 return _ff_remaining(f->depth, f->wr_idx, f->rd_idx);
647}
648
649/******************************************************************************/
669/******************************************************************************/
671{
672 return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth;
673}
674
675// Only use in case tu_fifo_overflow() returned true!
677{
678 _ff_lock(f->mutex_rd);
681}
682
683/******************************************************************************/
698/******************************************************************************/
700{
701 _ff_lock(f->mutex_rd);
702
703 // Peek the data
704 // f->rd_idx might get modified in case of an overflow so we can not use a local variable
705 bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx);
706
707 // Advance pointer
708 f->rd_idx = advance_index(f->depth, f->rd_idx, ret);
709
711 return ret;
712}
713
714/******************************************************************************/
729/******************************************************************************/
730uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n)
731{
733}
734
735#ifdef TUP_MEM_CONST_ADDR
736/******************************************************************************/
752/******************************************************************************/
754{
756}
757#endif
758
759/******************************************************************************/
771/******************************************************************************/
772bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer)
773{
774 _ff_lock(f->mutex_rd);
775 bool ret = _tu_fifo_peek(f, p_buffer, f->wr_idx, f->rd_idx);
777 return ret;
778}
779
780/******************************************************************************/
794/******************************************************************************/
795uint16_t tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n)
796{
797 _ff_lock(f->mutex_rd);
798 uint16_t ret = _tu_fifo_peek_n(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC);
800 return ret;
801}
802
803/******************************************************************************/
818/******************************************************************************/
819bool tu_fifo_write(tu_fifo_t* f, const void * data)
820{
821 _ff_lock(f->mutex_wr);
822
823 bool ret;
824 uint16_t const wr_idx = f->wr_idx;
825
826 if ( tu_fifo_full(f) && !f->overwritable )
827 {
828 ret = false;
829 }else
830 {
831 uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
832
833 // Write data
834 _ff_push(f, data, wr_ptr);
835
836 // Advance pointer
837 f->wr_idx = advance_index(f->depth, wr_idx, 1);
838
839 ret = true;
840 }
841
843
844 return ret;
845}
846
847/******************************************************************************/
860/******************************************************************************/
861uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n)
862{
864}
865
866#ifdef TUP_MEM_CONST_ADDR
867/******************************************************************************/
881/******************************************************************************/
882uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data, uint16_t n)
883{
885}
886#endif
887
888/******************************************************************************/
895/******************************************************************************/
897{
898 _ff_lock(f->mutex_wr);
899 _ff_lock(f->mutex_rd);
900
901 f->rd_idx = 0;
902 f->wr_idx = 0;
903
906 return true;
907}
908
909/******************************************************************************/
918/******************************************************************************/
919bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable)
920{
921 _ff_lock(f->mutex_wr);
922 _ff_lock(f->mutex_rd);
923
924 f->overwritable = overwritable;
925
928
929 return true;
930}
931
932/******************************************************************************/
947/******************************************************************************/
949{
950 f->wr_idx = advance_index(f->depth, f->wr_idx, n);
951}
952
953/******************************************************************************/
968/******************************************************************************/
970{
971 f->rd_idx = advance_index(f->depth, f->rd_idx, n);
972}
973
974/******************************************************************************/
988/******************************************************************************/
990{
991 // Operate on temporary values in case they change in between
992 uint16_t wr_idx = f->wr_idx;
993 uint16_t rd_idx = f->rd_idx;
994
995 uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx);
996
997 // Check overflow and correct if required - may happen in case a DMA wrote too fast
998 if (cnt > f->depth)
999 {
1000 _ff_lock(f->mutex_rd);
1001 rd_idx = _ff_correct_read_index(f, wr_idx);
1002 _ff_unlock(f->mutex_rd);
1003
1004 cnt = f->depth;
1005 }
1006
1007 // Check if fifo is empty
1008 if (cnt == 0)
1009 {
1010 info->len_lin = 0;
1011 info->len_wrap = 0;
1012 info->ptr_lin = NULL;
1013 info->ptr_wrap = NULL;
1014 return;
1015 }
1016
1017 // Get relative pointers
1018 uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
1019 uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
1020
1021 // Copy pointer to buffer to start reading from
1022 info->ptr_lin = &f->buffer[rd_ptr];
1023
1024 // Check if there is a wrap around necessary
1025 if (wr_ptr > rd_ptr)
1026 {
1027 // Non wrapping case
1028 info->len_lin = cnt;
1029
1030 info->len_wrap = 0;
1031 info->ptr_wrap = NULL;
1032 }
1033 else
1034 {
1035 info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full
1036
1037 info->len_wrap = cnt - info->len_lin;
1038 info->ptr_wrap = f->buffer;
1039 }
1040}
1041
1042/******************************************************************************/
1056/******************************************************************************/
1058{
1059 uint16_t wr_idx = f->wr_idx;
1060 uint16_t rd_idx = f->rd_idx;
1061 uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx);
1062
1063 if (remain == 0)
1064 {
1065 info->len_lin = 0;
1066 info->len_wrap = 0;
1067 info->ptr_lin = NULL;
1068 info->ptr_wrap = NULL;
1069 return;
1070 }
1071
1072 // Get relative pointers
1073 uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
1074 uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
1075
1076 // Copy pointer to buffer to start writing to
1077 info->ptr_lin = &f->buffer[wr_ptr];
1078
1079 if (wr_ptr < rd_ptr)
1080 {
1081 // Non wrapping case
1082 info->len_lin = rd_ptr-wr_ptr;
1083 info->len_wrap = 0;
1084 info->ptr_wrap = NULL;
1085 }
1086 else
1087 {
1088 info->len_lin = f->depth - wr_ptr;
1089 info->len_wrap = remain - info->len_lin; // Remaining length - n already was limited to remain or FIFO depth
1090 info->ptr_wrap = f->buffer; // Always start of buffer
1091 }
1092}
static struct @612 data
uint8_t const * buffer
Definition: midi_device.h:100
static TU_ATTR_ALWAYS_INLINE bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec)
static TU_ATTR_ALWAYS_INLINE bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
SemaphoreHandle_t osal_mutex_t
Definition: osal_freertos.h:54
static void * memcpy(void *dst, const void *src, size_t n)
Definition: ringbuffer.c:8
volatile uint16_t rd_idx
Definition: tusb_fifo.h:116
uint16_t depth
Definition: tusb_fifo.h:108
uint8_t * buffer
Definition: tusb_fifo.h:107
osal_mutex_t mutex_wr
Definition: tusb_fifo.h:119
volatile uint16_t wr_idx
Definition: tusb_fifo.h:115
osal_mutex_t mutex_rd
Definition: tusb_fifo.h:120
static TU_ATTR_ALWAYS_INLINE uint16_t tu_min16(uint16_t x, uint16_t y)
Definition: tusb_common.h:155
static TU_ATTR_ALWAYS_INLINE void tu_unaligned_write32(void *mem, uint32_t value)
Definition: tusb_common.h:213
static TU_ATTR_ALWAYS_INLINE uint32_t tu_unaligned_read32(const void *mem)
Definition: tusb_common.h:207
static uint16_t _tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_copy_mode_t copy_mode)
Definition: tusb_fifo.c:469
bool tu_fifo_overflowed(tu_fifo_t *f)
Check if overflow happened.
Definition: tusb_fifo.c:670
uint16_t tu_fifo_count(tu_fifo_t *f)
Get number of items in FIFO.
Definition: tusb_fifo.c:590
void tu_fifo_correct_read_pointer(tu_fifo_t *f)
Definition: tusb_fifo.c:676
uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t *f, const void *data, uint16_t n)
This function will write n elements into the array index specified by the write pointer and increment...
Definition: tusb_fifo.c:882
static TU_ATTR_ALWAYS_INLINE void _ff_lock(osal_mutex_t mutex)
Definition: tusb_fifo.c:41
static TU_ATTR_ALWAYS_INLINE uint16_t _ff_correct_read_index(tu_fifo_t *f, uint16_t wr_idx)
Definition: tusb_fifo.c:402
static void _ff_push_const_addr(uint8_t *ff_buf, const void *app_buf, uint16_t len)
Definition: tusb_fifo.c:101
void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
Get linear write info.
Definition: tusb_fifo.c:1057
static uint16_t _tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode)
Definition: tusb_fifo.c:444
bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable)
Definition: tusb_fifo.c:70
static void _ff_pull_n(tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_copy_mode_t copy_mode)
Definition: tusb_fifo.c:243
static bool _tu_fifo_peek(tu_fifo_t *f, void *p_buffer, uint16_t wr_idx, uint16_t rd_idx)
Definition: tusb_fifo.c:420
bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable)
Change the fifo mode to overwritable or not overwritable.
Definition: tusb_fifo.c:919
uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n)
This function will write n elements into the array index specified by the write pointer and increment...
Definition: tusb_fifo.c:861
uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n)
Read n items without removing it from the FIFO This function checks for an overflow and corrects read...
Definition: tusb_fifo.c:795
bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer)
Read one item without removing it from the FIFO. This function checks for an overflow and corrects re...
Definition: tusb_fifo.c:772
static void _ff_pull(tu_fifo_t *f, void *app_buf, uint16_t rel)
Definition: tusb_fifo.c:237
static TU_ATTR_ALWAYS_INLINE uint16_t idx2ptr(uint16_t depth, uint16_t idx)
Definition: tusb_fifo.c:391
static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset)
Definition: tusb_fifo.c:373
void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n)
Advance write pointer - intended to be used in combination with DMA. It is possible to fill the FIFO ...
Definition: tusb_fifo.c:948
uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t *f, void *buffer, uint16_t n)
This function will read n elements from the array index specified by the read pointer and increment t...
Definition: tusb_fifo.c:753
bool tu_fifo_full(tu_fifo_t *f)
Check if FIFO is full.
Definition: tusb_fifo.c:626
uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n)
This function will read n elements from the array index specified by the read pointer and increment t...
Definition: tusb_fifo.c:730
void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n)
Advance read pointer - intended to be used in combination with DMA. It is possible to read from the F...
Definition: tusb_fifo.c:969
static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset)
Definition: tusb_fifo.c:356
bool tu_fifo_read(tu_fifo_t *f, void *buffer)
Read one element out of the buffer.
Definition: tusb_fifo.c:699
bool tu_fifo_empty(tu_fifo_t *f)
Check if FIFO is empty.
Definition: tusb_fifo.c:608
static void _ff_push_n(tu_fifo_t *f, void const *app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode)
Definition: tusb_fifo.c:155
bool tu_fifo_write(tu_fifo_t *f, const void *data)
Write one element into the buffer.
Definition: tusb_fifo.c:819
static uint16_t _tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode)
Definition: tusb_fifo.c:556
static void _ff_push(tu_fifo_t *f, void const *app_buf, uint16_t rel)
Definition: tusb_fifo.c:149
tu_fifo_copy_mode_t
Write modes intended to allow special read and write functions to be able to copy data to and from US...
Definition: tusb_fifo.c:63
@ TU_FIFO_COPY_INC
Copy from/to an increasing source/destination address - default mode.
Definition: tusb_fifo.c:64
@ TU_FIFO_COPY_CST_FULL_WORDS
Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardwa...
Definition: tusb_fifo.c:66
static TU_ATTR_ALWAYS_INLINE void _ff_unlock(osal_mutex_t mutex)
Definition: tusb_fifo.c:46
uint16_t tu_fifo_remaining(tu_fifo_t *f)
Get remaining space in FIFO.
Definition: tusb_fifo.c:644
void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
Get read info.
Definition: tusb_fifo.c:989
static TU_ATTR_ALWAYS_INLINE uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx)
Definition: tusb_fifo.c:330
static void _ff_pull_const_addr(void *app_buf, const uint8_t *ff_buf, uint16_t len)
Definition: tusb_fifo.c:124
static TU_ATTR_ALWAYS_INLINE uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx)
Definition: tusb_fifo.c:344
bool tu_fifo_clear(tu_fifo_t *f)
Clear the fifo read and write pointers.
Definition: tusb_fifo.c:896