Skip to main content

Double Buffer

LibXR::DoubleBuffer is a double-buffered data structure designed for embedded scenarios. It is primarily used for seamless switching and filling control in high-speed transfers such as DMA and USB. It supports active and pending buffer management, making it especially suitable for performance-critical data transmission tasks.

Key Features

  • Splits a block of contiguous memory into two buffers.
  • Supports switching between the active buffer and the pending buffer.
  • Provides direct access and data fill interfaces for both buffers.
  • Supports manual switching and automatic validity checking.
  • Allows querying whether the pending buffer is ready and how much data it holds.

Interface Overview

Constructor

explicit DoubleBuffer(const LibXR::RawData& raw_data);
  • Accepts a block of continuous memory and splits it into two buffers.

Data Operation Interfaces

  • uint8_t* ActiveBuffer(): Get the currently active buffer.
  • uint8_t* PendingBuffer(): Get the pending buffer.
  • bool FillActive(const uint8_t* data, size_t len): Write data to the active buffer.
  • bool FillPending(const uint8_t* data, size_t len): Write data to the pending buffer.
  • void EnablePending(): Manually mark the pending buffer as valid (used with FillActive).
  • bool HasPending() const: Check if there is a pending buffer ready to be switched.
  • void Switch(): Switch between active and pending buffers.
  • size_t PendingLength() const: Get the valid data length in the pending buffer.
  • size_t Size() const: Get the capacity of each buffer.

Usage Example

LibXR::RawData mem{malloc(512), 512};
LibXR::DoubleBuffer buf(mem);

// First write to the pending buffer
buf.FillPending(data1, len1);
if (buf.HasPending()) {
buf.Switch(); // Switch to the new active buffer
}

// Fill the current active buffer for initial transmission
buf.FillActive(data2, len2);
buf.EnablePending(); // Mark the current active as the next pending

Notes

  • You must call Switch() after filling the pending buffer to activate it.
  • Dynamic allocation is not supported; memory must be prepared before construction.
  • FillPending is not reentrant; ensure the pending state is false before calling.
  • EnablePending() is used with FillActive() to support proactive switching.

Application Scenarios

  • USB CDC / Audio data transmission
  • Optimized DMA data streaming
  • Ping-pong buffering communication mechanism