SuperTinyKernel™ RTOS 1.06.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk::sync::Pipe Class Reference

Thread-safe FIFO communication pipe for inter-task data passing. More...

#include <stk_sync_pipe.h>

Inheritance diagram for stk::sync::Pipe:
Collaboration diagram for stk::sync::Pipe:

Public Member Functions

 Pipe (uint8_t *buf, size_t capacity, size_t element_size)
 Constructor.
 ~Pipe ()=default
 Destructor.
bool Write (const void *data, Timeout timeout_ticks=WAIT_INFINITE)
 Write a single element to the pipe.
bool TryWrite (const void *data)
 Attempt to write a single element to the pipe without blocking.
size_t WriteBulk (const void *src, size_t count, Timeout timeout_ticks=WAIT_INFINITE)
 Write multiple elements to the pipe.
size_t TryWriteBulk (const void *src, size_t count)
 Attempt to write multiple elements to the pipe without blocking.
bool Read (void *data, Timeout timeout_ticks=WAIT_INFINITE)
 Read a single element from the pipe.
bool TryRead (void *data)
 Attempt to read a single element from the pipe without blocking.
size_t ReadBulk (void *dst, size_t count, Timeout timeout_ticks=WAIT_INFINITE)
 Read multiple elements from the pipe.
size_t TryReadBulk (void *dst, size_t count)
 Attempt to read multiple elements from the pipe without blocking.
size_t ReadBulkTriggered (void *dst, size_t trigger, size_t max_count, Timeout timeout_ticks=WAIT_INFINITE)
 Read at least trigger elements, then drain up to max_count without blocking.
size_t TryReadBulkTriggered (void *dst, size_t max_count)
 Non-blocking variant of ReadBulkTriggered.
void Reset ()
 Discard all elements and reset the pipe to the empty state.
size_t GetCapacity () const
 Get the maximum number of elements the pipe can hold.
size_t GetElementSize () const
 Get the size of each element in bytes.
size_t GetCount () const
 Get the current number of elements in the pipe.
size_t GetSpace () const
 Get the number of free slots currently available.
uint8_t * GetBuffer ()
 Get a pointer to the raw backing buffer.
bool IsEmpty () const
 Check if the pipe is currently empty.
bool IsFull () const
 Check if the pipe is currently full.
bool IsStorageValid () const
 Verify that the backing storage is valid and the pipe is ready for use.
void SetTraceName (const char *name)
 Set name.
const char * GetTraceName () const
 Get name.

Static Public Attributes

static const size_t CAPACITY_MAX = 0xFFFEU
 Max capacity supported (number of elements).

Private Member Functions

 Pipe (const Pipe &)=delete
Pipeoperator= (const Pipe &)=delete
uint8_t * Slot (size_t idx) const
size_t Next (size_t idx) const
size_t DrainLocked (uint8_t *dst_bytes, size_t count)

Private Attributes

uint8_t * m_buffer
 flat byte ring-buffer: capacity slots of element_size bytes each
const size_t m_capacity
 maximum number of elements stored in the pipe
const size_t m_element_size
 size of each element in bytes
size_t m_count
 current number of elements stored in the pipe
size_t m_head
 write index (next slot to be written by Write())
size_t m_tail
 read index (next slot to be read by Read())
ConditionVariable m_cv_not_empty
 signaled by Write() when the pipe transitions from empty
ConditionVariable m_cv_not_full
 signaled by Read()/Reset() when the pipe is no longer full

Detailed Description

Thread-safe FIFO communication pipe for inter-task data passing.

Pipe provides a synchronized ring-buffer mechanism that allows tasks to exchange data safely. It is parameterised on an element byte count (element_size) rather than a C++ type, making it suitable for passing heterogeneous or C-ABI structs without requiring the element type to be copyable via the C++ assignment operator. All element payloads are copied with memcpy.

It follows the following blocking semantics:

  • Write() blocks if the pipe is full until space becomes available or the timeout expires.
  • Read() blocks if the pipe is empty until data is produced or the timeout expires.

The caller is responsible for providing an appropriately sized external buffer and ensuring it remains valid for the entire lifetime of the Pipe object. For a self-contained, type-safe alternative with compile-time capacity and direct typed assignment, see stk::sync::PipeT.

