diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 7c90e1d..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "Chassis Power Distro.cydsn/HindsightCAN"]
- path = Chassis Power Distro.cydsn/HindsightCAN
- url = https://github.com/huskyroboticsteam/HindsightCAN.git
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/ChassisPowerDistro2025-000.cywrk b/2024-2025/ChassisPowerDistro2025.cydsn/ChassisPowerDistro2025-000.cywrk
new file mode 100644
index 0000000..3750f14
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/ChassisPowerDistro2025-000.cywrk
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+.\ChassisPowerDistro2025.cyprj
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/ChassisPowerDistro2025.cydwr b/2024-2025/ChassisPowerDistro2025.cydsn/ChassisPowerDistro2025.cydwr
new file mode 100644
index 0000000..51b64ec
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/ChassisPowerDistro2025.cydwr
@@ -0,0 +1,3708 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/ChassisPowerDistro2025.cyprj b/2024-2025/ChassisPowerDistro2025.cydsn/ChassisPowerDistro2025.cyprj
new file mode 100644
index 0000000..60d454b
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/ChassisPowerDistro2025.cyprj
@@ -0,0 +1,2002 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANCommon.c b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANCommon.c
new file mode 100644
index 0000000..2c0662a
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANCommon.c
@@ -0,0 +1,260 @@
+/* File: CANCommon.c
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction definitions for Common Mode CAN Communication
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+#include "CANPacket.h"
+#include "CANCommon.h"
+#include "Port.h"
+// Assembles Emergency Stop Packet with given parameters
+// Inputs:
+// packet: CAN Packet to assemble (will overwrite).
+// targetDeviceGroup: Group to target
+// targetDeviceSerialNumber: Serial number of target device
+// errorCode: Emergency stop error code. E.G. ESTOP_ERR_GENERAL
+void AssembleEmergencyStopPacket(CANPacket *packet,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerialNumber,
+ uint8_t errorCode)
+{
+ packet->dlc = DLC_ESTOP;
+ packet->id = ConstructCANID(PACKET_PRIORITY_HIGH, targetDeviceGroup, targetDeviceSerialNumber);
+ int nextByte = WriteSenderSerialAndPacketID(packet->data, ID_ESTOP);
+ packet->data[nextByte] = errorCode;
+}
+
+// Assembles Emergency Stop Packet with given parameters.
+// This will broadcast the emergency stop command to a desired device group.
+// Inputs:
+// packet: CAN Packet to assemble (will overwrite).
+// deviceGroup: Group to target
+// errorCode: Emergency stop error code. E.G. ESTOP_ERR_GENERAL
+void AssembleGroupBroadcastingEmergencyStopPacket(CANPacket *packet,
+ uint8_t groupCode,
+ uint8_t errorCode)
+{
+ AssembleEmergencyStopPacket(packet, groupCode, DEVICE_SERIAL_BROADCAST, errorCode);
+}
+
+// Assembles Emergency Stop Packet with given parameters.
+// This will broadcast the emergency stop command to all devices
+// Inputs:
+// packet: CAN Packet to assemble (will overwrite).
+// errorCode: Emergency stop error code. E.G. ESTOP_ERR_GENERAL
+void AssembleBrodcastEmergencyStopPacket(CANPacket *packet,
+ uint8_t errorCode)
+{
+ AssembleGroupBroadcastingEmergencyStopPacket(packet, DEVICE_GROUP_BROADCAST, errorCode);
+}
+
+// Gets the Error Code reported from an emergency stop packet.
+// Inputs:
+// packet: Packet to check.
+uint8_t GetEmergencyStopErrorCode(CANPacket *packet)
+{
+ if (PacketIsOfID(packet, ID_ESTOP))
+ {
+ return packet->data[2];
+ }
+ else { return -1; }
+}
+
+// Validates the Heartbeat Packet, returns time between previous Heartbeat packets
+// Inputs:
+// packet: CAN Packet to check
+// lastHeartbeat: Timestamp (ms) of last detected heartbeat
+// Outputs:
+// Time (in ms) between this heartbeat and the previous detected heartbeat
+// Negative value if packet is not valid heartbeat packet
+uint32_t GetTimeBetweenHeartbeatPacket(CANPacket *packet, uint32_t lastHeartbeat)
+{
+ if (PacketIsOfID(packet, ID_HEARTBEAT))
+ {
+ return GetHeartbeatTimeStamp(packet) - lastHeartbeat;
+ }
+ else { return -1; }
+}
+
+// Validates the Heartbeat Packet, returns time between previous Heartbeat packets
+// Inputs:
+// packet: CAN Packet to check
+// lastHeartbeat: Timestamp (ms) of last detected heartbeat
+// Outputs:
+// Time (in ms) of the timestamp within the packet
+// Default return value is uint32 max value, which is used
+// if the packet is corrupt or not a heartbeat packet.
+uint32_t GetHeartbeatTimeStamp(CANPacket *packet)
+{
+ if (PacketIsOfID(packet, ID_HEARTBEAT))
+ {
+ uint32_t time = ((uint32_t)packet->data[3] << 24);
+ time |= ((uint32_t)packet->data[4] << 16);
+ time |= ((uint32_t)packet->data[5] << 8);
+ time |= packet->data[6];
+ return time;
+ }
+ else { return -1; }
+}
+
+// Validates the Heartbeat Packet, returns the heartbeat leniency code of the packet
+// Inputs:
+// packet: CAN Packet to check
+// Outputs:
+// Heartbeat leniency code of given packet
+uint8_t GetHeartbeatLeniencyCode(CANPacket *packet)
+{
+ if (PacketIsOfID(packet, ID_HEARTBEAT))
+ {
+ return packet->data[2];
+ } else {
+ return 0x00;
+ }
+}
+
+// Assembles Heartbeat Packet with given parameters
+// Inputs:
+// packetToAssemble: CAN Packet to assemble (will overwrite).
+// broadcast: 1 if broadcast to all devices. 0 to return to MAIN_CPU / Jetson.
+// heartbeatLeniencyCode: Max time between heartbeats before system automatically enters a safe operating condition.
+// timestamp: Current timestamp as seen by the sender device. (ms)
+//TODO, upon approval from @jaden, delete senderGroup and senderSerial params, as these are handled by getLocal functs
+void AssembleHeartbeatPacket(CANPacket *packetToAssemble,
+ int broadcast,
+ uint8_t heartbeatLeniencyCode,
+ uint32_t timestamp)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_HIGH, DEVICE_GROUP_BROADCAST, DEVICE_SERIAL_BROADCAST);
+ if (!broadcast)
+ {
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_HIGH, DEVICE_GROUP_JETSON, DEVICE_SERIAL_JETSON);
+ }
+ packetToAssemble->dlc = DLC_HEARTBEAT;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_HEARTBEAT);
+ packetToAssemble->data[nextByte] = heartbeatLeniencyCode;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, timestamp, nextByte + 1);
+}
+
+void AssembleFailReportPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t failedPacketID)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetGroup, targetSerial);
+ packetToAssemble->dlc = DLC_FAIL_REPORT;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_FAIL_REPORT);
+ packetToAssemble->data[nextByte] = failedPacketID;
+}
+
+// Assembles override protection packet with given parameters
+// Inputs:
+// packetToAssemble: CAN Packet to assemble (will overwrite).
+// targetGroup: Device gorup of target device.
+// targetSerial: Device serial of target device.
+void AssembleOverrideProtectionPacket(CANPacket *packetToAssemble, uint8_t targetGroup, uint8_t targetSerial)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetGroup, targetSerial);
+ packetToAssemble->dlc = DLC_OVRD_PROTECTION;
+ WritePacketIDOnly(packetToAssemble->data, ID_OVRD_PROTECTION);
+}
+
+void AssembleChipTypePullPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_CHIP_TYPE_PULL;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_CHIP_TYPE_PULL);
+ packetToAssemble->data[nextByte] = getChipType();
+}
+
+void AssembleChipTypeReportPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_CHIP_TYPE_REP;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_CHIP_TYPE_REP);
+ packetToAssemble->data[nextByte] = getChipType();
+}
+
+uint8_t GetChipTypeFromPacket(CANPacket *packet)
+{
+ return packet->data[1];
+}
+
+void AssembleTelemetryTimingPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t telemetryTypeCode,
+ uint32_t msBetweenReports)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetGroup, targetSerial);
+ packetToAssemble->dlc = DLC_TELEMETRY_TIMING;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_TELEMETRY_TIMING);
+ packetToAssemble->data[nextByte] = telemetryTypeCode;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, msBetweenReports, nextByte + 1);
+}
+uint32_t GetTelemetryTimingFromPacket(CANPacket *packetToAssemble)
+{
+ return DecodeTelemetryDataUnsigned(packetToAssemble);
+}
+
+void AssembleTelemetryPullPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t telemetryTypeCode)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetGroup, targetSerial);
+ packetToAssemble->dlc = DLC_TELEMETRY_PULL;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_TELEMETRY_PULL);
+ packetToAssemble->data[nextByte] = telemetryTypeCode;
+}
+
+void AssembleTelemetryReportPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t telemetryTypeCode,
+ int32_t data)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetGroup, targetSerial);
+ packetToAssemble->dlc = DLC_TELEMETRY_REPORT;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_TELEMETRY_REPORT);
+ packetToAssemble->data[nextByte] = telemetryTypeCode;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, data, nextByte + 1);
+}
+
+int32_t DecodeTelemetryDataSigned(CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, 4, 8);
+}
+
+uint32_t DecodeTelemetryDataUnsigned(CANPacket *packet)
+{
+ return (uint32_t) DecodeTelemetryDataSigned(packet);
+}
+
+uint8_t DecodeTelemetryType(CANPacket *packet)
+{
+ return packet->data[3];
+}
+
+void AssembleRGBColorPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t addrLED,
+ uint8_t R,
+ uint8_t G,
+ uint8_t B)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetGroup, targetSerial);
+ packetToAssemble->dlc = DLC_LED_COLOR;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_LED_COLOR);
+ packetToAssemble->data[nextByte] = R;
+ packetToAssemble->data[nextByte + 1] = G;
+ packetToAssemble->data[nextByte + 2] = B;
+ packetToAssemble->data[nextByte + 3] = addrLED;
+}
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANCommon.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANCommon.h
new file mode 100644
index 0000000..7a991d2
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANCommon.h
@@ -0,0 +1,137 @@
+/* File: CANCommon.h
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction prototypes for Common Mode CAN Communication
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+#pragma once
+
+#include "CANPacket.h"
+
+void AssembleEmergencyStopPacket(CANPacket *packet,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerialNumber,
+ uint8_t errorCode);
+void AssembleGroupBroadcastingEmergencyStopPacket(CANPacket *packet,
+ uint8_t groupCode,
+ uint8_t errorCode);
+void AssembleBrodcastEmergencyStopPacket(CANPacket *packet,
+ uint8_t errorCode);
+uint8_t GetEmergencyStopErrorCode(CANPacket *packet);
+
+uint32_t GetTimeBetweenHeartbeatPacket(CANPacket *packet, uint32_t lastHeartbeat);
+uint32_t GetHeartbeatTimeStamp(CANPacket *packet);
+void AssembleHeartbeatPacket(CANPacket *packetToAssemble,
+ int broadcast,
+ uint8_t heartbeatLeniencyCode,
+ uint32_t timestamp);
+
+void AssembleFailReportPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t failedPacketID);
+
+void AssembleOverrideProtectionPacket(CANPacket *packetToAssemble, uint8_t targetGroup, uint8_t targetSerial);
+
+//Chip type pull
+void AssembleChipTypePullPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial);
+void AssembleChipTypeReportPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial);
+uint8_t GetChipTypeFromPacket(CANPacket *packet);
+
+void AssembleTelemetryTimingPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t telemetryTypeCode,
+ uint32_t msBetweenReports);
+uint32_t GetTelemetryTimingFromPacket(CANPacket *packetToAssemble);
+
+void AssembleTelemetryPullPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t telemetryTypeCode);
+
+void AssembleTelemetryReportPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t telemetryTypeCode,
+ int32_t data);
+
+int32_t DecodeTelemetryDataSigned(CANPacket *packet);
+uint32_t DecodeTelemetryDataUnsigned(CANPacket *packet);
+uint8_t DecodeTelemetryType(CANPacket *packet);
+
+void AssembleRGBColorPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t addrLED,
+ uint8_t R,
+ uint8_t G,
+ uint8_t B);
+
+// Common Mode Packet IDs
+#define ID_ESTOP (uint8_t) 0xF0
+#define ID_HEARTBEAT (uint8_t) 0xF1
+#define ID_FAIL_REPORT (uint8_t) 0xF2
+#define ID_OVRD_PROTECTION (uint8_t) 0xF3
+#define ID_TELEMETRY_TIMING (uint8_t) 0xF4
+#define ID_TELEMETRY_PULL (uint8_t) 0xF5
+#define ID_TELEMETRY_REPORT (uint8_t) 0xF6
+#define ID_LED_COLOR (uint8_t) 0xF7
+#define ID_CHIP_TYPE_PULL (uint8_t) 0xF8
+#define ID_CHIP_TYPE_REP (uint8_t) 0xF9
+
+// DLC Common Mode Packets
+#define DLC_ESTOP (uint8_t) 0x04
+#define DLC_HEARTBEAT (uint8_t) 0x08
+#define DLC_FAIL_REPORT (uint8_t) 0x04
+#define DLC_OVRD_PROTECTION (uint8_t) 0x01
+#define DLC_TELEMETRY_TIMING (uint8_t) 0x08
+#define DLC_TELEMETRY_PULL (uint8_t) 0x04
+#define DLC_TELEMETRY_REPORT (uint8_t) 0x08
+#define DLC_LED_COLOR (uint8_t) 0x06
+#define DLC_CHIP_TYPE_PULL (uint8_t) 0x04
+#define DLC_CHIP_TYPE_REP (uint8_t) 0x04
+
+//Packet priorities
+#define PRIO_CHIP_TYPE_REP PACKET_PRIORITY_NORMAL
+
+// Telemetry Types
+#define PACKET_TELEMETRY_VOLTAGE ((uint8_t) 0x00)
+#define PACKET_TELEMETRY_CURRENT ((uint8_t) 0x01)
+#define PACKET_TELEMETRY_PWR_RAIL_STATE ((uint8_t) 0x02)
+#define PACKET_TELEMETRY_TEMPERATURE ((uint8_t) 0x03)
+#define PACKET_TELEMETRY_ANG_POSITION ((uint8_t) 0x04)
+#define PACKET_TELEMETRY_GPS_LAT ((uint8_t) 0x05)
+#define PACKET_TELEMETRY_GPS_LON ((uint8_t) 0x06)
+#define PACKET_TELEMETRY_MAG_DIR ((uint8_t) 0x07)
+#define PACKET_TELEMETRY_ACCEL_X ((uint8_t) 0x08)
+#define PACKET_TELEMETRY_ACCEL_Y ((uint8_t) 0x09)
+#define PACKET_TELEMETRY_ACCEL_Z ((uint8_t) 0x0A)
+#define PACKET_TELEMETRY_GYRO_X ((uint8_t) 0x0B)
+#define PACKET_TELEMETRY_GYRO_Y ((uint8_t) 0x0C)
+#define PACKET_TELEMETRY_GYRO_Z ((uint8_t) 0x0D)
+#define PACKET_TELEMETRY_LIM_SW_STATE ((uint8_t) 0x0E)
+#define PACKET_TELEMETRY_ADC_RAW ((uint8_t) 0x0F)
+#define PACKET_TELEMETRY_GPIO_STATE ((uint8_t) 0x10)
+#define PACKET_TELEMETRY_CHIP_TYPE ((uint8_t) 0x11)
+#define PACKET_TELEMETRY_QUATERNION_W ((uint8_t) 0x12)
+#define PACKET_TELEMETRY_QUATERNION_X ((uint8_t) 0x13)
+#define PACKET_TELEMETRY_QUATERNION_Y ((uint8_t) 0x14)
+#define PACKET_TELEMETRY_QUATERNION_Z ((uint8_t) 0x15)
+#define PACKET_TELEMETRY_SENSOR1 ((uint8_t) 0x16)
+#define PACKET_TELEMETRY_SENSOR2 ((uint8_t) 0x17)
+#define PACKET_TELEMETRY_SENSOR3 ((uint8_t) 0x18)
+#define PACKET_TELEMETRY_SENSOR4 ((uint8_t) 0x19)
+#define PACKET_TELEMETRY_SENSOR5 ((uint8_t) 0x1A)
+#define PACKET_TELEMETRY_SENSOR6 ((uint8_t) 0x1B)
+
+// ESTOP ERROR CODES
+#define ESTOP_ERR_GENERAL (uint8_t) 0x00
+// MORE TBD...
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANGPIO.c b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANGPIO.c
new file mode 100644
index 0000000..91671b2
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANGPIO.c
@@ -0,0 +1,170 @@
+/* File: CANGPIO.c
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction implementations for the GPIO board CAN Communication
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+//#include "CANPacket.h"
+#include "CANGPIO.h"
+
+//Set PWM Frequency Packet
+//Assembles a CAN Packet to set GPIO PWM Frequency
+// Inputs: CANPacket pointer to assemble packet
+// targetGroup & targetSerial - for CAN ID
+// pwmChannel - board specific PWM channel
+// frequency - frequency in Hz
+void AssembleGPIOSetPWMFrequencyPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t pwmChannel,
+ uint16_t frequency){
+
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_GPIO_PWM_FREQ;
+
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_GPIO_PWM_FREQ);
+ packetToAssemble->data[nextByte++] = pwmChannel;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, frequency, nextByte); //consider making a 16bit version of this function?
+
+}
+
+//returns GPIO PWM Channel
+//accepts packet to return data from
+uint8_t GetGPIOPWMChannelFromPacket(CANPacket *packet){
+ return packet->data[1];
+}
+//returns GPIO PWM frequency
+//accepts packet to return data from
+uint16_t GetGPIOPWMFrequencyFromPacket(CANPacket *packet){
+ return DecodeBytesToIntMSBFirst(packet->data, 2, 3);
+}
+
+//Set PWM Duty Cycle
+//Assembles a CAN Packet to set GPIO PWM Duty Cycle
+// Inputs: CANPacket pointer to assemble packet
+// targetGroup & targetSerial - for CAN ID
+// pwmChannel - board specific PWM channel
+// dutyCycle - duty cycle resolution
+void AssembleGPIOSetPWMDutyCyclePacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t pwmChannel,
+ uint16_t dutyCycle){
+
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_GPIO_PWM_DUTY_CYCLE;
+
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_GPIO_PWM_DUTY_CYCLE);
+ packetToAssemble->data[nextByte++] = pwmChannel;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, dutyCycle, nextByte);
+}
+
+//returns GPIO PWM duty cycle
+//accepts packet to return data from
+uint16_t GetGPIOPWMDutyCycle(CANPacket *packetToAssemble){
+ return DecodeBytesToIntMSBFirst(packetToAssemble->data, 2, 3);
+}
+
+
+//Set ADC State
+//Assembles a CAN Packet to set GPIO ADC
+// Inputs: CANPacket pointer to assemble packet
+// targetGroup & targetSerial - for CAN ID
+// ADCChannel - board specific ADC channel
+// state - bool (1 enable 0 disable)
+void AssembleGPIOSetADCStateConfiguration(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t ADCChannel,
+ uint8_t state){
+
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_GPIO_ADC_STATE;
+
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_GPIO_ADC_STATE);
+ packetToAssemble->data[nextByte++] = ADCChannel;
+ packetToAssemble->data[nextByte] = state;
+}
+//returns GPIO ADC channel
+//accepts packet to return data from
+uint8_t GetGPIOADCChannelFromPacket(CANPacket *packet){
+ return packet->data[1];
+}
+//returns GPIO ADC state
+//accepts packet to return data from
+uint8_t GetGPIOADCStateFromPacket(CANPacket *packet){
+ return packet->data[2];
+}
+
+
+//Set GPIO Configuration
+//Assembles a CAN Packet to set GPIO Config
+// Inputs: CANPacket pointer to assemble packet
+// targetGroup & targetSerial - for CAN ID
+// GPIORegister - GPIO Register
+// GPIO bit number - (number is the bit which is being set)
+// GPIO bit state - off, in, out, in/out, adc, pwm
+void AssembleGPIOSetConfigurationPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t GPIORegister,
+ uint8_t bitNumber,
+ uint8_t bitConfig){
+
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_GPIO_CONFIG;
+
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_GPIO_CONFIG);
+ packetToAssemble->data[nextByte++] = GPIORegister;
+ packetToAssemble->data[nextByte++] = bitNumber;
+ packetToAssemble->data[nextByte] = bitConfig;
+
+}
+//returns GPIO register
+//accepts packet to return data from
+uint8_t GetGPIORegisterFromPacket(CANPacket *packet){
+ return packet->data[1];
+}
+//returns GPIO bit number
+//accepts packet to return data from
+uint8_t GetGPIOBitNumberFromPacket(CANPacket *packet){
+ return packet->data[2];
+}
+//returns GPIO bit config
+//accepts packet to return data from
+uint8_t GetGPIOBitConfigFromPacket(CANPacket *packet){
+ return packet->data[3];
+}
+
+
+//GPIO Write
+//Assembles a CAN Packet to set GPIO Config
+// Inputs: CANPacket pointer to assemble packet
+// targetGroup & targetSerial - for CAN ID
+// GPIORegister - GPIO Register
+// GPIO bit number - (number is the bit which is being set)
+// GPIO bit writevalues - off, on, flip
+void AssembleGPIOWrite(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t GPIORegister,
+ uint8_t bitNumber,
+ uint8_t bitWriteValue){
+
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_GPIO_WRITE;
+
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_GPIO_WRITE);
+ packetToAssemble->data[nextByte++] = GPIORegister;
+ packetToAssemble->data[nextByte++] = bitNumber;
+ packetToAssemble->data[nextByte] = bitWriteValue;
+
+}
+
+//returns GPIO write values
+//accepts packet to return data from
+uint8_t GetGPIOWriteValuesFromPacket(CANPacket *packet){
+ return packet->data[3];
+}
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANGPIO.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANGPIO.h
new file mode 100644
index 0000000..b047c95
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANGPIO.h
@@ -0,0 +1,91 @@
+/* File: CANGPIO.h
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction prototypes for the GPIO board CAN Communication
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+#pragma once
+
+#include "CANPacket.h"
+
+//Set PWM Frequency
+void AssembleGPIOSetPWMFrequencyPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t pwmChannel,
+ uint16_t frequency);
+uint8_t GetGPIOPWMChannelFromPacket(CANPacket *packet);
+uint16_t GetGPIOPWMFrequencyFromPacket(CANPacket *packet);
+
+//Set PWM Duty Cycle
+void AssembleGPIOSetPWMDutyCyclePacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t pwmChannel,
+ uint16_t dutyCycle);
+uint16_t GetGPIOPWMDutyCycle(CANPacket *packetToAssemble);
+
+
+//Set ADC State
+void AssembleGPIOSetADCStateConfiguration(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t ADCChannel,
+ uint8_t state);
+uint8_t GetGPIOADCChannelFromPacket(CANPacket *packet);
+uint8_t GetGPIOADCStateFromPacket(CANPacket *packet);
+
+
+//Set GPIO Configuration
+void AssembleGPIOSetConfigurationPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t GPIORegister,
+ uint8_t bitNumber,
+ uint8_t bitConfig);
+uint8_t GetGPIORegisterFromPacket(CANPacket *packet);
+uint8_t GetGPIOBitNumberFromPacket(CANPacket *packet);
+uint8_t GetGPIOBitConfigFromPacket(CANPacket *packet);
+
+
+//GPIO Write
+void AssembleGPIOWrite(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t GPIORegister,
+ uint8_t bitNumber,
+ uint8_t bitWriteValue);
+uint8_t GetGPIOWriteValuesFromPacket(CANPacket *packet);
+
+//use this as bit number to configure or write to a whole register at once
+#define GPIO_WHOLE_REG_NUMBER 0xFF
+
+//GPIO configuration constants
+#define GPIO_CONFIG_OFF 0x0
+#define GPIO_CONFIG_INPUT 0x1
+#define GPIO_CONFIG_OUTPUT 0x2
+#define GPIO_CONFIG_IO 0x3
+#define GPIO_CONFIG_ADC 0x4
+#define GPIO_CONFIG_PWM 0x5
+
+//GPIO write values
+#define GPIO_WRITE_OFF 0x0
+#define GPIO_WRITE_ON 0x1
+#define GPIO_WRITE_FLIP 0x2
+
+//GPIO DLC
+#define DLC_GPIO_PWM_FREQ (uint8_t) 0x04
+#define DLC_GPIO_PWM_DUTY_CYCLE (uint8_t) 0x04
+#define DLC_GPIO_ADC_STATE (uint8_t) 0x03
+#define DLC_GPIO_CONFIG (uint8_t) 0x04
+#define DLC_GPIO_WRITE (uint8_t) 0x04
+
+//GPIO Packet IDs
+#define ID_GPIO_PWM_FREQ (uint8_t) 0x00
+#define ID_GPIO_PWM_DUTY_CYCLE (uint8_t) 0x01
+#define ID_GPIO_ADC_STATE (uint8_t) 0x02
+#define ID_GPIO_CONFIG (uint8_t) 0x03
+#define ID_GPIO_WRITE (uint8_t) 0x04
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANLibrary.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANLibrary.h
new file mode 100644
index 0000000..57cced2
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANLibrary.h
@@ -0,0 +1,21 @@
+/*
+ *This file includes all others for simple library integration. Better
+ *form would be just to include what you need. Essentials are:
+ *CANPacket.h, port.h, CANCommon.h
+ *You will also need any utility files required by your board, i.e.
+ *CANMotorUnit.h or CANLocalization.
+ */
+
+#pragma once
+
+//Essentials
+#include "CANPacket.h"
+#include "CANCommon.h"
+#include "Port.h"
+
+//Board specifics
+#include "CANGPIO.h"
+#include "CANLocalization.h"
+#include "CANMotorUnit.h"
+#include "CANPower.h"
+#include "CANSerialNumbers.h"
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANLocalization.c b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANLocalization.c
new file mode 100644
index 0000000..ae15bca
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANLocalization.c
@@ -0,0 +1,9 @@
+/* File: CANLocalization.c
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction implementations for the Localization board CAN Communication
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+#include "CANPacket.h"
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANLocalization.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANLocalization.h
new file mode 100644
index 0000000..6fa91b4
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANLocalization.h
@@ -0,0 +1,12 @@
+/* File: CANLocalization.h
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction prototypes for the Localization board CAN Communication
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+#pragma once
+
+#include "CANPacket.h"
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANMotorUnit.c b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANMotorUnit.c
new file mode 100644
index 0000000..b057764
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANMotorUnit.c
@@ -0,0 +1,326 @@
+/* File: CANMotorUnit.c
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin, Austin Chan.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes function definitions for CAN Packet manipulation
+ * using the Hindsight CAN Communication standard. Specific files
+ * for the motor unit boards.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+#include "CANPacket.h"
+#include "CANMotorUnit.h"
+#include "Port.h"
+
+void AssembleModeSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t mode)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_MODE_SEL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_MODE_SEL;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_MODE_SEL);
+ packetToAssemble->data[nextByte] = mode;
+}
+
+uint8_t GetModeFromPacket(CANPacket *packet)
+{
+ return packet->data[1];
+}
+
+
+void AssemblePWMDirSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int16_t PWMSet)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_PWM_DIR_SET, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_PWM_DIR_SET;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_PWM_DIR_SET);
+ PackShortIntoDataMSBFirst(packetToAssemble->data, PWMSet, nextByte);
+}
+
+int16_t GetPWMFromPacket(CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, 1, 2);
+}
+
+//Returns 2's compliment MSB (0 for stopped or forward, 1 for reverse)
+int32_t GetDirectionFromPacket(CANPacket *packet)
+{
+ return ((packet->data[1]) >> 7) & 0x1;
+}
+
+void AssemblePIDTargetSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int32_t target)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_PID_POS_TGT_SET;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_PID_POS_TGT_SET);
+ PackIntIntoDataMSBFirst(packetToAssemble->data, target, nextByte);
+}
+
+int32_t GetPIDTargetFromPacket(CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, DLC_MOTOR_UNIT_PID_POS_TGT_SET - 4, DLC_MOTOR_UNIT_PID_POS_TGT_SET);
+}
+
+void AssemblePSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int32_t pCoef)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_PID_P_SET;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_PID_P_SET);
+ PackIntIntoDataMSBFirst(packetToAssemble->data, pCoef, nextByte);
+}
+
+int32_t GetPFromPacket(CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, DLC_MOTOR_UNIT_PID_P_SET - 4, DLC_MOTOR_UNIT_PID_P_SET );
+}
+
+void AssembleISetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int32_t iCoef)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_PID_I_SET;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_PID_I_SET);
+ PackIntIntoDataMSBFirst(packetToAssemble->data, iCoef, nextByte);
+}
+
+int32_t GetIFromPacket(CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, DLC_MOTOR_UNIT_PID_I_SET - 4, DLC_MOTOR_UNIT_PID_I_SET );
+}
+
+void AssembleDSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int32_t dCoef)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_PID_D_SET;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_PID_D_SET);
+ PackIntIntoDataMSBFirst(packetToAssemble->data, dCoef, nextByte);
+}
+
+int32_t GetDFromPacket(CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, DLC_MOTOR_UNIT_PID_D_SET - 4, DLC_MOTOR_UNIT_PID_D_SET);
+}
+
+void AssembleInitializePacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t initMode)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_INIT, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_INIT;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_INIT);
+ packetToAssemble->data[nextByte] = initMode;
+}
+uint8_t GetInitModeFromPacket(CANPacket *packet)
+{
+ return packet->data[1];
+}
+
+void AssembleLimitSwitchAlertPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t switches)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_LIM_ALERT, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_LIM_ALERT;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_MOTOR_UNIT_LIM_ALERT);
+ packetToAssemble->data[nextByte] = switches;
+}
+uint8_t GetLimStatusFromPacket(CANPacket *packet)
+{
+ return packet->data[1];
+}
+
+void AssembleEncoderPPJRSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint32_t pulses)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_ENC_PPJR_SET, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_ENC_PPJR_SET;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_ENC_PPJR_SET);
+ PackIntIntoDataMSBFirst(packetToAssemble->data, pulses, nextByte);
+}
+
+uint32_t GetEncoderPPJRFromPacket(CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, 1, 4);
+}
+
+void AssembleMaxJointRevolutionPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint32_t revolutions)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_MAX_JNT_REV_SET, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_MAX_JNT_REV_SET;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_MAX_JNT_REV_SET);
+ PackIntIntoDataMSBFirst(packetToAssemble->data, revolutions, nextByte);
+
+}
+uint32_t GetMaxJointRevolutionsFromPacket(CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, 1, 4);
+}
+
+void AssemblePotHiSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint16_t adcHi,
+ int32_t mdegHi)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_POT_INIT, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_POT_INIT;
+
+ int idx = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_POT_INIT_HI);
+ PackShortIntoDataMSBFirst(packetToAssemble->data, adcHi, idx);
+ idx += 2;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, mdegHi, idx);
+}
+
+void AssemblePotLoSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint16_t adcLo,
+ int32_t mdegLo)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_POT_INIT, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_POT_INIT;
+
+ int idx = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_POT_INIT_LO);
+ PackShortIntoDataMSBFirst(packetToAssemble->data, adcLo, idx);
+ idx += 2;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, mdegLo, idx);
+}
+
+uint16_t GetPotADCFromPacket(const CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, 1, 2);
+}
+
+int32_t GetPotmDegFromPacket(const CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, 3, 6);
+}
+
+void AssembleEncoderInitializePacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t encoderType,
+ uint8_t angleDirection,
+ uint8_t zeroAngle)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_ENC_INIT, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_ENC_INIT;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_ENC_INIT);
+ packetToAssemble->data[nextByte] = 0;
+ if(encoderType)
+ {
+ packetToAssemble->data[nextByte] |= 0b100;
+ }
+ if(angleDirection)
+ {
+ packetToAssemble->data[nextByte] |= 0b010;
+ }
+ if(zeroAngle)
+ {
+ packetToAssemble->data[nextByte] |= 0b001;
+ }
+}
+
+uint8_t GetEncoderTypeFromPacket(CANPacket *packet)
+{
+ return(packet->data[1] & 0b100);
+}
+uint8_t GetEncoderDirectionFromPacket(CANPacket *packet)
+{
+ return(packet->data[1] & 0b010);
+}
+uint8_t GetEncoderZeroFromPacket(CANPacket *packet)
+{
+ return(packet->data[1] & 0b001);
+}
+
+void AssembleMaxPIDPWMPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint16_t PWMSetMax)
+ {
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_MAX_PID_PWM, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_MAX_PID_PWM;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, DLC_MOTOR_UNIT_MAX_PID_PWM);
+ PackShortIntoDataMSBFirst(packetToAssemble->data, PWMSetMax, nextByte);
+}
+
+uint16_t GetMaxPIDPWMFromPacket(CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, 1, 2);
+}
+
+void AssemblePCAServoPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t servoNum,
+ int32_t angle)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_PCA_SERVO, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_PCA_SERVO;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_PCA_SERVO);
+ packetToAssemble->data[nextByte] = servoNum;
+ nextByte++;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, angle, nextByte);
+}
+
+int32_t GetAngleValueFromPacket(const CANPacket *packet)
+{
+ return DecodeBytesToIntMSBFirst(packet->data, 2, 5);
+}
+
+uint8_t GetServoNumFromPacket(const CANPacket *packet)
+{
+ return packet->data[1];
+}
+
+void AssembleLimSwEncoderBoundPacket(CANPacket* packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t limSwNum,
+ int32_t encoderBound)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_MOTOR_UNIT_SET_ENCODER_BOUND, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = DLC_MOTOR_UNIT_ENCODER_BOUND;
+ int nextByte = WritePacketIDOnly(packetToAssemble->data, ID_MOTOR_UNIT_SET_ENCODER_BOUND);
+ packetToAssemble->data[nextByte] = limSwNum;
+ nextByte++;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, encoderBound, nextByte);
+}
+
+int32_t GetEncoderValueFromPacket(const CANPacket* packet) {
+ return DecodeBytesToIntMSBFirst(packet->data, 2, 5);
+}
+
+uint8_t GetLimSwNumFromPacket(const CANPacket* packet) {
+ return packet->data[1];
+}
+
+uint8_t GetPeripheralID(const CANPacket* packet) {
+ return packet->data[1];
+}
+
+uint16_t GetPeripheralData(const CANPacket* packet) {
+ return (packet->data[2] << 8) | packet->data[3];
+}
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANMotorUnit.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANMotorUnit.h
new file mode 100644
index 0000000..82c76bd
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANMotorUnit.h
@@ -0,0 +1,315 @@
+/* File: CANMotorUnit.h
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction prototypes for CAN Packet manipulation
+ * using the Hindsight CAN Communication standard. Specific files
+ * for the motor unit boards.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+#include "CANPacket.h"
+
+// TODO: Add parameters to packet assembly
+//Mode set (PWM or PID)
+void AssembleModeSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t mode);
+uint8_t GetModeFromPacket(CANPacket *packet);
+
+//PWM value and direction set
+void AssemblePWMDirSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int16_t PWMSet);
+int16_t GetPWMFromPacket(CANPacket *packet);
+int32_t GetDirectionFromPacket(CANPacket *packet);
+
+//PID postional target set
+void AssemblePIDTargetSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int32_t target);
+int32_t GetPIDTargetFromPacket(CANPacket *packet);
+
+//P coeffiecent set
+void AssemblePSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int32_t pCoef);
+int32_t GetPFromPacket(CANPacket *packet);
+
+//I coeffiecent set
+void AssembleISetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int32_t iCoef);
+int32_t GetIFromPacket(CANPacket *packet);
+
+//D coeffiecent set
+void AssembleDSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ int32_t dCoef);
+int32_t GetDFromPacket(CANPacket *packet);
+
+//Initialize with mode (motors shall not move until have been inited)
+void AssembleInitializePacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t initMode);
+uint8_t GetInitModeFromPacket(CANPacket *packet);
+
+//Limit switch alert
+//each bit represents one limit switch, 1 for closed, 0 for open,
+//switch number corresponds to the bit number
+void AssembleLimitSwitchAlertPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t switches);
+uint8_t GetLimStatusFromPacket(CANPacket *packet);
+
+//Encoder pulses per joint revolution set
+void AssembleEncoderPPJRSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint32_t pulses);
+uint32_t GetEncoderPPJRFromPacket(CANPacket *packet);
+
+//Maximum joint rotations set
+void AssembleMaxJointRevolutionPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint32_t revolutions);
+uint32_t GetMaxJointRevolutionsFromPacket(CANPacket *packet);
+
+
+// Potentiometer configuration packets
+/**
+ * @brief Assemble a packet to set the high point of the potentiometer.
+ *
+ * This, along with AssemblePotLoSetPacket() are required to initialize the potentiometer.
+ * Behavior is undefined if only one packet is sent and not the other.
+ *
+ * @param packetToAssemble The packet to write the data into.
+ * @param targetDeviceGroup The group of the target device.
+ * @param targetDeviceSerial Ther serial code of the target device.
+ * @param adcHi The raw ADC value of the pot at the max.
+ * @param mdegHi The joint pos in millideg at the max.
+ *
+ * @see https://github.com/huskyroboticsteam/HindsightCAN/wiki/Motor-Unit-Packets
+ */
+void AssemblePotHiSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint16_t adcHi,
+ int32_t mdegHi);
+
+/**
+ * @brief Assemble a packet to set the low point of the potentiometer.
+ *
+ * This, along with AssemblePotHiSetPacket() are required to initialize the potentiometer.
+ * Behavior is undefined if only one packet is sent and not the other.
+ *
+ * @param packetToAssemble The packet to write the data into.
+ * @param targetDeviceGroup The group of the target device.
+ * @param targetDeviceSerial Ther serial code of the target device.
+ * @param adcHi The raw ADC value of the pot at the low.
+ * @param mdegHi The joint pos in millideg at the low.
+ *
+ * @see https://github.com/huskyroboticsteam/HindsightCAN/wiki/Motor-Unit-Packets
+ */
+void AssemblePotLoSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint16_t adcLo,
+ int32_t mdegLo);
+
+/**
+ * @brief Get the raw ADC value from a pot initialization packet.
+ *
+ * @param packet The packet, produced by either AssemblePotHiSetPacket()
+ * or AssemblePotLoSetPacket(), to read from.
+ * @return uint16_t The raw ADC value.
+ */
+uint16_t GetPotInitADCFromPacket(const CANPacket *packet);
+
+/**
+ * @brief Get the joint position from a pot initialization packet.
+ *
+ * @param packet The packet, produced by either AssemblePotHiSetPacket()
+ * or AssemblePotLoSetPacket(), to read from.
+ * @return int32_t The joint position in millidegrees.
+ */
+int32_t GetPotInitmDegFromPacket(const CANPacket *packet);
+
+//Initialize Encoder Settings
+void AssembleEncoderInitializePacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t encoderType,
+ uint8_t angleDirection,
+ uint8_t zeroAngle);
+uint8_t GetEncoderTypeFromPacket(CANPacket *packet);
+uint8_t GetEncoderDirectionFromPacket(CANPacket *packet);
+uint8_t GetEncoderZeroFromPacket(CANPacket *packet);
+
+void AssembleMaxPIDPWMPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint16_t PWMSetMax);
+uint16_t GetMaxPIDPWMFromPacket(CANPacket *packet);
+
+/**
+ * @brief Assemble a packet to initialize the PCA servo
+ *
+ * @param packetToAssemble The packet to write the data into.
+ * @param targetDeviceGroup The group of the target device.
+ * @param targetDeviceSerial The serial code of the target device.
+ * @param serverNum The servo number
+ * @param angle The angle degree in millidegrees
+ *
+ * @see https://github.com/huskyroboticsteam/HindsightCAN/wiki/Motor-Unit-Packets
+ */
+void AssemblePCAServoPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t serverNum,
+ int32_t angle);
+
+/**
+ * @brief Get the PCA servo angle value from its packet
+ *
+ * @param packet The packet, produced by AssemblePCAServoPacket, to read from.
+ * @return int32_t The angle in millidegrees.
+ */
+int32_t GetAngleValueFromPacket(const CANPacket *packet);
+
+/**
+ * @brief Get the PCA servo number from its packet
+ *
+ * @param packet The packet, produced by AssemblePCAServoPacket, to read from.
+ * @return uint8_t the servo num.
+ */
+uint8_t GetServoNumFromPacket(const CANPacket *packet);
+
+/**
+ * @brief Assemble a packet to set the encoder bounds on limit switch interrupt
+ *
+ * @param packetToAssemble The packet to write the data into.
+ * @param targetDeviceGroup The group of the target device.
+ * @param targetDeviceSerial The serial code of the target device.
+ * @param limSwNum The limit switch that the encoder bound should be associated
+ * with.
+ * @param encoderBound The count the encoder should be set to when the given
+ * limit switch is hit.
+ *
+ * @see https://github.com/huskyroboticsteam/HindsightCAN/wiki/Motor-Unit-Packets
+ */
+void AssembleLimSwEncoderBoundPacket(CANPacket* packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t limSwNum,
+ int32_t encoderBound);
+
+/*
+ * @brief Get encoder bound value from the limit switch encoder bound packet
+ *
+ * @param packet The packet, produced by AssembleLimSwEncoderBoundPacket, to
+ * read from.
+ *
+ * @return int32_t The encoder bound limit.
+ */
+int32_t GetEncoderValueFromPacket(const CANPacket* packet);
+
+/*
+ * @brief Get limit switch number associated with encoder bound.
+ *
+ * @param packet The packet, produced by AssembleLimSwEncoderBoundPacket, to
+ * read from.
+ *
+ * @return uint8_t The limit switch associated with the encoder bound.
+ */
+uint8_t GetLimSwNumFromPacket(const CANPacket* packet);
+
+/**
+ * @brief Get the ID of the peripheral to control.
+ *
+ * @param packet The packet sent to read from.
+ * @return uint8_t The peripheral ID.
+*/
+uint8_t GetPeripheralID(const CANPacket* packet);
+
+/**
+ * @brief Get the data to set the peripheral.
+ *
+ * @param packet The packet sent to read from.
+ * @return uint8_t The data to set the peripheral to.
+*/
+uint16_t GetPeripheralData(const CANPacket* packet);
+
+// Motor Unit Packet IDs
+#define ID_MOTOR_UNIT_MODE_SEL (uint8_t) 0x00
+#define ID_MOTOR_UNIT_PWM_DIR_SET (uint8_t) 0x03
+#define ID_MOTOR_UNIT_PID_POS_TGT_SET (uint8_t) 0x04
+#define ID_MOTOR_UNIT_PID_P_SET (uint8_t) 0x05
+#define ID_MOTOR_UNIT_PID_I_SET (uint8_t) 0x06
+#define ID_MOTOR_UNIT_PID_D_SET (uint8_t) 0x07
+#define ID_MOTOR_UNIT_INIT (uint8_t) 0x08
+#define ID_MOTOR_UNIT_LIM_ALERT (uint8_t) 0x09
+#define ID_MOTOR_UNIT_ENC_PPJR_SET (uint8_t) 0x0A
+#define ID_MOTOR_UNIT_MAX_JNT_REV_SET (uint8_t) 0x0B
+#define ID_MOTOR_UNIT_ENC_INIT (uint8_t) 0x0C
+#define ID_MOTOR_UNIT_MAX_PID_PWM (uint8_t) 0x0D
+#define ID_MOTOR_UNIT_PCA_PWM (uint8_t) 0x0E
+#define ID_MOTOR_UNIT_POT_INIT_LO (uint8_t) 0x0F
+#define ID_MOTOR_UNIT_POT_INIT_HI (uint8_t) 0x10
+#define ID_MOTOR_UNIT_PCA_SERVO (uint8_t) 0x11
+#define ID_MOTOR_UNIT_SET_ENCODER_BOUND (uint8_t) 0x12
+#define ID_MOTOR_UNIT_SET_PERIPHERALS (uint8_t) 0x13
+
+// Packet DLCs
+#define DLC_MOTOR_UNIT_MODE_SEL (uint8_t) 0x02
+#define DLC_MOTOR_UNIT_PWM_DIR_SET (uint8_t) 0x03
+#define DLC_MOTOR_UNIT_PID_POS_TGT_SET (uint8_t) 0x05
+#define DLC_MOTOR_UNIT_PID_P_SET (uint8_t) 0x05
+#define DLC_MOTOR_UNIT_PID_I_SET (uint8_t) 0x05
+#define DLC_MOTOR_UNIT_PID_D_SET (uint8_t) 0x05
+#define DLC_MOTOR_UNIT_INIT (uint8_t) 0x02
+#define DLC_MOTOR_UNIT_LIM_ALERT (uint8_t) 0x04
+#define DLC_MOTOR_UNIT_ENC_PPJR_SET (uint8_t) 0x05
+#define DLC_MOTOR_UNIT_MAX_JNT_REV_SET (uint8_t) 0x02
+#define DLC_MOTOR_UNIT_ENC_INIT (uint8_t) 0x02
+#define DLC_MOTOR_UNIT_MAX_PID_PWM (uint8_t) 0x03
+#define DLC_MOTOR_UNIT_POT_INIT (uint8_t) 0x07
+#define DLC_MOTOR_UNIT_PCA_SERVO (uint8_t) 0x06
+#define DLC_MOTOR_UNIT_ENCODER_BOUND (uint8_t) 0x06
+#define DLC_MOTOR_UNIT_PERIPHERALS (uint8_t) 0x2
+
+//Packet priorities
+#define PRIO_MOTOR_UNIT_MODE_SEL PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_PWM_DIR_SET PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_PID_POS_TGT_SET PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_PID_P_SET PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_PID_I_SET PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_PID_D_SET PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_INIT PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_LIM_ALERT PACKET_PRIORITY_HIGH
+#define PRIO_MOTOR_UNIT_ENC_PPJR_SET PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_MAX_JNT_REV_SET PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_ENC_INIT PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_MAX_PID_PWM PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_POT_INIT PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_PCA_SERVO PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_SET_ENCODER_BOUND PACKET_PRIORITY_NORMAL
+#define PRIO_MOTOR_UNIT_SET_PERIPHERALS PACKET_PRIORITY_NORMAL
+
+// Motor Unit Mode IDs
+#define MOTOR_UNIT_MODE_PWM (uint8_t) 0x00
+#define MOTOR_UNIT_MODE_PID (uint8_t) 0x01
+
+// Motor Unit Peripheral IDs
+#define NULL_PERIPH_ID (uint8_t) 0x00
+#define LASER_PERIPH_ID (uint8_t) 0x01
+#define LINEAR_PERIPH_ID (uint8_t) 0x02
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPacket.c b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPacket.c
new file mode 100644
index 0000000..c613974
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPacket.c
@@ -0,0 +1,228 @@
+/* File: CANPacket.c
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction definitions for CAN Packet manipulation
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+#include "CANPacket.h"
+#include "Port.h"
+
+// Constructs a CAN ID according to standards set by electronics subsystem
+// for hindsight (PY2020 rover). Not compatible with Orpheus (PY2019)
+// Inputs:
+// priority: A byte determing if the packet should be prioritized
+// High priority would mean setting this value to 0
+// Low priority would mean setting this value to 1
+// devGroup: ID of device group
+// devSerial: Serial value of device in the device group
+// Output:
+// CANID: CAN ID with correct formatting
+uint16_t ConstructCANID(uint8_t priority, uint8_t devGroup, uint8_t devSerial)
+{
+ uint16_t CANID = 0x0000;
+ CANID = CANID | ((priority & 0x01) << 10);
+ CANID = CANID | ((devGroup & 0x0F) << 6);
+ CANID = CANID | (devSerial & 0x3F);
+
+ return CANID;
+}
+
+// Creates a CANPacket that can be used by fuctions in this file
+// Inputs:
+// id: CAN ID for the packet
+// dlc: Data length for the packet. It's the number of bytes used
+// in data payload for packet
+// data: An array of bytes used for sending data over CAN
+// Outputs:
+// CANPacket: A struct used for storing the parts needed for a CAN Packet
+CANPacket ConstructCANPacket(uint16_t id, uint8_t dlc, uint8_t* data)
+{
+ CANPacket cp;
+ cp.id = id;
+ cp.dlc = dlc;
+ for(int i = 0; i < dlc; i++)
+ {
+ cp.data[i] = data[i];
+ }
+
+ return cp;
+}
+
+// Writes sender group, serial number, and packet ID to data bytes. Writes to bytes 0 and 1 in data.
+// DO NOT OVERWRITE BYTES 0 AND 1 AFTER CALLING THIS FUNCTION.
+// Inputs:
+// data: Data to write to.
+//TODO, upon approval from @jaden, delete senderGroup and senderSerial params, as these are handled by getLocal functs
+// senderGroup: Device group the sender device is a part of.
+// senderSerial: Device serial number for sender.
+// packetID: ID for packet to be sent.
+// Output:
+// Index of next byte in `data` that can be written
+int WriteSenderSerialAndPacketID(uint8_t *data, uint8_t packetID)
+{
+ data[0] = packetID;
+ data[1] = getLocalDeviceGroup();
+ data[2] = getLocalDeviceSerial();
+ return 3;
+}
+
+// Writes packet ID to data bytes. Writes to byte 0 data.
+// DO NOT OVERWRITE BYTE 0 AFTER CALLING THIS FUNCTION.
+// Inputs:
+// data: Data to write to.
+// packetID: ID for packet to be sent.
+// Outputs:
+// Index to next byte in `data` that can be written;
+int WritePacketIDOnly(uint8_t *data, uint8_t packetID)
+{
+ data[0] = packetID;
+ return 1;
+}
+
+// Gets the priority of a given packet
+// Inputs:
+// packet: CAN Packet to analyze
+// Outputs:
+// priority byte representing packet priority,
+// (0 for high, 1 for low)
+uint8_t GetPacketPriority(CANPacket *packet)
+{
+ return (packet->id >> 10) & 0x1;
+}
+
+// Gets the device serial number from CAN packet
+// Inputs:
+// packet: CAN Packet to analyze
+// Outputs:
+// A byte representing the device
+// serial number.
+uint8_t GetDeviceSerialNumber(CANPacket *packet)
+{
+ uint8_t id = (packet->id & 0x00FF);
+ // Strip fo only serial number portion of id
+ return id & 0x3F;
+}
+
+// Returns Sender device serial number as
+// packet: CAN packet from which to resolve serial number
+// Outputs:
+// A byte representing the sender device number
+uint8_t GetSenderDeviceSerialNumber(CANPacket *packet)
+{
+ return packet->data[2];
+}
+
+// Gets the device group code from CAN packet
+// Inputs:
+// packet: CAN Packet to analyze
+// Outputs:
+// A byte representing the device
+// group code.
+uint8_t GetDeviceGroupCode(CANPacket *packet)
+{
+ uint8_t group = 0;
+ int id = packet->id;
+ group = (uint8_t) ((id & 0x03C0) >> 6);
+ return group;
+}
+
+// Gets the sender device group number from the payload data
+// Inputs:
+// data: Address of the byte array of the payload from CAN packet
+// Outputs:
+// A byte representing the sender device number
+uint8_t GetSenderDeviceGroupCode(CANPacket *packet)
+{
+ return packet->data[1];
+}
+
+// Ensures that the given packet is of a specified group
+// Inputs:
+// packet: CAN Packet to check
+// expectedType: ExpectedType of CAN packet
+// Outputs:
+// 0 if packet not of expectedType,
+// Other int otherwise
+int PacketIsInGroup(CANPacket *packet, uint8_t expectedType)
+{
+ return GetDeviceGroupCode(packet) == expectedType;
+}
+
+int SenderPacketIsInGroup(CANPacket *packet, uint8_t expectedType)
+{
+ return GetSenderDeviceGroupCode(packet) == expectedType;
+}
+
+int SenderPacketIsOfDevice(CANPacket *packet, uint8_t expectedType)
+{
+ return GetSenderDeviceSerialNumber(packet) == expectedType;
+}
+
+int GetPacketID(CANPacket *packet)
+{
+ return packet->data[0];
+}
+
+int PacketIsOfID(CANPacket *packet, uint8_t expectedID)
+{
+ return GetPacketID(packet) == expectedID;
+}
+
+// Determines if a given packet targets a specific device
+// Useful for determing if a packet should be interpreted by
+// the device
+// Inputs:
+// packet: CAN Packet to check
+// targetDeviceGroup: Device group of target device
+// targetDeviceSerialNumber: Serial number of target device
+// Outputs:
+// Returns 0 if packet does not target device
+// Returns any other int if packet does
+int TargetsDevice(CANPacket *packet, uint8_t targetDeviceGroup, uint8_t targetDeviceSerialNumber)
+{
+ uint8_t packetGroup = GetDeviceGroupCode(packet);
+ if (packetGroup == targetDeviceGroup)
+ {
+ uint8_t serialNumber = GetDeviceSerialNumber(packet);
+ // Return if serial number matches target
+ // Otherwise only return true if packet is broadcast to group
+ return serialNumber == DEVICE_SERIAL_BROADCAST || serialNumber == targetDeviceSerialNumber;
+ }
+ // Otherwise only return true if packet is broadcast to all devices
+ return packetGroup == DEVICE_GROUP_BROADCAST;
+}
+
+void PackIntIntoDataMSBFirst(uint8_t *data, int32_t dataToPack, int startIndex)
+{
+ data[startIndex] = (dataToPack & 0xFF000000) >> 24;
+ data[startIndex + 1] = (dataToPack & 0x00FF0000) >> 16;
+ data[startIndex + 2] = (dataToPack & 0x0000FF00) >> 8;
+ data[startIndex + 3] = (dataToPack & 0x000000FF);
+}
+
+void PackShortIntoDataMSBFirst(uint8_t *data, int16_t dataToPack, int startIndex)
+{
+ data[startIndex + 0] = (dataToPack & 0xFF00) >> 8;
+ data[startIndex + 1] = (dataToPack & 0x00FF);
+}
+
+int32_t DecodeBytesToIntMSBFirst(const uint8_t *data, int startIndex, int endIndex)
+{
+ int length = 4;
+ int32_t decodedData = 0;
+
+ if (endIndex > 0 && startIndex >= 0) {
+ length = endIndex - startIndex + 1;
+ if (length > 4) { length = 4; }
+ if (length < 1) { length = 0; }
+ }
+
+ for (int i = 0; i < length; i++)
+ {
+ decodedData |= (int32_t)data[startIndex + i] << (int32_t)(8 * (length-1-i));
+ }
+ return decodedData;
+}
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPacket.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPacket.h
new file mode 100644
index 0000000..6989ccb
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPacket.h
@@ -0,0 +1,95 @@
+/* File: CANPacket.h
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction prototypes for CAN Packet manipulation
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+#pragma once
+
+#include
+#include "CANSerialNumbers.h"
+
+typedef struct
+{
+ uint16_t id;
+ uint8_t dlc;
+ uint8_t data[8];
+} CANPacket;
+
+CANPacket ConstructCANPacket(uint16_t id, uint8_t dlc, uint8_t* data);
+uint16_t ConstructCANID(uint8_t priority, uint8_t devGroup, uint8_t devSerial);
+
+//Private library functions
+int WriteSenderSerialAndPacketID(uint8_t *data, uint8_t packetID);
+int WritePacketIDOnly(uint8_t *data, uint8_t packetID);
+
+uint8_t GetPacketPriority(CANPacket *packet);
+
+uint8_t GetDeviceGroupCode(CANPacket *packet);
+uint8_t GetDeviceSerialNumber(CANPacket *packet);
+uint8_t GetSenderDeviceSerialNumber(CANPacket *packet);
+uint8_t GetSenderDeviceGroupCode(CANPacket *packet);
+
+int PacketIsInGroup(CANPacket *packet, uint8_t expectedType);
+int SenderPacketIsInGroup(CANPacket *packet, uint8_t expectedType);
+int SenderPacketIsOfDevice(CANPacket *packet, uint8_t expectedType);
+int TargetsDevice(CANPacket *packet, uint8_t targetDeviceGroup, uint8_t targetDeviceSerialNumber);
+
+int GetPacketID(CANPacket *packet);
+int PacketIsOfID(CANPacket *packet, uint8_t expectedID);
+
+void PackIntIntoDataMSBFirst(uint8_t *data, int32_t dataToPack, int startIndex);
+void PackShortIntoDataMSBFirst(uint8_t *data, int16_t dataToPack, int startIndex);
+/**
+ * @brief Read at most 4 bytes into a signed int.
+ *
+ * @param data The array of bytes to read from, storing the bytes in big-endian order.
+ * @param startIndex The index of the MSB.
+ * @param endIndex The index after the LSB.
+ * @return int32_t The decoded integer.
+ *
+ * @warning Be careful using this for unsigned data, as it could overflow.
+ */
+int32_t DecodeBytesToIntMSBFirst(const uint8_t *data, int startIndex, int endIndex);
+
+// Device group nibbles
+#define DEVICE_GROUP_BROADCAST (uint8_t) 0x00
+#define DEVICE_GROUP_RESERVED (uint8_t) 0x01 // DO NOT USE. For future expansion
+#define DEVICE_GROUP_JETSON (uint8_t) 0x02
+#define DEVICE_GROUP_MASTER DEVICE_GROUP_JETSON
+#define DEVICE_GROUP_POWER (uint8_t) 0x03
+#define DEVICE_GROUP_MOTOR_CONTROL (uint8_t) 0x04
+#define DEVICE_GROUP_TELEMETRY (uint8_t) 0x05
+#define DEVICE_GROUP_GPIO_BOARDS (uint8_t) 0x06
+#define DEVICE_GROUP_SCIENCE (uint8_t) 0x07
+
+// Priority bits
+#define PACKET_PRIORITY_HIGH (uint8_t) 0x00
+#define PACKET_PRIORITY_NORMAL (uint8_t) 0x01
+#define PACKET_GROUP_NO_SENDER_SERIAL (uint8_t) 0x0C
+
+// GPIO Board Packet IDs
+#define ID_GPIO_BOARD_PWM_SET_STATE (uint8_t) 0x00
+#define ID_GPIO_BOARD_PWM_SET (uint8_t) 0x01
+#define ID_GPIO_BOARD_ADC_EN_SET (uint8_t) 0x02
+#define ID_GPIO_BOARD_ADC_READ (uint8_t) 0x03
+#define ID_GPIO_BOARD_ADC_READ_RESPONSE (uint8_t) 0x04
+#define ID_GPIO_BOARD_IO_SET_STATE (uint8_t) 0x05
+#define ID_GPIO_BOARD_IO_READ (uint8_t) 0x06
+#define ID_GPIO_BOARD_IO_READ_RESPONSE (uint8_t) 0x07
+#define ID_GPIO_BOARD_IO_WRITE (uint8_t) 0x08
+
+// Power Distribution Packet IDs
+/*No longer needed, some of this was put into telemetry, other was put into CANPower.h
+
+#define ID_POWER_DIST_RAIL_SET_STATE (uint8_t) 0x00
+#define ID_POWER_DIST_RAIL_REQ_STATE (uint8_t) 0x01
+#define ID_POWER_DIST_RAIL_RESPONSE (uint8_t) 0x02
+#define ID_POWER_DIST_OVC_LIM_SET (uint8_t) 0x03
+*/
+
+// Telemetry Packet IDs
+#define ID_TELEMETRY_SET_MAG_OFFSET (uint8_t) 0x00
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPower.c b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPower.c
new file mode 100644
index 0000000..9c6d680
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPower.c
@@ -0,0 +1,50 @@
+/* File: CANPower.c
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction implementations for the power boards CAN Communication
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+#include "CANPower.h"
+#include "CANPacket.h"
+
+//Power Rail Set State
+void AssemblePowerRailsSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerialNumber,
+ uint8_t state)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerialNumber);
+ packetToAssemble->dlc = DLC_POWER_RAIL_SET;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_POWER_RAIL_SET);
+ packetToAssemble->data[nextByte] = state;
+
+}
+uint8_t GetPowerRailsStateFromPacket(CANPacket *packet)
+{
+ return packet->data[2];
+}
+
+
+//Power Set Over Current Limit
+void AssembleOverCurrentPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerialNumber,
+ uint8_t railNumber,
+ uint32_t currentLim)
+{
+ packetToAssemble->id = ConstructCANID(PRIO_POWER_CURRENT_LIM_SET, targetDeviceGroup, targetDeviceSerialNumber);
+ packetToAssemble->dlc = DLC_POWER_CURRENT_LIM_SET;
+ int nextByte = WriteSenderSerialAndPacketID(packetToAssemble->data, ID_POWER_CURRENT_LIM_SET);
+ packetToAssemble->data[nextByte] = railNumber;
+ PackIntIntoDataMSBFirst(packetToAssemble->data, currentLim, nextByte + 1);
+}
+uint8_t GetOverCurrentRailNumFromPacket(CANPacket *packetToAssemble)
+{
+ return packetToAssemble->data[2];
+}
+uint8_t GetOverCurrentLimitFromPacket(CANPacket *packetToAssemble)
+{
+ return DecodeBytesToIntMSBFirst(packetToAssemble->data, 3, 6);
+}
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPower.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPower.h
new file mode 100644
index 0000000..edebc68
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANPower.h
@@ -0,0 +1,42 @@
+/* File: CANPower.h
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin.
+ * Organization: Husky Robotics Team
+ *
+ * This file includes fuction prototypes for the power boards CAN Communication
+ * using the Hindsight CAN Communication standard.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+#pragma once
+
+#include "CANPacket.h"
+
+
+void AssemblePowerRailsSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerialNumber,
+ uint8_t state);
+uint8_t GetPowerRailsStateFromPacket(CANPacket *packet);
+
+
+void AssembleOverCurrentPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerialNumber,
+ uint8_t railNumber,
+ uint32_t currentLim);
+uint8_t GetOverCurrentRailNumFromPacket(CANPacket *packetToAssemble);
+uint8_t GetOverCurrentLimitFromPacket(CANPacket *packetToAssemble);
+
+
+//TODO: Should we include all of this stuff in CANPacket.h?
+// Motor Unit Packet IDs
+#define ID_POWER_RAIL_SET (uint8_t) 0x00
+#define ID_POWER_CURRENT_LIM_SET (uint8_t) 0x01
+
+// Packet DLCs
+#define DLC_POWER_RAIL_SET (uint8_t) 0x02
+#define DLC_POWER_CURRENT_LIM_SET (uint8_t) 0x05
+
+//Packet priorities
+#define PRIO_POWER_RAIL_SET PACKET_PRIORITY_HIGH
+#define PRIO_POWER_CURRENT_LIM_SET PACKET_PRIORITY_NORMAL
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANScience.c b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANScience.c
new file mode 100644
index 0000000..c8dd185
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANScience.c
@@ -0,0 +1,59 @@
+#include "CANPacket.h"
+#include "CANCommon.h"
+#include "CANScience.h"
+#include "CANMotorUnit.h"
+
+void AssembleScienceLazySusanPosSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t position)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = 2;
+ WritePacketIDOnly(packetToAssemble->data, ID_SCIENCE_LAZY_SUSAN_POS_SET);
+ packetToAssemble->data[1] = position;
+}
+
+void AssembleScienceServoPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup,
+ uint8_t targetSerial,
+ uint8_t servo,
+ uint8_t degrees)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetGroup, targetSerial);
+ packetToAssemble->dlc = 3;
+ WritePacketIDOnly(packetToAssemble->data, ID_SCIENCE_SERVO_SET);
+ packetToAssemble->data[1] = servo;
+ packetToAssemble->data[2] = degrees;
+}
+
+void AssembleScienceContServoPowerSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t servo,
+ int8_t power)
+{
+ packetToAssemble->id = ConstructCANID(PACKET_PRIORITY_NORMAL, targetDeviceGroup, targetDeviceSerial);
+ packetToAssemble->dlc = 3;
+ WritePacketIDOnly(packetToAssemble->data, ID_SCIENCE_CONT_SERVO_POWER_SET);
+ packetToAssemble->data[1] = servo;
+ packetToAssemble->data[2] = power;
+}
+
+int8_t GetScienceContServoPowerFromPacket(const CANPacket *packet) {
+ return packet->data[2];
+}
+
+uint8_t GetScienceServoAngleFromPacket(const CANPacket *packet){
+ return packet->data[2];
+}
+
+uint8_t GetScienceLazySusanPosFromPacket(const CANPacket *packet) {
+ return packet->data[1];
+}
+
+uint8_t GetScienceServoIDFromPacket(const CANPacket *packet){
+ return packet->data[1];
+}
+
+
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANScience.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANScience.h
new file mode 100644
index 0000000..6ce3134
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANScience.h
@@ -0,0 +1,136 @@
+#ifndef CAN_SCIENCE_H
+#define CAN_SCIENCE_H
+
+/**
+ Telemetry ID for the temperature sensor on the science station.
+ */
+#define CAN_SCIENCE_SENSOR_TEMPERATURE PACKET_TELEMETRY_SENSOR1
+/**
+ Telemetry ID for the UV sensor on the science station.
+ */
+#define CAN_SCIENCE_SENSOR_UV PACKET_TELEMETRY_SENSOR2
+/**
+ Telemetry ID for the moisture sensor on the science station.
+ */
+#define CAN_SCIENCE_SENSOR_MOISTURE PACKET_TELEMETRY_SENSOR3
+
+/**
+ Packet ID for the Lazy Susan position set packet.
+ */
+#define ID_SCIENCE_LAZY_SUSAN_POS_SET ((uint8_t)0x0C)
+/**
+ Packet ID for the positional servo set packet.
+ */
+#define ID_SCIENCE_SERVO_SET ((uint8_t) 0x0D)
+/**
+ Packet ID for the continuous rotation servo power set packet.
+ */
+#define ID_SCIENCE_CONT_SERVO_POWER_SET ((uint8_t) 0x0E)
+
+#include "CANPacket.h"
+
+/**
+ * @brief Assemble a packet to set the position of a servo for the science station.
+ *
+ * @warning This packet is intended only for positional servos; the behavior is undefined if a
+ * continuous rotation servo is used.
+ *
+ * @param packetToAssemble The packet to write the data into.
+ * @param targetDeviceGroup The group of the target device.
+ * @param targetDeviceSerial Ther serial code of the target device.
+ * @param servo The ID of the servo.
+ * @param degrees The position of the servo in degrees, from 0-179.
+ *
+ * @see https://github.com/huskyroboticsteam/HindsightCAN/wiki/Science-(Sensor)-Board-Packets
+ */
+void AssembleScienceServoPacket(CANPacket *packetToAssemble,
+ uint8_t targetGroup, uint8_t targetSerial,
+ uint8_t servo, uint8_t degrees);
+
+/**
+ * @brief Assemble a packet to set the position of the Lazy Susan on the science
+ * station.
+ *
+ * Sets the position of the first cup (whichever cup is closest to the funnel on
+ * startup) to one of twelve positions around the circle, where 0 is the funnel. Even
+ * positions are under holes in the divider and odd positions are in between holes.
+ *
+ * @param packetToAssemble The packet to write the data into.
+ * @param targetDeviceGroup The group of the target device.
+ * @param targetDeviceSerial Ther serial code of the target device.
+ * @param position The position, from 0-11.
+ *
+ * @warning Behavior is undefined if a position above 11 is given.
+ *
+ * @see https://github.com/huskyroboticsteam/HindsightCAN/wiki/Science-(Sensor)-Board-Packets
+ */
+void AssembleScienceLazySusanPosSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t position);
+
+/**
+ * @brief Assemble a packet to set the power of a continuous rotation servo on
+ * the science station.
+ *
+ * @warning This packet is intended only for continuous rotation servos; the
+ * behavior is undefined if a positional servo is used.
+ *
+ * @param packetToAssemble The packet to write the data into.
+ * @param targetDeviceGroup The group of the target device.
+ * @param targetDeviceSerial Ther serial code of the target device.
+ * @param servo The ID of the servo.
+ * @param power The power of the servo, from -100 to 100.
+ *
+ * @warning Behavior is undefined if the power is outside of the [-100, 100]
+ * range.
+ *
+ * @see https://github.com/huskyroboticsteam/HindsightCAN/wiki/Science-(Sensor)-Board-Packets
+ */
+void AssembleScienceContServoPowerSetPacket(CANPacket *packetToAssemble,
+ uint8_t targetDeviceGroup,
+ uint8_t targetDeviceSerial,
+ uint8_t servo,
+ int8_t power);
+
+/**
+ * @brief Gets the servo ID from a science station servo packet.
+ * @param A CANPacket, that is one of the two science station servo-related packets.
+ * @return The servo ID for the packet.
+ *
+ * @warning This function is intended to be used only on servo-related packets; return value
+ * is undefined if packet is not a servo packet.
+ */
+uint8_t GetScienceServoIDFromPacket(const CANPacket *packet);
+
+/**
+ * @brief Gets the servo angle from a science station servo set packet.
+ * @param A science station servo set packet, as a CANPacket
+ * @return The servo angle in this packet.
+ *
+ * @warning This function is intended to be used only on positional servo set packets; return
+ * value is undefined otherwise.
+ */
+uint8_t GetScienceServoAngleFromPacket(const CANPacket *packet);
+
+/**
+ * @brief Gets the Lazy Susan position from a science station Lazy Susan position set packet.
+ * @param A science station Lazy Susan position set packet, as a CANPacket
+ * @return The Lazy Susan position in this packet.
+ *
+ * @warning This function is intended to be used only on Lazy Susan packets; return value
+ * is undefined otherwise.
+ */
+uint8_t GetScienceLazySusanPosFromPacket(const CANPacket *packet);
+
+/**
+ * @brief Gets the servo power from a science station continuous rotation servo set packet.
+ * @param A science station continuous rotation servo set packet, as a CANPacket
+ * @return The servo power in this packet.
+ *
+ * @warning This function is intended to be used only on continuous rotation servo set
+ * packets; return value is undefined otherwise.
+ */
+int8_t GetScienceContServoPowerFromPacket(const CANPacket *packet);
+
+#endif
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANSerialNumbers.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANSerialNumbers.h
new file mode 100644
index 0000000..d27a945
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/CANSerialNumbers.h
@@ -0,0 +1,72 @@
+/* File: CANSerialNumbers.h
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin
+ * Organization: Husky Robotics Team
+ *
+ * This file defines the serial numbers for each device
+ * on the Hindsight (PY2020 Rover). Sorted by Device Group
+ *
+ * Serial Numbers are 6bits wide.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+
+// BROADCAST GROUP
+// Use this serial number and the BROADCAST device group to
+// broadcast a packet to all devices.
+// Use this serial number and a specific device group to
+// broadcast a packet to all devices within a group.
+#pragma once
+
+#define DEVICE_SERIAL_BROADCAST (uint8_t) 0x00
+
+// JETSON GROUP
+#define DEVICE_SERIAL_JETSON (uint8_t) 0x01
+
+// MOTOR UNIT GROUP
+#define DEVICE_SERIAL_MOTOR_BASE (uint8_t) 0x01
+#define DEVICE_SERIAL_MOTOR_SHOULDER (uint8_t) 0x02
+#define DEVICE_SERIAL_MOTOR_ELBOW (uint8_t) 0x03
+#define DEVICE_SERIAL_MOTOR_FOREARM (uint8_t) 0x04
+#define DEVICE_SERIAL_MOTOR_WRIST_DIFF_LEFT (uint8_t) 0x05
+#define DEVICE_SERIAL_MOTOR_WRIST_DIFF_RIGHT (uint8_t) 0x0c
+#define DEVICE_SERIAL_MOTOR_HAND (uint8_t) 0x06
+#define DEVICE_SERIAL_LINEAR_ACTUATOR (uint8_t) 0x07
+
+#define DEVICE_SERIAL_MOTOR_CHASSIS_FL (uint8_t) 0x08 //Front Left
+#define DEVICE_SERIAL_MOTOR_CHASSIS_FR (uint8_t) 0x09
+#define DEVICE_SERIAL_MOTOR_CHASSIS_BL (uint8_t) 0x0a
+#define DEVICE_SERIAL_MOTOR_CHASSIS_BR (uint8_t) 0x0b //Back Right
+
+#define DEVICE_SERIAL_MOTOR_CHASSIS_FL_SW (uint8_t) 0x18 //Front Left
+#define DEVICE_SERIAL_MOTOR_CHASSIS_FR_SW (uint8_t) 0x19
+#define DEVICE_SERIAL_MOTOR_CHASSIS_BL_SW (uint8_t) 0x1a
+#define DEVICE_SERIAL_MOTOR_CHASSIS_BR_SW (uint8_t) 0x1b //Back Right
+
+//Power group
+#define DEVICE_SERIAL_POWER_BATT_MAN (uint8_t) 0x01
+#define DEVICE_SERIAL_POWER_CHASSIS_MAIN (uint8_t) 0x02
+#define DEVICE_SERIAL_POWER_CHASSIS_DRIVE_L (uint8_t) 0x03 //Left
+#define DEVICE_SERIAL_POWER_CHASSIS_DRIVE_R (uint8_t) 0x04 //Right
+#define DEVICE_SERIAL_POWER_ARM_LOWER_1 (uint8_t) 0x05 //may have more arm
+#define DEVICE_SERIAL_POWER_ARM_UPPER_1 (uint8_t) 0x06
+#define DEVICE_SERIAL_POWER_SCIENCE (uint8_t) 0x07
+
+//Telemetry group
+#define DEVICE_SERIAL_TELEM_LOCALIZATION (uint8_t) 0x01
+#define DEVICE_SERIAL_TELEM_IMU (uint8_t) 0x02
+#define DEVICE_SERIAL_TELEM_TEMPERATURE (uint8_t)0x03
+
+// Science group
+#define DEVICE_SERIAL_SCIENCE_STATION ((uint8_t) 0x01)
+#define DEVICE_SERIAL_DRILL_ARM_MOTOR (uint8_t) 0x02
+#define DEVICE_SERIAL_DRILL_MOTOR (uint8_t) 0x03
+
+//Group numbers
+/*
+#define DEVICE_GROUP_BROADCAST 0x0
+#define DEVICE_GROUP_RESERVED 0x1
+#define DEVICE_GROUP_MASTER 0x2
+#define DEVICE_GROUP_POWER 0x3
+#define DEVICE_GROUP_MOTORS 0x4
+#define DEVICE_GROUP_TELEM 0x5
+#define DEVICE_GROUP_GPIO 0x6
+*/
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/Port.h b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/Port.h
new file mode 100644
index 0000000..59eb6fd
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/HindsightCAN/Port.h
@@ -0,0 +1,52 @@
+/* File: Port.h
+ * Authors: Jaden Bottemiller, Benton Kwong, Dylan Tomberlin
+ * Organization: Husky Robotics Team
+ *
+ * This file includes function prototypes for all functions which must be
+ * implemented for each ported device. Just make a .c file called
+ * Port[DeviceName].c based on PortTemplate.
+ *
+ * Compile insturctions: in addition to cross compiling, you will need to
+ * define the constant CHIP_TYPE in your compiler options. On GCC, use
+ * -D CHIP_TYPE=CHIP_TYPE_TEMPLATE
+ * But obviously substitute template for your own constant. Add it to the list
+ * of constants below if its not already been defined.
+ * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2
+ */
+#pragma once
+
+#include "CANPacket.h"
+
+void InitCAN(int deviceGroup, int deviceAddress);
+
+//TODO: define constants for these error codes
+//Returns 0x0 for successful send
+//returns 0x1 for generic error
+//returns 0x2 all output buffers are full
+//Reserve higher numbers for future error codes
+int SendCANPacket(CANPacket *packetToSend);
+
+//Returns 0x0 for SUCCESSFUL packet return
+//Returns 0x1 for no message received
+//Returns 0x2 for generic error
+//Reserve higher numbers for future error codes
+int PollAndReceiveCANPacket(CANPacket *receivedPacket);
+
+uint8_t getLocalDeviceSerial();
+uint8_t getLocalDeviceGroup();
+
+//Returns constant
+uint8_t getChipType();
+
+//Chip type constants
+//TODO: Find specific chip names
+#define CHIP_TYPE_TEMPLATE 0x00
+#define CHIP_TYPE_STM32Fxxx 0x01
+#define CHIP_TYPE_PSOC_CY8C4248AZI_L485 0x02
+#define CHIP_TYPE_AT90CANxxx 0x03
+#define CHIP_TYPE_JETSON 0x04
+
+//Error code constants
+#define ERROR_NONE 0x00
+#define ERROR_GENERIC_ERROR 0x01
+#define ERROR_NULL_POINTER 0x02
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/PortPSOC_CY8C4248AZI_L485.c b/2024-2025/ChassisPowerDistro2025.cydsn/PortPSOC_CY8C4248AZI_L485.c
new file mode 100644
index 0000000..67e5aea
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/PortPSOC_CY8C4248AZI_L485.c
@@ -0,0 +1,200 @@
+/*
+ * Authors: Austin Chan
+ * Documentation: ClickUp
+ *
+ * Port specific notes:
+ * Design must include a CAN block called CAN (not CAN0 or variation)
+ * Must auto generate code within PSoC IDE to use APIs
+ */
+
+#include "HindsightCAN\Port.h"
+#include "project.h"
+
+//Flag internal to this port, 0xFF if no message waiting, doubles as mailbox number
+volatile uint8_t messagePresentFlag = 0xFF;
+volatile uint8_t messageReadFlag = 0x0;
+uint8_t FIFOSize(void);
+void countAddFIFO(void);
+void countRemoveFIFO(void);
+
+#define FIFO_SIZE 16
+volatile CANPacket latestMessage[FIFO_SIZE];//internal to this port acts like a FIFO with 10 packet storage
+volatile uint8_t latestMessageHead = 0; //which index to read
+volatile uint8_t latestMessageTail = 0; //which index to write to next
+volatile uint8_t latestMessageFull = 0; //FIFO is full
+
+#define STATUS_MAILBOX0 0x1
+#define STATUS_MAILBOX1 0x2
+#define STATUS_MAILBOX2 0x4
+#define STATUS_MAILBOX3 0x8
+#define STATUS_MAILBOX4 0x10
+#define STATUS_MAILBOX5 0x20
+
+
+CY_ISR_PROTO(CAN_FLAG_ISR);
+
+int deviceAddress;
+int deviceGroup;
+CAN_RX_CFG rxMailbox;
+void InitCAN(int deviceGroupInput, int deviceAddressInput)
+{
+ CAN_Start();//must name CAN Top Design block as "CAN"
+
+ //TODO: I'm sure there's a better way of doing this part
+ deviceGroup = deviceGroupInput & 0xF; // 4bits of ID
+ deviceAddress = deviceAddressInput & (0x3f);//6bits of ID
+
+ //sets up inidvidual recieve mailbox (3rd priority mailbox)
+ rxMailbox.rxmailbox = 0;
+ rxMailbox.rxacr = ((deviceGroup << 6)|(deviceAddress)) << 21; // first 11 bits are the CAN ID that is not extended
+ rxMailbox.rxamr = 0x801FFFFF; // what bits to ignore
+ rxMailbox.rxcmd = CAN_RX_CMD_REG(CAN_RX_MAILBOX_0);//need to know what this is
+ CAN_RxBufConfig(&rxMailbox);
+
+ //setup broadcast recieve mailbox (1st priority mailbox)
+ rxMailbox.rxmailbox = 1;
+ rxMailbox.rxacr = ((0x0 << 6)|(0x0)) << 21; //0x20F<<21; // first 11 bits are the CAN ID that is not extended
+ rxMailbox.rxamr = 0x801FFFFF; // what bits to ignore
+ rxMailbox.rxcmd = CAN_RX_CMD_REG(CAN_RX_MAILBOX_1);//need to know what this is
+ CAN_RxBufConfig(&rxMailbox);
+
+ //setup group broadcast recieve mailbox (2nd priority mailbox)
+ rxMailbox.rxmailbox = 2;
+ rxMailbox.rxacr = ((deviceGroup << 6)|(0x3F)) << 21; //0x20F<<21; // first 11 bits are the CAN ID that is not extended
+ rxMailbox.rxamr = 0x801FFFFF; // what bits to ignore
+ rxMailbox.rxcmd = CAN_RX_CMD_REG(CAN_RX_MAILBOX_2);//need to know what this is
+ CAN_RxBufConfig(&rxMailbox);
+
+ CAN_GlobalIntEnable();
+ CyIntSetVector(CAN_ISR_NUMBER, CAN_FLAG_ISR);
+ //CY_ISR_PROTO(CAN_FLAG_ISR);
+
+}
+int SendCANPacket(CANPacket *packetToSend)
+{
+ if(!packetToSend) {return ERROR_NULL_POINTER;}
+ CAN_TX_MSG PSoCMessage;//CAN structure
+ CAN_DATA_BYTES_MSG PSoCData;//CAN data
+ PSoCMessage.id = packetToSend->id;
+ PSoCMessage.rtr = 0x0;
+ PSoCMessage.ide = 0x0;//Not extended
+ PSoCMessage.dlc = packetToSend->dlc;
+ PSoCMessage.irq = 0x0;
+ PSoCMessage.msg = &PSoCData;
+
+ memcpy(PSoCData.byte, packetToSend->data, 8);
+
+ if(CAN_SendMsg(&PSoCMessage) == CYRET_SUCCESS) {
+ return ERROR_NONE;
+ } else
+ {
+ return ERROR_GENERIC_ERROR;
+ }
+}
+//
+int PollAndReceiveCANPacket(CANPacket *receivedPacket)
+{
+ if(!receivedPacket) {
+ return ERROR_NULL_POINTER;
+ }
+ volatile uint8_t size = FIFOSize();
+ if(size)
+ {
+ *(receivedPacket) = latestMessage[latestMessageHead];
+ countRemoveFIFO();
+ return ERROR_NONE;
+ }
+ return 0x02; //No message received error
+}
+
+uint8_t getLocalDeviceSerial()
+{
+ return deviceAddress;
+}
+uint8_t getLocalDeviceGroup()
+{
+ return deviceGroup;
+}
+
+uint8_t getChipType()
+{
+ return CHIP_TYPE_PSOC_CY8C4248AZI_L485;
+}
+
+//helper function calculate size of Fifo
+uint8_t FIFOSize(){
+ if(latestMessageFull) {
+ return FIFO_SIZE;
+ }
+ else if(latestMessageHead < latestMessageTail) {
+ return latestMessageTail - latestMessageHead;
+ }
+ else if(latestMessageHead > latestMessageTail) {
+ return (FIFO_SIZE - latestMessageHead) + latestMessageTail;
+ }
+ else { // latestMessageHead == latestMessageTail && !latestMessageFull
+ return 0;
+ }
+}
+
+void countAddFIFO(){
+ latestMessageTail++;
+ if(latestMessageTail >= FIFO_SIZE){
+ latestMessageTail = 0;
+ }
+ if(latestMessageFull) {
+ latestMessageHead++;
+ if(latestMessageHead >= FIFO_SIZE) {
+ latestMessageHead = 0;
+ }
+ }
+ latestMessageFull = (latestMessageHead == latestMessageTail);
+}
+
+void countRemoveFIFO(){
+ if(FIFOSize() > 0) {
+ latestMessageHead++;
+ if(latestMessageHead >= FIFO_SIZE) {
+ latestMessageHead = 0;
+ }
+ }
+}
+
+
+
+CY_ISR(CAN_FLAG_ISR)
+{
+
+ //*(reg32*)0x402F0000 = CAN_RX_MESSAGE_MASK & CAN_SST_FAILURE_MASK & CAN_CRC_ERROR_MASK; //Clear Receive Message flag
+ CAN_INT_SR_REG = CAN_RX_MESSAGE_MASK;
+ uint32_t statusReg = (uint32_t) CAN_BUF_SR_REG; //Hardcoded for speed, translation from reg
+ uint8_t mailbox;
+
+ if(statusReg & 0b1) { // mailbox0 is full (individual)
+ mailbox = CAN_RX_MAILBOX_0;
+ }
+ else if(statusReg & 0b10) { // mailbox1 is full (broadcast)
+ mailbox = CAN_RX_MAILBOX_1;
+ }
+ else if(statusReg & 0b100) { // mailbox2 is full (group broadcast)
+ mailbox = CAN_RX_MAILBOX_2;
+ }
+ else if(statusReg & 0b1000) { // mailbox3 is full currently recieves anything enable in top design
+ mailbox = CAN_RX_MAILBOX_3;
+ }
+
+ latestMessage[latestMessageTail].id = CAN_GET_RX_ID(mailbox);
+ latestMessage[latestMessageTail].dlc = CAN_GET_DLC(mailbox);
+ latestMessage[latestMessageTail].data[0] = CAN_RX_DATA_BYTE1(mailbox);
+ latestMessage[latestMessageTail].data[1] = CAN_RX_DATA_BYTE2(mailbox);
+ latestMessage[latestMessageTail].data[2] = CAN_RX_DATA_BYTE3(mailbox);
+ latestMessage[latestMessageTail].data[3] = CAN_RX_DATA_BYTE4(mailbox);
+ latestMessage[latestMessageTail].data[4] = CAN_RX_DATA_BYTE5(mailbox);
+ latestMessage[latestMessageTail].data[5] = CAN_RX_DATA_BYTE6(mailbox);
+ latestMessage[latestMessageTail].data[6] = CAN_RX_DATA_BYTE7(mailbox);
+ latestMessage[latestMessageTail].data[7] = CAN_RX_DATA_BYTE8(mailbox);
+ countAddFIFO();
+
+ //CAN_ReceiveMsg(messagePresentFlag);
+ CAN_RX_ACK_MESSAGE(mailbox);
+}
\ No newline at end of file
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/TopDesign/TopDesign.cysch b/2024-2025/ChassisPowerDistro2025.cydsn/TopDesign/TopDesign.cysch
new file mode 100644
index 0000000..8c0c74b
Binary files /dev/null and b/2024-2025/ChassisPowerDistro2025.cydsn/TopDesign/TopDesign.cysch differ
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/can.c b/2024-2025/ChassisPowerDistro2025.cydsn/can.c
new file mode 100644
index 0000000..82ace55
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/can.c
@@ -0,0 +1,13 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+
+/* [] END OF FILE */
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/can.h b/2024-2025/ChassisPowerDistro2025.cydsn/can.h
new file mode 100644
index 0000000..0a30f6c
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/can.h
@@ -0,0 +1,19 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+
+/* [] END OF FILE */
+
+#pragma once
+
+#include
+#include "PSoC4/CAN_1/CAN_1.h"
+
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/common.h b/2024-2025/ChassisPowerDistro2025.cydsn/common.h
new file mode 100644
index 0000000..82ace55
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/common.h
@@ -0,0 +1,13 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+
+/* [] END OF FILE */
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/cyapicallbacks.h b/2024-2025/ChassisPowerDistro2025.cydsn/cyapicallbacks.h
new file mode 100644
index 0000000..5151f03
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/cyapicallbacks.h
@@ -0,0 +1,21 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+#ifndef CYAPICALLBACKS_H
+#define CYAPICALLBACKS_H
+
+
+ /*Define your macro callbacks here */
+ /*For more information, refer to the Writing Code topic in the PSoC Creator Help.*/
+
+
+#endif /* CYAPICALLBACKS_H */
+/* [] */
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/fsm.c b/2024-2025/ChassisPowerDistro2025.cydsn/fsm.c
new file mode 100644
index 0000000..82ace55
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/fsm.c
@@ -0,0 +1,13 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+
+/* [] END OF FILE */
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/fsm.h b/2024-2025/ChassisPowerDistro2025.cydsn/fsm.h
new file mode 100644
index 0000000..0332c9c
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/fsm.h
@@ -0,0 +1,26 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+
+#ifndef FSM_H
+#define FSM_H
+
+typedef enum {
+ STATE_INIT,
+ // add other states
+} FSM_State;
+
+// function prototypes
+void FSM_Init(void);
+
+#endif
+
+/* [] END OF FILE */
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/i2c.c b/2024-2025/ChassisPowerDistro2025.cydsn/i2c.c
new file mode 100644
index 0000000..82ace55
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/i2c.c
@@ -0,0 +1,13 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+
+/* [] END OF FILE */
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/main.c b/2024-2025/ChassisPowerDistro2025.cydsn/main.c
new file mode 100644
index 0000000..af79122
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/main.c
@@ -0,0 +1,26 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+#include "project.h"
+
+int main(void)
+{
+ CyGlobalIntEnable; /* Enable global interrupts. */
+
+ /* Place your initialization/startup code here (e.g. MyInst_Start()) */
+
+ for(;;)
+ {
+ /* Place your application code here. */
+ }
+}
+
+/* [] END OF FILE */
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/uart.c b/2024-2025/ChassisPowerDistro2025.cydsn/uart.c
new file mode 100644
index 0000000..82ace55
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/uart.c
@@ -0,0 +1,13 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+
+/* [] END OF FILE */
diff --git a/2024-2025/ChassisPowerDistro2025.cydsn/uart.h b/2024-2025/ChassisPowerDistro2025.cydsn/uart.h
new file mode 100644
index 0000000..82ace55
--- /dev/null
+++ b/2024-2025/ChassisPowerDistro2025.cydsn/uart.h
@@ -0,0 +1,13 @@
+/* ========================================
+ *
+ * Copyright YOUR COMPANY, THE YEAR
+ * All Rights Reserved
+ * UNPUBLISHED, LICENSED SOFTWARE.
+ *
+ * CONFIDENTIAL AND PROPRIETARY INFORMATION
+ * WHICH IS THE PROPERTY OF your company.
+ *
+ * ========================================
+*/
+
+/* [] END OF FILE */