ChibiOS/HAL  6.1.0
hal_buffers.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 /**
18  * @file hal_buffers.c
19  * @brief I/O Buffers code.
20  *
21  * @addtogroup HAL_BUFFERS
22  * @details Buffers Queues are used when there is the need to exchange
23  * fixed-length data buffers between ISRs and threads.
24  * On the ISR side data can be exchanged only using buffers,
25  * on the thread side data can be exchanged both using buffers and/or
26  * using an emulation of regular byte queues.
27  * There are several kind of buffers queues:<br>
28  * - <b>Input queue</b>, unidirectional queue where the writer is the
29  * ISR side and the reader is the thread side.
30  * - <b>Output queue</b>, unidirectional queue where the writer is the
31  * ISR side and the reader is the thread side.
32  * - <b>Full duplex queue</b>, bidirectional queue. Full duplex queues
33  * are implemented by pairing an input queue and an output queue
34  * together.
35  * .
36  * @{
37  */
38 
39 #include <string.h>
40 
41 #include "hal.h"
42 
43 /*===========================================================================*/
44 /* Driver local definitions. */
45 /*===========================================================================*/
46 
47 /*===========================================================================*/
48 /* Driver exported variables. */
49 /*===========================================================================*/
50 
51 /*===========================================================================*/
52 /* Driver local variables and types. */
53 /*===========================================================================*/
54 
55 /*===========================================================================*/
56 /* Driver local functions. */
57 /*===========================================================================*/
58 
59 /*===========================================================================*/
60 /* Driver exported functions. */
61 /*===========================================================================*/
62 
63 /**
64  * @brief Initializes an input buffers queue object.
65  *
66  * @param[out] ibqp pointer to the @p input_buffers_queue_t object
67  * @param[in] suspended initial state of the queue
68  * @param[in] bp pointer to a memory area allocated for buffers
69  * @param[in] size buffers size
70  * @param[in] n number of buffers
71  * @param[in] infy callback called when a buffer is returned to the queue
72  * @param[in] link application defined pointer
73  *
74  * @init
75  */
76 void ibqObjectInit(input_buffers_queue_t *ibqp, bool suspended, uint8_t *bp,
77  size_t size, size_t n, bqnotify_t infy, void *link) {
78 
79  osalDbgCheck((ibqp != NULL) && (bp != NULL) && (size >= 2U));
80 
82  ibqp->suspended = suspended;
83  ibqp->bcounter = 0;
84  ibqp->brdptr = bp;
85  ibqp->bwrptr = bp;
86  ibqp->btop = bp + ((size + sizeof (size_t)) * n);
87  ibqp->bsize = size + sizeof (size_t);
88  ibqp->bn = n;
89  ibqp->buffers = bp;
90  ibqp->ptr = NULL;
91  ibqp->top = NULL;
92  ibqp->notify = infy;
93  ibqp->link = link;
94 }
95 
96 /**
97  * @brief Resets an input buffers queue.
98  * @details All the data in the input buffers queue is erased and lost, any
99  * waiting thread is resumed with status @p MSG_RESET.
100  * @note A reset operation can be used by a low level driver in order to
101  * obtain immediate attention from the high level layers.
102  *
103  * @param[in] ibqp pointer to the @p input_buffers_queue_t object
104  *
105  * @iclass
106  */
108 
110 
111  ibqp->bcounter = 0;
112  ibqp->brdptr = ibqp->buffers;
113  ibqp->bwrptr = ibqp->buffers;
114  ibqp->ptr = NULL;
115  ibqp->top = NULL;
116  osalThreadDequeueAllI(&ibqp->waiting, MSG_RESET);
117 }
118 
119 /**
120  * @brief Gets the next empty buffer from the queue.
121  * @note The function always returns the same buffer if called repeatedly.
122  *
123  * @param[in] ibqp pointer to the @p input_buffers_queue_t object
124  * @return A pointer to the next buffer to be filled.
125  * @retval NULL if the queue is full.
126  *
127  * @iclass
128  */
130 
132 
133  if (ibqIsFullI(ibqp)) {
134  return NULL;
135  }
136 
137  return ibqp->bwrptr + sizeof (size_t);
138 }
139 
140 /**
141  * @brief Posts a new filled buffer to the queue.
142  *
143  * @param[in] ibqp pointer to the @p input_buffers_queue_t object
144  * @param[in] size used size of the buffer, cannot be zero
145  *
146  * @iclass
147  */
148 void ibqPostFullBufferI(input_buffers_queue_t *ibqp, size_t size) {
149 
151 
152  osalDbgCheck((size > 0U) && (size <= (ibqp->bsize - sizeof (size_t))));
153  osalDbgAssert(!ibqIsFullI(ibqp), "buffers queue full");
154 
155  /* Writing size field in the buffer.*/
156  *((size_t *)ibqp->bwrptr) = size;
157 
158  /* Posting the buffer in the queue.*/
159  ibqp->bcounter++;
160  ibqp->bwrptr += ibqp->bsize;
161  if (ibqp->bwrptr >= ibqp->btop) {
162  ibqp->bwrptr = ibqp->buffers;
163  }
164 
165  /* Waking up one waiting thread, if any.*/
166  osalThreadDequeueNextI(&ibqp->waiting, MSG_OK);
167 }
168 
169 /**
170  * @brief Gets the next filled buffer from the queue.
171  * @note The function always acquires the same buffer if called repeatedly.
172  * @post After calling the function the fields @p ptr and @p top are set
173  * at beginning and end of the buffer data or @p NULL if the queue
174  * is empty.
175  *
176  * @param[in] ibqp pointer to the @p input_buffers_queue_t object
177  * @param[in] timeout the number of ticks before the operation timeouts,
178  * the following special values are allowed:
179  * - @a TIME_IMMEDIATE immediate timeout.
180  * - @a TIME_INFINITE no timeout.
181  * .
182  * @return The operation status.
183  * @retval MSG_OK if a buffer has been acquired.
184  * @retval MSG_TIMEOUT if the specified time expired.
185  * @retval MSG_RESET if the queue has been reset or has been put in
186  * suspended state.
187  *
188  * @api
189  */
191  sysinterval_t timeout) {
192  msg_t msg;
193 
194  osalSysLock();
195  msg = ibqGetFullBufferTimeoutS(ibqp, timeout);
196  osalSysUnlock();
197 
198  return msg;
199 }
200 
201  /**
202  * @brief Gets the next filled buffer from the queue.
203  * @note The function always acquires the same buffer if called repeatedly.
204  * @post After calling the function the fields @p ptr and @p top are set
205  * at beginning and end of the buffer data or @p NULL if the queue
206  * is empty.
207  *
208  * @param[in] ibqp pointer to the @p input_buffers_queue_t object
209  * @param[in] timeout the number of ticks before the operation timeouts,
210  * the following special values are allowed:
211  * - @a TIME_IMMEDIATE immediate timeout.
212  * - @a TIME_INFINITE no timeout.
213  * .
214  * @return The operation status.
215  * @retval MSG_OK if a buffer has been acquired.
216  * @retval MSG_TIMEOUT if the specified time expired.
217  * @retval MSG_RESET if the queue has been reset or has been put in
218  * suspended state.
219  *
220  * @sclass
221  */
223  sysinterval_t timeout) {
224 
226 
227  while (ibqIsEmptyI(ibqp)) {
228  if (ibqp->suspended) {
229  return MSG_RESET;
230  }
231  msg_t msg = osalThreadEnqueueTimeoutS(&ibqp->waiting, timeout);
232  if (msg < MSG_OK) {
233  return msg;
234  }
235  }
236 
237  osalDbgAssert(!ibqIsEmptyI(ibqp), "still empty");
238 
239  /* Setting up the "current" buffer and its boundary.*/
240  ibqp->ptr = ibqp->brdptr + sizeof (size_t);
241  ibqp->top = ibqp->ptr + *((size_t *)ibqp->brdptr);
242 
243  return MSG_OK;
244 }
245 
246 /**
247  * @brief Releases the buffer back in the queue.
248  * @note The object callback is called after releasing the buffer.
249  *
250  * @param[in] ibqp pointer to the @p input_buffers_queue_t object
251  *
252  * @api
253  */
255 
256  osalSysLock();
258  osalSysUnlock();
259 }
260 
261  /**
262  * @brief Releases the buffer back in the queue.
263  * @note The object callback is called after releasing the buffer.
264  *
265  * @param[in] ibqp pointer to the @p input_buffers_queue_t object
266  *
267  * @sclass
268  */
270 
272  osalDbgAssert(!ibqIsEmptyI(ibqp), "buffers queue empty");
273 
274  /* Freeing a buffer slot in the queue.*/
275  ibqp->bcounter--;
276  ibqp->brdptr += ibqp->bsize;
277  if (ibqp->brdptr >= ibqp->btop) {
278  ibqp->brdptr = ibqp->buffers;
279  }
280 
281  /* No "current" buffer.*/
282  ibqp->ptr = NULL;
283 
284  /* Notifying the buffer release.*/
285  if (ibqp->notify != NULL) {
286  ibqp->notify(ibqp);
287  }
288 }
289 
290 /**
291  * @brief Input queue read with timeout.
292  * @details This function reads a byte value from an input queue. If
293  * the queue is empty then the calling thread is suspended until a
294  * new buffer arrives in the queue or a timeout occurs.
295  *
296  * @param[in] ibqp pointer to the @p input_buffers_queue_t object
297  * @param[in] timeout the number of ticks before the operation timeouts,
298  * the following special values are allowed:
299  * - @a TIME_IMMEDIATE immediate timeout.
300  * - @a TIME_INFINITE no timeout.
301  * .
302  * @return A byte value from the queue.
303  * @retval MSG_TIMEOUT if the specified time expired.
304  * @retval MSG_RESET if the queue has been reset or has been put in
305  * suspended state.
306  *
307  * @api
308  */
310  msg_t msg;
311 
312  osalSysLock();
313 
314  /* This condition indicates that a new buffer must be acquired.*/
315  if (ibqp->ptr == NULL) {
316  msg = ibqGetFullBufferTimeoutS(ibqp, timeout);
317  if (msg != MSG_OK) {
318  osalSysUnlock();
319  return msg;
320  }
321  }
322 
323  /* Next byte from the buffer.*/
324  msg = (msg_t)*ibqp->ptr;
325  ibqp->ptr++;
326 
327  /* If the current buffer has been fully read then it is returned as
328  empty in the queue.*/
329  if (ibqp->ptr >= ibqp->top) {
331  }
332 
333  osalSysUnlock();
334  return msg;
335 }
336 
337 /**
338  * @brief Input queue read with timeout.
339  * @details The function reads data from an input queue into a buffer.
340  * The operation completes when the specified amount of data has been
341  * transferred or after the specified timeout or if the queue has
342  * been reset.
343  *
344  * @param[in] ibqp pointer to the @p input_buffers_queue_t object
345  * @param[out] bp pointer to the data buffer
346  * @param[in] n the maximum amount of data to be transferred, the
347  * value 0 is reserved
348  * @param[in] timeout the number of ticks before the operation timeouts,
349  * the following special values are allowed:
350  * - @a TIME_IMMEDIATE immediate timeout.
351  * - @a TIME_INFINITE no timeout.
352  * .
353  * @return The number of bytes effectively transferred.
354  * @retval 0 if a timeout occurred.
355  *
356  * @api
357  */
358 size_t ibqReadTimeout(input_buffers_queue_t *ibqp, uint8_t *bp,
359  size_t n, sysinterval_t timeout) {
360  size_t r = 0;
361 
362  osalDbgCheck(n > 0U);
363 
364  osalSysLock();
365 
366  while (true) {
367  size_t size;
368 
369  /* This condition indicates that a new buffer must be acquired.*/
370  if (ibqp->ptr == NULL) {
371  msg_t msg;
372 
373  /* Getting a data buffer using the specified timeout.*/
374  msg = ibqGetFullBufferTimeoutS(ibqp, timeout);
375 
376  /* Anything except MSG_OK interrupts the operation.*/
377  if (msg != MSG_OK) {
378  osalSysUnlock();
379  return r;
380  }
381  }
382 
383  /* Size of the data chunk present in the current buffer.*/
384  size = (size_t)ibqp->top - (size_t)ibqp->ptr;
385  if (size > (n - r)) {
386  size = n - r;
387  }
388 
389  /* Smaller chunks in order to not make the critical zone too long,
390  this impacts throughput however.*/
391  if (size > 64U) {
392  /* Giving the compiler a chance to optimize for a fixed size move.*/
393  memcpy(bp, ibqp->ptr, 64U);
394  bp += 64U;
395  ibqp->ptr += 64U;
396  r += 64U;
397  }
398  else {
399  memcpy(bp, ibqp->ptr, size);
400  bp += size;
401  ibqp->ptr += size;
402  r += size;
403  }
404 
405  /* Has the current data buffer been finished? if so then release it.*/
406  if (ibqp->ptr >= ibqp->top) {
408  }
409 
410  /* Giving a preemption chance.*/
411  osalSysUnlock();
412  if (r >= n) {
413  return r;
414  }
415  osalSysLock();
416  }
417 }
418 
419 /**
420  * @brief Initializes an output buffers queue object.
421  *
422  * @param[out] obqp pointer to the @p output_buffers_queue_t object
423  * @param[in] suspended initial state of the queue
424  * @param[in] bp pointer to a memory area allocated for buffers
425  * @param[in] size buffers size
426  * @param[in] n number of buffers
427  * @param[in] onfy callback called when a buffer is posted in the queue
428  * @param[in] link application defined pointer
429  *
430  * @init
431  */
432 void obqObjectInit(output_buffers_queue_t *obqp, bool suspended, uint8_t *bp,
433  size_t size, size_t n, bqnotify_t onfy, void *link) {
434 
435  osalDbgCheck((obqp != NULL) && (bp != NULL) && (size >= 2U));
436 
438  obqp->suspended = suspended;
439  obqp->bcounter = n;
440  obqp->brdptr = bp;
441  obqp->bwrptr = bp;
442  obqp->btop = bp + ((size + sizeof (size_t)) * n);
443  obqp->bsize = size + sizeof (size_t);
444  obqp->bn = n;
445  obqp->buffers = bp;
446  obqp->ptr = NULL;
447  obqp->top = NULL;
448  obqp->notify = onfy;
449  obqp->link = link;
450 }
451 
452 /**
453  * @brief Resets an output buffers queue.
454  * @details All the data in the output buffers queue is erased and lost, any
455  * waiting thread is resumed with status @p MSG_RESET.
456  * @note A reset operation can be used by a low level driver in order to
457  * obtain immediate attention from the high level layers.
458  *
459  * @param[in] obqp pointer to the @p output_buffers_queue_t object
460  *
461  * @iclass
462  */
464 
466 
467  obqp->bcounter = bqSizeX(obqp);
468  obqp->brdptr = obqp->buffers;
469  obqp->bwrptr = obqp->buffers;
470  obqp->ptr = NULL;
471  obqp->top = NULL;
472  osalThreadDequeueAllI(&obqp->waiting, MSG_RESET);
473 }
474 
475 /**
476  * @brief Gets the next filled buffer from the queue.
477  * @note The function always returns the same buffer if called repeatedly.
478  *
479  * @param[in] obqp pointer to the @p output_buffers_queue_t object
480  * @param[out] sizep pointer to the filled buffer size
481  * @return A pointer to the filled buffer.
482  * @retval NULL if the queue is empty.
483  *
484  * @iclass
485  */
487  size_t *sizep) {
488 
490 
491  if (obqIsEmptyI(obqp)) {
492  return NULL;
493  }
494 
495  /* Buffer size.*/
496  *sizep = *((size_t *)obqp->brdptr);
497 
498  return obqp->brdptr + sizeof (size_t);
499 }
500 
501 /**
502  * @brief Releases the next filled buffer back in the queue.
503  *
504  * @param[in] obqp pointer to the @p output_buffers_queue_t object
505  *
506  * @iclass
507  */
509 
511  osalDbgAssert(!obqIsEmptyI(obqp), "buffers queue empty");
512 
513  /* Freeing a buffer slot in the queue.*/
514  obqp->bcounter++;
515  obqp->brdptr += obqp->bsize;
516  if (obqp->brdptr >= obqp->btop) {
517  obqp->brdptr = obqp->buffers;
518  }
519 
520  /* Waking up one waiting thread, if any.*/
521  osalThreadDequeueNextI(&obqp->waiting, MSG_OK);
522 }
523 
524 /**
525  * @brief Gets the next empty buffer from the queue.
526  * @note The function always acquires the same buffer if called repeatedly.
527  * @post After calling the function the fields @p ptr and @p top are set
528  * at beginning and end of the buffer data or @p NULL if the queue
529  * is empty.
530  *
531  * @param[in] obqp pointer to the @p output_buffers_queue_t object
532  * @param[in] timeout the number of ticks before the operation timeouts,
533  * the following special values are allowed:
534  * - @a TIME_IMMEDIATE immediate timeout.
535  * - @a TIME_INFINITE no timeout.
536  * .
537  * @return The operation status.
538  * @retval MSG_OK if a buffer has been acquired.
539  * @retval MSG_TIMEOUT if the specified time expired.
540  * @retval MSG_RESET if the queue has been reset or has been put in
541  * suspended state.
542  *
543  * @api
544  */
546  sysinterval_t timeout) {
547  msg_t msg;
548 
549  osalSysLock();
550  msg = obqGetEmptyBufferTimeoutS(obqp, timeout);
551  osalSysUnlock();
552 
553  return msg;
554 }
555 
556 /**
557  * @brief Gets the next empty buffer from the queue.
558  * @note The function always acquires the same buffer if called repeatedly.
559  * @post After calling the function the fields @p ptr and @p top are set
560  * at beginning and end of the buffer data or @p NULL if the queue
561  * is empty.
562  *
563  * @param[in] obqp pointer to the @p output_buffers_queue_t object
564  * @param[in] timeout the number of ticks before the operation timeouts,
565  * the following special values are allowed:
566  * - @a TIME_IMMEDIATE immediate timeout.
567  * - @a TIME_INFINITE no timeout.
568  * .
569  * @return The operation status.
570  * @retval MSG_OK if a buffer has been acquired.
571  * @retval MSG_TIMEOUT if the specified time expired.
572  * @retval MSG_RESET if the queue has been reset or has been put in
573  * suspended state.
574  *
575  * @sclass
576  */
578  sysinterval_t timeout) {
579 
581 
582  while (obqIsFullI(obqp)) {
583  if (obqp->suspended) {
584  return MSG_RESET;
585  }
586  msg_t msg = osalThreadEnqueueTimeoutS(&obqp->waiting, timeout);
587  if (msg < MSG_OK) {
588  return msg;
589  }
590  }
591 
592  osalDbgAssert(!obqIsFullI(obqp), "still full");
593 
594  /* Setting up the "current" buffer and its boundary.*/
595  obqp->ptr = obqp->bwrptr + sizeof (size_t);
596  obqp->top = obqp->bwrptr + obqp->bsize;
597 
598  return MSG_OK;
599 }
600 
601 /**
602  * @brief Posts a new filled buffer to the queue.
603  * @note The object callback is called after releasing the buffer.
604  *
605  * @param[in] obqp pointer to the @p output_buffers_queue_t object
606  * @param[in] size used size of the buffer, cannot be zero
607  *
608  * @api
609  */
610 void obqPostFullBuffer(output_buffers_queue_t *obqp, size_t size) {
611 
612  osalSysLock();
613  obqPostFullBufferS(obqp, size);
614  osalSysUnlock();
615 }
616 
617 /**
618  * @brief Posts a new filled buffer to the queue.
619  * @note The object callback is called after releasing the buffer.
620  *
621  * @param[in] obqp pointer to the @p output_buffers_queue_t object
622  * @param[in] size used size of the buffer, cannot be zero
623  *
624  * @sclass
625  */
626 void obqPostFullBufferS(output_buffers_queue_t *obqp, size_t size) {
627 
629  osalDbgCheck((size > 0U) && (size <= (obqp->bsize - sizeof (size_t))));
630  osalDbgAssert(!obqIsFullI(obqp), "buffers queue full");
631 
632  /* Writing size field in the buffer.*/
633  *((size_t *)obqp->bwrptr) = size;
634 
635  /* Posting the buffer in the queue.*/
636  obqp->bcounter--;
637  obqp->bwrptr += obqp->bsize;
638  if (obqp->bwrptr >= obqp->btop) {
639  obqp->bwrptr = obqp->buffers;
640  }
641 
642  /* No "current" buffer.*/
643  obqp->ptr = NULL;
644 
645  /* Notifying the buffer release.*/
646  if (obqp->notify != NULL) {
647  obqp->notify(obqp);
648  }
649 }
650 
651 /**
652  * @brief Output queue write with timeout.
653  * @details This function writes a byte value to an output queue. If
654  * the queue is full then the calling thread is suspended until a
655  * new buffer is freed in the queue or a timeout occurs.
656  *
657  * @param[in] obqp pointer to the @p output_buffers_queue_t object
658  * @param[in] b byte value to be transferred
659  * @param[in] timeout the number of ticks before the operation timeouts,
660  * the following special values are allowed:
661  * - @a TIME_IMMEDIATE immediate timeout.
662  * - @a TIME_INFINITE no timeout.
663  * .
664  * @return A byte value from the queue.
665  * @retval MSG_TIMEOUT if the specified time expired.
666  * @retval MSG_RESET if the queue has been reset or has been put in
667  * suspended state.
668  *
669  * @api
670  */
672  sysinterval_t timeout) {
673  msg_t msg;
674 
675  osalSysLock();
676 
677  /* This condition indicates that a new buffer must be acquired.*/
678  if (obqp->ptr == NULL) {
679  msg = obqGetEmptyBufferTimeoutS(obqp, timeout);
680  if (msg != MSG_OK) {
681  osalSysUnlock();
682  return msg;
683  }
684  }
685 
686  /* Writing the byte to the buffer.*/
687  *obqp->ptr = b;
688  obqp->ptr++;
689 
690  /* If the current buffer has been fully written then it is posted as
691  full in the queue.*/
692  if (obqp->ptr >= obqp->top) {
693  obqPostFullBufferS(obqp, obqp->bsize - sizeof (size_t));
694  }
695 
696  osalSysUnlock();
697  return MSG_OK;
698 }
699 
700 /**
701  * @brief Output queue write with timeout.
702  * @details The function writes data from a buffer to an output queue. The
703  * operation completes when the specified amount of data has been
704  * transferred or after the specified timeout or if the queue has
705  * been reset.
706  *
707  * @param[in] obqp pointer to the @p output_buffers_queue_t object
708  * @param[in] bp pointer to the data buffer
709  * @param[in] n the maximum amount of data to be transferred, the
710  * value 0 is reserved
711  * @param[in] timeout the number of ticks before the operation timeouts,
712  * the following special values are allowed:
713  * - @a TIME_IMMEDIATE immediate timeout.
714  * - @a TIME_INFINITE no timeout.
715  * .
716  * @return The number of bytes effectively transferred.
717  * @retval 0 if a timeout occurred.
718  *
719  * @api
720  */
721 size_t obqWriteTimeout(output_buffers_queue_t *obqp, const uint8_t *bp,
722  size_t n, sysinterval_t timeout) {
723  size_t w = 0;
724 
725  osalDbgCheck(n > 0U);
726 
727  osalSysLock();
728 
729  while (true) {
730  size_t size;
731 
732  /* This condition indicates that a new buffer must be acquired.*/
733  if (obqp->ptr == NULL) {
734  msg_t msg;
735 
736  /* Getting an empty buffer using the specified timeout.*/
737  msg = obqGetEmptyBufferTimeoutS(obqp, timeout);
738 
739  /* Anything except MSG_OK interrupts the operation.*/
740  if (msg != MSG_OK) {
741  osalSysUnlock();
742  return w;
743  }
744  }
745 
746  /* Size of the space available in the current buffer.*/
747  size = (size_t)obqp->top - (size_t)obqp->ptr;
748  if (size > (n - w)) {
749  size = n - w;
750  }
751 
752  /* Smaller chunks in order to not make the critical zone too long,
753  this impacts throughput however.*/
754  if (size > 64U) {
755  /* Giving the compiler a chance to optimize for a fixed size move.*/
756  memcpy(obqp->ptr, bp, 64U);
757  bp += 64U;
758  obqp->ptr += 64U;
759  w += 64U;
760  }
761  else {
762  memcpy(obqp->ptr, bp, size);
763  bp += size;
764  obqp->ptr += size;
765  w += size;
766  }
767 
768  /* Has the current data buffer been finished? if so then release it.*/
769  if (obqp->ptr >= obqp->top) {
770  obqPostFullBufferS(obqp, obqp->bsize - sizeof (size_t));
771  }
772 
773  /* Giving a preemption chance.*/
774  osalSysUnlock();
775  if (w >= n) {
776  return w;
777  }
778  osalSysLock();
779  }
780 }
781 
782 /**
783  * @brief Flushes the current, partially filled, buffer to the queue.
784  * @note The notification callback is not invoked because the function
785  * is meant to be called from ISR context. An operation status is
786  * returned instead.
787  *
788  * @param[in] obqp pointer to the @p output_buffers_queue_t object
789  * @return The operation status.
790  * @retval false if no new filled buffer has been posted to the queue.
791  * @retval true if a new filled buffer has been posted to the queue.
792  *
793  * @iclass
794  */
796 
798 
799  /* If queue is empty and there is a buffer partially filled and
800  it is not being written.*/
801  if (obqIsEmptyI(obqp) && (obqp->ptr != NULL)) {
802  size_t size = (size_t)obqp->ptr - ((size_t)obqp->bwrptr + sizeof (size_t));
803 
804  if (size > 0U) {
805 
806  /* Writing size field in the buffer.*/
807  *((size_t *)obqp->bwrptr) = size;
808 
809  /* Posting the buffer in the queue.*/
810  obqp->bcounter--;
811  obqp->bwrptr += obqp->bsize;
812  if (obqp->bwrptr >= obqp->btop) {
813  obqp->bwrptr = obqp->buffers;
814  }
815 
816  /* No "current" buffer.*/
817  obqp->ptr = NULL;
818 
819  return true;
820  }
821  }
822  return false;
823 }
824 
825 /**
826  * @brief Flushes the current, partially filled, buffer to the queue.
827  *
828  * @param[in] obqp pointer to the @p output_buffers_queue_t object
829  *
830  * @api
831  */
833 
834  osalSysLock();
835 
836  /* If there is a buffer partially filled and not being written.*/
837  if (obqp->ptr != NULL) {
838  size_t size = ((size_t)obqp->ptr - (size_t)obqp->bwrptr) - sizeof (size_t);
839 
840  if (size > 0U) {
841  obqPostFullBufferS(obqp, size);
842  }
843  }
844 
845  osalSysUnlock();
846 }
847 /** @} */
#define ibqIsFullI(ibqp)
Evaluates to true if the specified input buffers queue is full.
Definition: hal_buffers.h:241
void obqFlush(output_buffers_queue_t *obqp)
Flushes the current, partially filled, buffer to the queue.
Definition: hal_buffers.c:832
uint8_t * ibqGetEmptyBufferI(input_buffers_queue_t *ibqp)
Gets the next empty buffer from the queue.
Definition: hal_buffers.c:129
uint8_t * obqGetFullBufferI(output_buffers_queue_t *obqp, size_t *sizep)
Gets the next filled buffer from the queue.
Definition: hal_buffers.c:486
msg_t obqGetEmptyBufferTimeoutS(output_buffers_queue_t *obqp, sysinterval_t timeout)
Gets the next empty buffer from the queue.
Definition: hal_buffers.c:577
void obqReleaseEmptyBufferI(output_buffers_queue_t *obqp)
Releases the next filled buffer back in the queue.
Definition: hal_buffers.c:508
void osalThreadDequeueAllI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up all threads from the queue.
Definition: osal.c:309
volatile size_t bcounter
Active buffers counter.
Definition: hal_buffers.h:71
#define ibqIsEmptyI(ibqp)
Evaluates to true if the specified input buffers queue is empty.
Definition: hal_buffers.h:229
msg_t ibqGetFullBufferTimeout(input_buffers_queue_t *ibqp, sysinterval_t timeout)
Gets the next filled buffer from the queue.
Definition: hal_buffers.c:190
HAL subsystem header.
#define obqIsEmptyI(obqp)
Evaluates to true if the specified output buffers queue is empty.
Definition: hal_buffers.h:256
#define osalDbgCheckClassI()
I-Class state check.
Definition: osal.h:292
#define obqIsFullI(obqp)
Evaluates to true if the specified output buffers queue is full.
Definition: hal_buffers.h:271
uint8_t * btop
Pointer to the buffers boundary.
Definition: hal_buffers.h:83
void ibqResetI(input_buffers_queue_t *ibqp)
Resets an input buffers queue.
Definition: hal_buffers.c:107
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition: osal.h:540
void * link
Application defined field.
Definition: hal_buffers.h:115
bqnotify_t notify
Data notification callback.
Definition: hal_buffers.h:111
void obqPostFullBufferS(output_buffers_queue_t *obqp, size_t size)
Posts a new filled buffer to the queue.
Definition: hal_buffers.c:626
uint8_t * ptr
Pointer for R/W sequential access.
Definition: hal_buffers.h:103
int32_t msg_t
Type of a message.
Definition: osal.h:160
size_t ibqReadTimeout(input_buffers_queue_t *ibqp, uint8_t *bp, size_t n, sysinterval_t timeout)
Input queue read with timeout.
Definition: hal_buffers.c:358
uint8_t * bwrptr
Buffer write pointer.
Definition: hal_buffers.h:75
void obqPostFullBuffer(output_buffers_queue_t *obqp, size_t size)
Posts a new filled buffer to the queue.
Definition: hal_buffers.c:610
size_t bn
Number of buffers.
Definition: hal_buffers.h:94
void ibqPostFullBufferI(input_buffers_queue_t *ibqp, size_t size)
Posts a new filled buffer to the queue.
Definition: hal_buffers.c:148
msg_t ibqGetFullBufferTimeoutS(input_buffers_queue_t *ibqp, sysinterval_t timeout)
Gets the next filled buffer from the queue.
Definition: hal_buffers.c:222
size_t obqWriteTimeout(output_buffers_queue_t *obqp, const uint8_t *bp, size_t n, sysinterval_t timeout)
Output queue write with timeout.
Definition: hal_buffers.c:721
bool obqTryFlushI(output_buffers_queue_t *obqp)
Flushes the current, partially filled, buffer to the queue.
Definition: hal_buffers.c:795
void(* bqnotify_t)(io_buffers_queue_t *bqp)
Double buffer notification callback type.
Definition: hal_buffers.h:54
msg_t obqGetEmptyBufferTimeout(output_buffers_queue_t *obqp, sysinterval_t timeout)
Gets the next empty buffer from the queue.
Definition: hal_buffers.c:545
void obqObjectInit(output_buffers_queue_t *obqp, bool suspended, uint8_t *bp, size_t size, size_t n, bqnotify_t onfy, void *link)
Initializes an output buffers queue object.
Definition: hal_buffers.c:432
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:278
uint8_t * buffers
Queue of buffer objects.
Definition: hal_buffers.h:98
uint32_t sysinterval_t
Type of system time interval.
Definition: osal.h:170
void osalThreadDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the queue, if any.
Definition: osal.c:294
msg_t obqPutTimeout(output_buffers_queue_t *obqp, uint8_t b, sysinterval_t timeout)
Output queue write with timeout.
Definition: hal_buffers.c:671
msg_t osalThreadEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout)
Enqueues the caller thread.
Definition: osal.c:277
size_t bsize
Size of buffers.
Definition: hal_buffers.h:90
Structure of a generic buffers queue.
Definition: hal_buffers.h:59
threads_queue_t waiting
Queue of waiting threads.
Definition: hal_buffers.h:63
#define bqSizeX(bqp)
Returns the queue&#39;s number of buffers.
Definition: hal_buffers.h:153
bool suspended
Queue suspended state flag.
Definition: hal_buffers.h:67
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition: osal.h:530
msg_t ibqGetTimeout(input_buffers_queue_t *ibqp, sysinterval_t timeout)
Input queue read with timeout.
Definition: hal_buffers.c:309
void obqResetI(output_buffers_queue_t *obqp)
Resets an output buffers queue.
Definition: hal_buffers.c:463
#define osalDbgCheckClassS()
S-Class state check.
Definition: osal.h:298
#define osalDbgAssert(c, remark)
Condition assertion.
Definition: osal.h:258
uint8_t * top
Boundary for R/W sequential access.
Definition: hal_buffers.h:107
void ibqReleaseEmptyBufferS(input_buffers_queue_t *ibqp)
Releases the buffer back in the queue.
Definition: hal_buffers.c:269
void ibqObjectInit(input_buffers_queue_t *ibqp, bool suspended, uint8_t *bp, size_t size, size_t n, bqnotify_t infy, void *link)
Initializes an input buffers queue object.
Definition: hal_buffers.c:76
static void osalThreadQueueObjectInit(threads_queue_t *tqp)
Initializes a threads queue object.
Definition: osal.h:653
uint8_t * brdptr
Buffer read pointer.
Definition: hal_buffers.h:79
void ibqReleaseEmptyBuffer(input_buffers_queue_t *ibqp)
Releases the buffer back in the queue.
Definition: hal_buffers.c:254