Skip to content

ComQueue queue ordering, drop mode, & command to reprioritize#4674

Open
Willmac16 wants to merge 26 commits intonasa:develfrom
Willmac16:claude/comqueue-channel-config-u4b8U
Open

ComQueue queue ordering, drop mode, & command to reprioritize#4674
Willmac16 wants to merge 26 commits intonasa:develfrom
Willmac16:claude/comqueue-channel-config-u4b8U

Conversation

@Willmac16
Copy link
Contributor

@Willmac16 Willmac16 commented Jan 30, 2026

Related Issue(s)
Has Unit Tests (y/n) Y
Documentation Included (y/n) Y
Generative AI was used in this contribution (y/n) Y

Change Description

Adds the abilities to change the ordering and drop mode of each queue in the com queue at compile time.

Also adds the ability to reprioritize queues w/ a command

Rationale

Many channels benefit from alternative queue ordering & drop mode (e.g. new telemetry is likely more important to preserve than stale telemetry). Additionally, mission demands like anomaly resolution may require the ability to reonfigure the priority of different data streams into the com queue.

Testing/Review Recommendations

Ensure the return scheme for Queue DROP_OLDEST mode feels appropriate. Decide if compile time vs command-able split in features matches expected usage. Verify that testing looks sufficient.

Future Work

N/A

AI Usage (see policy)

Claude Code for the Web (Sonnet 4.5) was used to perform initial implementation. I went through and read, reorganized, & refactored the code

claude and others added 17 commits January 30, 2026 10:29
…mQueue

This change adds the ability to configure each ComQueue input channel with:
- Queue mode: FIFO (First-In-First-Out) or LIFO (Last-In-First-Out)
- Overflow mode: DROP_NEWEST or DROP_OLDEST

Changes:
- Added QueueMode and OverflowMode enums to ComQueue.fpp
- Extended QueueConfigurationEntry with mode and overflowMode fields
- Modified Types::Queue to support LIFO dequeue and drop oldest overflow
- Added CircularBuffer::trim() method for removing from the back
- Updated ComQueue to pass mode configuration to underlying queues

The mode and overflow behavior are configured at compile time through the
QueueConfigurationTable passed to the configure() method. Priority can be
adjusted at initialization by modifying the configuration table.

Note: Runtime priority changes would require adding a command interface,
which has been deferred due to FPP syntax compatibility considerations.
- Added unit tests for Queue FIFO/LIFO modes
- Added unit tests for Queue DROP_NEWEST/DROP_OLDEST overflow modes
- Added tests for all combinations (FIFO+DROP_OLDEST, LIFO+DROP_OLDEST)
- Added CircularBuffer::trim() tests (TrimOkRule, TrimBadRule)
- Added trim() method to CircularState for test infrastructure
- Updated CMakeLists.txt to include Queue_ut test target
- All 10 Queue tests and 10 CircularBuffer tests passing
Tests added:
- FIFO mode verification for COM queues
- LIFO mode verification for COM queues
- DROP_NEWEST overflow mode (rejects when full)
- DROP_OLDEST overflow mode (drops oldest to make room)
- LIFO + DROP_OLDEST combined mode
- FIFO mode verification for Buffer queues
- LIFO mode verification for Buffer queues
- DROP_OLDEST overflow mode for Buffer queues

Implementation:
- Added 8 new test methods to ComQueueTester class
- Added corresponding TEST cases in ComQueueTestMain
- Included QueueModeEnumAc.hpp and OverflowModeEnumAc.hpp in ComQueue.hpp
- All 15 tests passing (7 existing + 8 new)

Coverage:
- Tests both COM and Buffer queue types
- Tests all combinations of queue modes and overflow modes
- Verifies correct ordering (FIFO vs LIFO)
- Verifies overflow behavior (DROP_NEWEST vs DROP_OLDEST)
- Validates events and buffer returns
Added SET_QUEUE_PRIORITY command to ComQueue component that allows
runtime adjustment of queue priorities. The command:
- Validates queue index and priority values
- Updates the priority in the m_prioritizedList
- Re-sorts the prioritized list to maintain ordering
- Emits QueuePriorityChanged event on success
- Emits InvalidQueueIndex event and returns VALIDATION_ERROR for invalid inputs

Also added comprehensive unit tests covering:
- Successful priority changes
- Invalid queue index handling
- Invalid priority value handling

All 18 unit tests pass.
Refactored to use Types::QueueMode and Types::QueueOverflowMode
from the Queue class instead of duplicating enum definitions in
ComQueue.fpp. This change:

