a vim plugin that displays stuff on an led matrix

feat: add inital firmware

dunkirk.sh 379f8b0a 079884a4

verified
+71
.clang-format
··· 1 + --- 2 + Language: Cpp 3 + BasedOnStyle: Google 4 + IndentWidth: 2 5 + TabWidth: 2 6 + UseTab: Never 7 + ColumnLimit: 100 8 + AlignAfterOpenBracket: Align 9 + AlignConsecutiveAssignments: false 10 + AlignConsecutiveDeclarations: false 11 + AlignEscapedNewlines: Left 12 + AlignOperands: true 13 + AlignTrailingComments: true 14 + AllowAllParametersOfDeclarationOnNextLine: false 15 + AllowShortBlocksOnASingleLine: false 16 + AllowShortCaseLabelsOnASingleLine: false 17 + AllowShortFunctionsOnASingleLine: Inline 18 + AllowShortIfStatementsOnASingleLine: false 19 + AllowShortLoopsOnASingleLine: false 20 + AlwaysBreakAfterReturnType: None 21 + AlwaysBreakBeforeMultilineStrings: true 22 + AlwaysBreakTemplateDeclarations: Yes 23 + BinPackArguments: true 24 + BinPackParameters: true 25 + BreakBeforeBinaryOperators: None 26 + BreakBeforeBraces: Attach 27 + BreakBeforeTernaryOperators: true 28 + BreakConstructorInitializers: BeforeColon 29 + BreakInheritanceList: BeforeColon 30 + BreakStringLiterals: true 31 + CompactNamespaces: false 32 + ConstructorInitializerAllOnOneLineOrOnePerLine: true 33 + ConstructorInitializerIndentWidth: 4 34 + ContinuationIndentWidth: 4 35 + Cpp11BracedListStyle: true 36 + DerivePointerAlignment: false 37 + FixNamespaceComments: true 38 + IncludeBlocks: Regroup 39 + IncludeCategories: 40 + - Regex: '^<.*\.h>' 41 + Priority: 1 42 + - Regex: '^<.*' 43 + Priority: 2 44 + - Regex: '.*' 45 + Priority: 3 46 + IndentCaseLabels: true 47 + IndentPPDirectives: None 48 + IndentWrappedFunctionNames: false 49 + KeepEmptyLinesAtTheStartOfBlocks: false 50 + MaxEmptyLinesToKeep: 1 51 + NamespaceIndentation: None 52 + PointerAlignment: Left 53 + ReflowComments: true 54 + SortIncludes: true 55 + SortUsingDeclarations: true 56 + SpaceAfterCStyleCast: false 57 + SpaceAfterTemplateKeyword: true 58 + SpaceBeforeAssignmentOperators: true 59 + SpaceBeforeCpp11BracedList: false 60 + SpaceBeforeCtorInitializerColon: true 61 + SpaceBeforeInheritanceColon: true 62 + SpaceBeforeParens: ControlStatements 63 + SpaceBeforeRangeBasedForLoopColon: true 64 + SpaceInEmptyParentheses: false 65 + SpacesBeforeTrailingComments: 2 66 + SpacesInAngles: false 67 + SpacesInContainerLiterals: false 68 + SpacesInCStyleCastParentheses: false 69 + SpacesInParentheses: false 70 + SpacesInSquareBrackets: false 71 + Standard: Cpp11
+1
.envrc
··· 1 + use flake
+3
.gitignore
··· 1 + .direnv 2 + result 3 + build/
+69
CRUSH.md
··· 1 + # CRUSH.md - Daedalus Project Guidelines 2 + 3 + ## Build Commands 4 + - Setup environment: `direnv allow` 5 + - Build firmware: `cd firmware && make` 6 + - Flash to RP2350: `cd firmware && make flash` 7 + - Disassemble: `cd firmware && make disasm` 8 + - Clean build: `cd firmware && make clean` 9 + - Format code: `clang-format -i firmware/src/*.cpp firmware/src/*.h` 10 + - Lint code: `cppcheck --enable=all firmware/src/` 11 + 12 + ## Test Commands 13 + - Run all tests: `ctest -S build` 14 + - Run single test: `ctest -R <test_name> -V` 15 + 16 + ## Code Style Guidelines 17 + 18 + ### General 19 + - Use 2-space indentation 20 + - Max line length: 100 characters 21 + - UTF-8 encoding for all files 22 + - Follow Google C++ Style Guide with modifications in .clang-format 23 + 24 + ### Naming Conventions 25 + - Classes: PascalCase (e.g., `LedController`) 26 + - Functions: camelCase (e.g., `initializeHardware()`) 27 + - Variables: camelCase (e.g., `ledPin`) 28 + - Constants: UPPER_SNAKE_CASE (e.g., `MAX_BUFFER_SIZE`) 29 + - Files: snake_case.ext (e.g., `led_controller.cpp`) 30 + 31 + ### Error Handling 32 + - Use return codes for error reporting 33 + - Check return values from SDK functions 34 + - Use assertions for invariants 35 + - Avoid dynamic memory allocation when possible 36 + 37 + ### Nix Development 38 + - Pico SDK is provided via nixpkgs with withSubmodules override 39 + - All tools are managed through Nix 40 + - Use `nix flake update` to update dependencies 41 + 42 + ## Code Style Guidelines 43 + 44 + ### General 45 + - Use 2-space indentation 46 + - Max line length: 100 characters 47 + - UTF-8 encoding for all files 48 + 49 + ### Naming Conventions 50 + - Functions/methods: camelCase 51 + - Variables: camelCase 52 + - Constants: UPPER_SNAKE_CASE 53 + - Classes: PascalCase 54 + - Files: kebab-case.ext 55 + 56 + ### Error Handling 57 + - Use explicit error handling (no silent failures) 58 + - Log errors with appropriate context 59 + - Return meaningful error messages 60 + 61 + ### Comments 62 + - Use JSDoc-style comments for functions 63 + - Keep comments current with code changes 64 + - Explain "why" not "what" in comments 65 + 66 + ### Git Practices 67 + - Commit messages: Start with verb in present tense 68 + - Keep commits focused on single changes 69 + - Reference issues in commit messages when applicable
+36
firmware/CMakeLists.txt
··· 1 + cmake_minimum_required(VERSION 3.25) 2 + 3 + # Need to include pico-sdk cmake support. Must happen before project. 4 + include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake) 5 + 6 + project(daedalus_firmware 7 + LANGUAGES C CXX ASM 8 + VERSION 1.0 9 + ) 10 + 11 + set(CMAKE_C_STANDARD 11) 12 + set(CMAKE_CXX_STANDARD 17) 13 + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Get compilation DB 14 + 15 + # initialize the Raspberry Pi Pico SDK 16 + pico_sdk_init() 17 + 18 + # Tell CMake where to find the executable source file 19 + add_executable(${PROJECT_NAME} 20 + src/main.cpp 21 + ) 22 + 23 + # Create map/bin/hex/uf2 files 24 + pico_add_extra_outputs(${PROJECT_NAME}) 25 + 26 + # Link to pico_stdlib (gpio, time, etc. functions) 27 + target_link_libraries(${PROJECT_NAME} 28 + pico_stdlib 29 + hardware_gpio 30 + hardware_uart 31 + pico_multicore 32 + ) 33 + 34 + # Choice of available stdio outputs 35 + pico_enable_stdio_usb(${PROJECT_NAME} 1) # ~13880 extra bytes 36 + pico_enable_stdio_uart(${PROJECT_NAME} 0) # ~1176 extra bytes
+30
firmware/Makefile
··· 1 + # Little driver makefile to make the complicated bootloader less of a hassle. 2 + 3 + PROJECT=daedalus_firmware 4 + 5 + TOOLCHAIN_PREFIX=arm-none-eabi- 6 + 7 + # Check if FORCE_FLASH is set 8 + PICOTOOL_OPTS = $(if $(FORCE_FLASH),-f,) 9 + 10 + build/$(PROJECT).uf2: 11 + 12 + flash : build/$(PROJECT).uf2 13 + picotool load $(PICOTOOL_OPTS) $< 14 + picotool reboot 15 + 16 + build/$(PROJECT).uf2 build/$(PROJECT).elf: build FORCE 17 + $(MAKE) -C build 18 + $(TOOLCHAIN_PREFIX)size build/$(PROJECT).elf 19 + $(TOOLCHAIN_PREFIX)nm --print-size --size-sort --radix=d build/$(PROJECT).elf | awk '{printf("%5d %s\n", $$2, $$4);}' | sort -nr | head -20 20 + 21 + disasm: build/$(PROJECT).elf 22 + $(TOOLCHAIN_PREFIX)objdump -C -S build/$(PROJECT).elf 23 + 24 + build: 25 + cmake -B build -DCMAKE_VERBOSE_MAKEFILE=ON -DPICO_BOARD=pico2 26 + 27 + clean: 28 + rm -rf build 29 + 30 + FORCE:
+33
firmware/README.md
··· 1 + # Daedalus Firmware 2 + 3 + This directory contains the firmware for the RP2350 board. 4 + 5 + ## Building 6 + 7 + 1. Make sure you have the Pico SDK set up (automatically handled by the Nix flake) 8 + 2. Configure the build: 9 + ``` 10 + cmake -B build -S . 11 + ``` 12 + 3. Build the firmware: 13 + ``` 14 + cmake --build build 15 + ``` 16 + 4. The output files will be in the `build` directory: 17 + - `daedalus_firmware.uf2`: UF2 file for drag-and-drop programming 18 + - `daedalus_firmware.elf`: ELF file for debugging 19 + - `daedalus_firmware.hex`: HEX file for programming with external tools 20 + 21 + ## Flashing 22 + 23 + Connect the RP2350 board in bootloader mode (hold BOOTSEL while connecting USB) and copy the UF2 file: 24 + 25 + ``` 26 + cp build/daedalus_firmware.uf2 /path/to/rp2350/ 27 + ``` 28 + 29 + Or use picotool: 30 + 31 + ``` 32 + picotool load -x build/daedalus_firmware.uf2 33 + ```
+30
firmware/STYLE.md
··· 1 + # C++ style guide for Daedalus firmware 2 + 3 + ## Formatting 4 + - Use clang-format with the provided .clang-format file 5 + - Run before committing: `clang-format -i firmware/src/*.cpp firmware/src/*.h` 6 + 7 + ## Naming 8 + - Classes: PascalCase (e.g., `LedController`) 9 + - Functions: camelCase (e.g., `initializeHardware()`) 10 + - Variables: camelCase (e.g., `ledPin`) 11 + - Constants: UPPER_SNAKE_CASE (e.g., `MAX_BUFFER_SIZE`) 12 + - Macros: UPPER_SNAKE_CASE (e.g., `DEBUG_ENABLE`) 13 + - Files: snake_case (e.g., `led_controller.cpp`) 14 + 15 + ## Headers 16 + - Use `#pragma once` for header guards 17 + - Order includes: standard library, Pico SDK, project headers 18 + 19 + ## Comments 20 + - Use Doxygen-style comments for functions and classes 21 + - Comment complex algorithms and non-obvious code 22 + 23 + ## Error handling 24 + - Use return codes for error reporting 25 + - Check return values from SDK functions 26 + - Use assertions for invariants 27 + 28 + ## Memory management 29 + - Avoid dynamic memory allocation when possible 30 + - If needed, use RAII principles with smart pointers
+65
firmware/pico_sdk_import.cmake
··· 1 + # This file is copied from the Pico SDK 2 + # It allows the CMake project to find the Pico SDK 3 + 4 + # This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake 5 + 6 + # This can be dropped into an external project to help locate the Pico SDK 7 + # It should be included prior to project() 8 + 9 + if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 10 + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 11 + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 12 + endif () 13 + 14 + if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 15 + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 16 + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 17 + endif () 18 + 19 + if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 20 + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 21 + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 22 + endif () 23 + 24 + set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 25 + set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 26 + set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 27 + 28 + if (NOT PICO_SDK_PATH) 29 + if (PICO_SDK_FETCH_FROM_GIT) 30 + include(FetchContent) 31 + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 32 + if (PICO_SDK_FETCH_FROM_GIT_PATH) 33 + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 34 + endif () 35 + FetchContent_Declare( 36 + pico_sdk 37 + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 38 + GIT_TAG master 39 + ) 40 + if (NOT pico_sdk) 41 + message("Downloading Raspberry Pi Pico SDK") 42 + FetchContent_Populate(pico_sdk) 43 + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 44 + endif () 45 + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 46 + else () 47 + message(FATAL_ERROR 48 + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 49 + ) 50 + endif () 51 + endif () 52 + 53 + get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 54 + if (NOT EXISTS ${PICO_SDK_PATH}) 55 + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 56 + endif () 57 + 58 + set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 59 + if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 60 + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 61 + endif () 62 + 63 + set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 64 + 65 + include(${PICO_SDK_INIT_CMAKE_FILE})
+122
firmware/src/main.cpp
··· 1 + #include <stdlib.h> 2 + 3 + #include <cstring> 4 + 5 + #include "pico/multicore.h" 6 + #include "pico/stdlib.h" 7 + 8 + // Define GPIO pins for rows and columns 9 + const uint ROW_PINS[4] = {12, 13, 14, 15}; 10 + const uint COL_PINS[6] = {17, 18, 19, 20, 21, 22}; 11 + 12 + #define ROWS 4 13 + #define COLS 6 14 + 15 + // LED state matrix 16 + uint8_t led_states[ROWS][COLS] = {0}; 17 + 18 + void setup_pins() { 19 + // Set up row pins 20 + for (int i = 0; i < ROWS; i++) { 21 + gpio_init(ROW_PINS[i]); 22 + gpio_set_dir(ROW_PINS[i], GPIO_OUT); 23 + gpio_put(ROW_PINS[i], 0); // Start with LEDs off 24 + } 25 + 26 + // Set up column pins 27 + for (int j = 0; j < COLS; j++) { 28 + gpio_init(COL_PINS[j]); 29 + gpio_set_dir(COL_PINS[j], GPIO_OUT); 30 + gpio_put(COL_PINS[j], 1); // Start with LEDs off 31 + } 32 + } 33 + 34 + // Function to update the display at variable frequencies 35 + void update_led_display(uint32_t refresh_rate_hz) { 36 + static uint32_t last_update = 0; 37 + uint32_t current_time = to_ms_since_boot(get_absolute_time()); 38 + uint32_t update_interval = 1000 / refresh_rate_hz; 39 + 40 + // Only update at the specified frequency 41 + if (current_time - last_update < update_interval) { 42 + return; 43 + } 44 + 45 + last_update = current_time; 46 + 47 + // Display the current state 48 + for (int row = 0; row < ROWS; row++) { 49 + // Set row active 50 + gpio_put(ROW_PINS[row], 1); 51 + 52 + // Set column states for this row 53 + for (int col = 0; col < COLS; col++) { 54 + // LED on = column LOW, LED off = column HIGH 55 + gpio_put(COL_PINS[col], led_states[row][col] ? 0 : 1); 56 + } 57 + 58 + // Small delay for this row to be visible 59 + sleep_us(100); 60 + 61 + // Deactivate row 62 + gpio_put(ROW_PINS[row], 0); 63 + } 64 + } 65 + 66 + // Function to set a specific LED state 67 + void set_led(int row, int col, bool state) { 68 + if (row >= 0 && row < ROWS && col >= 0 && col < COLS) { 69 + led_states[row][col] = state ? 1 : 0; 70 + } 71 + } 72 + 73 + // Function to set the entire matrix state 74 + void set_matrix_state(const uint8_t new_state[ROWS][COLS]) { 75 + memcpy(led_states, new_state, sizeof(led_states)); 76 + } 77 + 78 + void random_state(float density) { 79 + // clamp 80 + if (density > 1.0f) 81 + density = 1.0f; 82 + if (density < 0.0f) 83 + density = 0.0f; 84 + 85 + for (int row = 0; row < ROWS; row++) { 86 + for (int col = 0; col < COLS; col++) { 87 + float r = (float)rand() / (float)RAND_MAX; 88 + led_states[row][col] = (r < density) ? 1 : 0; 89 + } 90 + } 91 + } 92 + 93 + const uint8_t ALL_ON[ROWS][COLS] = {{1, 1, 1, 1, 1, 1}, 94 + {1, 1, 1, 1, 1, 1}, 95 + {1, 1, 1, 1, 1, 1}, 96 + {1, 1, 1, 1, 1, 1}}; 97 + 98 + const uint8_t ALL_OFF[ROWS][COLS] = {{0, 0, 0, 0, 0, 0}, 99 + {0, 0, 0, 0, 0, 0}, 100 + {0, 0, 0, 0, 0, 0}, 101 + {0, 0, 0, 0, 0, 0}}; 102 + 103 + void core1_main() { 104 + while (true) { 105 + update_led_display(1000); 106 + } 107 + } 108 + 109 + int main() { 110 + stdio_init_all(); 111 + setup_pins(); 112 + 113 + multicore_launch_core1(core1_main); 114 + 115 + while (true) { 116 + random_state(0.5); // Turn random LEDs ON 117 + // set_matrix_state(ALL_ON); 118 + sleep_ms(200); 119 + // set_matrix_state(ALL_OFF); 120 + // sleep_ms(500); 121 + } 122 + }
+61
flake.lock
··· 1 + { 2 + "nodes": { 3 + "flake-utils": { 4 + "inputs": { 5 + "systems": "systems" 6 + }, 7 + "locked": { 8 + "lastModified": 1731533236, 9 + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 10 + "owner": "numtide", 11 + "repo": "flake-utils", 12 + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 13 + "type": "github" 14 + }, 15 + "original": { 16 + "owner": "numtide", 17 + "repo": "flake-utils", 18 + "type": "github" 19 + } 20 + }, 21 + "nixpkgs": { 22 + "locked": { 23 + "lastModified": 1756542300, 24 + "narHash": "sha256-tlOn88coG5fzdyqz6R93SQL5Gpq+m/DsWpekNFhqPQk=", 25 + "owner": "NixOS", 26 + "repo": "nixpkgs", 27 + "rev": "d7600c775f877cd87b4f5a831c28aa94137377aa", 28 + "type": "github" 29 + }, 30 + "original": { 31 + "owner": "NixOS", 32 + "ref": "nixos-unstable", 33 + "repo": "nixpkgs", 34 + "type": "github" 35 + } 36 + }, 37 + "root": { 38 + "inputs": { 39 + "flake-utils": "flake-utils", 40 + "nixpkgs": "nixpkgs" 41 + } 42 + }, 43 + "systems": { 44 + "locked": { 45 + "lastModified": 1681028828, 46 + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 + "owner": "nix-systems", 48 + "repo": "default", 49 + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 + "type": "github" 51 + }, 52 + "original": { 53 + "owner": "nix-systems", 54 + "repo": "default", 55 + "type": "github" 56 + } 57 + } 58 + }, 59 + "root": "root", 60 + "version": 7 61 + }
+66
flake.nix
··· 1 + { 2 + description = "Daedalus - RP2350 firmware and Vim plugin"; 3 + 4 + inputs = { 5 + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 + flake-utils.url = "github:numtide/flake-utils"; 7 + }; 8 + 9 + outputs = 10 + { 11 + nixpkgs, 12 + flake-utils, 13 + ... 14 + }: 15 + flake-utils.lib.eachDefaultSystem ( 16 + system: 17 + let 18 + pkgs = import nixpkgs { 19 + inherit system; 20 + }; 21 + 22 + # Needs to be synced past 23 + # https://github.com/NixOS/nixpkgs/pull/321786 24 + local-pico-sdk = pkgs.pico-sdk.override { 25 + withSubmodules = true; 26 + }; 27 + in 28 + { 29 + devShells.default = pkgs.mkShell { 30 + buildInputs = with pkgs; [ 31 + # C/C++ development 32 + gcc 33 + gcc-arm-embedded 34 + cmake 35 + gnumake 36 + 37 + # Pico SDK dependencies 38 + git 39 + python3 40 + python3Packages.pip 41 + python3Packages.setuptools 42 + picotool 43 + 44 + # Debugging tools 45 + gdb 46 + openocd 47 + 48 + # Utilities 49 + pkg-config 50 + minicom 51 + 52 + # Code quality 53 + clang-tools # clang-format, clang-tidy 54 + cppcheck 55 + ]; 56 + 57 + shellHook = '' 58 + # Set environment variables 59 + export PICO_SDK_PATH="${local-pico-sdk}/lib/pico-sdk" 60 + 61 + echo "Daedalus development environment ready!" 62 + ''; 63 + }; 64 + } 65 + ); 66 + }