// Example: Producer-Consumer pattern with external buffer
struct Sample { uint32_t timestamp_ms; int16_t value; };
static uint8_t s_buf[8 * sizeof(Sample)];
stk::sync::Pipe g_DataPipe(s_buf, 8, sizeof(Sample));
void Task_Producer() {
Sample s = { GetTicks(), ReadSensor() };
// blocks if pipe is full
g_DataPipe.Write(&s);
}
void Task_Consumer() {
Sample received;
// blocks until data is available, with a 1 s timeout
if (g_DataPipe.Read(&received, 1000)) {
// ... process received value ...
}
}
Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:274
Thread-safe FIFO communication pipe for inter-task data passing.
See also
PipeT, MessageQueue, ConditionVariable
Note
Only available when kernel is compiled with KERNEL_SYNC mode enabled.

Definition at line 71 of file stk_sync_pipe.h.

Constructor & Destructor Documentation

◆ Pipe() [1/2]

stk::sync::Pipe::Pipe ( uint8_t * buf,
size_t capacity,
size_t element_size )
inlineexplicit

Constructor.

Parameters
[in]bufPointer to externally-allocated storage. Must be at least capacity * element_size bytes.
[in]capacityMaximum number of elements [1, CAPACITY_MAX].
[in]element_sizeSize of each element in bytes (>= 1).

Definition at line 330 of file stk_sync_pipe.h.

331: m_buffer(buf),
332 m_capacity(capacity),
333 m_element_size(element_size),
334 m_count(0U),
335 m_head(0U),
336 m_tail(0U)
337{
338 STK_ASSERT(buf != nullptr);
339 STK_ASSERT(capacity >= 1U);
340 STK_ASSERT(capacity <= CAPACITY_MAX);
341 STK_ASSERT(element_size >= 1U);
342}
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:411
const size_t m_capacity
maximum number of elements stored in the pipe
size_t m_head
write index (next slot to be written by Write())
const size_t m_element_size
size of each element in bytes
static const size_t CAPACITY_MAX
Max capacity supported (number of elements).
size_t m_tail
read index (next slot to be read by Read())
uint8_t * m_buffer
flat byte ring-buffer: capacity slots of element_size bytes each
size_t m_count
current number of elements stored in the pipe

References CAPACITY_MAX, m_buffer, m_capacity, m_count, m_element_size, m_head, m_tail, and STK_ASSERT.

Referenced by operator=().

Here is the caller graph for this function:

◆ ~Pipe()

stk::sync::Pipe::~Pipe ( )
default

Destructor.

Note
If tasks are still waiting at destruction time it is considered a logical error (dangling waiters). An assertion is triggered in debug builds via the ConditionVariable destructors.
MISRA deviation: [STK-DEV-005] Rule 10-3-2.

References STK_VIRT_DTOR, and stk::WAIT_INFINITE.

◆ Pipe() [2/2]

stk::sync::Pipe::Pipe ( const Pipe & )
privatedelete

Member Function Documentation

◆ DrainLocked()

size_t stk::sync::Pipe::DrainLocked ( uint8_t * dst_bytes,
size_t count )
inlineprivate

Definition at line 487 of file stk_sync_pipe.h.

488{
489 const size_t to_read = Min(count, m_count);
490 const size_t first_part = m_capacity - m_tail;
491
492 if (to_read <= first_part)
493 {
494 STK_MEMCPY(dst_bytes, Slot(m_tail), to_read * m_element_size);
495 }
496 else
497 {
498 STK_MEMCPY(dst_bytes, Slot(m_tail), first_part * m_element_size);
499 STK_MEMCPY(dst_bytes + (first_part * m_element_size), Slot(0U), (to_read - first_part) * m_element_size);
500 }
501
502 m_tail = (m_tail + to_read) % m_capacity;
503 m_count -= to_read;
504
505 m_cv_not_full.NotifyAll_CS();
506 return to_read;
507}
static void STK_MEMCPY(void *const dest, const void *const src, const size_t size)
A wrapper for a built-in memcpy, redefine to your own if required.
Definition stk_defs.h:617
static constexpr T Min(T a, T b)
Compile-time minimum of two values.
Definition stk_defs.h:633
uint8_t * Slot(size_t idx) const
ConditionVariable m_cv_not_full
signaled by Read()/Reset() when the pipe is no longer full

