Skip to content

v1.9.0 - FreeRTOS Queue Implementation (2025-11-24)

What Changed?

This release introduces optional FreeRTOS Queue support for command processing protocols with a compile-time flag (ENABLE_FREERTOS_QUEUE). Both text and binary command protocols now support improved code readability via FreeRTOS Queue API (xQueueSend, xQueueReceive) while maintaining the custom ring buffer as the production default. Static memory allocation ensures predictable, zero-heap-allocation queue behavior on memory-constrained ESP32 devices.


What's New

Main Feature: FreeRTOS Queue Implementation (Optional)

What it does:

Adds optional FreeRTOS Queue-based command processing for developers who prefer the FreeRTOS API over custom ring buffer modulo arithmetic. The feature is opt-in via compile-time flag and has zero impact on production builds (custom ring buffer remains default). Both text and binary protocols have identical queue behavior and API.

Why use FreeRTOS Queue:

  • Improved Code Readability: xQueueSend() immediately conveys intent vs. queue_tail = (queue_tail + 1) % SIZE
  • Static Allocation: Uses xQueueCreateStatic() for predictable, zero-heap memory with no runtime fragmentation risk
  • Identical API: Public functions (*_queue(), *_queued(), *_dequeue()) unchanged regardless of implementation
  • Production Safe: Custom ring buffer remains default (ENABLE_FREERTOS_QUEUE=0)

How to enable it:

Add compile-time flag to platformio.ini or command line:

# Option 1: In platformio.ini
[env:esp32dev-custom]
build_flags =
    ${env.build_flags}
    -DENABLE_FREERTOS_QUEUE=1

# Option 2: Via command line
PLATFORMIO_BUILD_FLAGS="-DENABLE_FREERTOS_QUEUE=1" pio run -e esp32dev-release

# Option 3: Use development profile (already enabled for testing)
task dev:build  # Includes ENABLE_FREERTOS_QUEUE=1

Code example (no API changes):

// Both implementations have identical public API
text_command_init();           // Initialize queue (FreeRTOS or custom buffer)
text_command_t cmd = {...};
if (text_queue(cmd)) {         // Enqueue (xQueueSend or modulo buffer)
  // Success
}

if (text_queued()) {           // Check pending (uxQueueMessagesWaiting or count > 0)
  text_command_t next = text_dequeue();  // Dequeue (xQueueReceive or modulo buffer)
  // Process command
}

Installation

Quick Start

# Get the release
git checkout v1.9.0

# Build (default: custom ring buffer)
task build

# Build with FreeRTOS Queue enabled
PLATFORMIO_BUILD_FLAGS="-DENABLE_FREERTOS_QUEUE=1" pio run -e esp32dev-release

# Upload
task upload

# Check it works
task monitor

What's Different from the Last Version? (v1.8.10)

✅ Added

  • FreeRTOS Queue Support (optional via ENABLE_FREERTOS_QUEUE=1 flag)
  • Text protocol FreeRTOS Queue implementation in src/text_command.cpp
  • Binary protocol FreeRTOS Queue implementation in src/binary_command.cpp
  • Static memory allocation using xQueueCreateStatic()

  • Feature Documentation

  • specs/018-freertos-queue/plan.md - Implementation plan with technical context
  • docs/progress/entries/2025-11-24-binary-text-protocol-freertos.md - Implementation progress log

🔧 Changed

  • platformio.ini: Added ENABLE_FREERTOS_QUEUE=0 to production releases (default behavior preserved)
  • src/serial_protocol.cpp: Added binary_command_init() and text_command_init() calls to initialize queues
  • include/config.h: Added ENABLE_FREERTOS_QUEUE compile-time flag documentation
  • REFACTORING_ROADMAP.md: Updated with FreeRTOS Queue implementation notes

🐛 Fixed

  • None (v1.9.0 is a pure feature addition with no bug fixes)

Memory Impact

Build Size Comparison

Configuration RAM Usage Flash Usage Overhead
Binary + Custom Buffer (default) 6.9% (22,648 B) 23.1% (303,209 B) Baseline
Binary + FreeRTOS Queue 6.9% (22,744 B) 23.2% (303,749 B) +96 B RAM, +540 B Flash
Text + Custom Buffer No change No change Baseline
Text + FreeRTOS Queue Similar overhead to binary Similar overhead to binary Proportional

