Skip to content

Develop - #57

Closed
photonicslice wants to merge 12 commits into
mainfrom
develop
Closed

Develop#57
photonicslice wants to merge 12 commits into
mainfrom
develop

Conversation

@photonicslice

Copy link
Copy Markdown

Fix critical race conditions as outlined in #55 and bug fixes and add comprehensive testing infrastructure for tx_cache

This commit addresses critical bugs in tx_cache and hardens can_wrapper with
queue validation

Phase 1: tx_cache Critical Bug Fixes

Bugs Fixed:

  1. TxCache_Erase - Fixed incorrect circular buffer index translation

    • Was comparing position to logical index (caused wrong items to be erased)
    • Now correctly translates logical index to circular buffer position
    • Location: Src/can_wrapper/tx_cache.c:57-75
  2. TxCache_At - Fixed missing head offset in position calculation

    • Was using index % TX_CACHE_SIZE without accounting for head
    • Now correctly calculates position as (head + index) % TX_CACHE_SIZE
    • Location: Src/can_wrapper/tx_cache.c:77-84

Defensive Programming:

  • Added TxCache_IsValid() helper with assertions for debug builds
  • Added null pointer checks on all public functions
  • Added bounds validation throughout
  • Added thread-safety documentation to source file

Testing Infrastructure:

  • Created comprehensive standalone test suite (15 tests, 200+ assertions)
  • Tests run without STM32 HAL or FreeRTOS dependencies
  • All tests passing with zero compiler warnings
  • Files created:
    • tests/test_tx_cache.c - 700+ lines of comprehensive tests
    • tests/tx_cache_standalone.c - Standalone implementation for testing
    • tests/mock_can_message.h - Mock CAN types
    • tests/mock_tx_cache.h - Mock cache header
    • tests/Makefile - Build system with multiple targets
    • tests/README.md - Complete testing documentation

Phase 2: can_wrapper Architecture Overhaul & Critical Bug Fixes

Architecture Transformation:

BEFORE (Original 3-thread design):

  • Error_Handler_Thread directly accessed s_tx_cache (race condition)
  • ISR directly accessed s_tx_cache via TxCache_Find/Erase (race condition)
  • Used osThreadFlagsSet for signaling
  • 3 threads: Message Handler, Acknowledgement, Error Handler

AFTER (Single-owner pattern with command queue):

  • Cache_Manager_Thread is sole owner of s_tx_cache (race-condition-free)
  • ISR communicates via command queue (s_cache_command_queue)
  • All cache operations go through CacheCommand messages
  • 4 threads: Message Handler, Acknowledgement, Cache Manager, Error Callback

Critical Bugs Fixed:

  1. Bitwise OR instead of AND in ISR - Multiple locations

    // BEFORE (always true!)
    if (rx_behaviour | RX_ACK && !item.msg.is_ack)
    
    // AFTER (correct bit checking)
    if ((rx_behaviour & RX_ACK) && !item.msg.is_ack)

    Impact: ACKs/messages were being sent incorrectly

  2. Wrong index comparison in ISR

    // BEFORE (misses index 0!)
    if (index > 0) { TxCache_Erase(...); }
    
    // AFTER
    if (index >= 0) { TxCache_Erase(...); }

    Impact: First cached message never removed on ACK

  3. Incorrect osMessageQueuePut usage

    // BEFORE (wrong - passing pointer to queue handle)
    osMessageQueuePut(&s_ack_queue, &ack, 0U, 0U);
    
    // AFTER (correct - queue handle is already a pointer)
    osMessageQueuePut(s_ack_queue, &ack, 0U, 0U);
  4. Missing parentheses in StdId calculation

    // BEFORE (wrong operator precedence)
    msg->priority << 5 & PRIORITY_MASK
    
    // AFTER (correct)
    (msg->priority << 5) & PRIORITY_MASK

Race Condition Elimination:

  • Implemented command queue pattern (CacheCommand enum)
  • Cache_Manager_Thread processes: ADD, REMOVE_BY_ACK, SHUTDOWN
  • ISR and other threads never directly touch s_tx_cache
  • Process_Expired_Items() isolated to cache manager thread

Queue Overflow Handling:

  • Added validation for all osMessageQueuePut() operations
  • Track overflows in diagnostic statistics structure
  • Prevents silent message/ACK loss
  • Locations: Transmit_Raw, ISR, Process_Expired_Items

