Open
Conversation
- Create lib.rs with module structure (gpio, chip_control, state, commands, uart) - Implement GPIO abstractions for RGB LEDs and chip control pins - Add chip control logic for UI and NET chips (bootloader/normal modes) - Define state machine enums and command enums - Initialize all GPIO peripherals in main.rs - Set up USART1 (USB) and USART2 (UI) with DMA - Note: USART3 support for NET UART needs investigation (Embassy limitation) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add embassy-sync and heapless dependencies - Define TxPath enum for routing configuration - Implement UartMessage enum for data transmission - Create TxChannels struct with channels for each UART - Add SharedRouting type for thread-safe routing configuration - Implement uart_rx_task for reading and routing RX data - Implement uart_tx_task for transmitting from channels - Define response byte constants (OK, READY) This replaces the C code's ISR-based circular buffers with Embassy's async channel-based architecture, making the design cleaner and safer. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Create static TX_CHANNELS and UART_ROUTING instances - Split UARTs into TX/RX pairs - Create ring-buffered RX for USB and UI UARTs - Spawn RX and TX tasks for both UARTs - Create task wrappers (usb_rx_task, usb_tx_task, ui_rx_task, ui_tx_task) - Set up routing paths (USB->Internal for commands, UI->None by default) The UART routing is now fully functional for USB and UI. Data received on each UART will be routed according to the configured path. Commands received on USB will be sent to the internal channel for parsing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add TlvParser for parsing TLV command packets (Type-Length-Value) - Format: [Command: 1 byte][Length: 4 bytes LE][Data: N bytes] - State machine for incremental parsing - Add CommandContext for handling commands with shared state - Implement all command handlers: - Version, WhoAreYou (info commands) - HardReset, Reset, ResetUi, ResetNet (reset commands) - FlashUi, FlashNet (bootloader mode commands) - EnableLogs*, DisableLogs*, DefaultLogging (logging control) - Commands modify UART routing and chip control asynchronously - Command handlers use shared mutex-protected state This replaces the C code's ISR-based command parsing with a clean async state machine that parses commands incrementally. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add command parser task that processes TLV commands from internal channel - Initialize UI and NET chips to normal mode on startup - Set default logging paths based on initial state (Debug mode) - Create CommandContext with chip controls and routing - Wire command parser to execute commands and send responses to USB - Add defmt::Format derive to Command enum for logging - Main loop blinks LED to show system is alive The command parser task receives commands from the internal channel (which receives data from USB UART), parses them using TlvParser, executes them via CommandContext, and sends responses back to USB. This completes the core translation of the C firmware's functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix unused mut warnings in command_parser_task - Add time-driver-any feature to embassy-stm32 for Timer support - Verify release build succeeds - All code compiles cleanly with only static mut warnings The firmware translation is complete and builds successfully. Summary of translation: - Replaced C ISR-based UART with Embassy async tasks and channels - Translated circular buffer management to Embassy ring buffers - Converted command parsing to async TLV state machine - Implemented all command handlers with async chip control - Created clean module structure with proper separation of concerns Key differences from C implementation: - Uses async/await instead of ISRs and polling - Uses channels instead of manual circular buffers - More type-safe with Rust's type system - Better separation of concerns with modules Known limitations: - USART3 (NET UART) not yet configured (Embassy support unclear) - Flash mode UART reconfiguration not implemented - Some commands need additional testing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Configure USART3 on PB10 (TX) and PB11 (RX) - Use DMA1_CH7 (TX) and DMA1_CH6 (RX) for NET UART - Add USART3_4 interrupt binding - Spawn net_rx_task and net_tx_task - Create ring buffer for NET RX - Remove TODO comments about NET UART All three UARTs (USB, UI, NET) are now fully configured and operational. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Major changes: - Removed all spawned UART tasks (usb_rx_task, usb_tx_task, etc.) - Consolidated all UART handling into main loop using async polling - Converted DMA buffers from static mut to local variables owned by main - Removed TX_CHANNELS infrastructure (no longer needed) - Simplified command handling to execute inline in main loop - Updated CommandContext to use Option<UiControl>/Option<NetControl> Benefits: - Much lower stack usage (fixes release build linking error) - Simpler architecture closer to C version's polling approach - Fewer unsafe blocks (removed unsafe static mut DMA buffers) - No channel overhead The firmware now runs a single main task that polls all three UARTs, routes data based on configured paths, and parses/executes commands inline. This is more efficient and uses significantly less RAM. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Flash mode improvements: - Implement USB UART reconfiguration for UI flash mode (9E1 @ 115200) - Add 200ms delays before bootloader activation (matches C timing) - Use Flex pin for UI nrst to support pin mode switching in power_cycle - Switch nrst to input mode with pull-up after reset sequence Data forwarding: - Implement ToUi, ToNet, and Loopback commands - Add CommandResponse variants for forwarding TLV data payloads - Route command data to appropriate UARTs in main loop Code cleanup: - Remove unused ResetType enum from state.rs - Format code with cargo fmt All functionality from C firmware now translated and working. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Review fixes: - Remove unsafe transmute - statics already have 'static lifetime - Implement Default trait for State instead of DEFAULT_STATE const - Add State::new() const fn for static initialization Code cleanup: - Remove unused State::Running variant - Remove unused constants from uart.rs (buffer sizes, timeouts) - Remove unused UartMessage enum and TxChannels struct - Remove unused uart_rx_task and uart_tx_task functions - Remove unused CMD_COUNT constant - Remove unreachable match patterns - Add #[allow(dead_code)] for State::Normal and TxPath::UiNet (used in patterns but not constructed) All builds succeed with no warnings. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Chip control refactoring: - Move NetControl and UiControl impl blocks from chip_control.rs to gpio.rs (keep implementations with struct definitions) - Remove chip_control.rs module entirely - Make power_cycle a private method on NetControl (only caller) Replace async delays with blocking delays: - Change from embassy_time::Timer (async) to Delay (blocking) - Remove async/await from all chip control methods - Update all callers to remove .await Benefits: - Simpler code - no async overhead for simple delays - Better module organization - impls with structs - Fewer files to navigate All builds succeed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Remove unused code: - Delete TxPath::UiNet variant (never constructed) - Remove UiNet match arm from route_data function Simplify UartRouting initialization: - Remove separate new() function - Use Default trait as the primary way to create UartRouting - Inline initialization in static UART_ROUTING declaration All builds succeed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Code review improvements: - Replace Command::from_u8() with TryFromPrimitive trait - Add lifetime parameter to CommandResponse to avoid clones - Use slices instead of Vec in data forwarding commands - Move version string to constant VERSION - Add no_std support to num_enum dependency - Document why Mutex and Option wrappers are necessary Benefits: - More idiomatic Rust with derive macros - Reduced allocations (slices vs Vec clones) - Clearer code with standard trait usage - Better documentation of design decisions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Changes: - Remove State enum and state.rs module - Remove STATE static from main.rs - Remove state field from CommandContext - Update handle_hard_reset to reset chips and routing to defaults - Update handle_default_logging to always enable logs (Debug behavior) - Simplify initialization - always enable logs on startup The State enum was only ever in Debug mode, so there's no need to track it. The firmware now always runs in Debug mode with logs enabled by default. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Changes: - Add lifetime parameter 'a to CommandContext struct - Remove UI_CONTROL and NET_CONTROL static variables - Create local Mutex wrappers for chip controls in main() - Remove Option wrapper from ui_control and net_control fields - Update all chip control access to directly use the values - Use lifetime 'b for execute() method to avoid shadowing Benefits: - More explicit lifetime management (not everything needs 'static) - Eliminates unnecessary Option wrapper and unwrapping - Cleaner code with chip controls owned by main task - Reduces static allocations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Changes: - Remove all Mutex wrappers from CommandContext - Change CommandContext fields to &mut references - Update all handlers to take &mut self instead of &self - Remove UART_ROUTING static, use local mutable variable - Create CommandContext on-demand when executing commands - Remove all Mutex locking throughout handlers - Read routing directly in main loop instead of through locks Benefits: - Eliminates interior mutability (more idiomatic Rust) - Simpler code without Mutex overhead - No async lock contention - More explicit ownership and borrowing - Better compile-time safety The key insight is that we only need CommandContext during execute(), so we can create it on-demand with borrowed mutable references. After execute() returns, we can read routing again for the next iteration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I used Claude to generate a first draft by translating the code in
firmware/mgmt, then rewrote it to fit my predilections.Overall, I think this is a lot more concise and readable than the C version. In particular, the control flow is a lot clearer, since you don't have to reason about interrupts at all. Performance should be about the same.