References m_capacity, m_count, m_cv_not_full, m_element_size, m_tail, stk::Min(), Slot(), and STK_MEMCPY().

Referenced by ReadBulk(), and ReadBulkTriggered().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetBuffer()

uint8_t * stk::sync::Pipe::GetBuffer ( )
inline

Get a pointer to the raw backing buffer.

Returns
Pointer to the beginning of the element buffer.
Note
ISR-safe.

Definition at line 277 of file stk_sync_pipe.h.

277{ return m_buffer; }

References m_buffer.

◆ GetCapacity()

size_t stk::sync::Pipe::GetCapacity ( ) const
inline

Get the maximum number of elements the pipe can hold.

Returns
Construction-time capacity.
Note
ISR-safe.

Definition at line 252 of file stk_sync_pipe.h.

252{ return m_capacity; }

References m_capacity.

Referenced by stk_pipe_get_capacity(), and xStreamBufferSetTriggerLevel().

Here is the caller graph for this function:

◆ GetCount()

size_t stk::sync::Pipe::GetCount ( ) const
inline

Get the current number of elements in the pipe.

Returns
Point-in-time snapshot of the element count. May be stale by the time the caller acts on it in a multi-task environment.
Note
ISR-safe on targets where a size_t-aligned read is atomic.

Definition at line 265 of file stk_sync_pipe.h.

265{ return m_count; }

References m_count.

Referenced by stk_pipe_get_count().

Here is the caller graph for this function:

◆ GetElementSize()

size_t stk::sync::Pipe::GetElementSize ( ) const
inline

Get the size of each element in bytes.

Returns
Construction-time element size.
Note
ISR-safe.

Definition at line 258 of file stk_sync_pipe.h.

258{ return m_element_size; }

References m_element_size.

Referenced by stk_pipe_get_element_size().

Here is the caller graph for this function:

◆ GetSpace()

size_t stk::sync::Pipe::GetSpace ( ) const
inline

Get the number of free slots currently available.

Returns
Point-in-time snapshot of the free-slot count.
Note
ISR-safe.

Definition at line 271 of file stk_sync_pipe.h.

271{ return (m_capacity - m_count); }

References m_capacity, and m_count.

Referenced by stk_pipe_get_space().

Here is the caller graph for this function:

◆ GetTraceName()

const char * stk::ITraceable::GetTraceName ( ) const
inlineinherited

Get name.

Returns
Name string, or NULL if not set or if STK_SYNC_DEBUG_NAMES is 0.

Definition at line 406 of file stk_common.h.

407 {
408 #if STK_SYNC_DEBUG_NAMES
409 return m_trace_name;
410 #else
411 return nullptr;
412 #endif
413 }

◆ IsEmpty()

bool stk::sync::Pipe::IsEmpty ( ) const
inline

Check if the pipe is currently empty.

Returns
true if empty, otherwise false.
Note
The returned value is a point-in-time snapshot.
ISR-safe.

Definition at line 284 of file stk_sync_pipe.h.

284{ return (m_count == 0U); }

References m_count.

Referenced by stk_pipe_is_empty().

Here is the caller graph for this function:

◆ IsFull()

bool stk::sync::Pipe::IsFull ( ) const
inline

Check if the pipe is currently full.

Returns
true if full, otherwise false.
Note
The returned value is a point-in-time snapshot.
ISR-safe.

Definition at line 291 of file stk_sync_pipe.h.

291{ return (m_count == m_capacity); }

References m_capacity, and m_count.

Referenced by stk_pipe_is_full().

Here is the caller graph for this function:

◆ IsStorageValid()

bool stk::sync::Pipe::IsStorageValid ( ) const
inline

Verify that the backing storage is valid and the pipe is ready for use.

Always true for pipes constructed with external storage. For heap-constructed pipes, false if operator new failed. Must be checked after the heap constructor when operating without exceptions (the typical embedded configuration).

Returns
true if the pipe is ready for use.
Note
ISR-safe.

Definition at line 301 of file stk_sync_pipe.h.

301{ return (m_buffer != nullptr); }

References m_buffer.

Referenced by stk_pipe_is_storage_valid().

Here is the caller graph for this function:

◆ Next()

size_t stk::sync::Pipe::Next ( size_t idx) const
inlineprivate

Definition at line 310 of file stk_sync_pipe.h.

310{ return (idx + 1U) % m_capacity; }