RTOS Object Validation:

  • Changed RTOS_Init() return type from void to ErrorCode
  • Validate all queue and thread creation (9 objects total)
  • Fail fast on resource exhaustion instead of crashing later
  • Location: Src/can_wrapper/can_wrapper.c:137-216

Diagnostic Statistics System:

  • Added CANWrapper_Statistics struct with 8 counters:
    • Queue overflow counts (4 queues)
    • Operational metrics (TX/RX/ACK counts, timeouts)
  • Enables telemetry monitoring and queue tuning
  • Location: Src/can_wrapper/can_wrapper.c:69-80

Code Quality Improvements:

  • Use TxCache_At() for safe cache access (better encapsulation)
  • Removed unused Calculate_Next_Timeout() declaration
  • Added 40+ lines of thread-safety documentation
  • Comprehensive header documentation of threading model

New Error Codes:

  • ERR_CWM_RTOS_QUEUE_CREATE_FAILED
  • ERR_CWM_RTOS_THREAD_CREATE_FAILED
  • ERR_CWM_CACHE_QUEUE_FULL
  • ERR_CWM_ACK_QUEUE_FULL
  • ERR_CWM_MSG_QUEUE_FULL
  • ERR_CWM_ERROR_QUEUE_FULL

Testing:

  • tx_cache: 15 tests, 200+ assertions, all passed
  • Memory safety: Verified with Address Sanitizer (zero issues)
  • can_wrapper: Manual testing required (hardware-dependent)

…ture

This commit addresses critical bugs in tx_cache and hardens can_wrapper with
queue validation and diagnostic statistics for production-ready operation.

## Phase 1: tx_cache Critical Bug Fixes

### Bugs Fixed:
1. **TxCache_Erase** - Fixed incorrect circular buffer index translation
   - Was comparing position to logical index (caused wrong items to be erased)
   - Now correctly translates logical index to circular buffer position
   - Location: Src/can_wrapper/tx_cache.c:57-75

2. **TxCache_At** - Fixed missing head offset in position calculation
   - Was using `index % TX_CACHE_SIZE` without accounting for head
   - Now correctly calculates position as `(head + index) % TX_CACHE_SIZE`
   - Location: Src/can_wrapper/tx_cache.c:77-84

### Defensive Programming:
- Added TxCache_IsValid() helper with assertions for debug builds
- Added null pointer checks on all public functions
- Added bounds validation throughout
- Added thread-safety documentation to source file

### Testing Infrastructure:
- Created comprehensive standalone test suite (15 tests, 200+ assertions)
- Tests run without STM32 HAL or FreeRTOS dependencies
- All tests passing with zero compiler warnings
- Files created:
  * tests/test_tx_cache.c - 700+ lines of comprehensive tests
  * tests/tx_cache_standalone.c - Standalone implementation for testing
  * tests/mock_can_message.h - Mock CAN types
  * tests/mock_tx_cache.h - Mock cache header
  * tests/Makefile - Build system with multiple targets
  * tests/README.md - Complete testing documentation

## Phase 2: can_wrapper Reliability Improvements

### Queue Overflow Handling:
- Added validation for all osMessageQueuePut() operations
- Track overflows in diagnostic statistics structure
- Prevents silent message/ACK loss
- Locations: Transmit_Raw, ISR, Process_Expired_Items

### RTOS Object Validation:
- Changed RTOS_Init() return type from void to ErrorCode
- Validate all queue and thread creation (9 objects total)
- Fail fast on resource exhaustion instead of crashing later
- Location: Src/can_wrapper/can_wrapper.c:137-216

### Diagnostic Statistics System:
- Added CANWrapper_Statistics struct with 8 counters:
  * Queue overflow counts (4 queues)
  * Operational metrics (TX/RX/ACK counts, timeouts)
- Enables telemetry monitoring and queue tuning
- Location: Src/can_wrapper/can_wrapper.c:69-80

### New Error Codes:
- ERR_CWM_RTOS_QUEUE_CREATE_FAILED
- ERR_CWM_RTOS_THREAD_CREATE_FAILED
- ERR_CWM_CACHE_QUEUE_FULL
- ERR_CWM_ACK_QUEUE_FULL
- ERR_CWM_MSG_QUEUE_FULL
- ERR_CWM_ERROR_QUEUE_FULL

## Testing:
- tx_cache: 15 tests, 200+ assertions, 100% pass rate
- Memory safety: Verified with Address Sanitizer (zero issues)
- can_wrapper: Manual testing required (hardware-dependent)
…ture

This commit addresses critical bugs in tx_cache and hardens can_wrapper with
queue validation and diagnostic statistics for production-ready operation.

