+INLINE bool fifo_isfull(const FIFOBuffer *fb)
+{
+ //ASSERT_VALID_FIFO(fb);
+ return
+ ((fb->head == fb->begin) && (fb->tail == fb->end))
+ || (fb->tail == fb->head - 1);
+}
+
+
+/*!
+ * Pop a character from the fifo buffer.
+ *
+ * \note Calling \c fifo_push() on a full buffer is undefined.
+ * The caller must make sure the buffer has at least
+ * one free slot before calling this function.
+ *
+ * \note It is safe to call fifo_pop() and fifo_push() from
+ * concurrent contexts, unless the CPU can't update
+ * a pointer atomically (which the AVR and other 8-bit
+ * processors can't do).
+ *
+ * \sa fifo_push_locked
+ */
+INLINE void fifo_push(FIFOBuffer *fb, unsigned char c)
+{
+#ifdef __MWERKS__
+#pragma interrupt called
+#endif
+ //ASSERT_VALID_FIFO(fb);
+
+ /* Write at tail position */
+ *(fb->tail) = c;
+
+ if (UNLIKELY(fb->tail == fb->end))
+ /* wrap tail around */
+ fb->tail = fb->begin;
+ else
+ /* Move tail forward */
+ fb->tail++;
+}
+
+
+/*!
+ * Pop a character from the fifo buffer.
+ *
+ * \note Calling \c fifo_pop() on an empty buffer is undefined.
+ * The caller must make sure the buffer contains at least
+ * one character before calling this function.
+ *
+ * \note It is safe to call fifo_pop() and fifo_push() from
+ * concurrent contexts.
+ */
+INLINE unsigned char fifo_pop(FIFOBuffer *fb)
+{
+#ifdef __MWERKS__
+#pragma interrupt called
+#endif
+ //ASSERT_VALID_FIFO(fb);
+
+ if (UNLIKELY(fb->head == fb->end))
+ {
+ /* wrap head around */
+ fb->head = fb->begin;
+ return *(fb->end);
+ }
+ else
+ /* move head forward */
+ return *(fb->head++);
+}
+