References m_capacity.

Referenced by Read(), and Write().

Here is the caller graph for this function:

◆ operator=()

Pipe & stk::sync::Pipe::operator= ( const Pipe & )
privatedelete

References Pipe().

Here is the call graph for this function:

◆ Read()

bool stk::sync::Pipe::Read ( void * data,
Timeout timeout_ticks = WAIT_INFINITE )
inline

Read a single element from the pipe.

Copies element_size bytes from the oldest slot in the ring buffer into the buffer pointed to by data. If the pipe is empty, the calling task is suspended until data is produced or the timeout expires.

Parameters
[out]dataDestination buffer for the retrieved element (must be at least element_size bytes).
[in]timeout_ticksMaximum time to wait for data (ticks). Default: WAIT_INFINITE.
Warning
ISR-safe only with timeout_ticks=NO_WAIT, ISR-unsafe otherwise.
Returns
true if data was successfully read, false if timeout expired before any data became available.

Definition at line 454 of file stk_sync_pipe.h.

455{
456 STK_ASSERT(data != nullptr);
457
458 ScopedCriticalSection cs_;
459 bool success = true;
460
461 while (m_count == 0U)
462 {
463 if (!m_cv_not_empty.Wait(cs_, timeout_ticks))
464 {
465 success = false;
466 break;
467 }
468 }
469
470 if (success)
471 {
473 m_tail = Next(m_tail);
474 m_count--;
475
476 // notify producer that space is now available
477 m_cv_not_full.NotifyOne_CS();
478 }
479
480 return success;
481}
size_t Next(size_t idx) const
ConditionVariable m_cv_not_empty
signaled by Write() when the pipe transitions from empty

References m_count, m_cv_not_empty, m_cv_not_full, m_element_size, m_tail, Next(), Slot(), STK_ASSERT, and STK_MEMCPY().

Referenced by stk_pipe_read(), and TryRead().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadBulk()

size_t stk::sync::Pipe::ReadBulk ( void * dst,
size_t count,
Timeout timeout_ticks = WAIT_INFINITE )
inline

Read multiple elements from the pipe.

Attempts to retrieve count elements from the FIFO. If the pipe does not contain enough elements to satisfy the request, it will block until the full amount is read or the timeout expires.

Parameters
[out]dstPointer to the destination array (must hold at least count elements of element_size bytes each).
[in]countNumber of elements to read.
[in]timeout_ticksMaximum time to wait for data (ticks). Default: WAIT_INFINITE.
Warning
ISR-safe only with timeout_ticks=NO_WAIT, ISR-unsafe otherwise.
Returns
Number of elements actually read. Equal to count unless a timeout occurred.
// Example:
Sample frame[64];
size_t result = g_Pipe.ReadBulk(frame, 64, 500);
if (result == 64) {
// process full frame
} else {
// handle partial read / timeout
}

Definition at line 513 of file stk_sync_pipe.h.

514{
515 size_t read_count = 0U;
516
517 if ((dst != nullptr) && (count != 0U))
518 {
519 uint8_t *const dst_bytes = static_cast<uint8_t *>(dst);
520 const bool timed_wait = (timeout_ticks != WAIT_INFINITE) && (timeout_ticks != NO_WAIT);
521
522 // capture an absolute deadline once, before entering the wait loop,
523 // preventing the timeout from resetting on intermediate partial reads
524 const Timeout deadline = (timed_wait ?
525 static_cast<Timeout>(GetTicks() + timeout_ticks) : timeout_ticks);
526
527 ScopedCriticalSection cs_;
528
529 while (read_count < count)
530 {
531 bool is_timeout = false;
532
533 while (m_count == 0U)
534 {
535 Timeout remaining = deadline;
536 if (timed_wait)
537 {
538 const Timeout now = static_cast<Timeout>(GetTicks());
539 remaining = (now >= deadline ? NO_WAIT : (deadline - now));
540 }
541
542 if (!m_cv_not_empty.Wait(cs_, remaining))
543 {
544 is_timeout = true;
545 break; // break inner condition variable loop
546 }
547 }
548
549 // if a timeout occurred, drop out of the chunk processing loop
550 if (is_timeout)
551 {
552 break;
553 }
554
555 // drain data using the state tracker's relative byte offsets
556 read_count += DrainLocked(dst_bytes + (read_count * m_element_size), count - read_count);
557 }
558 }
559
560 return read_count;
561}
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:189
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:125
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:183
size_t DrainLocked(uint8_t *dst_bytes, size_t count)