## Phase 1: tx_cache Critical Bug Fixes

### Bugs Fixed:
1. **TxCache_Erase** - Fixed incorrect circular buffer index translation
   - Was comparing position to logical index (caused wrong items to be erased)
   - Now correctly translates logical index to circular buffer position
   - Location: Src/can_wrapper/tx_cache.c:57-75

2. **TxCache_At** - Fixed missing head offset in position calculation
   - Was using `index % TX_CACHE_SIZE` without accounting for head
   - Now correctly calculates position as `(head + index) % TX_CACHE_SIZE`
   - Location: Src/can_wrapper/tx_cache.c:77-84

### Defensive Programming:
- Added TxCache_IsValid() helper with assertions for debug builds
- Added null pointer checks on all public functions
- Added bounds validation throughout
- Added thread-safety documentation to source file

### Testing Infrastructure:
- Created comprehensive standalone test suite (15 tests, 200+ assertions)
- Tests run without STM32 HAL or FreeRTOS dependencies
- All tests passing with zero compiler warnings
- Files created:
  * tests/test_tx_cache.c - 700+ lines of comprehensive tests
  * tests/tx_cache_standalone.c - Standalone implementation for testing
  * tests/mock_can_message.h - Mock CAN types
  * tests/mock_tx_cache.h - Mock cache header
  * tests/Makefile - Build system with multiple targets
  * tests/README.md - Complete testing documentation

## Phase 2: can_wrapper Architecture Overhaul & Critical Bug Fixes

### Architecture Transformation:

**BEFORE (Original 3-thread design):**
- Error_Handler_Thread directly accessed s_tx_cache (race condition)
- ISR directly accessed s_tx_cache via TxCache_Find/Erase (race condition)
- Used osThreadFlagsSet for signaling
- 3 threads: Message Handler, Acknowledgement, Error Handler

**AFTER (Single-owner pattern with command queue):**
- Cache_Manager_Thread is sole owner of s_tx_cache (race-condition-free)
- ISR communicates via command queue (s_cache_command_queue)
- All cache operations go through CacheCommand messages
- 4 threads: Message Handler, Acknowledgement, Cache Manager, Error Callback

### Critical Bugs Fixed:

1. **Bitwise OR instead of AND in ISR** - Multiple locations
   ```c
   // BEFORE (always true!)
   if (rx_behaviour | RX_ACK && !item.msg.is_ack)

   // AFTER (correct bit checking)
   if ((rx_behaviour & RX_ACK) && !item.msg.is_ack)
   ```
   Impact: ACKs/messages were being sent incorrectly

2. **Wrong index comparison in ISR**
   ```c
   // BEFORE (misses index 0!)
   if (index > 0) { TxCache_Erase(...); }

   // AFTER
   if (index >= 0) { TxCache_Erase(...); }
   ```
   Impact: First cached message never removed on ACK

3. **Incorrect osMessageQueuePut usage**
   ```c
   // BEFORE (wrong - passing pointer to queue handle)
   osMessageQueuePut(&s_ack_queue, &ack, 0U, 0U);

   // AFTER (correct - queue handle is already a pointer)
   osMessageQueuePut(s_ack_queue, &ack, 0U, 0U);
   ```

4. **Missing parentheses in StdId calculation**
   ```c
   // BEFORE (wrong operator precedence)
   msg->priority << 5 & PRIORITY_MASK

   // AFTER (correct)
   (msg->priority << 5) & PRIORITY_MASK
   ```

### Race Condition Elimination:

- Implemented command queue pattern (CacheCommand enum)
- Cache_Manager_Thread processes: ADD, REMOVE_BY_ACK, SHUTDOWN
- ISR and other threads never directly touch s_tx_cache
- Process_Expired_Items() isolated to cache manager thread

### Queue Overflow Handling:
- Added validation for all osMessageQueuePut() operations
- Track overflows in diagnostic statistics structure
- Prevents silent message/ACK loss
- Locations: Transmit_Raw, ISR, Process_Expired_Items

### RTOS Object Validation:
- Changed RTOS_Init() return type from void to ErrorCode
- Validate all queue and thread creation (9 objects total)
- Fail fast on resource exhaustion instead of crashing later
- Location: Src/can_wrapper/can_wrapper.c:137-216

### Diagnostic Statistics System:
- Added CANWrapper_Statistics struct with 8 counters:
  * Queue overflow counts (4 queues)
  * Operational metrics (TX/RX/ACK counts, timeouts)
- Enables telemetry monitoring and queue tuning
- Location: Src/can_wrapper/can_wrapper.c:69-80

### Code Quality Improvements:
- Use TxCache_At() for safe cache access (better encapsulation)
- Removed unused Calculate_Next_Timeout() declaration
- Added 40+ lines of thread-safety documentation
- Comprehensive header documentation of threading model

### New Error Codes:
- ERR_CWM_RTOS_QUEUE_CREATE_FAILED
- ERR_CWM_RTOS_THREAD_CREATE_FAILED
- ERR_CWM_CACHE_QUEUE_FULL
- ERR_CWM_ACK_QUEUE_FULL
- ERR_CWM_MSG_QUEUE_FULL
- ERR_CWM_ERROR_QUEUE_FULL

## Testing:
- tx_cache: 15 tests, 200+ assertions, 100% pass rate
- Memory safety: Verified with Address Sanitizer (zero issues)
- can_wrapper: Manual testing required (hardware-dependent)
Comment thread tests/test_tx_cache.dSYM/Contents/Info.plist
@@ -0,0 +1,137 @@
/** (c) 2024 UMSATS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I don't think having two copies of the implementation is a good idea.
To mock a file's imports we should get the linker to link a mock implementation.

Comment thread tests/mock_tx_cache.h
@@ -0,0 +1,35 @@
/** (c) 2024 UMSATS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could we move the mocks to a mocks folder

#define RX_CLEAR_TX_STORE 0b100
#endif

// Simple test framework macros

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Logan and I had discussed using a testing framework. Not sure if we should use that.
Either way, we could move these assertions to a test utilities file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We'll discuss this in a workshop


// Integration into your main application
// Add this to your main.c:
/*

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Commented out code

Comment thread tests/README.md
make clean && make asan
```

## Critical Bugs Fixed

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can get rid of bugs fixed. This PR will keep track of them.

Comment thread tests/README.md
This single-owner pattern ensures race-condition-free operation in the FreeRTOS environment.

## License

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@Koloss0 what's our license for this codebase?

Comment thread tests/README.md
2. Run test suite to verify changes
3. Add new tests for new functionality

## Compiler Warnings

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can get rid of this section and the next. As a developer you don't really need to know what warning flags are enabled.
I like the zero warnings tolerated though.

Comment thread tests/README.md
@@ -0,0 +1,271 @@
# TxCache Standalone Test Suite

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can get rid of overview and files section.


// Performance benchmark (basic)
void test_basic_performance(void) {
printf("\n=== Basic Performance Test ===\n");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

What is the point of this test?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It's just a smoke test to confirm the RTOS tick counter works and time is progressing normally. As noted in the comment, it's very rudimentary level testing. Real performance testing would require hardware timers for accurate microsecond-level measurements. The point was to confirm that osKernelGetTickCount() actually works and returns sensible values before relying on the timeouts and time-based operations elsewhere in CAN Wrapper(e.g. timeout handling in cache-manager) as I couldn't do the hardware testing.

@Koloss0 Koloss0 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I appreciate the work you put into this. However, there's just far too much in here for me to properly review. It's also addressing much more than the original issue and I don't feel comfortable merging it until I understand all the decisions that went into the unit testing stuff. We're going to have to split this into smaller pieces. Sorry about this. Let's discuss it in the next meeting.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You have tsat-utilities-kit as a submodule of itself. This is definitely not right.

Comment thread tests/test_tx_cache.dSYM/Contents/Info.plist
Comment thread tests/Makefile
@@ -0,0 +1,58 @@
# Makefile for tx_cache standalone tests

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't change it yet until we've discussed it. I was mainly suggesting we might be able to integrate our tests with the IDE better with CMake since it supports it as a build system. But I don't know for sure how well it'd work.

Comment thread Src/debug/debug_logger.c

#include "tuk/debug/debug_logger.h"
#include "tuk/debug/print.h"
#include "../../Inc/tuk/debug/debug_logger.h"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Avoid backtracking in include paths.

#include <tuk/can_wrapper/tx_cache.h>
#include <assert.h>
#include <stddef.h>
#include <../../Inc/tuk/can_wrapper/tx_cache.h>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Avoid backtracking in include paths.

@Koloss0 Koloss0 closed this Jan 24, 2026
@Koloss0
Koloss0 deleted the develop branch January 24, 2026 22:32
Comment thread Src/can_wrapper/main.c

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This main function shouldn't be here since TUK is only a library. You only need main for running the unit tests.

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