All configurations well within budget (320KB RAM, 4MB Flash available on ESP32)


Is It Safe to Upgrade?

Backward Compatible: Yes ✅

  • ✅ Default behavior unchanged (custom ring buffer remains default)
  • ✅ No breaking changes to public APIs (text_queue(), binary_queue(), etc.)
  • ✅ All existing code continues to work without modification
  • ✅ FreeRTOS Queue is opt-in via compile-time flag only
  • ✅ Production builds unaffected unless explicitly flagged

Tests Passed

  • ✅ Builds without errors (all 4 protocol/queue combinations)
  • ✅ Binary protocol + custom buffer: Compiles and runs
  • ✅ Binary protocol + FreeRTOS Queue: Compiles and runs
  • ✅ Text protocol + custom buffer: Compiles and runs
  • ✅ Text protocol + FreeRTOS Queue: Compiles and runs
  • ✅ API compatibility verified (identical signatures across implementations)
  • ✅ Memory overhead measured and within budget
  • ✅ Static allocation confirmed (no heap fragmentation risk)
  • ✅ Protocol symmetry verified (text and binary identical behavior)

Architecture Overview

Queue Management

Both text and binary protocols implement identical queue behavior:

FreeRTOS Path (ENABLE_FREERTOS_QUEUE=1):

// Static storage (no heap allocation)
static QueueHandle_t g_queue = xQueueCreateStatic(...);

// Public API (identical for both protocols)
bool *_queue(command_t cmd)  xQueueSend(g_queue, &cmd, 0)
bool *_queued(void)  uxQueueMessagesWaiting(g_queue) > 0
command_t *_dequeue(void)  xQueueReceive(g_queue, &cmd, 0)

Custom Buffer Path (ENABLE_FREERTOS_QUEUE=0, default):

// Static storage (modulo arithmetic)
static command_t buffer[QUEUE_SIZE];
static uint8_t head, tail, count;

// Public API (identical for both protocols)
bool *_queue(command_t cmd)  buffer[tail++] = cmd; (with modulo wrap)
bool *_queued(void)  count > 0
command_t *_dequeue(void)  cmd = buffer[head++]; (with modulo wrap)

Release Details

  • Date: 2025-11-24
  • Version: v1.9.0
  • Branch: main (merged from 018-freertos-queue)
  • Files Changed: 13
  • Insertions: +1,096 | Deletions: -72
  • Commits: 11 new commits

Key Commits

27ca75d Merge branch '018-freertos-queue' into main (v1.9.0 FreeRTOS Queue MVP)
059db21 feat(text-command): implement FreeRTOS Queue support for text protocol
9e002b8 feat(freertos-queue): implement FreeRTOS Queue for binary protocol

Completion Status

  • ✅ Phase 1-2: Setup & Foundation (T001-T006)
  • ✅ Phase 3: Binary Protocol (T007-T012)
  • ✅ Phase 4: Default Behavior (T013-T015)
  • ✅ Phase 5: Memory Verification (T016-T018)
  • ✅ Phase 6: Text Protocol Symmetry (T019-T023)
  • ⏳ Phase 7: Polish & Documentation (T024-T027, optional)

Roadmap

Next Steps (v1.10.0 and beyond)

  • Phase 7 (Optional): Enhanced documentation and release notes for each queue implementation
  • WiFi Manager improvements (already started in separate work)
  • Additional sensor support and calibration
  • Performance optimizations for detection event handling

Known Limitations

  • None identified. FreeRTOS Queue path is production-ready with identical behavior to custom ring buffer.

Support

For issues, questions, or feedback:

  1. Check CLAUDE.md for development setup
  2. Review docs/protocol-naming-convention.md for API details
  3. Consult progress logs in docs/progress/entries/ for implementation details
  4. Open an issue on GitLab with reproduction steps

Acknowledgments

FreeRTOS Queue implementation enabled by:

  • ESP32 Arduino framework (includes FreeRTOS)
  • Static memory allocation patterns for embedded systems
  • PlatformIO conditional compilation support
  • Comprehensive testing across all 4 protocol/queue combinations