References DrainLocked(), stk::GetTicks(), m_count, m_cv_not_empty, m_element_size, stk::NO_WAIT, and stk::WAIT_INFINITE.

Referenced by stk_pipe_read_bulk(), and TryReadBulk().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadBulkTriggered()

size_t stk::sync::Pipe::ReadBulkTriggered ( void * dst,
size_t trigger,
size_t max_count,
Timeout timeout_ticks = WAIT_INFINITE )
inline

Read at least trigger elements, then drain up to max_count without blocking.

Blocks until at least trigger elements are simultaneously available in the pipe, or the timeout expires. Once the threshold is reached the call dequeues min(max_count, available) elements in a single critical-section pass — no busy-spin, no second call.

Parameters
[out]dstDestination buffer; must hold at least max_count elements of element_size bytes.
[in]triggerMinimum number of elements that must be available before any data is dequeued. Clamped to [1, max_count] internally.
[in]max_countMaximum number of elements to return in total.
[in]timeout_ticksMaximum time to wait for trigger elements. Default: WAIT_INFINITE.
Warning
ISR-safe only with timeout_ticks=NO_WAIT, ISR-unsafe otherwise.
Returns
Number of elements actually read.
  • Equal to zero if timeout fired before a single element arrived.
  • Greater than zero but less than trigger if a partial trigger's worth of data was written before timeout (this can only happen when trigger > 1 and the timeout expires after some — but not enough — elements arrive).
  • Greater than or equal to trigger if the threshold was satisfied (the caller may then assume the trigger callback condition is met).

Definition at line 567 of file stk_sync_pipe.h.

568{
569 size_t read_count = 0U;
570
571 if ((dst != nullptr) && (max_count != 0U))
572 {
573 // trigger must be in [1, max_count]
574 if (trigger == 0U) { trigger = 1U; }
575 if (trigger > max_count) { trigger = max_count; }
576
577 uint8_t *const dst_bytes = static_cast<uint8_t *>(dst);
578 const bool timed_wait = (timeout_ticks != WAIT_INFINITE) && (timeout_ticks != NO_WAIT);
579
580 // capture an absolute deadline once, before entering the wait loop,
581 // preventing the timeout from resetting on intermediate spurious wakeups
582 const Timeout deadline = (timed_wait ?
583 static_cast<Timeout>(GetTicks() + timeout_ticks) : timeout_ticks);
584
585 ScopedCriticalSection cs_;
586
587 while (m_count < trigger)
588 {
589 Timeout remaining = deadline;
590 if (timed_wait)
591 {
592 const Timeout now = static_cast<Timeout>(GetTicks());
593 remaining = (now >= deadline ? NO_WAIT : (deadline - now));
594 }
595
596 if (!m_cv_not_empty.Wait(cs_, remaining))
597 {
598 break; // break the waiting loop on timeout
599 }
600 }
601
602 // whether we broke out via satisfying the trigger or hitting a timeout,
603 // we drain whatever is currently available up to max_count
604 read_count = DrainLocked(dst_bytes, max_count);
605 }
606
607 return read_count;
608}

References DrainLocked(), stk::GetTicks(), m_count, m_cv_not_empty, stk::NO_WAIT, and stk::WAIT_INFINITE.

Referenced by stk_pipe_read_bulk_triggered(), TryReadBulkTriggered(), and xStreamBufferReceive().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Reset()

void stk::sync::Pipe::Reset ( )
inline

Discard all elements and reset the pipe to the empty state.

Resets head, tail and count to zero. Any tasks blocked in Write() are woken so they can re-evaluate and enqueue into the now-empty pipe.

Warning
Elements that were in the pipe are silently discarded. Ensure no consumers depend on them before calling Reset().
ISR-safe.

Definition at line 614 of file stk_sync_pipe.h.

615{
616 const ScopedCriticalSection cs_;
617
618 m_count = 0U;
619 m_head = 0U;
620 m_tail = 0U;
621
622 // wake all blocked producers: the pipe is now entirely empty, every slot is free
623 // note: we do not release readers here
624 m_cv_not_full.NotifyAll_CS();
625}