- Removed QueueMode and OverflowMode enum definitions from ComQueue.fpp
- Removed includes of QueueModeEnumAc.hpp and OverflowModeEnumAc.hpp
- Updated QueueConfigurationEntry and QueueMetadata to use Types:: enums
- Removed enum conversion code in configure() method
- Updated all test code to use Types::QUEUE_FIFO, Types::QUEUE_LIFO,
  Types::QUEUE_DROP_NEWEST, and Types::QUEUE_DROP_OLDEST

All 18 unit tests continue to pass.
*/
struct TrimOkRule : public STest::Rule<MockTypes::CircularState> {
// Constructor
TrimOkRule(const char* const name);

Check warning

Code scanning / CppCheck

Single-parameter constructors should be marked explicit.

Single-parameter constructors should be marked explicit.
*/
struct TrimBadRule : public STest::Rule<MockTypes::CircularState> {
// Constructor
TrimBadRule(const char* const name);

Check warning

Code scanning / CppCheck

Single-parameter constructors should be marked explicit.

Single-parameter constructors should be marked explicit.
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
}

void ComQueue::SET_QUEUE_PRIORITY_cmdHandler(FwOpcodeType opCode,

Check notice

Code scanning / CodeQL

Long function without assertion

All functions of more than 10 lines should have at least one assertion.
namespace Types {

Queue::Queue() : m_internal(), m_message_size(0) {}
Queue::Queue() : m_internal(), m_message_size(0), m_mode(QUEUE_FIFO), m_overflow_mode(QUEUE_DROP_NEWEST) {}

Check notice

Code scanning / CodeQL

More than one statement per line

This line contains 2 statements; only one is allowed.
return Fw::FW_DESERIALIZE_BUFFER_EMPTY;
}
FwSizeType offset = current_size - m_message_size;
result = m_internal.peek(message, m_message_size, offset);

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter message has not been checked.

if (m_mode == QUEUE_FIFO) {
// FIFO: Dequeue from the front (oldest message)
result = m_internal.peek(message, m_message_size, 0);

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter message has not been checked.
static_cast<FwAssertArgType>(m_message_size)); // Message size is as expected
return m_internal.serialize(message, m_message_size);

Fw::SerializeStatus status = m_internal.serialize(message, m_message_size);

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter message has not been checked.
m_internal.setup(storage, total_needed_size);
m_message_size = message_size;
m_mode = mode;
m_overflow_mode = overflow_mode;

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter overflow_mode has not been checked.
static_cast<FwAssertArgType>(depth), static_cast<FwAssertArgType>(message_size));
m_internal.setup(storage, total_needed_size);
m_message_size = message_size;
m_mode = mode;

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter mode has not been checked.
// Validate queue index
if (queueIndex < 0 || queueIndex >= TOTAL_PORT_COUNT) {
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
return;

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter opCode has not been checked.

// Validate queue index
if (queueIndex < 0 || queueIndex >= TOTAL_PORT_COUNT) {
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter cmdSeq has not been checked.

// Validate queue index
if (queueIndex < 0 || queueIndex >= TOTAL_PORT_COUNT) {
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter opCode has not been checked.
// Acquire the queue that we need to drain
FwIndexType queueIndex =
(queueType == QueueType::COM_QUEUE) ? index : static_cast<FwIndexType>(index + COM_PORT_COUNT);
FwIndexType queueIndex = this->getQueueNum(queueType, index);

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter index has not been checked.
// Acquire the queue that we need to drain
FwIndexType queueIndex =
(queueType == QueueType::COM_QUEUE) ? index : static_cast<FwIndexType>(index + COM_PORT_COUNT);
FwIndexType queueIndex = this->getQueueNum(queueType, index);

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter queueType has not been checked.
@Willmac16 Willmac16 marked this pull request as ready for review February 2, 2026 14:26

FwIndexType ComQueue::getQueueNum(Svc::QueueType queueType, FwIndexType portNum) {
// Acquire the queue that we need to drain
return static_cast<FwIndexType>(portNum + ((queueType == QueueType::COM_QUEUE) ? 0 : COM_PORT_COUNT));

Check warning

Code scanning / CodeQL

Unchecked function argument

This use of parameter portNum has not been checked.
async command SET_QUEUE_PRIORITY(
queueType: QueueType @< The Queue data type
indexType: FwIndexType @< The index of the queue (within the supplied type) to modify
newPriority: U32 @< New priority value for the queue
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This uses a U32.... Is this the right type?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Priority is set in the C++ as a FwIndexType. We should keep this for consistency, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched all the priority instances to FwIndexType. Good Catch! Now I'm wondering if there's anywhere that ensures the priority is >= 0 for the configuration on startup

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like negative priorities won't get populated, but I don't see anything that will explicitly warn you

async command SET_QUEUE_PRIORITY(
queueType: QueueType @< The Queue data type
indexType: FwIndexType @< The index of the queue (within the supplied type) to modify
newPririty: FwIndexType @< New priority value for the queue

Check failure

Code scanning / check-spelling

Unrecognized Spelling

[Pririty](#security-tab) is not a recognized word. \(unrecognized-spelling\)
// ----------------------------------------------------------------------

class ComQueue final : public ComQueueComponentBase {
// Added to enable easy testing of queue reprioritization

Check failure

Code scanning / check-spelling

Unrecognized Spelling

[reprioritization](#security-tab) is not a recognized word. \(unrecognized-spelling\)
LeStarch
LeStarch previously approved these changes Feb 5, 2026
Copy link
Collaborator

@LeStarch LeStarch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Willmac16 looks good to me, I would recommend a static assert that TOTAL_PORTS >= 1 for future proofing, but it looks good to me!

break; // Since we shouldn't find more than one queue at this port index
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should assert (static_assert) TOTAL_PORT_COUNT >= 1

this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
}

void ComQueue::SET_QUEUE_PRIORITY_cmdHandler(FwOpcodeType opCode,

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
namespace Types {

Queue::Queue() : m_internal(), m_message_size(0) {}
Queue::Queue() : m_internal(), m_message_size(0), m_mode(QUEUE_FIFO), m_overflow_mode(QUEUE_DROP_NEWEST) {}

Check notice

Code scanning / CodeQL

More than one statement per line Note

This line contains 2 statements; only one is allowed.
return Fw::FW_DESERIALIZE_BUFFER_EMPTY;
}
FwSizeType offset = current_size - m_message_size;
result = m_internal.peek(message, m_message_size, offset);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter message has not been checked.

if (m_mode == QUEUE_FIFO) {
// FIFO: Dequeue from the front (oldest message)
result = m_internal.peek(message, m_message_size, 0);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter message has not been checked.
static_cast<FwAssertArgType>(m_message_size)); // Message size is as expected
return m_internal.serialize(message, m_message_size);

Fw::SerializeStatus status = m_internal.serialize(message, m_message_size);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter message has not been checked.
m_internal.setup(storage, total_needed_size);
m_message_size = message_size;
m_mode = mode;
m_overflow_mode = overflow_mode;

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter overflow_mode has not been checked.
static_cast<FwAssertArgType>(depth), static_cast<FwAssertArgType>(message_size));
m_internal.setup(storage, total_needed_size);
m_message_size = message_size;
m_mode = mode;

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter mode has not been checked.
// Validate queue index
if (queueIndex < 0 || queueIndex >= TOTAL_PORT_COUNT) {
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
return;

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter opCode has not been checked.

// Validate queue index
if (queueIndex < 0 || queueIndex >= TOTAL_PORT_COUNT) {
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter cmdSeq has not been checked.

// Validate queue index
if (queueIndex < 0 || queueIndex >= TOTAL_PORT_COUNT) {
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter opCode has not been checked.
// Acquire the queue that we need to drain
FwIndexType queueIndex =
(queueType == QueueType::COM_QUEUE) ? index : static_cast<FwIndexType>(index + COM_PORT_COUNT);
FwIndexType queueIndex = this->getQueueNum(queueType, index);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter index has not been checked.
// Acquire the queue that we need to drain
FwIndexType queueIndex =
(queueType == QueueType::COM_QUEUE) ? index : static_cast<FwIndexType>(index + COM_PORT_COUNT);
FwIndexType queueIndex = this->getQueueNum(queueType, index);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter queueType has not been checked.
*/
struct TrimOkRule : public STest::Rule<MockTypes::CircularState> {
// Constructor
TrimOkRule(const char* const name);

Check warning

Code scanning / CppCheck

Single-parameter constructors should be marked explicit. Warning test

Single-parameter constructors should be marked explicit.
*/
struct TrimBadRule : public STest::Rule<MockTypes::CircularState> {
// Constructor
TrimBadRule(const char* const name);

Check warning

Code scanning / CppCheck

Single-parameter constructors should be marked explicit. Warning test

Single-parameter constructors should be marked explicit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants