ComQueue queue ordering, drop mode, & command to reprioritize#4674
ComQueue queue ordering, drop mode, & command to reprioritize#4674Willmac16 wants to merge 26 commits intonasa:develfrom
Conversation
…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.
| */ | ||
| 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.
| 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
| 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
| 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
|
|
||
| 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
| 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
| 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
| 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
| // 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
|
|
||
| // 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
|
|
||
| // 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
| // 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
| // 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
Svc/ComQueue/ComQueueCommands.fppi
Outdated
| 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 |
There was a problem hiding this comment.
This uses a U32.... Is this the right type?
There was a problem hiding this comment.
Priority is set in the C++ as a FwIndexType. We should keep this for consistency, no?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
It looks like negative priorities won't get populated, but I don't see anything that will explicitly warn you
Svc/ComQueue/ComQueueCommands.fppi
Outdated
| 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
Svc/ComQueue/ComQueue.hpp
Outdated
| // ---------------------------------------------------------------------- | ||
|
|
||
| class ComQueue final : public ComQueueComponentBase { | ||
| // Added to enable easy testing of queue reprioritization |
Check failure
Code scanning / check-spelling
Unrecognized Spelling
LeStarch
left a comment
There was a problem hiding this comment.
@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 | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
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
| 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
| 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
|
|
||
| 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
| 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
| 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
| 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
| // 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
|
|
||
| // 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
|
|
||
| // 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
| // 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
| // 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
| */ | ||
| 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
| */ | ||
| 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
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_OLDESTmode 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