References m_count, m_cv_not_full, m_head, and m_tail.

Referenced by stk_pipe_reset().

Here is the caller graph for this function:

◆ SetTraceName()

void stk::ITraceable::SetTraceName ( const char * name)
inlineinherited

Set name.

Parameters
[in]nameNull-terminated string or NULL.
Note
If STK_SYNC_DEBUG_NAMES is 0 then calling this function has no effect.

Definition at line 394 of file stk_common.h.

395 {
396 #if STK_SYNC_DEBUG_NAMES
397 m_trace_name = name;
398 #else
399 STK_UNUSED(name);
400 #endif
401 }
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:610

References STK_UNUSED.

Referenced by stk::memory::BlockMemoryPool::BlockMemoryPool(), and stk::memory::BlockMemoryPool::BlockMemoryPool().

Here is the caller graph for this function:

◆ Slot()

uint8_t * stk::sync::Pipe::Slot ( size_t idx) const
inlineprivate

Definition at line 307 of file stk_sync_pipe.h.

307{ return m_buffer + (idx * m_element_size); }

References m_buffer, and m_element_size.

Referenced by DrainLocked(), Read(), Write(), and WriteBulk().

Here is the caller graph for this function:

◆ TryRead()

bool stk::sync::Pipe::TryRead ( void * data)
inline

Attempt to read a single element from the pipe without blocking.

Dequeues an element only if one is immediately available. Returns false instantly if the pipe is empty.

Parameters
[out]dataDestination buffer for the retrieved element.
Warning
ISR-safe.
Returns
true if data was successfully read, false if the pipe was empty.

Definition at line 166 of file stk_sync_pipe.h.

166{ return Read(data, NO_WAIT); }
bool Read(void *data, Timeout timeout_ticks=WAIT_INFINITE)
Read a single element from the pipe.

References stk::NO_WAIT, and Read().

Referenced by stk_pipe_tryread().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ TryReadBulk()

size_t stk::sync::Pipe::TryReadBulk ( void * dst,
size_t count )
inline

Attempt to read multiple elements from the pipe without blocking.

Reads as many elements as are currently available without blocking.

Parameters
[out]dstPointer to the destination array.
[in]countNumber of elements to read.
Warning
ISR-safe.
Returns
Number of elements actually read.

Definition at line 199 of file stk_sync_pipe.h.

199{ return ReadBulk(dst, count, NO_WAIT); }
size_t ReadBulk(void *dst, size_t count, Timeout timeout_ticks=WAIT_INFINITE)
Read multiple elements from the pipe.

References stk::NO_WAIT, and ReadBulk().

Referenced by stk_pipe_tryread_bulk(), and xStreamBufferReceiveFromISR().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ TryReadBulkTriggered()

size_t stk::sync::Pipe::TryReadBulkTriggered ( void * dst,
size_t max_count )
inline

Non-blocking variant of ReadBulkTriggered.

Returns immediately with however many elements are available, up to max_count. The trigger threshold is not enforced (equivalent to trigger = 1 with NO_WAIT).

Parameters
[out]dstDestination buffer.
[in]max_countMaximum number of elements to read.
Warning
ISR-safe.
Returns
Number of elements actually read.

Definition at line 234 of file stk_sync_pipe.h.

235 {
236 return ReadBulkTriggered(dst, 1U, max_count, NO_WAIT);
237 }
size_t ReadBulkTriggered(void *dst, size_t trigger, size_t max_count, Timeout timeout_ticks=WAIT_INFINITE)
Read at least trigger elements, then drain up to max_count without blocking.

References stk::NO_WAIT, and ReadBulkTriggered().

Referenced by stk_pipe_tryread_bulk_triggered().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ TryWrite()

bool stk::sync::Pipe::TryWrite ( const void * data)
inline

Attempt to write a single element to the pipe without blocking.

Enqueues the element only if a free slot is immediately available. Returns false instantly if the pipe is full.

Parameters
[in]dataPointer to the element payload.
Warning
ISR-safe.
Returns
true if data was successfully written, false if no space is available.

Definition at line 112 of file stk_sync_pipe.h.

112{ return Write(data, NO_WAIT); }
bool Write(const void *data, Timeout timeout_ticks=WAIT_INFINITE)
Write a single element to the pipe.

References stk::NO_WAIT, and Write().

