Skip to content

Latest commit

 

History

History
132 lines (96 loc) · 6.3 KB

File metadata and controls

132 lines (96 loc) · 6.3 KB

ProbeStream API Reference

Target-side C API. For a high-level overview and measured performance, see the top-level README. For the on-wire layout of the control block and ring buffers, see wire-protocol.md.


Table of contents


Header: target/probestream.h. Implementation: target/probestream.c.

Configuration macros

Defined in target/probestream_conf.h. Override any of these by defining them in your build system or by replacing the file. All sizes are in bytes; all counts are integer limits.

Macro Default Meaning
PS_ENABLED 1 Master switch. Set to 0 to compile every ProbeStream call to a no-op.
PS_MAX_UP_CHANNELS 3 Maximum number of target → host channels the control block can hold.
PS_MAX_DOWN_CHANNELS 3 Maximum number of host → target channels.
PS_ENABLE_PRINTF 1 If 0, drops PS_Printf (removes the dependency on vsnprintf).
PS_PRINTF_BUFFER_SIZE 128 Stack buffer used by PS_Printf. Strings longer than this are truncated.
PS_DEFAULT_MODE 0 (PS_MODE_SKIP) Default mode for newly created channels.

Initialization

typedef struct {
    void*    pBuffer;          // RAM region you provide (must outlive PS_Init)
    uint32_t bufferSize;       // size of pBuffer in bytes
    uint8_t  numUpChannels;    // 1..PS_MAX_UP_CHANNELS
    uint8_t  numDownChannels;  // 0..PS_MAX_DOWN_CHANNELS
    uint8_t  defaultMode;      // PS_MODE_SKIP | PS_MODE_TRIM | PS_MODE_BLOCK
} PS_Config_t;

void PS_Init(const PS_Config_t* config);

PS_Init lays out the control block at the start of pBuffer, then allocates the remainder equally between up- and down-channel ring buffers. The magic ID is written last so a partial init can never be observed by the host.

Constraints:

  • pBuffer must be in RAM (the host needs to read and write its descriptors). Static __attribute__((aligned(4))) allocation is recommended.
  • Minimum useful bufferSize depends on numUpChannels + numDownChannels. The control block header is 32 + (PS_MAX_UP_CHANNELS + PS_MAX_DOWN_CHANNELS) * 20 bytes; the rest is split evenly. Each ring needs at least 32 bytes.
  • PS_Init should be called once, early in main, before any other PS_* call.

Writing to a channel (target → host)

uint32_t PS_Write(uint8_t channel, const void* data, uint32_t numBytes);
uint32_t PS_WriteString(uint8_t channel, const char* str);
uint32_t PS_WriteInt(uint8_t channel, int32_t value);
uint32_t PS_WriteUInt(uint8_t channel, uint32_t value);
uint32_t PS_WriteFloat(uint8_t channel, float value);
uint32_t PS_WriteDouble(uint8_t channel, double value);
int      PS_Printf(uint8_t channel, const char* fmt, ...);   // if PS_ENABLE_PRINTF
  • Returns the number of bytes actually committed to the ring (may be 0 or less than requested depending on mode and free space).
  • These calls are interrupt-safe on the writer side as long as only one context writes a given channel at a time. Concurrent writers to the same channel need external locking. The host (reader) side is always safe regardless.
  • PS_Printf uses an internal stack buffer of PS_PRINTF_BUFFER_SIZE. Output is truncated to fit.

Typed numeric channels

void PS_SetChannelType(uint8_t channel, uint8_t type);

Channel type lives in the channel descriptor and tells host tools how to interpret a channel. The type applies to the whole channel, so do not mix text logs and numeric samples on the same channel if you want graphing or stats.

Type Constant Payload format
Raw bytes PS_CHANNEL_TYPE_RAW Untyped bytes; not graphable.
Text PS_CHANNEL_TYPE_TEXT Human-readable text; not graphable.
ASCII number PS_CHANNEL_TYPE_ASCII_NUMBER Strict numeric ASCII tokens such as 12, 12.4, -0.23.
Signed 32-bit PS_CHANNEL_TYPE_INT32 Little-endian int32_t samples.
Unsigned 32-bit PS_CHANNEL_TYPE_UINT32 Little-endian uint32_t samples.
32-bit float PS_CHANNEL_TYPE_FLOAT32 Little-endian float samples.
64-bit float PS_CHANNEL_TYPE_FLOAT64 Little-endian double samples.

PS_WriteInt, PS_WriteUInt, PS_WriteFloat, and PS_WriteDouble mark the up-channel with the matching type before writing the sample. Use PS_SetChannelType(channel, PS_CHANNEL_TYPE_ASCII_NUMBER) when you want to emit numeric ASCII with PS_WriteString or PS_Printf.

PS_WriteFloat(0, temperature_c);

PS_SetChannelType(1, PS_CHANNEL_TYPE_ASCII_NUMBER);
PS_Printf(1, "%.3f\n", current_ma);

PS_SetMode preserves channel type bits, and PS_SetChannelType preserves the current full-buffer mode.

Reading from a channel (host → target)

uint32_t PS_Read(uint8_t channel, void* data, uint32_t maxBytes);
uint32_t PS_HasData(uint8_t channel);
  • PS_Read consumes bytes from down-channel channel and returns how many it copied (0..maxBytes). Call it from your main loop or a low-priority task there's no callback, just polling.
  • PS_HasData returns the number of currently-buffered bytes without consuming them.

Modes

void PS_SetMode(uint8_t channel, uint8_t mode);   // up-channels only

Behavior when an up-channel ring is full and a write arrives:

Mode Constant Behavior
Skip PS_MODE_SKIP Drop the entire write. Return value is 0.
Trim PS_MODE_TRIM Write as many bytes as fit, drop the rest. Return value is what was committed.
Block PS_MODE_BLOCK Busy-wait until the host advances the read pointer. Return value equals numBytes.

PS_MODE_BLOCK is convenient for never-lose-a-byte streams but will stall your firmware indefinitely if the host stops reading. Use it only when you know the host is alive.

Compile-out kill switch

#define PS_ENABLED 0

Every public function becomes ((void)0) / returns 0. No symbols are emitted, no buffer is allocated. Useful for shipping a single binary that supports both debug and release without #ifdef clutter at every call site.