diff --git a/.gitignore b/.gitignore index 3909b5d16..0e4de6258 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ .DS_STORE -.vscode \ No newline at end of file +.vscode + +env/ +venv/ +.env/ +.venv/ +__pycache__/ \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..f651d0108 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +# Minimum version of pre-commit +minimum_pre_commit_version: "2.9.0" + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + # Prevent committing directly to the main branch + - id: no-commit-to-branch + args: [--branch, main] + stages: [commit] + + - repo: local + hooks: + - id: clang-format + name: Run git-clang-format + entry: git clang-format --style=file --staged + language: python + stages: [commit] + additional_dependencies: + - clang-format~=19.0 diff --git a/datasheets/analog_devices/MAX33042E.pdf b/datasheets/analog_devices/MAX33042E.pdf new file mode 100644 index 000000000..0899c6331 Binary files /dev/null and b/datasheets/analog_devices/MAX33042E.pdf differ diff --git a/docs/docs/firmware/compile-project.md b/docs/docs/firmware/compile-project.md index 8acd244e5..308533aec 100644 --- a/docs/docs/firmware/compile-project.md +++ b/docs/docs/firmware/compile-project.md @@ -1,8 +1,10 @@ # Compiling a Project -We have a CMake build system and Makefile front end. +We have a CMake build system and Makefile front end. The Makefile expects 2 variables from the command line. -The Makefile expects 2 variables from the command line +!!! note "Virtual Environment" + + These instructions assume that your [`cangen` virtual environment is active](dev-setup.md/#install-cangen). ## Makefile Variables @@ -42,3 +44,8 @@ This command only applies when `#!bash PLATFORM=stm32f767`. It deletes all "giti ### `st-flash` Calls `build` then downloads the firmware to a connected stm device. + +!!! tip + You should use the [STM32CubeProgrammer](dev-setup.md/#stm32cubeprogrammer) software instead of `st-flash`. + + See [Flashing Firmware](flashing/index.md). diff --git a/docs/docs/firmware/dev-setup.md b/docs/docs/firmware/dev-setup.md index 7ffedf16e..f18347f71 100644 --- a/docs/docs/firmware/dev-setup.md +++ b/docs/docs/firmware/dev-setup.md @@ -45,12 +45,6 @@ Follow these steps to begin developing in `racecar/firmware`. C:\path-to-msys2\mingw64\lib ``` - 5. Install the Arm GNU Toolchain from . - - 1. Download the `.exe` installer under "Windows hosted cross toolchains -> AArch32 bare-metal target (arm-none-eabi)". - 2. Run the installer. - 3. After the installer finishes, check `Add path to environment variable.` - === "Linux" 1. Set up the Kitware APT repository . @@ -61,25 +55,21 @@ Follow these steps to begin developing in `racecar/firmware`. ```bash sudo apt-get update - sudo apt-get install software-properties-common + sudo apt-get install software-properties-common python3-launchpadlib sudo add-apt-repository ppa:deadsnakes/ppa sudo apt-get update sudo apt-get install git-all build-essential cmake python3.12 wget gcc-13 ``` - 3. Install the Arm GNU Toolchain. +### Arm Toolchain - 1. Download and unzip the x86_64 Linux arm-none-eabi toolchain binaries. +Install the Arm GNU Toolchain (v13 or newer) from . - wget https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz - sudo tar xf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz -C /usr/share - rm arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz +1. Find the __ hosted cross toolchains__ section for your computer's architecture then download and install the __AArch32 bare-metal target (arm-none-eabi)__. - 2. Add the binaries to your profile PATH. + > There are multiple downloads available in this section. Choose the installer: `.exe` on Windows, `.tar.xz` on Linux, `.pkg` on MacOS. - Open `~/.profile` in a text editor and add this to the end of the file. - - PATH="/usr/share/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:$PATH" +2. Add the folder containing the binaries to your path. ### Verify Installation @@ -150,7 +140,7 @@ Navigate to a directory where you would like to hold the `racecar` repo (I used git clone --recurse-submodules https://github.com/macformula/racecar.git -## Install CANgen dependencies +## Install CANgen Create a Python virtual environment for CANgen. Navigate into `racecar/firmware` and run. @@ -168,14 +158,16 @@ Create a Python virtual environment for CANgen. Navigate into `racecar/firmware` source .env/bin/activate ``` -The second command "activates" the virtual environment. You will see `(.env)` beside your terminal prompt when it is activated, and it must be activated before building any project. +The second command "activates" the virtual environment. You will see `(.env)` beside your terminal prompt when it is activated. __It must be activated before building any project.__ -Finally, with the environment activated, install the CANgen requirements. +With the environment activated, change into `racecar/` and install CANgen: ```bash -pip install -r ../scripts/cangen/requirements.txt +pip install -e scripts/cangen ``` +> The `-e` flag is _very_ important. It installs CANgen as an editable package which means you won't have to reinstall when the package is changed. + You can now start developing in `racecar`! However, I recommend you configure your IDE with `clangd`, so continue to the next section. ## IDE Integration @@ -234,3 +226,23 @@ __Important:__ Create an empty file named `.clangd` in the `firmware/` directory You will need a Unix development environment (Unix machine, WSL, or remote into the Raspberry Pi). Go through the [gRPC C++ Quickstart Guide](https://grpc.io/docs/languages/cpp/quickstart/). Build the example project. + +## Pre-Commit Setup + +We use `pre-commit` hooks to run formatting and code checks before the code is pushed. + +### Installing Pre-Commit + +1. Install `pre-commit` via pip: + + ```bash + pip install pre-commit + ``` + +2. Install the git hooks by running this command in the `racecar` directory: + + ```bash + pre-commit install + ``` + + This will install the hooks so they run automatically when you use `git commit`. diff --git a/docs/docs/firmware/flashing/img/.gitignore b/docs/docs/firmware/flashing/img/.gitignore new file mode 100644 index 000000000..87118d95b --- /dev/null +++ b/docs/docs/firmware/flashing/img/.gitignore @@ -0,0 +1,2 @@ +# draw.io backups +*.bkp \ No newline at end of file diff --git a/docs/docs/firmware/flashing/img/blue_chest.jpg b/docs/docs/firmware/flashing/img/blue_chest.jpg new file mode 100644 index 000000000..a6aa9c12b Binary files /dev/null and b/docs/docs/firmware/flashing/img/blue_chest.jpg differ diff --git a/docs/docs/firmware/flashing/img/chest-bags.png b/docs/docs/firmware/flashing/img/chest-bags.png new file mode 100644 index 000000000..4cad2965d Binary files /dev/null and b/docs/docs/firmware/flashing/img/chest-bags.png differ diff --git a/docs/docs/firmware/flashing/img/cubeprog.png b/docs/docs/firmware/flashing/img/cubeprog.png new file mode 100644 index 000000000..6021bb593 Binary files /dev/null and b/docs/docs/firmware/flashing/img/cubeprog.png differ diff --git a/docs/docs/firmware/flashing/img/cubeprog_diagram-Download.png b/docs/docs/firmware/flashing/img/cubeprog_diagram-Download.png new file mode 100644 index 000000000..af9e01150 Binary files /dev/null and b/docs/docs/firmware/flashing/img/cubeprog_diagram-Download.png differ diff --git a/docs/docs/firmware/flashing/img/cubeprog_diagram-STLink.png b/docs/docs/firmware/flashing/img/cubeprog_diagram-STLink.png new file mode 100644 index 000000000..5d88c69c7 Binary files /dev/null and b/docs/docs/firmware/flashing/img/cubeprog_diagram-STLink.png differ diff --git a/docs/docs/firmware/flashing/img/cubeprog_diagram.drawio b/docs/docs/firmware/flashing/img/cubeprog_diagram.drawio new file mode 100644 index 000000000..60a865767 --- /dev/null +++ b/docs/docs/firmware/flashing/img/cubeprog_diagram.drawio @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/docs/firmware/flashing/img/cubeprog_firstscreen.png b/docs/docs/firmware/flashing/img/cubeprog_firstscreen.png new file mode 100644 index 000000000..3bafa42a1 Binary files /dev/null and b/docs/docs/firmware/flashing/img/cubeprog_firstscreen.png differ diff --git a/docs/docs/firmware/flashing/img/etape.jpg b/docs/docs/firmware/flashing/img/etape.jpg new file mode 100644 index 000000000..8716ba642 Binary files /dev/null and b/docs/docs/firmware/flashing/img/etape.jpg differ diff --git a/docs/docs/firmware/flashing/img/notch-2.jpg b/docs/docs/firmware/flashing/img/notch-2.jpg new file mode 100644 index 000000000..e19450c2d Binary files /dev/null and b/docs/docs/firmware/flashing/img/notch-2.jpg differ diff --git a/docs/docs/firmware/flashing/img/nucleo144-f767zi.png b/docs/docs/firmware/flashing/img/nucleo144-f767zi.png new file mode 100644 index 000000000..997fd10eb Binary files /dev/null and b/docs/docs/firmware/flashing/img/nucleo144-f767zi.png differ diff --git a/docs/docs/firmware/flashing/img/setup_labelled.jpg b/docs/docs/firmware/flashing/img/setup_labelled.jpg new file mode 100644 index 000000000..3c0ff947e Binary files /dev/null and b/docs/docs/firmware/flashing/img/setup_labelled.jpg differ diff --git a/docs/docs/firmware/flashing/img/st-bag.jpg b/docs/docs/firmware/flashing/img/st-bag.jpg new file mode 100644 index 000000000..4432f5e04 Binary files /dev/null and b/docs/docs/firmware/flashing/img/st-bag.jpg differ diff --git a/docs/docs/firmware/flashing/img/tms-jtag.jpg b/docs/docs/firmware/flashing/img/tms-jtag.jpg new file mode 100644 index 000000000..0d5ee872e Binary files /dev/null and b/docs/docs/firmware/flashing/img/tms-jtag.jpg differ diff --git a/docs/docs/firmware/flashing/index.md b/docs/docs/firmware/flashing/index.md new file mode 100644 index 000000000..bf56e6ea8 --- /dev/null +++ b/docs/docs/firmware/flashing/index.md @@ -0,0 +1,111 @@ +# :material-download: Flashing Firmware + +After [compiling a project](../compile-project.md) for the `stm32f767` platform, you need to flash the firmware to the board. This article describes how to connect to a board and flash using [STM32CubeProgrammer](../dev-setup.md/#stm32cubeprogrammer). + +## Connect to the Board + +We flash using ST-Link which is an interface to STM microcontrollers. + +### Development Boards + Dashboard + +Most development boards (such as the [Nucleo-144](https://www.st.com/en/evaluation-tools/nucleo-f767zi.html) and [dashboard kit](https://www.st.com/en/evaluation-tools/stm32f7508-dk.html)) have built-in ST-Link hardware and a USB interface. + +Simply connect the board to your laptop with a USB cable. + +
+ ![nucleo stlink](img/nucleo144-f767zi.png){ width="100%" } +
ST-Link on Nucleo-144 F767ZI
+
+ +### Vehicle ECUs + +The vehicle ECUs are not development boards. They are bare STM32F7 processors soldered to a circuit board. These boards do not have a built-in ST-Link or USB interface so we must use a different connector. + +You will need and external ST-Link and a USB cable from the blue tool chest in the Hatch bay. Some of the ST-Links are Micro-USB and others are USB-C. We should have cables for both. + +
+![](img/chest-bags.png){ width="80%" } +
ST-Link and cables are kept in bags in this drawer. Return them when finished!
+
+ +Please wrap the ST-Link in electrical tape since it has exposed conductors and is very easy to fry. + +
+![](img/etape.jpg){ width="80%" } +
E-Tape would have prevented the Great ST-Link Massacre of Comp '24.
+
+ +1. Ensure the ECU is off (not receiving power) and the USB is not connected to your laptop. +2. Carefully connect the grey ribbon cable to the ST-Link and the JTAG connector on the ECU board. + + Both ends of the ribbon cable have a tab which must align with the notch on the connector. + +
+ ![](img/notch-2.jpg){ width="80%" } +
Connector tab and notch
+
+ +3. Power on the ECU. Talk to an upper year SW or Electrical member for help. +4. Connect your laptop to the ST-Link using the USB cable. + +Full setup: + +![](img/setup_labelled.jpg) + +## Open CubeProgrammer + +You installed Cube Programmer when [Setting up your Development Environment](../dev-setup.md). Run the program. It will open to a screen like this: + +
+![](img/cubeprog_firstscreen.png){ width="100%" } +
+ +### Connect to the STM32 with ST Link + +
+![](img/cubeprog_diagram-STLink.png){ width="60%" } +
+ +1. Select __ST-LINK__ as the programming interface. +2. Select the ST-Link device serial number. There should only be one option if you are plugged into a single device. +3. Verify the ST-Link configuration. +4. Click __Connect__. + +### Flash your program + +
+![](img/cubeprog_diagram-Download.png){ width="80%" } +
+ +1. Switch to the __Download__ window. +2. Select the binary file to flash. This is the `.bin` file located in + + ```text + racecar/firmware/build/PROJECT/PLATFORM/ + ``` + +3. Verify the flash configuration. +4. Click __Start Programming__. + +## Troubleshooting + +### First flash succeeds, second fails + +Disconnect from the ST-Link then reconnect. Wait a few seconds and click __Start Programming__ again. + +### Cannot flash at all + +You are connected to ST-Link but unable to flash. + +* Is the ECU powered? The ST-Link is powered by your laptop but the ECU needs external power. + +### Cannot connect to ST-Link + +The ST-Link serial appears but I cannot connect: + +1. Verify the ST-Link configuration. + +The ST-Link serial number does NOT appear: + +1. Check your USB connections. +2. Verify the ST-Link is receiving power by looking for LED lights. diff --git a/docs/docs/firmware/hw-debug.md b/docs/docs/firmware/hw-debug.md new file mode 100644 index 000000000..c82453979 --- /dev/null +++ b/docs/docs/firmware/hw-debug.md @@ -0,0 +1,113 @@ +# :material-bug: Hardware Debugging + +## Background + +For debugging our boards, we use OpenOCD and GDB. + +[OpenOCD (Open On-Chip Debugger)](https://openocd.org/) is a tool that enables on-chip debugging, flash programming, and testing for microcontrollers. It will start a server that listens for commands from various sources such as GDB. + +[GDB (GNU Debugger)](https://www.sourceware.org/gdb/) is a debugging tool that enables inspection, modification, and control of program execution on microcontrollers. + +## Installation + +=== "Windows" + ```text + choco install openocd + ``` + +=== "Linux" + ```text + sudo apt-get install openocd + ``` + +=== "Mac" + ```text + brew install openocd + ``` + +The ARM GNU Toolchain containing GDB is already installed if you followed the [Firmware Development Setup](../firmware/dev-setup.md) guide. Refer to that if it is not installed. + +### Verify Installation + +Check that both programs are installed and have an acceptable version. + +Do not copy the `# version comments`. + +```text +openocd --version # >= 0.12.0 +arm-none-eabi-gdb --version # >= 13.0 +``` + +## Usage + +To debug a program, the OpenOCD server must be started and GDB connected to it. + +1. Build your project for the `stm32f767` platform. See [Compiling a Project](../firmware/compile-project.md) for more details: + + ```bash + make PROJECT=Demo/Blink PLATFORM=stm32f767 build + ``` + +2. Plug your board into your computer and ensure it is powered on. + +3. Start the OpenOCD server: + + ```bash + make PROJECT=Demo/Blink PLATFORM=stm32f767 debug-openocd + ``` + +4. In a separate terminal, start GDB: + + ```bash + make PROJECT=Demo/Blink PLATFORM=stm32f767 debug-gdb + ``` + +5. Start debugging in the GDB terminal. See the list of common commands and an example below. + +### GDB Commands + +These commands are executed directly in the GDB terminal. + +`help`: Displays a list of available commands and their syntax/descriptions. + +`load`: Loads the program into the target device's memory. The `debug-gdb` command has been configured to do this automatically on startup. + +`continue`: Resumes program execution until the next breakpoint or end. + +`finish`: Continues execution until the current function finishes, then stops. + +`next`: Executes the next line of code, stepping over any function calls. + +`step`: Executes the next line of code, stepping into any function calls. + +`break`: Sets a breakpoint at a specified line or function to pause execution. + +`info breakpoints`: Lists all active breakpoints and their details. + +`where`: Displays the current call stack, showing the active function and its caller hierarchy. + +Refer to [VisualGDB](https://visualgdb.com/gdbreference/commands/) and [GDB Cheat Sheet](https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf) for more commands and details. + +### Example + +The following commands show an example debugging session with the Blink project. + +```bash + make PROJECT=Demo/Blink PLATFORM=stm32f767 debug-openocd +``` + +```bash + make PROJECT=Demo/Blink PLATFORM=stm32f767 debug-gdb +``` + +```text + (gdb) break main # Set a breakpoint at the main function + (gdb) continue # Continue the execution of the program + (gdb) where # Display the current call stack + (gdb) next # Execute the next line of code + (gdb) quit # Exit GDB +``` + +## Resources + +Refer to additional documentation for more information on debugging with [OpenOCD](https://openocd.org/doc/html/index.html) and [GDB](https://sourceware.org/gdb/current/onlinedocs/gdb/). diff --git a/docs/docs/firmware/project-structure/index.md b/docs/docs/firmware/project-structure/index.md index bf2fb0dbd..ca416543b 100644 --- a/docs/docs/firmware/project-structure/index.md +++ b/docs/docs/firmware/project-structure/index.md @@ -94,7 +94,7 @@ We now add 3 elements to our contract. --8<-- "inc/bindings.h" ``` -This completes the bindings contract. We can now write the application code, knowing that the platforms will all stasify this contract. +This completes the bindings contract. We can now write the application code, knowing that the platforms will all satisfy this contract. ## Application code diff --git a/docs/docs/tutorials/ssh-signing/clone-with-ssh.png b/docs/docs/tutorials/ssh-signing/clone-with-ssh.png new file mode 100644 index 000000000..24e7a0840 Binary files /dev/null and b/docs/docs/tutorials/ssh-signing/clone-with-ssh.png differ diff --git a/docs/docs/tutorials/ssh-signing/index.md b/docs/docs/tutorials/ssh-signing/index.md new file mode 100644 index 000000000..27b3f5226 --- /dev/null +++ b/docs/docs/tutorials/ssh-signing/index.md @@ -0,0 +1,121 @@ +# :material-key: SSH and Commit Signing + +This tutorial will guide you through setting up an SSH key and commit signing for GitHub. SSH keys are a more secure way to connect to GitHub, rather than other protocols like HTTPS. Commit signing is used to verify that commits are coming from you and have not been tampered with. + +!!! warning + You must have a [verified email address on GitHub](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/verifying-your-email-address) to add SSH keys and sign commits. + +## Create an SSH Key + +In a bash terminal, enter the following command: + +=== "Windows" + + ```text + ssh-keygen -t ed25519 -C "your_github_email@example.com" + ``` + + When prompted, save to the default location `c:/Users/YOU/.ssh/id_ed25519` and do not enter a passphrase. This will allow you to use the key without entering a password every time you push to GitHub. + + Continue with the following commands: + + ```text + cat c:/Users/YOU/.ssh/id_ed25519 | clip + eval "$(ssh-agent -s)" + ssh-add c:/Users/YOU/.ssh/id_ed25519 + ``` + +=== "Linux/Mac" + + ```text + ssh-keygen -t ed25519 -C "your_github_email@example.com" + ``` + + When prompted, save to the default location `~/.ssh/id_ed25519` and do not enter a passphrase. This will allow you to use the key without entering a password every time you push to GitHub. + + Continue with the following commands: + + ```text + pbcopy < ~/.ssh/id_ed25519.pub + eval "$(ssh-agent -s)" + ssh-add ~/.ssh/id_ed25519 + ``` + +To add the key to your GitHub account, go to . + +- Name your key something descriptive. +- Select "Authentication Key" as the key type. +- Paste the contents of `id_ed25519.pub` into the "Key" box. +- Click "Add SSH Key". + +Open another terminal to test your connection to GitHub by entering the following command: + +```text +ssh -T git@github.com +``` + +Type "yes" when it asks if you want to continue connecting. +You should see a message like "Hi username! You've successfully authenticated, but GitHub does not provide shell access." + +## Enable Commit Signing + +To add a signing key to your GitHub account, go to . + +- Name your key something descriptive. +- Select "Signing Key" as the key type. +- Paste the contents of `id_ed25519.pub` into the "Key" box. +- Click "Add SSH Key." + +Update your git configuration in your terminal to automatically sign commits with your key: + +=== "Windows" + ```text + git config --global user.signingkey c:/Users/YOU/.ssh/id_ed25519 + git config --global gpg.format ssh + git config --global commit.gpgsign true + ``` + +=== "Linux/Mac" + ```text + git config --global user.signingkey ~/.ssh/id_ed25519 + git config --global gpg.format ssh + git config --global commit.gpgsign true + ``` + +## Enable Vigilant Mode + +Go to and scroll down to the "Vigilant Mode" section. Enable "Enable Vigilant Mode". + +![Vigilant Mode](./vigilant-mode.png) + +This will now mark and display all of your commits with a signature verification status tag. + +![Marked Commits](./marked-commits.png) + +Verify your commits are signed by checking your commit history on GitHub for "Verified" tags. + +## Set Repo to Use SSH + +It is likely your repository is using HTTPS to connect to GitHub. To check which remote URL is currently being used, run the following terminal command inside of a repository: + +```text +git remote -v +``` + +To convert to SSH, run the following command, replacing `orgname` and `reponame` with your GitHub organization and repository names (i.e. `macformula` and `racecar`): + +```text +git remote set-url origin git@github.com:orgname/reponame.git +``` + +To avoid this manual configuration in the future, clone repositories using their SSH URL instead of HTTPS. + +![Clone with SSH](./clone-with-ssh.png) + +## Resources + +- [Generating a new SSH key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) + +- [Testing your SSH connection](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection) + +- [Managing commit signature verification](https://docs.github.com/en/authentication/managing-commit-signature-verification) diff --git a/docs/docs/tutorials/ssh-signing/marked-commits.png b/docs/docs/tutorials/ssh-signing/marked-commits.png new file mode 100644 index 000000000..60ac56b7c Binary files /dev/null and b/docs/docs/tutorials/ssh-signing/marked-commits.png differ diff --git a/docs/docs/tutorials/ssh-signing/vigilant-mode.png b/docs/docs/tutorials/ssh-signing/vigilant-mode.png new file mode 100644 index 000000000..0c89f4a9e Binary files /dev/null and b/docs/docs/tutorials/ssh-signing/vigilant-mode.png differ diff --git a/docs/docs/tutorials/wsl-can/img/gui1.webp b/docs/docs/tutorials/wsl-can/img/gui1.webp new file mode 100644 index 000000000..4923a6e93 Binary files /dev/null and b/docs/docs/tutorials/wsl-can/img/gui1.webp differ diff --git a/docs/docs/tutorials/wsl-can/img/gui2.webp b/docs/docs/tutorials/wsl-can/img/gui2.webp new file mode 100644 index 000000000..08685661f Binary files /dev/null and b/docs/docs/tutorials/wsl-can/img/gui2.webp differ diff --git a/docs/docs/tutorials/wsl-can/img/gui3.webp b/docs/docs/tutorials/wsl-can/img/gui3.webp new file mode 100644 index 000000000..ba7bf50e8 Binary files /dev/null and b/docs/docs/tutorials/wsl-can/img/gui3.webp differ diff --git a/docs/docs/tutorials/wsl-can/img/gui4.webp b/docs/docs/tutorials/wsl-can/img/gui4.webp new file mode 100644 index 000000000..f60d5c85e Binary files /dev/null and b/docs/docs/tutorials/wsl-can/img/gui4.webp differ diff --git a/docs/docs/tutorials/wsl-can/index.md b/docs/docs/tutorials/wsl-can/index.md new file mode 100644 index 000000000..be205bb84 --- /dev/null +++ b/docs/docs/tutorials/wsl-can/index.md @@ -0,0 +1,126 @@ +# :material-linux: Virtual CAN on WSL2 + +By default, WSL2 does not support Virtual CAN, however it can be enabled by building a custom WSL2 kernel. + +!!! warning "This setup assumes you are running within WSL. If you do not have WSL installed, open up a Windows terminal and run:" + wsl --install + +## Step 1: Update the WSL Environment + +Run the following commands in your WSL terminal to update your environment and install the required dependencies. + + sudo apt-get update -y + +### Install dependencies + + sudo apt install -y dwarves libelf-dev flex bison libssl-dev libncurses-dev bc build-essential make + sudo apt install -y --no-install-recommends wslu + +## Step 2: Download the WSL2 Linux Kernel + +To ensure compatibility, you need the specific kernel version of WSL2. + +1. **Check your kernel version:** + + uname -r + + - Example output: `5.15.153.1-microsoft-standard-WSL2` + - Note the version number, as it must match with `` in step 2, 3, and 4. + +2. **Download the kernel source**: + + - Go to the [WSL2 Linux Kernel repository](https://github.com/microsoft/WSL2-Linux-Kernel/tags). + - Find and copy the link for the `Source code (tar.gz)` file matching your kernel version. + +3. **Download and extract the file**: + + wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-.tar.gz + tar -xf linux-msft-wsl-.tar.gz + +4. **Navigate to the extracted folder:** + + cd WSL2-Linux-Kernel- + +## Step 3: Configure Kernel Settings + +1. **Load current configuration**: + + cat /proc/config.gz | gunzip > .config + +2. **Prepare the kernel for modules**: + + make prepare modules_prepare -j $(expr $(nproc) - 1) + +3. **Open the configuration menu**: + + make menuconfig -j $(expr $(nproc) - 1) + + A menu interface should open. Use this to enable the necessary drivers for Virtual CAN. + +![Step 1](img/gui1.webp) + +### Enable CAN Drivers + +- Navigate to **Networking Support** and press `Enter`. +- Select **CAN BUS subsystem support** by pressing `M`, then press `Enter`. + +![Step 2](img/gui2.webp) +![Step 3](img/gui3.webp) + +### Enable CAN Device Drivers + +- Navigate to **CAN Device Drivers**. +- For each driver shown in the screenshot, press `M` to enable as a module. +- Save and exit the configuration menu. + +![Step 4](img/gui4.webp) + +## Step 4: Compile and Install Kernel Modules + +Run the following commands to compile and install the Virtual CAN modules: + + make modules -j $(expr $(nproc) - 1) + sudo make modules_install + +Then, compile the kernel: + + make -j $(expr $(nproc) - 1) + +## Step 5: Configure WSL to Use the Custom Kernel + +1. **Create a symbolic link** for the module directory, matching your kernel version: + + sudo ln -s /lib/modules/5.15.153.1-microsoft-standard-WSL2+ /lib/modules/5.15.153.1-microsoft-standard-WSL2 + +2. **Copy the vmlinux file**: + + Replace `` with your actual Windows username: + + cp vmlinux /mnt/c/Users// + + - In Windows File Explorer, you should now see a file named `vmlinux`. + +3. **Configure `.wslconfig`**: + + Create a file named `.wslconfig` in the same directory (i.e. in `/mnt/c/Users//`) and paste the following to the file: + + [wsl2] + kernel=C:\\Users\\\\vmlinux + +## Step 6: Restart WSL and Verify + +1. In a separate Windows terminal (not WSL), restart WSL: + + wsl --shutdown + +2. Wait ~10 seconds, then check that WSL has no active processes: + + wsl --list -v + +3. **Verify the setup** by running WSL again, then execute these commands: + + sudo modprobe can + sudo modprobe can-raw + sudo modprobe vcan + +If there is no other message, the installation was successful. diff --git a/docs/includes/abbreviations.md b/docs/includes/abbreviations.md index ddfd76b7a..81cd52c11 100644 --- a/docs/includes/abbreviations.md +++ b/docs/includes/abbreviations.md @@ -17,3 +17,5 @@ *[LV]: Low Voltage. The vehicle circuit that powers all non-motor electronics. Contrast with HV. *[HV]: High Voltage. The vehicle circuit which powers our motors. Contrast with LV. *[MCAL]: MicroController Abstraction Layer. +*[BMS]: Battery Management System. A vehicle device responsible for consistently and safely drawing power from the accumulator / battery. +*[SSH]: Secure Shell. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index a72e2aac3..f4dcf97e5 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -125,12 +125,16 @@ nav: - tutorials/index.md - tutorials/git.md - tutorials/site-dev.md + - tutorials/wsl-can/index.md + - tutorials/ssh-signing/index.md - Firmware: - firmware/index.md - firmware/dev-setup.md - firmware/architecture.md - firmware/project-structure/index.md - firmware/compile-project.md + - firmware/flashing/index.md + - firmware/hw-debug.md - firmware/can-traffic/index.md - Glossary: glossary.md diff --git a/firmware/Makefile b/firmware/Makefile index dab038068..d597d01fb 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -12,12 +12,12 @@ PLATFORM_DIR := projects/$(PROJECT)/platforms/$(PLATFORM) GENERATOR := -G"Unix Makefiles" LOG_LEVEL := STATUS -# Name must be a valid filename (i.e. cannot have '/') -PROJECT_NAME := $(subst /,-,$(PROJECT)) +#Extract the project folder name from the path, removing any parent directories and trailing slashes. +PROJECT_NAME := $(notdir $(patsubst %/,%,$(PROJECT))) COMPILE_COMMANDS_DEST := $(BUILD)/compile_commands.json -.PHONY: build config clean deepclean st-flash +.PHONY: build config clean deepclean st-flash debug-openocd debug-gdb build: config cmake --build $(BUILD_DIR) @@ -44,3 +44,9 @@ endif st-flash: build st-flash --reset write $(BUILD_DIR)/$(PROJECT_NAME).bin 0x08000000 + +debug-openocd: + openocd -f interface/stlink.cfg -f target/stm32f7x.cfg -c "gdb_port 3333" + +debug-gdb: + arm-none-eabi-gdb "$(BUILD_DIR)/main.elf" -ex "target extended-remote localhost:3333" -ex "load" diff --git a/firmware/cmake/cangen.cmake b/firmware/cmake/cangen.cmake index 9336c671d..6f308158b 100644 --- a/firmware/cmake/cangen.cmake +++ b/firmware/cmake/cangen.cmake @@ -1,22 +1,14 @@ -find_package(Python3 COMPONENTS Interpreter) -message(${Python3_EXECUTABLE}) - -if(NOT ${Python3_FOUND}) - message(FATAL_ERROR "Python 3 executable not found") -endif() - -FILE(GLOB_RECURSE CAN_DEPENDENCIES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/../scripts/cangen/*" "${CMAKE_SOURCE_DIR}/dbcs/*") - list(APPEND CAN_DEPENDENCIES "${CMAKE_CURRENT_SOURCE_DIR}/config.yaml") cmake_language(GET_MESSAGE_LOG_LEVEL LOG_LEVEL) +# cangen is provided by racecar/scripts/cangen add_custom_target( generated_can - COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/../scripts/cangen/main.py" "--project=\"${CMAKE_CURRENT_SOURCE_DIR}\"" "--log-level=${LOG_LEVEL}" - DEPENDS ${CAN_DEPENDENCIES} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT Generating CAN code from DBCs + COMMAND "cangen" ${CMAKE_CURRENT_SOURCE_DIR} "--log-level=${LOG_LEVEL}" + DEPENDS ${CAN_DEPENDENCIES} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT Generating CAN code from DBCs ) add_dependencies(main generated_can) diff --git a/firmware/cmake/generate_cubemx.mk b/firmware/cmake/generate_cubemx.mk index 2320f5bf7..0402195bd 100644 --- a/firmware/cmake/generate_cubemx.mk +++ b/firmware/cmake/generate_cubemx.mk @@ -1,5 +1,6 @@ -ifeq ($(OS),Windows_NT) -# Convert windows backslash to regular slash +# Find the STM32CubeMX executable +ifeq ($(OS), Windows_NT) +# Convert Windows backslash to regular slash CUBEMX_PATH := $(subst \,/,$(shell where STM32CubeMX)) else # Linux / MacOS CUBEMX_PATH := $(shell which STM32CubeMX) @@ -7,7 +8,15 @@ endif # Find the JAVA which is installed with CubeMX. Spaces in path are escaped. space := $(subst ,, ) -CUBEMX_JAVA := $(dir $(subst $(space),\$(space),$(CUBEMX_PATH)))jre/bin/java + +ifeq ($(shell uname), Darwin) +# MacOS + CUBEMX_JAVA := $(dir $(subst $(space),\$(space),$(CUBEMX_PATH)))jre/Contents/Home/bin/java +else +# Windows / Linux + CUBEMX_JAVA := $(dir $(subst $(space),\$(space),$(CUBEMX_PATH)))jre/bin/java +endif + # Known bug: Expanding CUBEMX_JAVA twice does not work. IOC_FILE = board_config.ioc @@ -32,7 +41,7 @@ CustomMakefile.mk: Makefile $(CUSTOM_TARGETS_FILE) Makefile: $(IOC_FILE) $(CUBEMX_GEN_SCRIPT_TEMPLATE) @echo "Autogenerating from CubeMX. If you don't want to do this, you must manually 'Generate Code' before building." # Create an file containing commands to generate the cubemx code. - sed $(CUBEMX_GEN_SCRIPT_TEMPLATE) -e 's/IOC_FILE/$(IOC_FILE)/g' > $(CUBEMX_GEN_SCRIPT) + sed -e 's/IOC_FILE/$(IOC_FILE)/g' $(CUBEMX_GEN_SCRIPT_TEMPLATE) > $(CUBEMX_GEN_SCRIPT) # Run the cubemx program to generate code. $(CUBEMX_JAVA) -jar "$(CUBEMX_PATH)" -q "$(CUBEMX_GEN_SCRIPT)" \ No newline at end of file diff --git a/firmware/mcal/cli/periph/analog_output.h b/firmware/mcal/cli/periph/analog_output.h new file mode 100644 index 000000000..de5f12d6e --- /dev/null +++ b/firmware/mcal/cli/periph/analog_output.h @@ -0,0 +1,26 @@ +/// @author Tamara Xu +/// @date 2024-10-03 + +#pragma once + +#include +#include + +#include "shared/periph/analog_output.h" + +namespace mcal::cli::periph { + +class AnalogOutput : public shared::periph::AnalogOutput { +public: + AnalogOutput(std::string name) : name_(name) {} + + void SetVoltage (float voltage) override { + std::cout << "Setting AnalogOutput " << name_ << " to " << voltage << " V" + << std::endl; + } + +private: + std::string name_; +}; + +} // namespace mcal::cli::periph \ No newline at end of file diff --git a/firmware/mcal/cli/periph/pwm.h b/firmware/mcal/cli/periph/pwm.h index 3d3589262..9985bc49e 100644 --- a/firmware/mcal/cli/periph/pwm.h +++ b/firmware/mcal/cli/periph/pwm.h @@ -27,18 +27,33 @@ class PWMOutput : public shared::periph::PWMOutput { duty_cycle_ = shared::util::Clamper::Evaluate(duty_cycle, 0, 100); - std::cout << "Setting PWM " << name_ << " to " << duty_cycle_ << "%" + std::cout << "Setting PWM " << name_ << " duty cycle to " << duty_cycle_ << "%" << std::endl; } + float GetDutyCycle() override { std::cout << "PWM " << name_ << " has duty cycle " << duty_cycle_ << "%" << std::endl; return duty_cycle_; } + void SetFrequency(float frequency) override { + frequency_ = std::max((float) 0, frequency); + + std::cout << "Setting PWM " << name_ << " frequency to " << frequency_ + << " Hz" << std::endl; + } + + float GetFrequency() override { + std::cout << "PWM " << name_ << " has frequency " << frequency_ + << " Hz" << std::endl; + return frequency_; + } + private: std::string name_; float duty_cycle_; + float frequency_; }; } // namespace mcal::cli::periph diff --git a/firmware/mcal/stm32f767/periph/analog_output.h b/firmware/mcal/stm32f767/periph/analog_output.h new file mode 100644 index 000000000..fa246cbad --- /dev/null +++ b/firmware/mcal/stm32f767/periph/analog_output.h @@ -0,0 +1,32 @@ +/// @author Tamara Xu +/// @date 2024-10-13 + +#pragma once + +#include + +#include "shared/periph/analog_output.h" +#include "shared/util/mappers/clamper.h" +#include "stm32f7xx_hal.h" + +namespace mcal::stm32f767::periph { + +class AnalogOutput : public shared::periph::AnalogOutput { +public: + AnalogOutput(TIM_HandleTypeDef* htim, uint32_t channel) + : htim_(htim), channel_(channel) {} + + void SetVoltage (float voltage) override { + uint32_t maxPulse = __HAL_TIM_GetAutoreload(htim_); + uint32_t pulse = shared::util::Clamper::Evaluate( + (voltage * maxPulse) / 3.3f, 0, maxPulse); + + __HAL_TIM_SetCompare(htim_, channel_, pulse); + } + +private: + TIM_HandleTypeDef* htim_; + uint32_t channel_; +}; + +} // namespace mcal::stm32f767::periph diff --git a/firmware/mcal/stm32f767/periph/can.h b/firmware/mcal/stm32f767/periph/can.h index 8b44f5103..d6674da0a 100644 --- a/firmware/mcal/stm32f767/periph/can.h +++ b/firmware/mcal/stm32f767/periph/can.h @@ -15,12 +15,12 @@ namespace mcal::stm32f767::periph { class CanBase : public shared::periph::CanBase { public: - CanBase(CAN_HandleTypeDef* hcan) : hcan_(hcan){}; + CanBase(CAN_HandleTypeDef* hcan) : hcan_(hcan) {}; void Setup() { - HAL_CAN_ActivateNotification(hcan_, kCanRxActiveInterruptFifo0); ConfigFilters(); HAL_CAN_Start(hcan_); + HAL_CAN_ActivateNotification(hcan_, kCanRxActiveInterruptFifo0); } void Send(const shared::can::RawCanMsg& can_tx_msg) override { diff --git a/firmware/mcal/stm32f767/periph/pwm.h b/firmware/mcal/stm32f767/periph/pwm.h index eaf506ecf..3ffbcd54f 100644 --- a/firmware/mcal/stm32f767/periph/pwm.h +++ b/firmware/mcal/stm32f767/periph/pwm.h @@ -33,37 +33,44 @@ class PWMOutput : public shared::periph::PWMOutput { __HAL_TIM_SetCompare(htim_, channel_, pulse); } - /** - * @brief Quickly get the duty cycle which was last sent to this device. - * @note Compared to GetHardwareDutyCycle, this method is faster (doesn't - * read registers) and is less likely to cause issues when performing - * arithmetic since the hardware duty cycle is limited by integer - * resolution. - * - * @return float - */ - float GetDutyCycle() override { - return duty_cycle_; - } - /** * @brief Get the duty cycle from the PWM registers. - * @note Compared to GetDutyCycle(), this method returns the "most accurate" - * current duty cycle. + * @note This method returns the "most accurate" current duty cycle. * * @return float */ - float GetHardwareDutyCycle() { + float GetDutyCycle() override { uint32_t pulse = __HAL_TIM_GetCompare(htim_, channel_); uint32_t period = __HAL_TIM_GetAutoreload(htim_); return float(pulse) / float(period) * 100.0f; } + void SetFrequency(float frequency) override { + frequency_ = std::max(kMinimumFrequency, frequency); + uint32_t autoreload = GetTimerFrequency() / frequency_; + + __HAL_TIM_SetAutoreload(htim, autoreload); + } + + float GetFrequency() override { + float frequency = GetTimerFrequency() / __HAL_TIM_GetAutoreload(htim_); + + return frequency; + } + private: TIM_HandleTypeDef* htim_; + // stm32f767 has a 16-bit autoreload register -> min frequency = 1/65535 + static constexpr kMinimumFrequency = 0.000015259022f; uint32_t channel_; float duty_cycle_ = 0; + + uint32_t GetTimerFrequency() { + uint32_t tickFreq = __HAL_TIM_GetTickFreq(); + + return tickFreq; + } }; } // namespace mcal::stm32f767::periph diff --git a/firmware/projects/Demo/AnalogPWM/CMakeLists.txt b/firmware/projects/Demo/AnalogPWM/CMakeLists.txt new file mode 100644 index 000000000..d528587c7 --- /dev/null +++ b/firmware/projects/Demo/AnalogPWM/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(main PUBLIC main.cc) \ No newline at end of file diff --git a/firmware/projects/Demo/AnalogPWM/README.md b/firmware/projects/Demo/AnalogPWM/README.md new file mode 100644 index 000000000..7f0909548 --- /dev/null +++ b/firmware/projects/Demo/AnalogPWM/README.md @@ -0,0 +1,8 @@ +# DemoAnalogPWM + +This demonstrates the utility of PWMOutput class and AnalogOutput class through +their respective Set and Get methods + +The classes were separated because PWM can be used for two different purposes: + 1. Output an analog voltage + 2. Output a digital signal with a specific frequency and duty cycle \ No newline at end of file diff --git a/firmware/projects/Demo/AnalogPWM/bindings.h b/firmware/projects/Demo/AnalogPWM/bindings.h new file mode 100644 index 000000000..2bb0670b1 --- /dev/null +++ b/firmware/projects/Demo/AnalogPWM/bindings.h @@ -0,0 +1,14 @@ +#pragma once + +#include "shared/periph/pwm.h" +#include "shared/periph/analog_output.h" + +namespace bindings { + +extern shared::periph::PWMOutput& pwm; +extern shared::periph::AnalogOutput& analog_out; + +extern void DelayMS(unsigned int ms); +extern void Initialize(); + +} // namespace bindings \ No newline at end of file diff --git a/firmware/projects/Demo/AnalogPWM/main.cc b/firmware/projects/Demo/AnalogPWM/main.cc new file mode 100644 index 000000000..9c30911ae --- /dev/null +++ b/firmware/projects/Demo/AnalogPWM/main.cc @@ -0,0 +1,62 @@ +#include "bindings.h" + +using namespace bindings; + +/** + * @brief Tests the PWMOutput class using various frequencies and duty cycles. + */ +void DemoPWM() { + pwm.Start(); + DelayMS(1000); + + pwm.SetFrequency(100); + pwm.SetDutyCycle(50.); + DelayMS(1000); + + pwm.GetFrequency(); + pwm.GetDutyCycle(); + DelayMS(1000); + + pwm.SetFrequency(100); + DelayMS(1000); + + pwm.GetFrequency(); + DelayMS(1000); + + pwm.SetFrequency(-5); + pwm.GetFrequency(); + DelayMS(1000); + + pwm.GetFrequency(); + DelayMS(1000); + + pwm.Stop(); +} + +/** + * @brief Tests the AnalogOutput class using various voltages. + */ +void DemoAnalog() { + analog_out.SetVoltage(1.0f); + DelayMS(1000); + analog_out.SetVoltage(4.5f); + DelayMS(1000); + analog_out.SetVoltage(0.0f); + DelayMS(1000); + analog_out.SetVoltage(3.3f); + DelayMS(1000); +} + +int main() { + Initialize(); + + while (true) { + DemoPWM(); + DelayMS(1000); + + DemoAnalog(); + DelayMS(1000); + } + + return 0; +} diff --git a/firmware/projects/Demo/AnalogPWM/platforms/cli/CMakeLists.txt b/firmware/projects/Demo/AnalogPWM/platforms/cli/CMakeLists.txt new file mode 100644 index 000000000..6748669b7 --- /dev/null +++ b/firmware/projects/Demo/AnalogPWM/platforms/cli/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(bindings PRIVATE bindings.cc) + +target_link_libraries(bindings PUBLIC mcal-cli) \ No newline at end of file diff --git a/firmware/projects/Demo/AnalogPWM/platforms/cli/bindings.cc b/firmware/projects/Demo/AnalogPWM/platforms/cli/bindings.cc new file mode 100644 index 000000000..1c2a35dcc --- /dev/null +++ b/firmware/projects/Demo/AnalogPWM/platforms/cli/bindings.cc @@ -0,0 +1,31 @@ +#include + +#include + +#include "../../bindings.h" +#include "mcal/cli/periph/pwm.h" +#include "shared/periph/pwm.h" +#include "mcal/cli/periph/analog_output.h" +#include "shared/periph/analog_output.h" + +namespace mcal { + +cli::periph::PWMOutput pwm{"test"}; +cli::periph::AnalogOutput analog_out{"test"}; + +} // namespace mcal + +namespace bindings { + +shared::periph::PWMOutput& pwm = mcal::pwm; +shared::periph::AnalogOutput& analog_out = mcal::analog_out; + +void DelayMS(unsigned int ms) { + usleep(ms * 1000); +} + +void Initialize() { + std::cout << "Initializing the CLI..." << std::endl; +} + +} // namespace bindings diff --git a/firmware/projects/Demo/AnalogPWM/platforms/cli/mcal_conf.cmake b/firmware/projects/Demo/AnalogPWM/platforms/cli/mcal_conf.cmake new file mode 100644 index 000000000..a30e90e12 --- /dev/null +++ b/firmware/projects/Demo/AnalogPWM/platforms/cli/mcal_conf.cmake @@ -0,0 +1 @@ +set(MCAL cli) \ No newline at end of file diff --git a/firmware/projects/Demo/CAN/Bar/config.yaml b/firmware/projects/Demo/CAN/Bar/config.yaml index 23f7a4e2e..2599bb986 100644 --- a/firmware/projects/Demo/CAN/Bar/config.yaml +++ b/firmware/projects/Demo/CAN/Bar/config.yaml @@ -1,6 +1,6 @@ canGen: - ourNode: bar busses: - - busName: veh + - name: veh + node: bar dbcFiles: - "../demo.dbc" diff --git a/firmware/projects/Demo/CAN/Foo/config.yaml b/firmware/projects/Demo/CAN/Foo/config.yaml index b1b143053..4ef5a0ddc 100644 --- a/firmware/projects/Demo/CAN/Foo/config.yaml +++ b/firmware/projects/Demo/CAN/Foo/config.yaml @@ -1,6 +1,6 @@ canGen: - ourNode: foo busses: - - busName: veh + - name: veh + node: foo dbcFiles: - "../demo.dbc" \ No newline at end of file diff --git a/firmware/projects/EV5/FrontController/config.yaml b/firmware/projects/EV5/FrontController/config.yaml index d2135f17f..3ad948f65 100644 --- a/firmware/projects/EV5/FrontController/config.yaml +++ b/firmware/projects/EV5/FrontController/config.yaml @@ -1,9 +1,8 @@ canGen: - ourNode: fc busses: - - busName: veh - dbcFiles: - - "../veh.dbc" - - busName: pt - dbcFiles: - - "../pt.dbc" + - name: veh + node: fc + dbcFile: "../veh.dbc" + - name: pt + node: fc + dbcFile: "../pt.dbc" diff --git a/firmware/projects/EV5/LVController/config.yaml b/firmware/projects/EV5/LVController/config.yaml index 3a30623c2..187420ce3 100644 --- a/firmware/projects/EV5/LVController/config.yaml +++ b/firmware/projects/EV5/LVController/config.yaml @@ -1,6 +1,5 @@ canGen: - ourNode: lvc busses: - - busName: veh - dbcFiles: - - "../veh.dbc" \ No newline at end of file + - name: veh + node: lvc + dbcFile: "../veh.dbc" \ No newline at end of file diff --git a/firmware/projects/EV5/LVController/inc/app.h b/firmware/projects/EV5/LVController/inc/app.h index e78c9ebcd..ce695b8db 100644 --- a/firmware/projects/EV5/LVController/inc/app.h +++ b/firmware/projects/EV5/LVController/inc/app.h @@ -116,6 +116,8 @@ class Fan : public Subsystem { * @param interval_sec */ void Update(float interval_sec) const { + // max_duty_step must be greater than any platform's PWM duty cycle + // resolution float max_duty_step = duty_per_second_ * interval_sec; float current_duty = pwm_output_.GetDutyCycle(); diff --git a/firmware/projects/EV5/TMS/config.yaml b/firmware/projects/EV5/TMS/config.yaml index ca6c88649..4e9f70c6d 100644 --- a/firmware/projects/EV5/TMS/config.yaml +++ b/firmware/projects/EV5/TMS/config.yaml @@ -1,6 +1,5 @@ canGen: - ourNode: tms busses: - - busName: veh - dbcFiles: - - "../veh.dbc" + - name: veh + node: tms + dbcFile: "../veh.dbc" \ No newline at end of file diff --git a/firmware/projects/EV5/TMS/inc/app.h b/firmware/projects/EV5/TMS/inc/app.h index 4880f5f8f..ed8a60832 100644 --- a/firmware/projects/EV5/TMS/inc/app.h +++ b/firmware/projects/EV5/TMS/inc/app.h @@ -25,14 +25,14 @@ class TempSensor { public: TempSensor(shared::periph::ADCInput& adc, - shared::util::Mapper& adc_to_temp) - : adc_(adc), adc_to_temp_(adc_to_temp), rolling_temperature_() {} + const shared::util::Mapper& volt_to_temp) + : adc_(adc), volt_to_temp_(volt_to_temp), rolling_temperature_() {} private: shared::periph::ADCInput& adc_; /// @brief Mapping from raw ADC value to temperature [degC] - shared::util::Mapper& adc_to_temp_; + const shared::util::Mapper& volt_to_temp_; static constexpr int moving_average_length_ = 20; shared::util::MovingAverage @@ -40,7 +40,8 @@ class TempSensor { float Read() { uint32_t adc_value = adc_.Read(); - float temperature = adc_to_temp_.Evaluate(float(adc_value)); + float volt = static_cast(adc_value) * 3.3f / 4095.0f; + float temperature = volt_to_temp_.Evaluate(volt); return temperature; } diff --git a/firmware/projects/EV5/TMS/main.cc b/firmware/projects/EV5/TMS/main.cc index 648b4b633..c98d4cec2 100644 --- a/firmware/projects/EV5/TMS/main.cc +++ b/firmware/projects/EV5/TMS/main.cc @@ -13,7 +13,9 @@ #include "shared/periph/gpio.h" #include "shared/periph/pwm.h" #include "shared/util/algorithms/arrays.h" +#include "shared/util/mappers/linear_map.h" #include "shared/util/mappers/lookup_table.h" +#include "shared/util/mappers/mapper.h" #include "veh_can_messages.h" #include "veh_msg_registry.h" @@ -27,54 +29,76 @@ extern "C" { void UpdateTask(void* argument); } -const float temp_lut_data[][2] = { +namespace tempsensor { + +/// This table is directly copied from Table 4 of the temperature sensor +/// datasheet. `datasheets/energus/Datasheet_with_VTC6_rev_A(2021-10-26).pdf` +const float ts_table[][2] = { // clang-format off - {2475, 120}, - {2480, 115}, - {2485, 110}, - {2491, 105}, - {2496, 100}, - {2501, 95}, - {2512, 90}, - {2517, 85}, - {2528, 80}, - {2543, 75}, - {2554, 70}, - {2570, 65}, - {2586, 60}, - {2607, 55}, - {2628, 50}, - {2649, 45}, - {2675, 40}, - {2707, 35}, - {2739, 30}, - {2771, 25}, - {2802, 20}, - {2839, 15}, - {2871, 10}, - {2903, 5}, - {2934, 0}, - {2966, -5}, - {2987, -10}, - {3014, -15}, - {3029, -20}, - {3045, -25}, - {3056, -30}, - {3066, -35}, - {3077, -40}, + {1.30f, 120.0f}, + {1.31f, 115.0f}, + {1.32f, 110.0f}, + {1.33f, 105.0f}, + {1.34f, 100.0f}, + {1.35f, 95.0f}, + {1.37f, 90.0f}, + {1.38f, 85.0f}, + {1.40f, 80.0f}, + {1.43f, 75.0f}, + {1.45f, 70.0f}, + {1.48f, 65.0f}, + {1.51f, 60.0f}, + {1.55f, 55.0f}, + {1.59f, 50.0f}, + {1.63f, 45.0f}, + {1.68f, 40.0f}, + {1.74f, 35.0f}, + {1.80f, 30.0f}, + {1.86f, 25.0f}, + {1.92f, 20.0f}, + {1.99f, 15.0f}, + {2.05f, 10.0f}, + {2.11f, 5.0f}, + {2.17f, 0.0f}, + {2.23f, -5.0f}, + {2.27f, -10.0f}, + {2.32f, -15.0f}, + {2.35f, -20.0f}, + {2.38f, -25.0f}, + {2.40f, -30.0f}, + {2.42f, -35.0f}, + {2.44f, -40.0f} // clang-format on }; +constexpr int lut_length = (sizeof(ts_table)) / (sizeof(ts_table[0])); +const shared::util::LookupTable volt_ts_to_degC{ts_table}; + +/// Calculate the voltage at the temperature sensor from the voltage at the STM. +/// They are not equal because there is a non-unity gain buffer between them. +/// V_STM = 1.44 + 0.836 * V_TS / 2 +/// So the inverse is +/// V_TS = 2 * (V_STM - 1.44) / 0.836 = 2/0.836 * V_STM - 2*1.44/0.836 +const shared::util::LinearMap volt_stm_to_volt_ts{ + 2.0f / 0.836f, + -2.0f * 1.44f / 0.836f, +}; + +/// Compose the two maps to get the final map from the STM voltage to the +/// temperature in degrees C. +const shared::util::CompositeMap volt_stm_to_degC{ + volt_ts_to_degC, // outer (second) function + volt_stm_to_volt_ts, // inner (first) function +}; + +} // namespace tempsensor +/// Spin the fan faster when the acculumator is hotter. const float fan_lut_data[][2] = { {-1, 0}, {0, 30}, {50, 100}, }; -constexpr int temp_lut_length = - (sizeof(temp_lut_data)) / (sizeof(temp_lut_data[0])); -shared::util::LookupTable temp_adc_lut{temp_lut_data}; - constexpr int fan_lut_length = (sizeof(fan_lut_data) / (sizeof(fan_lut_data[0]))); shared::util::LookupTable fan_temp_lut{fan_lut_data}; @@ -99,12 +123,12 @@ DebugIndicator debug_green{bindings::debug_led_green}; DebugIndicator debug_red{bindings::debug_led_red}; TempSensor temp_sensors[] = { - TempSensor{bindings::temp_sensor_adc_1, temp_adc_lut}, - TempSensor{bindings::temp_sensor_adc_2, temp_adc_lut}, - TempSensor{bindings::temp_sensor_adc_3, temp_adc_lut}, - TempSensor{bindings::temp_sensor_adc_4, temp_adc_lut}, - TempSensor{bindings::temp_sensor_adc_5, temp_adc_lut}, - TempSensor{bindings::temp_sensor_adc_6, temp_adc_lut}, + TempSensor{bindings::temp_sensor_adc_1, tempsensor::volt_stm_to_degC}, + TempSensor{bindings::temp_sensor_adc_2, tempsensor::volt_stm_to_degC}, + TempSensor{bindings::temp_sensor_adc_3, tempsensor::volt_stm_to_degC}, + TempSensor{bindings::temp_sensor_adc_4, tempsensor::volt_stm_to_degC}, + TempSensor{bindings::temp_sensor_adc_5, tempsensor::volt_stm_to_degC}, + TempSensor{bindings::temp_sensor_adc_6, tempsensor::volt_stm_to_degC}, }; const int kSensorCount = 6; @@ -122,7 +146,6 @@ void Update() { static uint8_t high_thermistor_idx; debug_green.Toggle(); - debug_red.Toggle(); veh_can_bus.Update(); ts_manager.Update(); diff --git a/firmware/projects/EV5/TMS/platforms/stm32f767/bindings.cc b/firmware/projects/EV5/TMS/platforms/stm32f767/bindings.cc index 6dbd41b3c..a78bdd24b 100644 --- a/firmware/projects/EV5/TMS/platforms/stm32f767/bindings.cc +++ b/firmware/projects/EV5/TMS/platforms/stm32f767/bindings.cc @@ -1,6 +1,8 @@ /// @author Blake Freer /// @date 2023-12-25 +#include + #include // cubemx files @@ -59,17 +61,28 @@ shared::periph::ADCInput& temp_sensor_adc_6 = mcal::temp_sensor_adc_6; shared::periph::PWMOutput& fan_controller_pwm = mcal::fan_controller_pwm; shared::periph::DigitalOutput& debug_led_green = mcal::debug_led_green; shared::periph::DigitalOutput& debug_led_red = mcal::debug_led_red; -// shared::periph::DigitalOutput& debug_led_red = mcal::debug_led_nucleo; +// shared::periph::DigitalOutput& debug_led_red = mcal::debug_led_nucleo; shared::periph::CanBase& veh_can_base = mcal::veh_can_base; void Initialize() { - SystemClock_Config(); HAL_Init(); + SystemClock_Config(); MX_ADC1_Init(); MX_TIM4_Init(); MX_GPIO_Init(); MX_CAN2_Init(); + + mcal::veh_can_base.Setup(); } } // namespace bindings + +void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* hcan) { + CAN_RxHeaderTypeDef RxHeader; + uint8_t RxData[8]; + + // TMS doesn't care about any Rx messages but we need to call this to + // clear the interrupt flag. + HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData); +} \ No newline at end of file diff --git a/firmware/projects/EV5/debug/FrontControllerSimple/config.yaml b/firmware/projects/EV5/debug/FrontControllerSimple/config.yaml index 44d67931a..0f3b27531 100644 --- a/firmware/projects/EV5/debug/FrontControllerSimple/config.yaml +++ b/firmware/projects/EV5/debug/FrontControllerSimple/config.yaml @@ -1,9 +1,8 @@ canGen: - ourNode: fc busses: - - busName: veh - dbcFiles: - - "../../veh.dbc" - - busName: pt - dbcFiles: - - "../../pt.dbc" + - name: veh + node: fc + dbcFile: "../../veh.dbc" + - name: pt + node: fc + dbcFile: "../../pt.dbc" diff --git a/firmware/projects/EV5/debug/IoCheckoutFc/config.yaml b/firmware/projects/EV5/debug/IoCheckoutFc/config.yaml index 88bc63970..c273590ff 100644 --- a/firmware/projects/EV5/debug/IoCheckoutFc/config.yaml +++ b/firmware/projects/EV5/debug/IoCheckoutFc/config.yaml @@ -1,6 +1,5 @@ canGen: - ourNode: FC busses: - - busName: io - dbcFiles: - - "io.dbc" + - name: io + node: FC + dbcFile: "io.dbc" diff --git a/firmware/projects/EV5/debug/MotorDebug/config.yaml b/firmware/projects/EV5/debug/MotorDebug/config.yaml index 238f2d0e1..4e37a4191 100644 --- a/firmware/projects/EV5/debug/MotorDebug/config.yaml +++ b/firmware/projects/EV5/debug/MotorDebug/config.yaml @@ -1,6 +1,5 @@ canGen: - ourNode: FRONTCONTROLLER busses: - - busName: vehicle - dbcFiles: - - "pedal.dbc" + - name: vehicle + node: FRONTCONTROLLER + dbcFile: "pedal.dbc" diff --git a/firmware/shared/periph/analog_output.h b/firmware/shared/periph/analog_output.h new file mode 100644 index 000000000..1f72d2c70 --- /dev/null +++ b/firmware/shared/periph/analog_output.h @@ -0,0 +1,15 @@ +/// @author Tamara Xu +/// @date 2024-10-03 + +#pragma once + +#include "shared/util/peripheral.h" + +namespace shared::periph { + +class AnalogOutput : public util::Peripheral { +public: + virtual void SetVoltage(float voltage) = 0; +}; + +} // namespace shared::periph \ No newline at end of file diff --git a/firmware/shared/periph/pwm.h b/firmware/shared/periph/pwm.h index 5ec740517..febcbc3c5 100644 --- a/firmware/shared/periph/pwm.h +++ b/firmware/shared/periph/pwm.h @@ -13,6 +13,8 @@ class PWMOutput : public util::Peripheral { virtual void Stop() = 0; virtual void SetDutyCycle(float duty_cycle) = 0; virtual float GetDutyCycle() = 0; + virtual void SetFrequency(float frequency) = 0; + virtual float GetFrequency() = 0; }; } // namespace shared::periph diff --git a/firmware/shared/util/mappers/mapper.h b/firmware/shared/util/mappers/mapper.h index 09cb4757f..c4dcc3a06 100644 --- a/firmware/shared/util/mappers/mapper.h +++ b/firmware/shared/util/mappers/mapper.h @@ -34,7 +34,8 @@ class CompositeMap : public Mapper { * @param g Inner function. * @note Evaulates `f(g(x))`, so `g` is applied before `f`. */ - CompositeMap(Mapper& f, Mapper& g) : f_(f), g_(g) {} + CompositeMap(const Mapper& f, const Mapper& g) + : f_(f), g_(g) {} /** * @brief Evaluates `f(g(x))`. diff --git a/scripts/.gitignore b/scripts/.gitignore deleted file mode 100644 index ed8ebf583..000000000 --- a/scripts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -__pycache__ \ No newline at end of file diff --git a/scripts/cangen/README.md b/scripts/cangen/README.md new file mode 100644 index 000000000..303c1f64c --- /dev/null +++ b/scripts/cangen/README.md @@ -0,0 +1,43 @@ +# Cangen + +Generates C++ files from a corresponding dbc file. Ensures repeatable generation between all projects. + +## Installation + +From the `racecar/` directory, run + +```bash +pip install scripts/cangen +``` + +## Usage + +To generate CAN code for a project, execute `cangen` and pass the project folder. The project folder is the one which contains `config.yaml`. + +## Example + +If you are in the `racecar/firmware/` directory, you could generate `EV5/FrontController` code with + +```bash +cangen projects/EV5/FrontController +``` + +This command will generate code in a `generated/can/` subfolder of the project. + +``` +FrontController +├─ fc_docs +├─ generated/can +│  ├─ .gitignore +│  ├─ pt_can_messages.h +│  ├─ pt_msg_registry.h +│  ├─ veh_can_messages.h +│  └─ veh_msg_registry.h +├─ inc +├─ platforms +├─ vehicle_control_system +├─ CMakeLists.txt +├─ config.yaml +├─ main.cc +└─ README.md +``` diff --git a/scripts/cangen/cangen/__init__.py b/scripts/cangen/cangen/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/cangen/can_generator.py b/scripts/cangen/cangen/can_generator.py similarity index 65% rename from scripts/cangen/can_generator.py rename to scripts/cangen/cangen/can_generator.py index e8bdb7a72..2b8348ed3 100644 --- a/scripts/cangen/can_generator.py +++ b/scripts/cangen/cangen/can_generator.py @@ -7,12 +7,15 @@ import math import os import re +import shutil import time from typing import Dict, List, Tuple import numpy as np from cantools.database import Database, Message, Signal -from jinja2 import Environment +from jinja2 import Environment, PackageLoader + +from .config import Bus, Config logger = logging.getLogger(__name__) @@ -22,43 +25,40 @@ MSG_REGISTRY_FILE_NAME = "_msg_registry.h" CAN_MESSAGES_FILE_NAME = "_can_messages.h" - -def _assert_valid_dbc(filename: str): - """Raise an error if filename is not a valid and existant dbc file.""" - - if not os.path.isfile(filename): - raise FileNotFoundError(f"Could not find a file at {filename}.") - - _, extension = os.path.splitext(filename) - if extension != ".dbc": - raise ValueError(f"{filename} is not a .dbc file.") - - logger.debug(f"{filename} is a valid dbc file.") +CAN_MESSAGES_TEMPLATE_FILENAME = "can_messages.h.jinja2" +MSG_REGISTRY_TEMPLATE_FILENAME = "msg_registry.h.jinja2" -def _parse_dbc_files(dbc_files: List[str]) -> Database: - logger.info(f"Parsing DBC files: {dbc_files}") +def _parse_dbc_files(dbc_file: str) -> Database: + logger.info(f"Parsing DBC files: {dbc_file}") can_db = Database() - for dbc_file in dbc_files: - _assert_valid_dbc(dbc_file) - with open(dbc_file, "r") as f: - can_db.add_dbc(f) - logger.info(f"Successfully added DBC: {dbc_file}") + with open(dbc_file, "r") as f: + can_db.add_dbc(f) + logger.info(f"Successfully added DBC: {dbc_file}") return can_db -def _normalize_node_name( - node_name: str -) -> str: + +def _normalize_node_name(node_name: str) -> str: return node_name.upper() + def _filter_messages_by_node( messages: List[Message], node: str ) -> Tuple[List[Message], List[Message]]: normalized_node_name = _normalize_node_name(node) - tx_msgs = [msg for msg in messages if normalized_node_name in map(_normalize_node_name, msg.senders)] - rx_msgs = [msg for msg in messages if normalized_node_name in map(_normalize_node_name, msg.receivers)] + + tx_msgs = [ + msg + for msg in messages + if normalized_node_name in map(_normalize_node_name, msg.senders) + ] + rx_msgs = [ + msg + for msg in messages + if normalized_node_name in map(_normalize_node_name, msg.receivers) + ] logger.debug( f"Filtered messages by node: {node}. " @@ -91,7 +91,6 @@ def _get_mask_shift_big( def _get_mask_shift_little( length: int, start: int ) -> Tuple[np.ndarray[int], np.ndarray[int]]: - idx = np.arange(64) mask_bool = (idx >= start) & (idx < start + length) mask_bytes = np.packbits(mask_bool, bitorder="little") @@ -107,7 +106,6 @@ def _get_mask_shift_little( def _get_masks_shifts( msgs: List[Message], ) -> Dict[str, Dict[str, Tuple[List[int], List[int]]]]: - # Create a dictionary of empty dictionaries, indexed by message names masks_shifts_dict = {msg.name: {} for msg in msgs} @@ -151,7 +149,6 @@ def _get_signal_datatype(signal: Signal, allow_floating_point: bool = True) -> s def _get_signal_types(can_db: Database, allow_floating_point=True): - # Create a dictionary (indexed by message name) of dictionaries (indexed by signal # name) corresponding to the datatype of each signal within each message. sig_types = { @@ -174,64 +171,29 @@ def _camel_to_snake(text): return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower() -def _decimal_to_hex(decimal_value): - """ - Converts a non-negative decimal integer to a lowercase hexadecimal string. - - Raises: - ValueError: If the input is negative. - """ - - if decimal_value < 0: - raise ValueError("Input must be a non-negative integer") - - return hex(decimal_value) - - def _generate_from_jinja2_template( template_path: str, output_path: str, context_dict: dict ): - # Read the template string from a file - with open(template_path, "r") as file: - template_str = file.read() - # Create the environment with trim_blocks and lstrip_blocks settings - env = Environment(trim_blocks=True, lstrip_blocks=True) + env = Environment( + loader=PackageLoader("cangen"), trim_blocks=True, lstrip_blocks=True + ) # Register the camel_to_snake filter env.filters["camel_to_snake"] = _camel_to_snake - env.filters["decimal_to_hex"] = _decimal_to_hex - - # Load the template from the string content - template = env.from_string(template_str) + env.filters["decimal_to_hex"] = hex - # Render the template with the context + # Load and render template + template = env.get_template(template_path) rendered_code = template.render(**context_dict) - # Write the rendered code to a file - output_dir = os.path.dirname(output_path) - os.makedirs(output_dir, exist_ok=True) - - # Create a git ignore for everything in the generated path. Ignore everything. - gitignore_path = os.path.join(output_dir, ".gitignore") - if not os.path.exists(gitignore_path): - with open(gitignore_path, "w") as f: - f.write("*") - with open(output_path, "w") as output_file: output_file.write(rendered_code) logger.info(f"Rendered code written to '{os.path.abspath(output_path)}'") -def generate_code( - dbc_files: List[str], - our_node: str, - bus_name: str, - output_dir: str, - can_messages_template_path: str, - msg_registry_template_path: str, -): +def generate_code(bus: Bus, config: Config): """ Parses DBC files, extracts information, and generates code using Jinja2 templates. @@ -243,42 +205,54 @@ def generate_code( logger.info("Generating code") - can_db = _parse_dbc_files(dbc_files) - - signal_types = _get_signal_types(can_db) - temp_signal_types = _get_signal_types(can_db, allow_floating_point=False) - - rx_msgs, tx_msgs = _filter_messages_by_node(can_db.messages, our_node) - all_msgs = rx_msgs + tx_msgs - - unpack_masks_shifts = _get_masks_shifts(rx_msgs) - pack_masks_shifts = _get_masks_shifts(tx_msgs) + can_db = _parse_dbc_files(bus.dbc_file_path) + rx_msgs, tx_msgs = _filter_messages_by_node(can_db.messages, bus.node) context = { "date": time.strftime("%Y-%m-%d"), "rx_msgs": rx_msgs, "tx_msgs": tx_msgs, - "all_msgs": all_msgs, - "signal_types": signal_types, - "temp_signal_types": temp_signal_types, - "unpack_info": unpack_masks_shifts, - "pack_info": pack_masks_shifts, - "bus_name": bus_name, + "all_msgs": rx_msgs + tx_msgs, + "signal_types": _get_signal_types(can_db), + "temp_signal_types": _get_signal_types(can_db, allow_floating_point=False), + "unpack_info": _get_masks_shifts(rx_msgs), + "pack_info": _get_masks_shifts(tx_msgs), + "bus_name": bus.bus_name, } - # Replace these lines with your Jinja2 template logic logger.debug("Generating code for can messages") _generate_from_jinja2_template( - can_messages_template_path, - os.path.join(output_dir, bus_name.lower() + CAN_MESSAGES_FILE_NAME), + CAN_MESSAGES_TEMPLATE_FILENAME, + os.path.join(config.output_dir, bus.bus_name.lower() + CAN_MESSAGES_FILE_NAME), context, ) logger.debug("Generating code for msg registry") _generate_from_jinja2_template( - msg_registry_template_path, - os.path.join(output_dir, bus_name.lower() + MSG_REGISTRY_FILE_NAME), + MSG_REGISTRY_TEMPLATE_FILENAME, + os.path.join(config.output_dir, bus.bus_name.lower() + MSG_REGISTRY_FILE_NAME), context, ) logger.info("Code generation complete") + + +def _prepare_output_directory(output_dir): + """Deletes previously generated files and creates a gitignore for the directory""" + if os.path.exists(output_dir): + shutil.rmtree(output_dir) + os.makedirs(output_dir, exist_ok=True) + + gitignore_path = os.path.join(output_dir, ".gitignore") + with open(gitignore_path, "w") as f: + f.write("*") + + +def generate_can_from_dbc(project_folder_name: str): + os.chdir(project_folder_name) + config = Config.from_yaml("config.yaml") + + _prepare_output_directory(config.output_dir) + + for bus in config.busses: + generate_code(bus, config) diff --git a/scripts/cangen/cangen/config.py b/scripts/cangen/cangen/config.py new file mode 100644 index 000000000..4025202b3 --- /dev/null +++ b/scripts/cangen/cangen/config.py @@ -0,0 +1,33 @@ +from __future__ import annotations +import yaml + +DEFAULT_OUTPUT_DIR = "generated/can" + + +class Bus: + def __init__(self, bus: dict): + self.dbc_file_path: str = bus.pop("dbcFile") + self.bus_name: str = bus.pop("name").capitalize() + self.node = bus.pop("node") + + if bus: + raise ValueError( + f"{bus.keys()} field/s not expected in configuration file for bus {self.bus_name}." + ) + + +class Config: + @staticmethod + def from_yaml(config_file_name: str) -> Config: + with open(config_file_name, "r") as file: + config = yaml.safe_load(file) + return Config(config.pop("canGen")) + + def __init__(self, config: dict): + self.output_dir = config.pop("outputPath", DEFAULT_OUTPUT_DIR) + self.busses = [Bus(bus) for bus in config.pop("busses")] + + if config: + raise ValueError( + f"{config.keys()} field/s not expected in configuration file from node." + ) diff --git a/scripts/cangen/cangen/main.py b/scripts/cangen/cangen/main.py new file mode 100644 index 000000000..f2912e7fe --- /dev/null +++ b/scripts/cangen/cangen/main.py @@ -0,0 +1,42 @@ +""" +Author: Samuel Parent +Date: 2024-04-13 +""" + +import argparse +import logging + +from .can_generator import generate_can_from_dbc + +logging.basicConfig(level="INFO", format="%(levelname)-8s| (%(name)s) %(message)s") +logger = logging.getLogger(__name__) + + +def parse(): + parser = argparse.ArgumentParser(description="DBC to C code generator") + parser.add_argument("project", type=str, help="Name of the project") + parser.add_argument( + "--log-level", + dest="level", + choices=["STATUS", "INFO", "VERBOSE", "DEBUG"], + default="INFO", + help="Log verbosity threshold", + ) + + # If parsing fails (ex incorrect or no arguments provided) then this exits with + # code 2. + return parser.parse_args() + + +def main(): + args = parse() + + cmake_to_python_level = { + "STATUS": "INFO", + "INFO": "INFO", + "VERBOSE": "DEBUG", + "DEBUG": "DEBUG", + } + logger.setLevel(cmake_to_python_level[args.level]) + + generate_can_from_dbc(args.project) diff --git a/scripts/cangen/templates/can_messages.h.jinja2 b/scripts/cangen/cangen/templates/can_messages.h.jinja2 similarity index 100% rename from scripts/cangen/templates/can_messages.h.jinja2 rename to scripts/cangen/cangen/templates/can_messages.h.jinja2 diff --git a/scripts/cangen/templates/msg_registry.h.jinja2 b/scripts/cangen/cangen/templates/msg_registry.h.jinja2 similarity index 100% rename from scripts/cangen/templates/msg_registry.h.jinja2 rename to scripts/cangen/cangen/templates/msg_registry.h.jinja2 diff --git a/scripts/cangen/main.py b/scripts/cangen/main.py deleted file mode 100644 index 6fd651a03..000000000 --- a/scripts/cangen/main.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -Author: Samuel Parent -Date: 2024-04-13 -""" - -import argparse -import logging -import os - -import can_generator -import yaml -import shutil - -# Generate a set of directory paths, all based on this file's location -DIR_THIS_FILE = os.path.abspath(os.path.dirname(__file__)) - -DIR_FIRMWARE = os.path.join(DIR_THIS_FILE, os.pardir, os.pardir, "firmware") -DIR_PROJECTS = os.path.join(DIR_FIRMWARE, "projects") - -CONFIG_FILE_NAME = "config.yaml" -DEFAULT_OUTPUT_DIR = "generated/can" - -DIR_TEMPLATES = os.path.join(DIR_THIS_FILE, "templates") -CAN_MESSAGES_TEMPLATE_FILENAME = "can_messages.h.jinja2" -MSG_REGISTRY_TEMPLATE_FILENAME = "msg_registry.h.jinja2" - - -logging.basicConfig(level="INFO", format="%(levelname)-8s| (%(name)s) %(message)s") - - -def parse(): - parser = argparse.ArgumentParser(description="DBC to C code generator") - parser.add_argument( - "--project", type=str, required=True, help="Name of the project" - ) - parser.add_argument( - "--log-level", dest='level', choices=["STATUS", "INFO", "VERBOSE", "DEBUG"], default="INFO", help="Log verbosity threshold" - ) - - # If parsing fails (ex incorrect or no arguments provided) then this exits with - # code 2. - return parser.parse_args() - - -if __name__ == "__main__": - - # Change directory to the project folder - args = parse() - project_folder_name = args.project - os.chdir(os.path.join(DIR_PROJECTS, project_folder_name)) - - # Map CMAKE log levels -> Python log levels - log_level_mappings = { - "STATUS": "INFO", - "INFO": "INFO", - "VERBOSE": "DEBUG", - "DEBUG": "DEBUG" - } - # Set log level threshold to specified verbosity - logging.getLogger().setLevel(log_level_mappings[args.level]) - - # Read & Parse the config file - with open(CONFIG_FILE_NAME, "r") as file: - config = yaml.safe_load(file) - - config_file_path = os.path.abspath(CONFIG_FILE_NAME) - - our_node = config["canGen"]["ourNode"] - bus_list = config["canGen"]["busses"] - output_path = config["canGen"].get("outputPath", DEFAULT_OUTPUT_DIR) - - # Deletes output path folder and files within, before creating new ones - if os.path.exists(output_path): - shutil.rmtree(output_path) - - for bus in bus_list: - # import pdb - - # pdb.set_trace() - bus_name = bus['busName'].capitalize() - dbc_files = bus['dbcFiles'] - - dbc_file_paths = [os.path.normpath(os.path.join(os.path.dirname(config_file_path), dbc)) for dbc in dbc_files] - - can_messages_template_path = os.path.join( - DIR_TEMPLATES, CAN_MESSAGES_TEMPLATE_FILENAME - ) - msg_registry_template_path = os.path.join( - DIR_TEMPLATES, MSG_REGISTRY_TEMPLATE_FILENAME - ) - - can_generator.generate_code( - dbc_file_paths, - our_node, - bus_name, - output_path, - can_messages_template_path, - msg_registry_template_path, - ) diff --git a/scripts/cangen/poetry.lock b/scripts/cangen/poetry.lock new file mode 100644 index 000000000..cbca92dfe --- /dev/null +++ b/scripts/cangen/poetry.lock @@ -0,0 +1,573 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "argparse-addons" +version = "0.12.0" +description = "Additional argparse types and actions." +optional = false +python-versions = ">=3.6" +files = [ + {file = "argparse_addons-0.12.0-py3-none-any.whl", hash = "sha256:48b70ecd719054fcb0d7e6f25a1fecc13607aac61d446e83f47d211b4ead0d61"}, + {file = "argparse_addons-0.12.0.tar.gz", hash = "sha256:6322a0dcd706887e76308d23136d5b86da0eab75a282dc6496701d1210b460af"}, +] + +[[package]] +name = "bitstruct" +version = "8.19.0" +description = "This module performs conversions between Python values and C bit field structs represented as Python byte strings." +optional = false +python-versions = ">=3.7" +files = [ + {file = "bitstruct-8.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d1f3eb18ddc33ba73f5cbb55c885584bcec51c421ac3551b79edc0ffeaecc3d"}, + {file = "bitstruct-8.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a35e0b267d12438e6a7b28850a15d4cffe767db6fc443a406d0ead97fa1d7d5b"}, + {file = "bitstruct-8.19.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5732aff5c8eb3a572f7b20d09fc4c213215f9e60c0e66f2910b31eb65b457744"}, + {file = "bitstruct-8.19.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc8f1871b42b705eb34b8722c3ec358fbf1b97fd37a62693564ee72648afb100"}, + {file = "bitstruct-8.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:01bdfc3adbe15b05ba27ab6dce7959caa29a000f066201944b29c64bb8888f03"}, + {file = "bitstruct-8.19.0-cp310-cp310-win32.whl", hash = "sha256:961845a29333119b70dd9aab54bc714bf9ba5efefc55cb4c747c35c1390b8842"}, + {file = "bitstruct-8.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:9fbe12d464db909f58d5e2a2485b3047a488fa1373e8f74b22d6759ee6b2437a"}, + {file = "bitstruct-8.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1300cd635814e40b1f4105aa4f404cb5d1b8cc54e06e267ba1616725f9c2beea"}, + {file = "bitstruct-8.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2fb23b5973ce1e9f349c4dc90873eeff9800fe917ffd345f39b9b964f6d119"}, + {file = "bitstruct-8.19.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e0c18d557474d8452c4f8b59320fd4d9efcf52eae2144bdf317d25c64dcf85"}, + {file = "bitstruct-8.19.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bba06607f956cc39ceee19fd11b542e8e66a43180d48fa36c4609443893c273e"}, + {file = "bitstruct-8.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f2fa607d111077145e6374d49be6098f33e7cee0967b42cfc117df53eee13332"}, + {file = "bitstruct-8.19.0-cp311-cp311-win32.whl", hash = "sha256:abdb7bdb5b04c2f1bbda0eae828c627252243ddc042aea6b72af8fcc63696598"}, + {file = "bitstruct-8.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:464f102999402a2624ee3106dbfa1f3745810036814a33e6bc706b7d312c480f"}, + {file = "bitstruct-8.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:55768b1f5e33594178f0b3e1596b89d831b006713a60caa09de61fd385bf22b1"}, + {file = "bitstruct-8.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c026a7cf8d954ef53cf4d0ae5ee3dd1ac66e24e9a474c5afe55467ab7d609f2e"}, + {file = "bitstruct-8.19.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7488fd4e2fde3d8111971e2040cd5b008be918381afc80387d3fdf047c801293"}, + {file = "bitstruct-8.19.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:45b66e20633f1e083e37fa396c81761e0fc688ffa06ff5559e990e37234f9e18"}, + {file = "bitstruct-8.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9c1542d5ae888ebc31614775938bfd13454f0d897dc2515363a4607efadc990b"}, + {file = "bitstruct-8.19.0-cp312-cp312-win32.whl", hash = "sha256:7ea57e4e793b595cd3e037920852f2c676b4f5f1734c41985db3f48783928e2c"}, + {file = "bitstruct-8.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:1c4d9b75248adee84e7e6c95bf95966f152b78363cb20a81920da2aeadc4375f"}, + {file = "bitstruct-8.19.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7b4745b099d3d85307495e25ff0f265deeea675621dcecb25ba059ee68ce88d5"}, + {file = "bitstruct-8.19.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:645da560acd20dd73a1ef220e3ddc08e108866e30a708ef2f6193e0a3725113e"}, + {file = "bitstruct-8.19.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01402fbc3dba2286b3ac9b74d5936dd984736f928aacd371458a4b0cf95f0755"}, + {file = "bitstruct-8.19.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2c5eda42d55db67072c6cf7cc79b1df1074269004bad119b79e4ad38cfa61877"}, + {file = "bitstruct-8.19.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2ea093522b12ce714a3a95851a8c3dd97f620126bbe983eb261b3bf18ac945e7"}, + {file = "bitstruct-8.19.0-cp37-cp37m-win32.whl", hash = "sha256:da00da004830800323554e7a83f1f32a1f49345f5379476de4b5f6ae227ee962"}, + {file = "bitstruct-8.19.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a0ca55fba25d6c631e17933f20cf87f553d7bceec7659e3de9ef48dc85ced2bf"}, + {file = "bitstruct-8.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d3f6e3aeb598215062c505a06135fbdfa3bb4eeb249b55f87e865a86b3fd9e99"}, + {file = "bitstruct-8.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df74c72feba80014b05ab6f1e1a0bb90be9f9e7eb60a9bab1e00728f7f46d79d"}, + {file = "bitstruct-8.19.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:976c39ad771c6773d6fbd14d71e62242d5b3bca7b72428fd183e1f1085d5e858"}, + {file = "bitstruct-8.19.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d2c176ff6727206805760f45c2151468aed843256aa239c14f4730b9e1d84fc7"}, + {file = "bitstruct-8.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7774e2a51e254ef1ba98a1ee38573c819d4ee7e396d5121c5ecae17df927501"}, + {file = "bitstruct-8.19.0-cp38-cp38-win32.whl", hash = "sha256:b86d192d658eaf35f10efb2e1940ec755cc28e081f46de294a2e91a74ea298aa"}, + {file = "bitstruct-8.19.0-cp38-cp38-win_amd64.whl", hash = "sha256:5e7f78aedec2881017026eb7f7ab79514aef09a24afd8acf5fa8c73b1cd0e9f4"}, + {file = "bitstruct-8.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2bb49acc2ccc6efd3c9613cae8f7e1316c92f832bff860a6fcb78a4275974e90"}, + {file = "bitstruct-8.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bed7b2761c18a515298145a4f67b6c71ce302453fe7d87ec6b7d2e77fd3c22b"}, + {file = "bitstruct-8.19.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d0cafd2e2974c4bbe349fb67951d43d221ea304218c2ee65f9fe4c62acabc2f"}, + {file = "bitstruct-8.19.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d9ba0299f624e7c8ea1eec926fc77741f82ffc5b3c3ba4f89303d33d5605f4d8"}, + {file = "bitstruct-8.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bfa0326057c9b02c4e65e74e45b9914a7f8c59590a8e718e20a899a02b41f2e6"}, + {file = "bitstruct-8.19.0-cp39-cp39-win32.whl", hash = "sha256:14c3ebdec92c486142327d934cb451d96b411543ec6f72aeb2b4b4334e9408bf"}, + {file = "bitstruct-8.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:7836852d5c15444e87a2029f922b48717e6e199d2332d55e8738e92d8590987e"}, + {file = "bitstruct-8.19.0.tar.gz", hash = "sha256:d75ba9dded85c17e885a209a00eb8e248ee40762149f2f2a79360ca857467dac"}, +] + +[[package]] +name = "cantools" +version = "39.4.5" +description = "CAN BUS tools." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cantools-39.4.5-py3-none-any.whl", hash = "sha256:d05b428c2d0afa9fb27a1f9f16b943ef573e0138aa466990dfa4e162d14a8a61"}, + {file = "cantools-39.4.5.tar.gz", hash = "sha256:594f2ae80deadb8c6b08e8e1322d42e258f40d42c80d6886d84e0143f90b5a23"}, +] + +[package.dependencies] +argparse-addons = "*" +bitstruct = ">=8.16.1" +crccheck = "*" +diskcache = "*" +python-can = ">=3.3.4" +textparser = ">=0.21.1" + +[package.extras] +dev = ["mypy", "pipx", "ruff", "tox"] +plot = ["matplotlib"] +windows-all = ["windows-curses"] + +[[package]] +name = "crccheck" +version = "1.3.0" +description = "Calculation library for CRCs and checksums" +optional = false +python-versions = "*" +files = [ + {file = "crccheck-1.3.0-py3-none-any.whl", hash = "sha256:278ec53d6f417f197f7e0e29b485093d4879b0bc7a2d29b657ef8242e633b48d"}, + {file = "crccheck-1.3.0.tar.gz", hash = "sha256:5384f437de610ade5c3d8689efc80ccd1267b8c452ade83411fd8500a1024f3e"}, +] + +[[package]] +name = "diskcache" +version = "5.6.3" +description = "Disk Cache -- Disk and file backed persistent cache." +optional = false +python-versions = ">=3" +files = [ + {file = "diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19"}, + {file = "diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc"}, +] + +[[package]] +name = "jinja2" +version = "3.1.3" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "3.0.2" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +files = [ + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + +[[package]] +name = "msgpack" +version = "1.0.8" +description = "MessagePack serializer" +optional = false +python-versions = ">=3.8" +files = [ + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"}, + {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"}, + {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"}, + {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"}, + {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"}, + {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"}, + {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"}, + {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"}, + {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, + {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, + {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, + {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, +] + +[[package]] +name = "numpy" +version = "1.26.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +] + +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "python-can" +version = "4.4.2" +description = "Controller Area Network interface module for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python_can-4.4.2-py3-none-any.whl", hash = "sha256:e956d781b45563c244c1f3c8fe001e292d1857519cff663d7c184673a68879f9"}, + {file = "python_can-4.4.2.tar.gz", hash = "sha256:1c46c0935f39f7a9c3e76b03249af0580689ebf7a1844195e92f87257f009df5"}, +] + +[package.dependencies] +msgpack = {version = ">=1.0.0,<1.1.0", markers = "platform_system != \"Windows\""} +packaging = ">=23.1" +pywin32 = {version = ">=305", markers = "platform_system == \"Windows\" and platform_python_implementation == \"CPython\""} +typing-extensions = ">=3.10.0.0" +wrapt = ">=1.10,<2.0" + +[package.extras] +canalystii = ["canalystii (>=0.1.0)"] +canine = ["python-can-canine (>=0.2.2)"] +cantact = ["cantact (>=0.0.7)"] +cvector = ["python-can-cvector"] +gs-usb = ["gs-usb (>=0.2.1)"] +lint = ["black (==24.4.*)", "mypy (==1.10.*)", "pylint (==3.2.*)", "ruff (==0.4.8)"] +mf4 = ["asammdf (>=6.0.0)"] +neovi = ["filelock", "python-ics (>=2.12)"] +nixnet = ["nixnet (>=0.3.2)"] +pcan = ["uptime (>=3.0.1,<3.1.0)"] +remote = ["python-can-remote"] +seeedstudio = ["pyserial (>=3.0)"] +serial = ["pyserial (>=3.0,<4.0)"] +sontheim = ["python-can-sontheim (>=0.1.2)"] +viewer = ["windows-curses"] + +[[package]] +name = "pywin32" +version = "308" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, + {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, + {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, + {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, + {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, + {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, + {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, + {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, + {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, + {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, + {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, + {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, + {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, + {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, + {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, + {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, + {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, + {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "ruff" +version = "0.6.9" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"}, + {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"}, + {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"}, + {file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"}, + {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"}, + {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"}, + {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"}, +] + +[[package]] +name = "textparser" +version = "0.24.0" +description = "Text parser." +optional = false +python-versions = "*" +files = [ + {file = "textparser-0.24.0-py3-none-any.whl", hash = "sha256:379d25cdb21332f403bfa37b9ef11192b7796340d2602d88fc9246bfdba2a1cf"}, + {file = "textparser-0.24.0.tar.gz", hash = "sha256:56f708e75aa9d002adb76d823ba6ef166d7ecec1e3e4ca4c1ca103f817568335"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "wrapt" +version = "1.16.0" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "2e720bbda2d5750ab9e0b3fcec76dc474d9087ad806bbbb5462874e769c8aa6e" diff --git a/scripts/cangen/pyproject.toml b/scripts/cangen/pyproject.toml new file mode 100644 index 000000000..28c7c45d7 --- /dev/null +++ b/scripts/cangen/pyproject.toml @@ -0,0 +1,24 @@ +[tool.poetry] +name = "cangen" +version = "0.1.0" +description = "Converts .dbc files into C++ files for a CAN bus system." +authors = ["Andrew Iammancini"] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.10" +cantools = "39.4.5" +Jinja2 = "3.1.3" +numpy = "1.26.4" +PyYAML = "6.0.1" + + +[tool.poetry.scripts] +cangen = "cangen.main:main" + +[tool.poetry.group.dev.dependencies] +ruff = "^0.6.9" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/scripts/cangen/requirements.txt b/scripts/cangen/requirements.txt deleted file mode 100644 index 38752ea3d..000000000 --- a/scripts/cangen/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -argparse-addons==0.12.0 -bitstruct==8.19.0 -cantools==39.4.5 -crccheck==1.3.0 -diskcache==5.6.3 -Jinja2==3.1.3 -MarkupSafe==2.1.5 -numpy==1.26.4 -packaging==24.0 -python-can==4.3.1 -PyYAML==6.0.1 -textparser==0.24.0 -typing_extensions==4.11.0 -wrapt==1.16.0