Referenced by stk_pipe_trywrite().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ TryWriteBulk()

size_t stk::sync::Pipe::TryWriteBulk ( const void * src,
size_t count )
inline

Attempt to write multiple elements to the pipe without blocking.

Copies as many elements as possible without blocking. Elements that do not fit are discarded.

Parameters
[in]srcPointer to the source array.
[in]countNumber of elements to write.
Warning
ISR-safe.
Returns
Number of elements actually written.

Definition at line 145 of file stk_sync_pipe.h.

145{ return WriteBulk(src, count, NO_WAIT); }
size_t WriteBulk(const void *src, size_t count, Timeout timeout_ticks=WAIT_INFINITE)
Write multiple elements to the pipe.

References stk::NO_WAIT, and WriteBulk().

Referenced by stk_pipe_trywrite_bulk(), and xStreamBufferSendFromISR().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Write()

bool stk::sync::Pipe::Write ( const void * data,
Timeout timeout_ticks = WAIT_INFINITE )
inline

Write a single element to the pipe.

Copies element_size bytes from data into the next available slot in the ring buffer. If the pipe is full, the calling task is suspended until space becomes available or the timeout expires.

Parameters
[in]dataPointer to the element payload (must be at least element_size bytes).
[in]timeout_ticksMaximum time to wait for space (ticks). Default: WAIT_INFINITE.
Warning
ISR-safe only with timeout_ticks=NO_WAIT, ISR-unsafe otherwise.
Returns
true if data was successfully written, false if timeout expired before space became available.

Definition at line 348 of file stk_sync_pipe.h.

349{
350 STK_ASSERT(data != nullptr);
352
353 ScopedCriticalSection cs_;
354 bool success = true;
355
356 while (m_count == m_capacity)
357 {
358 if (!m_cv_not_full.Wait(cs_, timeout_ticks))
359 {
360 success = false;
361 break;
362 }
363 }
364
365 if (success)
366 {
368 m_head = Next(m_head);
369 m_count++;
370
371 // notify consumer that data is ready
372 m_cv_not_empty.NotifyOne_CS();
373 }
374
375 return success;
376}

References CAPACITY_MAX, m_capacity, m_count, m_cv_not_empty, m_cv_not_full, m_element_size, m_head, Next(), Slot(), STK_ASSERT, and STK_MEMCPY().

Referenced by stk_pipe_write(), and TryWrite().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteBulk()

size_t stk::sync::Pipe::WriteBulk ( const void * src,
size_t count,
Timeout timeout_ticks = WAIT_INFINITE )
inline

Write multiple elements to the pipe.

Copies a block of count elements into the FIFO. If the pipe does not have enough space for the entire block, it will block until the full amount can be written or the timeout expires.

Parameters
[in]srcPointer to the source array (must hold at least count elements of element_size bytes each).
[in]countNumber of elements to write.
[in]timeout_ticksMaximum time to wait for sufficient space (ticks). Default: WAIT_INFINITE.
Warning
ISR-safe only with timeout_ticks=NO_WAIT, ISR-unsafe otherwise.
Returns
Number of elements actually written. Equal to count unless a timeout occurred.
// Example:
Sample frame[64];
FillFrame(frame);
size_t result = g_Pipe.WriteBulk(frame, 64, 500);
if (result < 64) {
// handle partial write / timeout
}

Definition at line 382 of file stk_sync_pipe.h.

383{
384 size_t written = 0U;
385
386 if ((src != nullptr) && (count != 0U))
387 {
388 const uint8_t *const src_bytes = static_cast<const uint8_t *>(src);
389 const bool timed_wait = (timeout_ticks != WAIT_INFINITE) && (timeout_ticks != NO_WAIT);
390
391 // capture an absolute deadline once, before entering the wait loop,
392 // preventing the timeout from resetting on intermediate partial writes
393 const Timeout deadline = (timed_wait ?
394 static_cast<Timeout>(GetTicks() + timeout_ticks) : timeout_ticks);
395
396 ScopedCriticalSection cs_;
397
398 while (written < count)
399 {
400 bool is_timeout = false;
401
402 while (m_count == m_capacity)
403 {
404 Timeout remaining = deadline;
405 if (timed_wait)
406 {
407 const Timeout now = static_cast<Timeout>(GetTicks());
408 remaining = (now >= deadline ? NO_WAIT : (deadline - now));
409 }
410
411 if (!m_cv_not_full.Wait(cs_, remaining))
412 {
413 is_timeout = true;
414 break; // break inner condition variable loop
415 }
416 }
417
418 // if a timeout occurred, drop out of the chunk processing loop
419 if (is_timeout)
420 {
421 break;
422 }
423
424 const size_t available = m_capacity - m_count;
425 const size_t to_write = ((count - written) < available) ? (count - written) : available;
426 const size_t first_part = m_capacity - m_head;
427
428 if (to_write <= first_part)
429 {
430 STK_MEMCPY(Slot(m_head), src_bytes + (written * m_element_size), to_write * m_element_size);
431 }
432 else
433 {
434 STK_MEMCPY(Slot(m_head), src_bytes + (written * m_element_size), first_part * m_element_size);
435 STK_MEMCPY(Slot(0U), src_bytes + ((written + first_part) * m_element_size), (to_write - first_part) * m_element_size);
436 }
437
438 written += to_write;
439 m_head = (m_head + to_write) % m_capacity;
440 m_count += to_write;
441
442 // notify consumers that data is ready
443 m_cv_not_empty.NotifyAll_CS();
444 }
445 }
446
447 return written;
448}

References stk::GetTicks(), m_capacity, m_count, m_cv_not_empty, m_cv_not_full, m_element_size, m_head, stk::NO_WAIT, Slot(), STK_MEMCPY(), and stk::WAIT_INFINITE.

Referenced by stk_pipe_write_bulk(), TryWriteBulk(), and xStreamBufferSend().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ CAPACITY_MAX

const size_t stk::sync::Pipe::CAPACITY_MAX = 0xFFFEU
static

Max capacity supported (number of elements).

Definition at line 76 of file stk_sync_pipe.h.

Referenced by Pipe(), and Write().

◆ m_buffer

uint8_t* stk::sync::Pipe::m_buffer
private

flat byte ring-buffer: capacity slots of element_size bytes each

Definition at line 316 of file stk_sync_pipe.h.

Referenced by GetBuffer(), IsStorageValid(), Pipe(), and Slot().

◆ m_capacity

const size_t stk::sync::Pipe::m_capacity
private

maximum number of elements stored in the pipe

Definition at line 317 of file stk_sync_pipe.h.

Referenced by DrainLocked(), GetCapacity(), GetSpace(), IsFull(), Next(), Pipe(), Write(), and WriteBulk().

◆ m_count

size_t stk::sync::Pipe::m_count
private

current number of elements stored in the pipe

Definition at line 319 of file stk_sync_pipe.h.

Referenced by DrainLocked(), GetCount(), GetSpace(), IsEmpty(), IsFull(), Pipe(), Read(), ReadBulk(), ReadBulkTriggered(), Reset(), Write(), and WriteBulk().

◆ m_cv_not_empty

ConditionVariable stk::sync::Pipe::m_cv_not_empty
private

signaled by Write() when the pipe transitions from empty

Definition at line 322 of file stk_sync_pipe.h.

Referenced by Read(), ReadBulk(), ReadBulkTriggered(), Write(), and WriteBulk().

◆ m_cv_not_full

ConditionVariable stk::sync::Pipe::m_cv_not_full
private

signaled by Read()/Reset() when the pipe is no longer full

Definition at line 323 of file stk_sync_pipe.h.

Referenced by DrainLocked(), Read(), Reset(), Write(), and WriteBulk().

◆ m_element_size

const size_t stk::sync::Pipe::m_element_size
private

size of each element in bytes

Definition at line 318 of file stk_sync_pipe.h.

Referenced by DrainLocked(), GetElementSize(), Pipe(), Read(), ReadBulk(), Slot(), Write(), and WriteBulk().

◆ m_head

size_t stk::sync::Pipe::m_head
private

write index (next slot to be written by Write())

Definition at line 320 of file stk_sync_pipe.h.

Referenced by Pipe(), Reset(), Write(), and WriteBulk().

◆ m_tail

size_t stk::sync::Pipe::m_tail
private

read index (next slot to be read by Read())

Definition at line 321 of file stk_sync_pipe.h.

Referenced by DrainLocked(), Pipe(), Read(), and Reset().


The documentation for this class was generated from the following file: