From 5d65a6b6587bc3a5e32ded6057397774f1e6b4f0 Mon Sep 17 00:00:00 2001 From: FLinLan Date: Sat, 19 Apr 2025 14:23:16 -0700 Subject: [PATCH 01/10] added the HindsightCAN lib --- .gitmodules | 3 +++ HindsightCAN | 1 + 2 files changed, 4 insertions(+) create mode 160000 HindsightCAN diff --git a/.gitmodules b/.gitmodules index 25da2f8..6faed38 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "PSoC Project Template.cydsn/HindsightCAN"] path = PSoC Project Template.cydsn/HindsightCAN url = https://github.com/huskyroboticsteam/HindsightCAN.git +[submodule "HindsightCAN"] + path = HindsightCAN + url = https://github.com/huskyroboticsteam/HindsightCAN.git diff --git a/HindsightCAN b/HindsightCAN new file mode 160000 index 0000000..58fae5b --- /dev/null +++ b/HindsightCAN @@ -0,0 +1 @@ +Subproject commit 58fae5bbcb403a0026fa11a54cdabfed9148d697 From 505cfd9bb66e25e000abf8db14600cf7f2b27110 Mon Sep 17 00:00:00 2001 From: FLinLan Date: Thu, 24 Apr 2025 18:34:10 -0700 Subject: [PATCH 02/10] intialized all block components except for SPI and configured the pins --- .gitignore | 36 +- .gitmodules | 6 +- .../CAN_Bridge.cydwr | 8090 +++++++++-------- .../CAN_Bridge.cyprj | 6471 +++++-------- .../CAN_Stuff.c | 180 +- .../CAN_Stuff.h | 58 +- .../FSM_Stuff.c | 70 +- .../FSM_Stuff.h | 66 +- CAN_Bridge.cydsn/HindsightCAN/.gitignore | 55 + CAN_Bridge.cydsn/HindsightCAN/CANCommon.c | 260 + CAN_Bridge.cydsn/HindsightCAN/CANCommon.h | 137 + CAN_Bridge.cydsn/HindsightCAN/CANGPIO.c | 170 + CAN_Bridge.cydsn/HindsightCAN/CANGPIO.h | 91 + CAN_Bridge.cydsn/HindsightCAN/CANLibrary.h | 21 + .../HindsightCAN/CANLocalization.c | 9 + .../HindsightCAN/CANLocalization.h | 12 + CAN_Bridge.cydsn/HindsightCAN/CANMotorUnit.c | 326 + CAN_Bridge.cydsn/HindsightCAN/CANMotorUnit.h | 315 + CAN_Bridge.cydsn/HindsightCAN/CANPacket.c | 228 + CAN_Bridge.cydsn/HindsightCAN/CANPacket.h | 95 + CAN_Bridge.cydsn/HindsightCAN/CANPower.c | 50 + CAN_Bridge.cydsn/HindsightCAN/CANPower.h | 42 + CAN_Bridge.cydsn/HindsightCAN/CANScience.c | 59 + CAN_Bridge.cydsn/HindsightCAN/CANScience.h | 136 + .../HindsightCAN/CANSerialNumbers.h | 72 + CAN_Bridge.cydsn/HindsightCAN/CMakeLists.txt | 125 + CAN_Bridge.cydsn/HindsightCAN/Port.h | 53 + .../HindsightCAN/PortFiles/PortAT90CANxxx.c | 233 + .../HindsightCAN/PortFiles/PortJetson.c | 34 + .../PortFiles/PortPSOC_CY8C4248AZI_L485.c | 202 + .../HindsightCAN/PortFiles/PortTemplate.c | 39 + CAN_Bridge.cydsn/HindsightCAN/README.md | 37 + .../cmake/HindsightCANConfig.cmake.in | 10 + CAN_Bridge.cydsn/TopDesign/TopDesign.cysch | Bin 0 -> 110081 bytes .../cyapicallbacks.h | 42 +- CAN_Bridge.cydsn/main.c | 256 + .../main.h | 66 +- ...Project Template.cywrk => CAN_Bridge.cywrk | 42 +- ComponentUpdateLog.txt | 14 +- HindsightCAN | 1 - PSoC Project Template.cydsn/HindsightCAN | 1 - .../TopDesign/TopDesign.cysch | Bin 103165 -> 0 bytes PSoC Project Template.cydsn/main.c | 159 - README.md | 6 +- 44 files changed, 9850 insertions(+), 8525 deletions(-) rename PSoC Project Template.cydsn/PSoC Project Template.cydwr => CAN_Bridge.cydsn/CAN_Bridge.cydwr (95%) rename PSoC Project Template.cydsn/PSoC Project Template.cyprj => CAN_Bridge.cydsn/CAN_Bridge.cyprj (61%) rename {PSoC Project Template.cydsn => CAN_Bridge.cydsn}/CAN_Stuff.c (96%) rename {PSoC Project Template.cydsn => CAN_Bridge.cydsn}/CAN_Stuff.h (96%) rename {PSoC Project Template.cydsn => CAN_Bridge.cydsn}/FSM_Stuff.c (95%) rename {PSoC Project Template.cydsn => CAN_Bridge.cydsn}/FSM_Stuff.h (95%) create mode 100644 CAN_Bridge.cydsn/HindsightCAN/.gitignore create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANCommon.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANCommon.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANGPIO.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANGPIO.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANLibrary.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANLocalization.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANLocalization.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANMotorUnit.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANMotorUnit.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANPacket.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANPacket.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANPower.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANPower.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANScience.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANScience.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CANSerialNumbers.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/CMakeLists.txt create mode 100644 CAN_Bridge.cydsn/HindsightCAN/Port.h create mode 100644 CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortAT90CANxxx.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortJetson.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortPSOC_CY8C4248AZI_L485.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortTemplate.c create mode 100644 CAN_Bridge.cydsn/HindsightCAN/README.md create mode 100644 CAN_Bridge.cydsn/HindsightCAN/cmake/HindsightCANConfig.cmake.in create mode 100644 CAN_Bridge.cydsn/TopDesign/TopDesign.cysch rename {PSoC Project Template.cydsn => CAN_Bridge.cydsn}/cyapicallbacks.h (96%) create mode 100644 CAN_Bridge.cydsn/main.c rename {PSoC Project Template.cydsn => CAN_Bridge.cydsn}/main.h (96%) rename PSoC Project Template.cywrk => CAN_Bridge.cywrk (79%) delete mode 160000 HindsightCAN delete mode 160000 PSoC Project Template.cydsn/HindsightCAN delete mode 100644 PSoC Project Template.cydsn/TopDesign/TopDesign.cysch delete mode 100644 PSoC Project Template.cydsn/main.c diff --git a/.gitignore b/.gitignore index 3a8f689..daa4d98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,18 @@ -# Project Settings -*.cywrk.* -*.cyprj.* - -# Generated Assets and Resources -Debug/ -Release/ -Export/ -**/codegentemp -**/Generated_Source -*_datasheet.pdf -*_timing.html -*.cycdx -*.cyfit -*.rpt -*.svd -*.log -*.zip +# Project Settings +*.cywrk.* +*.cyprj.* + +# Generated Assets and Resources +Debug/ +Release/ +Export/ +**/codegentemp +**/Generated_Source +*_datasheet.pdf +*_timing.html +*.cycdx +*.cyfit +*.rpt +*.svd +*.log +*.zip diff --git a/.gitmodules b/.gitmodules index 6faed38..68e0314 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "PSoC Project Template.cydsn/HindsightCAN"] - path = PSoC Project Template.cydsn/HindsightCAN - url = https://github.com/huskyroboticsteam/HindsightCAN.git +[submodule "PSoC Project Template.cydsn/HindsightCAN"] + path = PSoC Project Template.cydsn/HindsightCAN + url = https://github.com/huskyroboticsteam/HindsightCAN.git [submodule "HindsightCAN"] path = HindsightCAN url = https://github.com/huskyroboticsteam/HindsightCAN.git diff --git a/PSoC Project Template.cydsn/PSoC Project Template.cydwr b/CAN_Bridge.cydsn/CAN_Bridge.cydwr similarity index 95% rename from PSoC Project Template.cydsn/PSoC Project Template.cydwr rename to CAN_Bridge.cydsn/CAN_Bridge.cydwr index 96b7e10..c5bae99 100644 --- a/PSoC Project Template.cydsn/PSoC Project Template.cydwr +++ b/CAN_Bridge.cydsn/CAN_Bridge.cydwr @@ -1,4028 +1,4064 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PSoC Project Template.cydsn/PSoC Project Template.cyprj b/CAN_Bridge.cydsn/CAN_Bridge.cyprj similarity index 61% rename from PSoC Project Template.cydsn/PSoC Project Template.cyprj rename to CAN_Bridge.cydsn/CAN_Bridge.cyprj index 11fff61..2767c16 100644 --- a/PSoC Project Template.cydsn/PSoC Project Template.cyprj +++ b/CAN_Bridge.cydsn/CAN_Bridge.cyprj @@ -1,4045 +1,2428 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PSoC Project Template.cydsn/CAN_Stuff.c b/CAN_Bridge.cydsn/CAN_Stuff.c similarity index 96% rename from PSoC Project Template.cydsn/CAN_Stuff.c rename to CAN_Bridge.cydsn/CAN_Stuff.c index 9b24ca1..711ab5a 100644 --- a/PSoC Project Template.cydsn/CAN_Stuff.c +++ b/CAN_Bridge.cydsn/CAN_Stuff.c @@ -1,91 +1,91 @@ -/* ======================================== - * - * Copyright YOUR COMPANY, THE YEAR - * All Rights Reserved - * UNPUBLISHED, LICENSED SOFTWARE. - * - * CONFIDENTIAL AND PROPRIETARY INFORMATION - * WHICH IS THE PROPERTY OF your company. - * - * ======================================== -*/ - -#include -#include "main.h" -#include "CAN_Stuff.h" -#include "FSM_Stuff.h" -#include "HindsightCAN/CANLibrary.h" - -extern char txData[TX_DATA_SIZE]; -extern uint8 address; - -//Reads from CAN FIFO and changes the state and mode accordingly -int ProcessCAN(CANPacket* receivedPacket, CANPacket* packetToSend) { - uint16_t packageID = GetPacketID(receivedPacket); - uint8_t sender_DG = GetSenderDeviceGroupCode(receivedPacket); - uint8_t sender_SN = GetSenderDeviceSerialNumber(receivedPacket); - int32_t data = 0; - int err = 0; - - switch(packageID){ - // Board-specific packets - case(ID_MOTOR_UNIT_MODE_SEL): - data = GetModeFromPacket(receivedPacket); - - if(data == MODE1) { - SetModeTo(MODE1); - // initialize MODE1 - } else { - err = ERROR_INVALID_MODE; - } - break; - - // Common Packets - case(ID_ESTOP): - Print("\r\n\r\nSTOP\r\n\r\n"); - // stop all movement - GotoUninitState(); - err = ESTOP_ERR_GENERAL; - break; - - case(ID_TELEMETRY_PULL): - switch(DecodeTelemetryType(receivedPacket)) - { - // USE CONSTANTS FOR CASES - case(0): - data = 105; - break; - default: - err = ERROR_INVALID_TTC; - break; - } - - // Assemble and send packet - AssembleTelemetryReportPacket(packetToSend, sender_DG, sender_SN, receivedPacket->data[3], data); - - if (err == 0) - SendCANPacket(packetToSend); - - break; - - default: //recieved Packet with non-valid ID - // could be due to corruption, don't uninit - return ERROR_INVALID_PACKET; - } - - return err; -} - -void PrintCanPacket(CANPacket packet){ - for(int i = 0; i < packet.dlc; i++ ) { - sprintf(txData,"Byte%d %x ", i+1, packet.data[i]); - Print(txData); - } - - sprintf(txData,"ID:%x %x %x\r\n",packet.id >> 10, - (packet.id >> 6) & 0xF , packet.id & 0x3F); - Print(txData); -} - - +/* ======================================== + * + * Copyright YOUR COMPANY, THE YEAR + * All Rights Reserved + * UNPUBLISHED, LICENSED SOFTWARE. + * + * CONFIDENTIAL AND PROPRIETARY INFORMATION + * WHICH IS THE PROPERTY OF your company. + * + * ======================================== +*/ + +#include +#include "main.h" +#include "CAN_Stuff.h" +#include "FSM_Stuff.h" +#include "HindsightCAN/CANLibrary.h" + +extern char txData[TX_DATA_SIZE]; +extern uint8 address; + +//Reads from CAN FIFO and changes the state and mode accordingly +int ProcessCAN(CANPacket* receivedPacket, CANPacket* packetToSend) { + uint16_t packageID = GetPacketID(receivedPacket); + uint8_t sender_DG = GetSenderDeviceGroupCode(receivedPacket); + uint8_t sender_SN = GetSenderDeviceSerialNumber(receivedPacket); + int32_t data = 0; + int err = 0; + + switch(packageID){ + // Board-specific packets + case(ID_MOTOR_UNIT_MODE_SEL): + data = GetModeFromPacket(receivedPacket); + + if(data == MODE1) { + SetModeTo(MODE1); + // initialize MODE1 + } else { + err = ERROR_INVALID_MODE; + } + break; + + // Common Packets + case(ID_ESTOP): + Print("\r\n\r\nSTOP\r\n\r\n"); + // stop all movement + GotoUninitState(); + err = ESTOP_ERR_GENERAL; + break; + + case(ID_TELEMETRY_PULL): + switch(DecodeTelemetryType(receivedPacket)) + { + // USE CONSTANTS FOR CASES + case(0): + data = 105; + break; + default: + err = ERROR_INVALID_TTC; + break; + } + + // Assemble and send packet + AssembleTelemetryReportPacket(packetToSend, sender_DG, sender_SN, receivedPacket->data[3], data); + + if (err == 0) + SendCANPacket(packetToSend); + + break; + + default: //recieved Packet with non-valid ID + // could be due to corruption, don't uninit + return ERROR_INVALID_PACKET; + } + + return err; +} + +void PrintCanPacket(CANPacket packet){ + for(int i = 0; i < packet.dlc; i++ ) { + sprintf(txData,"Byte%d %x ", i+1, packet.data[i]); + Print(txData); + } + + sprintf(txData,"ID:%x %x %x\r\n",packet.id >> 10, + (packet.id >> 6) & 0xF , packet.id & 0x3F); + Print(txData); +} + + /* [] END OF FILE */ \ No newline at end of file diff --git a/PSoC Project Template.cydsn/CAN_Stuff.h b/CAN_Bridge.cydsn/CAN_Stuff.h similarity index 96% rename from PSoC Project Template.cydsn/CAN_Stuff.h rename to CAN_Bridge.cydsn/CAN_Stuff.h index d5f2c26..1de5422 100644 --- a/PSoC Project Template.cydsn/CAN_Stuff.h +++ b/CAN_Bridge.cydsn/CAN_Stuff.h @@ -1,30 +1,30 @@ -/* ======================================== - * - * Copyright YOUR COMPANY, THE YEAR - * All Rights Reserved - * UNPUBLISHED, LICENSED SOFTWARE. - * - * CONFIDENTIAL AND PROPRIETARY INFORMATION - * WHICH IS THE PROPERTY OF your company. - * - * ======================================== -*/ - -#pragma once - -#include -#include "HindsightCAN/CANLibrary.h" - -// CAN Errors (0x10-0x1F) -#define ERROR_NO_NEW_PACKET 0xFFFF -#define ERROR_WRONG_MODE 0x10 -#define ERROR_INVALID_MODE 0x11 -#define ERROR_INVALID_TTC 0x12 -#define ERROR_INVALID_PACKET 0x13 - -int ReadCAN(CANPacket *receivedPacket); -int ProcessCAN(CANPacket* receivedPacket, CANPacket* packetToSend); -void PrintCanPacket(CANPacket packet); - -/* [] END OF FILE */ +/* ======================================== + * + * Copyright YOUR COMPANY, THE YEAR + * All Rights Reserved + * UNPUBLISHED, LICENSED SOFTWARE. + * + * CONFIDENTIAL AND PROPRIETARY INFORMATION + * WHICH IS THE PROPERTY OF your company. + * + * ======================================== +*/ + +#pragma once + +#include +#include "HindsightCAN/CANLibrary.h" + +// CAN Errors (0x10-0x1F) +#define ERROR_NO_NEW_PACKET 0xFFFF +#define ERROR_WRONG_MODE 0x10 +#define ERROR_INVALID_MODE 0x11 +#define ERROR_INVALID_TTC 0x12 +#define ERROR_INVALID_PACKET 0x13 + +int ReadCAN(CANPacket *receivedPacket); +int ProcessCAN(CANPacket* receivedPacket, CANPacket* packetToSend); +void PrintCanPacket(CANPacket packet); + +/* [] END OF FILE */ \ No newline at end of file diff --git a/PSoC Project Template.cydsn/FSM_Stuff.c b/CAN_Bridge.cydsn/FSM_Stuff.c similarity index 95% rename from PSoC Project Template.cydsn/FSM_Stuff.c rename to CAN_Bridge.cydsn/FSM_Stuff.c index c5f989c..99c8cf4 100644 --- a/PSoC Project Template.cydsn/FSM_Stuff.c +++ b/CAN_Bridge.cydsn/FSM_Stuff.c @@ -1,36 +1,36 @@ -/* ======================================== - * - * Copyright YOUR COMPANY, THE YEAR - * All Rights Reserved - * UNPUBLISHED, LICENSED SOFTWARE. - * - * CONFIDENTIAL AND PROPRIETARY INFORMATION - * WHICH IS THE PROPERTY OF your company. - * - * ======================================== -*/ - -#include "FSM_Stuff.h" -#include "project.h" - -uint8_t currentState = UNINIT; -uint8_t currentMode = 0xFF; - -void GotoUninitState() { - currentState = UNINIT; - // reset any parameters -} -void SetStateTo(uint8_t state) { - currentState = state; -} -void SetModeTo(uint8_t mode) { - currentMode = mode; -} -uint8_t GetState(){ - return currentState; -} -uint8_t GetMode(){ - return currentMode; -} - +/* ======================================== + * + * Copyright YOUR COMPANY, THE YEAR + * All Rights Reserved + * UNPUBLISHED, LICENSED SOFTWARE. + * + * CONFIDENTIAL AND PROPRIETARY INFORMATION + * WHICH IS THE PROPERTY OF your company. + * + * ======================================== +*/ + +#include "FSM_Stuff.h" +#include "project.h" + +uint8_t currentState = UNINIT; +uint8_t currentMode = 0xFF; + +void GotoUninitState() { + currentState = UNINIT; + // reset any parameters +} +void SetStateTo(uint8_t state) { + currentState = state; +} +void SetModeTo(uint8_t mode) { + currentMode = mode; +} +uint8_t GetState(){ + return currentState; +} +uint8_t GetMode(){ + return currentMode; +} + /* [] END OF FILE */ \ No newline at end of file diff --git a/PSoC Project Template.cydsn/FSM_Stuff.h b/CAN_Bridge.cydsn/FSM_Stuff.h similarity index 95% rename from PSoC Project Template.cydsn/FSM_Stuff.h rename to CAN_Bridge.cydsn/FSM_Stuff.h index 6174d0c..b1447c0 100644 --- a/PSoC Project Template.cydsn/FSM_Stuff.h +++ b/CAN_Bridge.cydsn/FSM_Stuff.h @@ -1,34 +1,34 @@ -/* ======================================== - * - * Copyright YOUR COMPANY, THE YEAR - * All Rights Reserved - * UNPUBLISHED, LICENSED SOFTWARE. - * - * CONFIDENTIAL AND PROPRIETARY INFORMATION - * WHICH IS THE PROPERTY OF your company. - * - * ======================================== -*/ - -#pragma once -#include - -//States in FSM -#define UNINIT 0x0 -#define CHECK_CAN 0x1 -#define DO_MODE1 0x2 - -//Operation modes -#define MODE1 0x2 - -// FSM Errors (0x20-0x2F) -#define ERROR_ESTOP 0x20 -#define ERROR_INVALID_STATE 0x21 - -void GotoUninitState(); -void SetStateTo(uint8_t state); -void SetModeTo(uint8_t mode); -uint8_t GetState(); -uint8_t GetMode(); - +/* ======================================== + * + * Copyright YOUR COMPANY, THE YEAR + * All Rights Reserved + * UNPUBLISHED, LICENSED SOFTWARE. + * + * CONFIDENTIAL AND PROPRIETARY INFORMATION + * WHICH IS THE PROPERTY OF your company. + * + * ======================================== +*/ + +#pragma once +#include + +//States in FSM +#define UNINIT 0x0 +#define CHECK_CAN 0x1 +#define DO_MODE1 0x2 + +//Operation modes +#define MODE1 0x2 + +// FSM Errors (0x20-0x2F) +#define ERROR_ESTOP 0x20 +#define ERROR_INVALID_STATE 0x21 + +void GotoUninitState(); +void SetStateTo(uint8_t state); +void SetModeTo(uint8_t mode); +uint8_t GetState(); +uint8_t GetMode(); + /* [] END OF FILE */ \ No newline at end of file diff --git a/CAN_Bridge.cydsn/HindsightCAN/.gitignore b/CAN_Bridge.cydsn/HindsightCAN/.gitignore new file mode 100644 index 0000000..68d7671 --- /dev/null +++ b/CAN_Bridge.cydsn/HindsightCAN/.gitignore @@ -0,0 +1,55 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +.vscode/c_cpp_properties.json +.vscode/tasks.json +/build/ diff --git a/CAN_Bridge.cydsn/HindsightCAN/CANCommon.c b/CAN_Bridge.cydsn/HindsightCAN/CANCommon.c new file mode 100644 index 0000000..9024206 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANCommon.h b/CAN_Bridge.cydsn/HindsightCAN/CANCommon.h new file mode 100644 index 0000000..bbaddb2 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANGPIO.c b/CAN_Bridge.cydsn/HindsightCAN/CANGPIO.c new file mode 100644 index 0000000..514f98e --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANGPIO.h b/CAN_Bridge.cydsn/HindsightCAN/CANGPIO.h new file mode 100644 index 0000000..a90da7c --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANLibrary.h b/CAN_Bridge.cydsn/HindsightCAN/CANLibrary.h new file mode 100644 index 0000000..49bf977 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANLocalization.c b/CAN_Bridge.cydsn/HindsightCAN/CANLocalization.c new file mode 100644 index 0000000..5f99c3e --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANLocalization.h b/CAN_Bridge.cydsn/HindsightCAN/CANLocalization.h new file mode 100644 index 0000000..189abb8 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANMotorUnit.c b/CAN_Bridge.cydsn/HindsightCAN/CANMotorUnit.c new file mode 100644 index 0000000..f6cf268 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANMotorUnit.h b/CAN_Bridge.cydsn/HindsightCAN/CANMotorUnit.h new file mode 100644 index 0000000..063c96c --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANPacket.c b/CAN_Bridge.cydsn/HindsightCAN/CANPacket.c new file mode 100644 index 0000000..1955ae8 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANPacket.h b/CAN_Bridge.cydsn/HindsightCAN/CANPacket.h new file mode 100644 index 0000000..749e753 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANPower.c b/CAN_Bridge.cydsn/HindsightCAN/CANPower.c new file mode 100644 index 0000000..653d476 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANPower.h b/CAN_Bridge.cydsn/HindsightCAN/CANPower.h new file mode 100644 index 0000000..01c8268 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANScience.c b/CAN_Bridge.cydsn/HindsightCAN/CANScience.c new file mode 100644 index 0000000..a16e086 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANScience.h b/CAN_Bridge.cydsn/HindsightCAN/CANScience.h new file mode 100644 index 0000000..fa2499a --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CANSerialNumbers.h b/CAN_Bridge.cydsn/HindsightCAN/CANSerialNumbers.h new file mode 100644 index 0000000..5f53053 --- /dev/null +++ b/CAN_Bridge.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/CAN_Bridge.cydsn/HindsightCAN/CMakeLists.txt b/CAN_Bridge.cydsn/HindsightCAN/CMakeLists.txt new file mode 100644 index 0000000..6201d9e --- /dev/null +++ b/CAN_Bridge.cydsn/HindsightCAN/CMakeLists.txt @@ -0,0 +1,125 @@ +cmake_minimum_required(VERSION 3.12) + +# Include some helper packages for installation +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +if(DEFINED PROJECT_NAME) + set(IS_SUBPROJECT ON) +else() + set(IS_SUBPROJECT OFF) +endif() + +# define the project if we're not being used as a subproject +if(NOT IS_SUBPROJECT) + # Define project. Version number should be updated with changes according to + # Semantic Versioning (https://semver.org) + # - Major version (first number) should be incremented when + # backwards-incompatible changes are made (such as removing packets) + # - Minor version (second number) should be incremented when features are added + # in a backwards-compatible manner (such as adding packets, or adding packet + # fields) + # - Patch version (third number) should be incremented when you make small + # backwards-compatible changes or bug fixes. + project(HindsightCAN + LANGUAGES C + VERSION 1.6.1) # <-- Change when you make commits to master; see above +endif() + +# The list of header files for the CAN library +set(CAN_HEADERS + CANCommon.h + CANGPIO.h + CANLibrary.h + CANLocalization.h + CANMotorUnit.h + CANPacket.h + CANPower.h + CANScience.h + CANSerialNumbers.h + Port.h) + +# The list of sources for the CAN library +set(CAN_SOURCES + CANCommon.c + CANGPIO.c + CANLocalization.c + CANMotorUnit.c + CANPacket.c + CANPower.c + CANScience.c + PortFiles/PortJetson.c) + +# Preprocessor flag required for the CAN library; see +# https://github.com/huskyroboticsteam/HindsightCAN#how-to-port-to-a-new-chip +add_definitions(-DCHIP_TYPE=CHIP_TYPE_JETSON) + +# Define a static library, compiled from the files in the CAN_SOURCES list +add_library(HindsightCAN STATIC ${CAN_SOURCES}) +# Include the header files when installed to the system +target_include_directories(HindsightCAN PUBLIC + $ + $) + +# kind of a hack: if we're building as a subproject, copy headers to a folder +# called HindsightCAN in the build directory, so client code can include it +# by doing #include +if(IS_SUBPROJECT) + file(GLOB HEADER_FILES + "${CMAKE_CURRENT_SOURCE_DIR}/*.h" + ) + file(COPY ${HEADER_FILES} DESTINATION HindsightCAN) +endif() + +### Installation config ### + +# If this project is not being included as a submodule +if (NOT IS_SUBPROJECT) + # Install the static library to the system, and export the list of installed + # targets to hindsight-can-targets + install(TARGETS HindsightCAN + EXPORT hindsight-can-targets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + # Install the header files to the system + install(FILES ${CAN_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/HindsightCAN) + + # Install the list of targets to the system + install(EXPORT hindsight-can-targets + FILE HindsightCANTargets.cmake + NAMESPACE HindsightCAN:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/HindsightCAN) + + # Generate a CMake package configuration file for the library + configure_package_config_file( + ${CMAKE_CURRENT_LIST_DIR}/cmake/HindsightCANConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/HindsightCANConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/HindsightCAN) + write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/HindsightCANConfigVersion.cmake + VERSION ${CMAKE_PROJECT_VERSION} + COMPATIBILITY SameMinorVersion) + # Install the CMake package configuration file + install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/HindsightCANConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/HindsightCANConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/HindsightCAN) + + ### Packaging configuration ### + # Borrowed/adapted from https://www.scivision.dev/cmake-cpack-basic/ + set(CPACK_GENERATOR "DEB") + set(CPACK_PACKAGE_NAME "hindsight-can") + # Version format: major.minor.patch + set(CPACK_PACKAGE_VERSION "${CMAKE_PROJECT_VERSION}") + set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}) + set(CPACK_PACKAGE_CONTACT "Husky Robotics Team ") + set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") + set(CPACK_PACKAGE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + install(FILES ${CPACK_RESOURCE_FILE_README} + DESTINATION share/docs/${PROJECT_NAME}) + + include(CPack) + +endif() + + diff --git a/CAN_Bridge.cydsn/HindsightCAN/Port.h b/CAN_Bridge.cydsn/HindsightCAN/Port.h new file mode 100644 index 0000000..089efe1 --- /dev/null +++ b/CAN_Bridge.cydsn/HindsightCAN/Port.h @@ -0,0 +1,53 @@ +/* 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/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortAT90CANxxx.c b/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortAT90CANxxx.c new file mode 100644 index 0000000..c8499ca --- /dev/null +++ b/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortAT90CANxxx.c @@ -0,0 +1,233 @@ +/* + * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2 + */ +#if CHIP_TYPE == CHIP_TYPE_AT90CANxxx + +#include "Port.h" +#include + +#ifndef F_CPU +#define F_CPU 16000000L +#endif + +#include "config.h" + +#define CAN_1000_BAUD 0x020413L +#define CAN_500_BAUD 0x060413L +#define CAN_250_BAUD 0x0E0413L +#define CAN_125_BAUD 0x1E0413L +#define CAN_100_BAUD 0x260413L + +#include +#include +#include + +volatile uint8_t msgs_av; //Number of messages unclaimed messages +volatile uint8_t rxed_mobs[2]; //Tracks which MObs have messages received + +uint8_t devGrp, devSer; + +/*Selects the MOB to operate on*/ +void inline select_mob(uint8_t mob){ + CANPAGE = ((mob & 0x0F) << 4); +} + +/*Disables the interrupt for the specified MOb*/ +void disable_mob_interrupt(uint8_t mob){ + if(mob < 8){ + CANIE2 &= ~(1 << mob); + } else { + CANIE1 &= ~(1 << (mob - 8)); + } +} + +/*Enable the interrupt for the specified MOb*/ +void enable_mob_interrupt(uint8_t mob){ + if(mob < 8){ + CANIE2 |= (1 << mob); + } else { + CANIE1 |= (1 << (mob - 8)); + } +} + +/*CAN controller interrupt handler*/ +ISR(CANIT_vect){ + uint8_t canpage = CANPAGE; //Save CAN page + if((CANHPMOB & 0xF0) != 0xF0){ //Message io? + int mob = (CANHPMOB >> 4); + select_mob(mob); + if(CANSTMOB & (1 << TXOK)){ //TX + /*Reset the MOb*/ + CANSTMOB &= 0; + CANCDMOB = 0; + enable_mob_interrupt(mob); + } else { //RX + msgs_av++; //Increase count of messages + rxed_mobs[!!(mob & 8)] |= (1 << (mob & 7)); // Mark which MOb has a message + CANSTMOB &= 0; //Reset the MOb + disable_mob_interrupt(mob); + } + } else { + CANGIT |= 0; //Error interrupt - Handle these? + } + CANPAGE = canpage; //restore CAN page +} + +/*Reset the receive filter for the given MOb*/ +void set_mob_rx_filter(int mob){ + select_mob(mob); + uint16_t RX_mask = 0x3FF; // mask out priority bit, compare on everything else + uint16_t RX_tag = 0x3F; //0th MOb is for broadcast packets, group = 0, serial = 0x3F + if(mob > 0 && mob <= 2){ //1st und 2nd MOb is for device group broadcasts, match device group and 0x3F serial + RX_tag = (devGrp << 6) | 0x3F; + } else if(mob > 2 && mob <= 4){ //2nd and 3rd MOb is for the device specific message. Match the whole ID + RX_tag = (devGrp << 6) | devSer; + } + + CANIDM4 = 0; + CANIDM3 = 0; + CANIDT4 = 0; + CANIDT3 = 0; + CANIDT2 = ((RX_tag & 7) << 5); + CANIDT1 = ((RX_tag & 0x7F8) >> 3); + CANIDM2 = ((RX_mask & 7) << 5); + CANIDM1 = ((RX_mask & 0x7F8) >> 3); +} + +/*Initalizes and enables the CAN controller +Parameters: +uint32_t rate: the baud rate selection +uint8_t txmobs: how many MOBs to dedicate to transmission +uint8_t mode: The mode to operate the CAN controller in +*/ +void init_CAN(uint32_t rate, uint16_t deviceGroup, uint16_t deviceSerial){ + CANGCON |= (1<> 16; + CANBT2 = (uint32_t)(rate & 0x00FF00L) >> 8; + CANBT3 = (uint32_t)(rate & 0x0000FFL); + CANGIE = (1 << CANIT) | (1 << ENRX) | (1 << ENTX); //Enable CAN interrupts + CANTCON = 255; //Set the can timer to run at 1/2048th of F_CPU + rxed_mobs[0] = rxed_mobs[1] = 0; + uint8_t i; + /*Initialize MOBs*/ + for(i = 0;i < 15;i++){ + if(i <= 4){ /*MObs <= 4 are RX mobs*/ + /*Set up the match registers*/ + CANSTMOB &= 0; + set_mob_rx_filter(i); + CANCDMOB = (1 << CONMOB1); //Mark RX mobs + enable_mob_interrupt(i); // enable the receive interrupt + } else { + CANCDMOB = 0; //Mark as TX MOb + } + } + msgs_av = 0; + //Enable the CAN controller + CANGCON = (1 << ENASTB); +} + +/*Returns the number of CAN messages waiting*/ +uint8_t inline CAN_msg_available(){ + return msgs_av; +} + +/*Finds a free MOb or returns -1 if they're all used*/ +int8_t find_free_mob(){ + uint8_t i; + uint8_t status; + for(i = 0;i < 15;i++){ + select_mob(i); + status = CANCDMOB; + if(!(status & ((1 << CONMOB1) | (1 << CONMOB0)))){ + return i; + } + } + return -1; +} + + +void InitCAN(int deviceGroup, int deviceAddress) +{ + init_CAN(CAN_125_BAUD, deviceGroup, deviceAddress); +} + +int SendCANPacket(CANPacket *packetToSend) +{ + uint8_t i; + int8_t mob = find_free_mob(); + if(mob == -1){ + return 0x02; //No MObs available + } + select_mob(mob); + CANSTMOB &= 0; + CANCDMOB = packetToSend->dlc & 0x0F; + for(i = 0;i < packetToSend->dlc && i < 8;i++){ //Copy the data into the MOb + CANMSG = packetToSend->data[i]; + } + CANIDT4 = 0; //CAN v2.0 - we don't care + CANIDT3 = 0; + CANIDT2 = ((packetToSend->id & 7) << 5); + CANIDT1 = ((packetToSend->id & 0x7F8) >> 3); + CANCDMOB |= (1<dlc = CANCDMOB & 0x0F; //Length in the lower 8 bits + receivedPacket->id = (CANIDT2 >> 5) | ((uint16_t)CANIDT1 << 3); + for(i = 0;i < receivedPacket->dlc && i < 8;i++){ + receivedPacket->data[i] = CANMSG; //Get the data from the MOb and copy it into the buffer + } + //Atomically decrement the number of messages available + cli(); + msgs_av--; + sei(); + /*Reset the MOb*/ + set_mob_rx_filter(mob); + enable_mob_interrupt(mob); + rxed_mobs[!!(mob & 8)] &= ~(1 << (mob & 7)); //Mark that the message has been taken + CANCDMOB = (1<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; +} + +//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); +} +#endif //CHIP_TYPE == CHIP_TYPE_PSOC_CY8C4248AZI_L485 diff --git a/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortTemplate.c b/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortTemplate.c new file mode 100644 index 0000000..e7c0ad7 --- /dev/null +++ b/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortTemplate.c @@ -0,0 +1,39 @@ +/* + * Documentation: https://huskyroboticsteam.slite.com/app/channels/iU0BryG7M9/collections/aXvWTcIR6c/notes/4otlSFsSp2 + */ +#if CHIP_TYPE == CHIP_TYPE_TEMPLATE//Replace this with the chip you are porting + +#include "../Port.h" + +void InitCAN(int deviceGroup, int deviceAddress) +{ + // Implement hardware initialization of CAN + // Including receive filters +} +int SendCANPacket(CANPacket *packetToSend) +{ + //Implement sending/ queing to send packet +} +int PollAndReceiveCANPacket(CANPacket *receivedPacket) +{ + //Implement get next CAN packet from buffers/registers +} + +uint8_t getLocalDeviceSerial() +{ + //Reading DIP switches? Hard coded? + //This might be board specific, rather than chip specific. + return DEVICE_SERIAL_MOTOR_CHASSIS_FR; // example value (also used for testing) +} +uint8_t getLocalDeviceGroup() +{ + //Definitely board specific. + return DEVICE_GROUP_MOTOR_CONTROL; // example value (also used for testing) +} + +uint8_t getChipType() +{ + return CHIP_TYPE; + //Should be same for all ports, just not sure where to put it. +} +#endif //CHIP_TYPE == CHIP_TYPE_TEMPLATE diff --git a/CAN_Bridge.cydsn/HindsightCAN/README.md b/CAN_Bridge.cydsn/HindsightCAN/README.md new file mode 100644 index 0000000..37f507c --- /dev/null +++ b/CAN_Bridge.cydsn/HindsightCAN/README.md @@ -0,0 +1,37 @@ +# Hindsight CAN Drivers +## Use these drivers for Embedded CAN Communications on Hindsight (PY2020) Rover. + +### More information +For more information on the protocol standard, please visit the Slite documentation HUB for Husky Robotics. The protocol documentation is under the Electronics/CAN/CAN Protocol sheet.
+ +## Implementation information + +### How To Use +_Note: You will need to have the standard C libraries compiled with your code. This is usually done automatically. If you have problems with `stdint.h` let Jaden know._

+*STEP 1*
+Within your repository for your firmware create a submodule with this repo in it. You can follow [this guide](https://git-scm.com/book/en/v2/Git-Tools-Submodules) for instructions on how to do that and explanations for what exactly a submodule is.
+Usually this command is done as follows:
+```git submodule add git@github.com:huskyroboticsteam/HindsightCAN.git path_to_your_source```
+And then:
+```git submodule init```
+If you **put these files in the same folder as your source code**, you can skip the next step.
+ +*STEP 2*
+Add all of the source files to your compiler path within whatever IDE you are using. This will be dependent on what IDE you are using and how you are building your code. Since most people here will not be using a Makefile, we cannot give explicit direction on how to do this. If you have trouble, talk to Jaden, Dylan, or someone else who has done it. Please try Googling it and figuring it out yourself first though.

+*STEP 3*
+Import all of the relevant headers into your project. All devices will need to import `CANCommon.h`, which gives you access to the files that are necessary for interpretting and creating Common Mode packets. But if you are working on a Motor Unit for example, you will need to also import `CANMotorUnit.h` to give you access to the functions pertinent to specifically a motor unit. If you are writing software for the Jetson, you will need to import all of them! Yay! /s

+*STEP 4*
+You have to implement all of the hardware functionality for physically sending and receiving packets. In this repo, you will find a `Port.h` file. Please create a C-code file called `Port[DeviceName].c`, in that file `#include "Port.h"` and implement all of the functions in that header. Right now these CAN Drivers do not actually call those functions, so arbitrating when to send and receive is up to you as the firmware developer, so you will have to manually call those functions. This header is just to get you started and to make sure everyone is on the same page. + +### How to Update This Library in Your Project +To update your submodule call: ```git submodule update```, this should pull the changes from the master branch of this repo so you can get updates when we fix our broken code. + +### How to Port to a New Chip +This library was built to be portable to any microcontroller or processor. To port it: +1.) Create Port[chipname].c file in a folder of port files (you can copy the PortTemplate.c file to get started) +2.) Add #if CHIP_TYPE == CHIP_TYPE_xxx to top of C file, #endif at the bottom +3.) Add CHIP_TYPE_xxx to the list of defined chips in port.h, with an incremented value. +4.) Implement functs whose prototypes are in port.h +5.) Compile, passing in constant to gcc using -D CHIP_TYPE=CHIP_TYPE_xxx . + +Using this method, there should only be one implementation of these port functions visible to the complier after the preprocessor has run. diff --git a/CAN_Bridge.cydsn/HindsightCAN/cmake/HindsightCANConfig.cmake.in b/CAN_Bridge.cydsn/HindsightCAN/cmake/HindsightCANConfig.cmake.in new file mode 100644 index 0000000..b2a9662 --- /dev/null +++ b/CAN_Bridge.cydsn/HindsightCAN/cmake/HindsightCANConfig.cmake.in @@ -0,0 +1,10 @@ +@PACKAGE_INIT@ + + +# Avoid repeatedly including the targets +if(NOT TARGET HindsightCAN::HindsightCAN) + # Provide path for scripts + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") + + include(${CMAKE_CURRENT_LIST_DIR}/HindsightCANTargets.cmake) +endif() diff --git a/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch b/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch new file mode 100644 index 0000000000000000000000000000000000000000..4e0dc48cb2c03b30fd4cd8f82b19f2d406f2ea44 GIT binary patch literal 110081 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 literal 0 HcmV?d00001 diff --git a/PSoC Project Template.cydsn/cyapicallbacks.h b/CAN_Bridge.cydsn/cyapicallbacks.h similarity index 96% rename from PSoC Project Template.cydsn/cyapicallbacks.h rename to CAN_Bridge.cydsn/cyapicallbacks.h index 1d312fa..24d9c0c 100644 --- a/PSoC Project Template.cydsn/cyapicallbacks.h +++ b/CAN_Bridge.cydsn/cyapicallbacks.h @@ -1,21 +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 */ -/* [] */ +/* ======================================== + * + * 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/CAN_Bridge.cydsn/main.c b/CAN_Bridge.cydsn/main.c new file mode 100644 index 0000000..0a38e31 --- /dev/null +++ b/CAN_Bridge.cydsn/main.c @@ -0,0 +1,256 @@ +/* ======================================== + * + * Copyright YOUR COMPANY, THE YEAR + * All Rights Reserved + * UNPUBLISHED, LICENSED SOFTWARE. + * + * CONFIDENTIAL AND PROPRIETARY INFORMATION + * WHICH IS THE PROPERTY OF your company. + * + * ======================================== +*/ + +#include +#include +#include +#include +#include "main.h" +#include "cyapicallbacks.h" +#include "CAN_Stuff.h" +#include "FSM_Stuff.h" +#include "HindsightCAN/CANLibrary.h" +#define UNKNOWN_PACKET 0xFFFF + +// testing out the headers +#include "cytypes.h" +#include "cyfitter.h" +#include "cydevice_trm.h" + +// LED stuff +volatile uint8_t CAN_time_LED = 0; +volatile uint8_t ERROR_time_LED = 0; + +// UART stuff +char txData[TX_DATA_SIZE]; + +// CAN stuff +CANPacket can_recieve; +CANPacket can_send; +uint8 address = 0; +char8 uart_tx[64]; +char8 uart_rx[64]; +CANPacket can_tx; +CANPacket can_rx; + +uint8 uart_rx_len = 0; + + + +CY_ISR(Period_Reset_Handler) { + CAN_time_LED++; + ERROR_time_LED++; + + if (ERROR_time_LED >= 3) { + LED_ERR_Write(OFF); + } + if (CAN_time_LED >= 3) { + LED_CAN_Write(OFF); + } +} + +/* +CY_ISR(Button_1_Handler) { + LED_DBG_Write(!LED_DBG_Read()); +} +*/ + +uint8 s2x(char8 c) { + switch(c) { + case '1': return 1; case '2': return 2; + case '3': return 3; case '4': return 4; + case '5': return 5; case '6': return 6; + case '7': return 7; case '8': return 8; + case '9': return 9; case 'A': return 10; + case 'B': return 11;case 'C': return 12; + case 'D': return 13;case 'E': return 14; + case 'F': return 15;case 'a': return 10; + case 'b': return 11;case 'c': return 12; + case 'd': return 13;case 'e': return 14; + case 'f': return 15;default: return 0; + } +} + +void parseLine(CANPacket* p, char8 line[], int length) { + uint16 pr = (uint16) s2x(line[0]) << 10; + uint16 dg = (uint16) s2x(line[2]) << 6; + uint16 sn = (uint16) s2x(line[4]) << 4 | s2x(line[5]); + p->id = (pr | dg | sn); + + int i = 0; + int j = 8; + while (j < length && i < 8) { + p->data[i] = (s2x(line[j-1])<<4) | s2x(line[j]); + j += 3; + i++; + } + p->dlc = i; +} + +uint32_t decodeFromBytes(int msb_index, int lsb_index, uint8_t data[]) { + uint32_t result = 0; + if (msb_index < lsb_index) + for (int i = msb_index; i <= lsb_index; i++) + result = result << 8 | data[i]; + else + for (int i = msb_index; i >= lsb_index; i--) + result = (result | data[i]) << 8; + return result; +} + +void sprintCANPacket(CANPacket* packet, char* buffer) { + uint8 pri = (packet->id & 0x400) >> 10; + uint8 dg = (packet->id & 0x3C0) >> 6; + uint8 sn = (packet->id & 0x03F) >> 0; + + int len = sprintf(buffer, "%01X %02X %02X ", pri, dg, sn); + for(int i = 0; i < packet->dlc; i++) + len += sprintf(buffer+len," %02X", packet->data[i]); + + sprintf(buffer+len,"\r\n"); +} + + +int main(void) +{ + // intialize the two CAN blocks here + Initialize(); + + // CAN_Start(); + // CAN_1_Start(); + int err; + + // we can read CAN packets and pass it into uart first + for(;;) + { + /* + err = 0; + switch(GetState()) { + case(UNINIT): + SetStateTo(CHECK_CAN); + break; + case(CHECK_CAN): + if (!PollAndReceiveCANPacket(&can_recieve)) { + LED_CAN_Write(ON); + CAN_time_LED = 0; + err = ProcessCAN(&can_recieve, &can_send); + } + if (GetMode() == MODE1) + SetStateTo(DO_MODE1); + else + SetStateTo(CHECK_CAN); + break; + case(DO_MODE1): + // mode 1 tasks + SetStateTo(CHECK_CAN); + break; + default: + err = ERROR_INVALID_STATE; + SetStateTo(UNINIT); + break; + } + + if (err) DisplayErrorCode(err); + + if (DBG_UART_SpiUartGetRxBufferSize()) { + DebugPrint(DBG_UART_UartGetByte()); + } + + CyDelay(100); + */ + + if (CAN_time_LED > 0) { + LED_CAN_Write(0); + CAN_time_LED--; + } else { + LED_CAN_Write(0); + } + + uint32 c = DBG_UART_UartGetChar(); + if (c) { + if (c == '\r') { + parseLine(&can_tx, uart_rx+1, uart_rx_len-1); + if (SendCANPacket(&can_tx) == 0) { + sprintCANPacket(&can_tx, uart_tx); + Print("sent "); + Print(uart_tx); + uart_rx_len = 0; + } else { + Print("Epic FAIL\r\n"); + } + } else { + uart_rx[uart_rx_len] = c; + uart_rx_len++; + } + } + + if (PollAndReceiveCANPacket(&can_rx) == ERROR_NONE) { + sprintCANPacket(&can_rx, uart_tx); + Print(uart_tx); + } + CyDelay(100); + } +} + +void Initialize(void) { + CyGlobalIntEnable; /* Enable global interrupts. LED arrays need this first */ + + // address = getSerialAddress(); + + DBG_UART_Start(); + // sprintf(txData, "Dip Addr: %x \r\n", address); + printf("starting program \n"); + Print(txData); + + LED_DBG_Write(0); + + InitCAN(0x4, (int)address); + Timer_Period_Reset_Start(); + + // isr_Button_1_StartEx(Button_1_Handler); + isr_Period_Reset_StartEx(Period_Reset_Handler); +} + +void DebugPrint(char input) { + switch(input) { + case 'f': + sprintf(txData, "Mode: %x State:%x \r\n", GetMode(), GetState()); + break; + case 'x': + sprintf(txData, "bruh\r\n"); + break; + default: + sprintf(txData, "what\r\n"); + break; + } + Print(txData); +} + +void DisplayErrorCode(uint8_t code) { + ERROR_time_LED = 0; + LED_ERR_Write(ON); + + sprintf(txData, "Error %X\r\n", code); + Print(txData); + + switch(code) + { + case ERROR_INVALID_TTC: + Print("Cannot Send That Data Type!\n\r"); + break; + default: + //some error + break; + } +} + +/* [] END OF FILE */ diff --git a/PSoC Project Template.cydsn/main.h b/CAN_Bridge.cydsn/main.h similarity index 96% rename from PSoC Project Template.cydsn/main.h rename to CAN_Bridge.cydsn/main.h index 3729811..1094fdd 100644 --- a/PSoC Project Template.cydsn/main.h +++ b/CAN_Bridge.cydsn/main.h @@ -1,33 +1,33 @@ -/* ======================================== - * - * Copyright YOUR COMPANY, THE YEAR - * All Rights Reserved - * UNPUBLISHED, LICENSED SOFTWARE. - * - * CONFIDENTIAL AND PROPRIETARY INFORMATION - * WHICH IS THE PROPERTY OF your company. - * - * ======================================== -*/ -#pragma once - -#include "cyapicallbacks.h" -#include - -#define ON 1 -#define OFF 0 - -#define TX_DATA_SIZE (100u) - -#define Print(message) DBG_UART_UartPutString(message) -#define PrintChar(character) DBG_UART_UartPutChar(character) -#define PrintInt(integer) DBG_UART_UartPutString(itoa(integer, txData, 10)) -#define PrintIntBin(integer) DBG_UART_UartPutString(itoa(integer, txData, 2)) - -void Initialize(void); -int getSerialAddress(); -void DebugPrint(char input); -void DisplayErrorCode(uint8_t code); - - -/* [] END OF FILE */ +/* ======================================== + * + * Copyright YOUR COMPANY, THE YEAR + * All Rights Reserved + * UNPUBLISHED, LICENSED SOFTWARE. + * + * CONFIDENTIAL AND PROPRIETARY INFORMATION + * WHICH IS THE PROPERTY OF your company. + * + * ======================================== +*/ +#pragma once + +#include "cyapicallbacks.h" +#include + +#define ON 1 +#define OFF 0 + +#define TX_DATA_SIZE (100u) + +#define Print(message) DBG_UART_UartPutString(message) +#define PrintChar(character) DBG_UART_UartPutChar(character) +#define PrintInt(integer) DBG_UART_UartPutString(itoa(integer, txData, 10)) +#define PrintIntBin(integer) DBG_UART_UartPutString(itoa(integer, txData, 2)) + +void Initialize(void); +int getSerialAddress(); +void DebugPrint(char input); +void DisplayErrorCode(uint8_t code); + + +/* [] END OF FILE */ diff --git a/PSoC Project Template.cywrk b/CAN_Bridge.cywrk similarity index 79% rename from PSoC Project Template.cywrk rename to CAN_Bridge.cywrk index badcc4e..7605971 100644 --- a/PSoC Project Template.cywrk +++ b/CAN_Bridge.cywrk @@ -1,22 +1,22 @@ - - - - - - - - - -.\PSoC Project Template.cydsn\PSoC Project Template.cyprj - - - - - - - - - - - + + + + + + + + + +.\CAN_Bridge.cydsn\CAN_Bridge.cyprj + + + + + + + + + + + \ No newline at end of file diff --git a/ComponentUpdateLog.txt b/ComponentUpdateLog.txt index 929d638..25b5ecb 100644 --- a/ComponentUpdateLog.txt +++ b/ComponentUpdateLog.txt @@ -1,7 +1,7 @@ -Last Modified Date & Time: 12/03/2022 10:42:53 - -PSoC Project Template: PSoC Project Template.cydwr - cy_boot [v6.0] to [v6.10] - LIN_Dynamic [v5.0] to [v6.0] - - +Last Modified Date & Time: 12/03/2022 10:42:53 + +PSoC Project Template: PSoC Project Template.cydwr + cy_boot [v6.0] to [v6.10] + LIN_Dynamic [v5.0] to [v6.0] + + diff --git a/HindsightCAN b/HindsightCAN deleted file mode 160000 index 58fae5b..0000000 --- a/HindsightCAN +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 58fae5bbcb403a0026fa11a54cdabfed9148d697 diff --git a/PSoC Project Template.cydsn/HindsightCAN b/PSoC Project Template.cydsn/HindsightCAN deleted file mode 160000 index 857c34c..0000000 --- a/PSoC Project Template.cydsn/HindsightCAN +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 857c34c4555f4e2f5c097276c2c91caf7ccb9c0a diff --git a/PSoC Project Template.cydsn/TopDesign/TopDesign.cysch b/PSoC Project Template.cydsn/TopDesign/TopDesign.cysch deleted file mode 100644 index 49f12089a8ff577599f203641def8dc2510bbe1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103165 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%0AJN8<*iRSh)vCZoZ#0(t2>@C$8XFvic< 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 diff --git a/PSoC Project Template.cydsn/main.c b/PSoC Project Template.cydsn/main.c deleted file mode 100644 index a158aa9..0000000 --- a/PSoC Project Template.cydsn/main.c +++ /dev/null @@ -1,159 +0,0 @@ -/* ======================================== - * - * Copyright YOUR COMPANY, THE YEAR - * All Rights Reserved - * UNPUBLISHED, LICENSED SOFTWARE. - * - * CONFIDENTIAL AND PROPRIETARY INFORMATION - * WHICH IS THE PROPERTY OF your company. - * - * ======================================== -*/ - -#include -#include -#include -#include -#include "main.h" -#include "cyapicallbacks.h" -#include "CAN_Stuff.h" -#include "FSM_Stuff.h" -#include "HindsightCAN/CANLibrary.h" - -// LED stuff -volatile uint8_t CAN_time_LED = 0; -volatile uint8_t ERROR_time_LED = 0; - -// UART stuff -char txData[TX_DATA_SIZE]; - -// CAN stuff -CANPacket can_recieve; -CANPacket can_send; -uint8 address = 0; - -CY_ISR(Period_Reset_Handler) { - CAN_time_LED++; - ERROR_time_LED++; - - if (ERROR_time_LED >= 3) { - LED_ERR_Write(OFF); - } - if (CAN_time_LED >= 3) { - LED_CAN_Write(OFF); - } -} - -CY_ISR(Button_1_Handler) { - LED_DBG_Write(!LED_DBG_Read()); -} - -int main(void) -{ - Initialize(); - int err; - - for(;;) - { - err = 0; - switch(GetState()) { - case(UNINIT): - SetStateTo(CHECK_CAN); - break; - case(CHECK_CAN): - if (!PollAndReceiveCANPacket(&can_recieve)) { - LED_CAN_Write(ON); - CAN_time_LED = 0; - err = ProcessCAN(&can_recieve, &can_send); - } - if (GetMode() == MODE1) - SetStateTo(DO_MODE1); - else - SetStateTo(CHECK_CAN); - break; - case(DO_MODE1): - // mode 1 tasks - SetStateTo(CHECK_CAN); - break; - default: - err = ERROR_INVALID_STATE; - SetStateTo(UNINIT); - break; - } - - if (err) DisplayErrorCode(err); - - if (DBG_UART_SpiUartGetRxBufferSize()) { - DebugPrint(DBG_UART_UartGetByte()); - } - - CyDelay(100); - } -} - -void Initialize(void) { - CyGlobalIntEnable; /* Enable global interrupts. LED arrays need this first */ - - address = getSerialAddress(); - - DBG_UART_Start(); - sprintf(txData, "Dip Addr: %x \r\n", address); - Print(txData); - - LED_DBG_Write(0); - - InitCAN(0x4, (int)address); - Timer_Period_Reset_Start(); - - isr_Button_1_StartEx(Button_1_Handler); - isr_Period_Reset_StartEx(Period_Reset_Handler); -} - -void DebugPrint(char input) { - switch(input) { - case 'f': - sprintf(txData, "Mode: %x State:%x \r\n", GetMode(), GetState()); - break; - case 'x': - sprintf(txData, "bruh\r\n"); - break; - default: - sprintf(txData, "what\r\n"); - break; - } - Print(txData); -} - -int getSerialAddress() { - int address = 0; - - if (DIP1_Read()==0) address += 1; - if (DIP2_Read()==0) address += 2; - if (DIP3_Read()==0) address += 4; - if (DIP4_Read()==0) address += 8; - - if (address == 0) - address = DEVICE_SERIAL_TELEM_LOCALIZATION; - - return address; -} - -void DisplayErrorCode(uint8_t code) { - ERROR_time_LED = 0; - LED_ERR_Write(ON); - - sprintf(txData, "Error %X\r\n", code); - Print(txData); - - switch(code) - { - case ERROR_INVALID_TTC: - Print("Cannot Send That Data Type!\n\r"); - break; - default: - //some error - break; - } -} - -/* [] END OF FILE */ diff --git a/README.md b/README.md index 7fd072b..13f8b96 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# PSoC Project Template - -Adapt this project to make board firmware! +# PSoC Project Template + +Adapt this project to make board firmware! From 78adc5147669a2cdaab3c8e1253d358dd8f04f4f Mon Sep 17 00:00:00 2001 From: FLinLan Date: Thu, 24 Apr 2025 21:05:02 -0700 Subject: [PATCH 03/10] added CAN to UART tester code --- CAN_Bridge.cydsn/CAN_Bridge.cydwr | 6 ++ CAN_Bridge.cydsn/CAN_Bridge.cyprj | 42 ++++++++++++- CAN_Bridge.cydsn/TopDesign/TopDesign.cysch | Bin 110081 -> 111691 bytes CAN_Bridge.cydsn/main.c | 66 +++++---------------- 4 files changed, 63 insertions(+), 51 deletions(-) diff --git a/CAN_Bridge.cydsn/CAN_Bridge.cydwr b/CAN_Bridge.cydsn/CAN_Bridge.cydwr index c5bae99..09909b5 100644 --- a/CAN_Bridge.cydsn/CAN_Bridge.cydwr +++ b/CAN_Bridge.cydsn/CAN_Bridge.cydwr @@ -27,6 +27,7 @@ + @@ -3902,6 +3903,11 @@
+ + + + + diff --git a/CAN_Bridge.cydsn/CAN_Bridge.cyprj b/CAN_Bridge.cydsn/CAN_Bridge.cyprj index 2767c16..1eb831c 100644 --- a/CAN_Bridge.cydsn/CAN_Bridge.cyprj +++ b/CAN_Bridge.cydsn/CAN_Bridge.cyprj @@ -1765,6 +1765,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2414,7 +2454,7 @@ - + diff --git a/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch b/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch index 4e0dc48cb2c03b30fd4cd8f82b19f2d406f2ea44..89afe3de28551d77ad02b3adbad542d8fead1a74 100644 GIT binary patch delta 20986 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 delta 19591 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 diff --git a/CAN_Bridge.cydsn/main.c b/CAN_Bridge.cydsn/main.c index 0a38e31..43a7f40 100644 --- a/CAN_Bridge.cydsn/main.c +++ b/CAN_Bridge.cydsn/main.c @@ -45,14 +45,13 @@ CANPacket can_rx; uint8 uart_rx_len = 0; - CY_ISR(Period_Reset_Handler) { CAN_time_LED++; ERROR_time_LED++; - - if (ERROR_time_LED >= 3) { + + /*if (ERROR_time_LED >= 3) { LED_ERR_Write(OFF); - } + }*/ if (CAN_time_LED >= 3) { LED_CAN_Write(OFF); } @@ -125,56 +124,18 @@ int main(void) // intialize the two CAN blocks here Initialize(); - // CAN_Start(); - // CAN_1_Start(); - int err; + // int err; // we can read CAN packets and pass it into uart first for(;;) - { - /* - err = 0; - switch(GetState()) { - case(UNINIT): - SetStateTo(CHECK_CAN); - break; - case(CHECK_CAN): - if (!PollAndReceiveCANPacket(&can_recieve)) { - LED_CAN_Write(ON); - CAN_time_LED = 0; - err = ProcessCAN(&can_recieve, &can_send); - } - if (GetMode() == MODE1) - SetStateTo(DO_MODE1); - else - SetStateTo(CHECK_CAN); - break; - case(DO_MODE1): - // mode 1 tasks - SetStateTo(CHECK_CAN); - break; - default: - err = ERROR_INVALID_STATE; - SetStateTo(UNINIT); - break; - } - - if (err) DisplayErrorCode(err); - - if (DBG_UART_SpiUartGetRxBufferSize()) { - DebugPrint(DBG_UART_UartGetByte()); - } - - CyDelay(100); - */ - + { if (CAN_time_LED > 0) { LED_CAN_Write(0); CAN_time_LED--; } else { LED_CAN_Write(0); } - + uint32 c = DBG_UART_UartGetChar(); if (c) { if (c == '\r') { @@ -205,18 +166,22 @@ void Initialize(void) { CyGlobalIntEnable; /* Enable global interrupts. LED arrays need this first */ // address = getSerialAddress(); - - DBG_UART_Start(); + // CAN_Start(); + // CAN_1_Start(); + + // DBG_UART_Start(); + // DBG_UART_1_Start(); + // sprintf(txData, "Dip Addr: %x \r\n", address); printf("starting program \n"); Print(txData); + // make these LED + LED_DBG_Write(0); InitCAN(0x4, (int)address); Timer_Period_Reset_Start(); - - // isr_Button_1_StartEx(Button_1_Handler); isr_Period_Reset_StartEx(Period_Reset_Handler); } @@ -237,7 +202,8 @@ void DebugPrint(char input) { void DisplayErrorCode(uint8_t code) { ERROR_time_LED = 0; - LED_ERR_Write(ON); + // LED_ERR_Write(ON); + // LED_DBG_1_Write(ON); sprintf(txData, "Error %X\r\n", code); Print(txData); From 0e9c3504cb4cd8ed5e3fdbbcd226459b12846e6b Mon Sep 17 00:00:00 2001 From: FLinLan Date: Sat, 26 Apr 2025 11:37:08 -0700 Subject: [PATCH 04/10] most current version --- CAN_Bridge.cydsn/main.c | 138 ++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 63 deletions(-) diff --git a/CAN_Bridge.cydsn/main.c b/CAN_Bridge.cydsn/main.c index 43a7f40..9f96bdf 100644 --- a/CAN_Bridge.cydsn/main.c +++ b/CAN_Bridge.cydsn/main.c @@ -37,6 +37,8 @@ char txData[TX_DATA_SIZE]; CANPacket can_recieve; CANPacket can_send; uint8 address = 0; + +// from CAN packet char8 uart_tx[64]; char8 uart_rx[64]; CANPacket can_tx; @@ -44,14 +46,13 @@ CANPacket can_rx; uint8 uart_rx_len = 0; - CY_ISR(Period_Reset_Handler) { CAN_time_LED++; ERROR_time_LED++; - /*if (ERROR_time_LED >= 3) { + if (ERROR_time_LED >= 3) { LED_ERR_Write(OFF); - }*/ + } if (CAN_time_LED >= 3) { LED_CAN_Write(OFF); } @@ -118,15 +119,84 @@ void sprintCANPacket(CANPacket* packet, char* buffer) { sprintf(buffer+len,"\r\n"); } +void DebugPrint(char input) { + switch(input) { + case 'f': + sprintf(txData, "Mode: %x State:%x \r\n", GetMode(), GetState()); + break; + case 'x': + sprintf(txData, "bruh\r\n"); + break; + default: + sprintf(txData, "what\r\n"); + break; + } + Print(txData); +} + +void DisplayErrorCode(uint8_t code) { + ERROR_time_LED = 0; + LED_ERR_Write(ON); + // LED_DBG_1_Write(ON); + + sprintf(txData, "Error %X\r\n", code); + Print(txData); + + switch(code) + { + case ERROR_INVALID_TTC: + Print("Cannot Send That Data Type!\n\r"); + break; + default: + //some error + break; + } +} + +// remove a occurrences of serial address, since not mentioned on the board +void Initialize(void) { + CyGlobalIntEnable; /* Enable global interrupts. LED arrays need this first */ + + // address = getSerialAddress(); + CAN_Start(); + CAN_1_Start(); + + DBG_UART_Start(); + DBG_UART_1_Start(); + + Print(txData); + + // LED_DBG_Write(0); + + // InitCAN(0x4, (int)address); + // InitCAN(); + + Timer_Period_Reset_Start(); + isr_Period_Reset_StartEx(Period_Reset_Handler); +} + int main(void) { // intialize the two CAN blocks here + /*for (int i = 0; i < 10000; i++) { + LED_CAN_Write(0); + CyDelay(100); + LED_CAN_Write(1); + }*/ + Initialize(); - + // toggle for debugging + // int err; - // we can read CAN packets and pass it into uart first + Print("format:\r\n"); + Print("X XX XX XX XX XX XX XX XX XX XX\r\n"); + Print("p | | | | | | | | | |\r\n"); + Print(" dg | | | | | | | | |\r\n"); + Print(" sn | | | | | | | |\r\n"); + Print(" 0 1 2 3 4 5 6 7 (data)\r\n"); + for(;;) { if (CAN_time_LED > 0) { @@ -161,62 +231,4 @@ int main(void) CyDelay(100); } } - -void Initialize(void) { - CyGlobalIntEnable; /* Enable global interrupts. LED arrays need this first */ - - // address = getSerialAddress(); - // CAN_Start(); - // CAN_1_Start(); - - // DBG_UART_Start(); - // DBG_UART_1_Start(); - - // sprintf(txData, "Dip Addr: %x \r\n", address); - printf("starting program \n"); - Print(txData); - - // make these LED - - LED_DBG_Write(0); - - InitCAN(0x4, (int)address); - Timer_Period_Reset_Start(); - isr_Period_Reset_StartEx(Period_Reset_Handler); -} - -void DebugPrint(char input) { - switch(input) { - case 'f': - sprintf(txData, "Mode: %x State:%x \r\n", GetMode(), GetState()); - break; - case 'x': - sprintf(txData, "bruh\r\n"); - break; - default: - sprintf(txData, "what\r\n"); - break; - } - Print(txData); -} - -void DisplayErrorCode(uint8_t code) { - ERROR_time_LED = 0; - // LED_ERR_Write(ON); - // LED_DBG_1_Write(ON); - - sprintf(txData, "Error %X\r\n", code); - Print(txData); - - switch(code) - { - case ERROR_INVALID_TTC: - Print("Cannot Send That Data Type!\n\r"); - break; - default: - //some error - break; - } -} - /* [] END OF FILE */ From 53d6a6e99b8d3ba8f08f3688e5bc5318101227f6 Mon Sep 17 00:00:00 2001 From: FLinLan Date: Sat, 26 Apr 2025 12:50:09 -0700 Subject: [PATCH 05/10] get data sent through CAN --- CAN_Bridge.cydsn/CAN_Bridge.cyprj | 52 +++++++++++++++++++++ CAN_Bridge.cydsn/TopDesign/TopDesign.cysch | Bin 111691 -> 111719 bytes CAN_Bridge.cydsn/main.c | 37 +++++++++------ 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/CAN_Bridge.cydsn/CAN_Bridge.cyprj b/CAN_Bridge.cydsn/CAN_Bridge.cyprj index 1eb831c..1514486 100644 --- a/CAN_Bridge.cydsn/CAN_Bridge.cyprj +++ b/CAN_Bridge.cydsn/CAN_Bridge.cyprj @@ -1805,6 +1805,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch b/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch index 89afe3de28551d77ad02b3adbad542d8fead1a74..aabf7dc29422f36a70ad62de087e3ba576944795 100644 GIT binary patch delta 5693 zcmeI0dr(wW9LMkX!tBDbyc7Zz1(wCqQd!b=5fu~!pBUv-DB&YC#e88nh9=^mP>yM{ z+E2qq(Z&a23Y%VEgfM1fzScCILdPDCU}L6PjiWQx*|U4$*v-kD{KFZC;qKng`Tc(P z-1GgNbAD%!H0zq0bvp(`%8JfDPwwCt6L~4pr(fbvhTluhm)S3*hC0S4oe9)0ha^Q^ z@Np!Km^aKfu3nOS1`PVXxBX!GUVp0;FSY#JfB7TKv3|{~GM3e>{VE9Yj#Jyq0`aUp zyROWurxfRCsw*_wlTR8QQ;*hr!D8>>EVFla8tnDXV)SyPoIExp+W%JsNs=^J%8*7% z1Em+(XMbs!6mxDUqpYzzjf+5-VvWFWIs?1+X4obbC~+|u0l93k@#! zTYfZd9MW9INmG$G?S^k_xLq2b-JI-USM`zmIJqWx)p8=nspCZKXgw!)e5rUm(rjYO z5smjTjrR#ooPM-qEut)J_SDH{PTYE2dyLU9+;`A5PtDC~a4%S0j3K&zI&fTc+zV8{*;Em4I64 zbu55Iil;-pu}=0iD3cPAr7G8+rnP~dF80B97^ZyQ7yZ1kK=B@c0zYL$HjE(aK!kg~ zj!tX&T9mGSRW4_u)~M#l-W--Ar|EnSl5tw;GzOjF$&EXLEMjh$WH$7M4Tz%kV-ZS+ z$0FR5EhhPzFF7Z|6h?I-BNc zeAe=nGlX8rL$rRDziS?sQ1yJa8h?-nGiE9K@*avd`H!{1KWLM}HqMN@wdtjA;Ifpt zWqEA|lchl^oAFR&sedfX-(;ySz%m3=|JiK22v!!(#uyoi$`5le0SHnC6(UR4j|y_I+lozML9>B@W@Ci5B=@K6ypBVC!k0Aqof3M;1i z%9u$3CD^U6=J7ss$7?EK@v0S{MaTzs(A>pXtaoyQCYM1tMU}D*&8ei6VwDajlygfl z)w{@F*vSL=W-XQ&!5Y$5Lqa+6Wo3_A5rk=M+G$7!Hz^Xf(vBLVNDYbBkQfb#)sQDO zq>G0Xwf6dHjZrrZ>7gMOPU6{Befypoo98sdrjnu-x858jva1@XFDLy3lFUhefuwMf zDv&fz(giY@lOX~b#)(VlJoRB299$@;o*aS%ol4U5Peo4VSl)rTl7Ix{^(*)ynae z4`nS}75KP(xO+`ORb=r z9`*6>ES}WvRY9|pX0ShU8N$%(js&*J1w zc2)Z_TjMoH<5kGXT*2#Yw+&@%L2!upfMVXT&`7hkpl4fgaevq2a(xVXsfz;nS0X$_ ze2Ep@ioIq+B_h058711@7oj1gY*^JEm%9TQsJId)oA`(dPfM%q22MU^SJitXC+q=@ z%=@mcSE((*TiM8pFIB@^972?xoa_?FZcfDB?Bzs^vtMKLna1XT+eWOO8Z<@+HGvLs z@&&u9FM61hF9mXx6S0fOIT5?){^PPZoOhZ Jg~{7R{sP~zQSSf% delta 6441 zcmeI0c~F#f7{}l5N-W?49;6&5*J|ZB${{P52!UdXj7Q^yM}meOC<>NFgf4hN2;3^X~h8e$Vr} zzR&Oc@rv&kSA5^gh%}A%b(EVToOzL#BmF8i|K?h~=(}pixuN$vr=@)pY%YSLM4j_> zrj0Hi<)438Q7Y1Q44>*aTKj%rvXZRCD+%IfbNqa>yL0WTCrzl@{Z4ZyBsx#-tPVzk zWAdSDNBRki^ZKC@ONRkUoU`Eg=N*{$Z>o0mYYK22ZmLAQGxJ2l$os6WjRA_*kA9b`d)~_4EmuLUZ?a` zaHu{H;)cmo*pc3N7+qCMA2gUTlg`8=3Ad?J0tVx@nv;N7pn^&g@j%~2BD*qfaO~M^ z#hvvML2meaNtMTjuCGO5NQ;zGqo>SThjHNx1Kj?%nCW?~(bG|cEYl5tN_!iHv*gnD z3JX>8*)Pa-sgw@{k!y575ILVig2;6{?6INfS;)$iy}vMcHwe4s=@dt-S~|)m_i!{BHu6D;_k@jG>v1D zS>tTVOh#3h)2!Dp@E7>7TyvCCwp`^)7m|^Ht!lRv9Du(cr`R||`_Y*}Si}9UmOp|C z9?c_YRu`D*)?l2+NcD6ohWMaV4b8yZj%v{;_<^#AA=L9aJBwc|)ay6nX+!4Oq+<5-Q(YZt1`u*jOm(% zzE8vew~k}xZ~+U}!TLv0qXXMT_4dHsiW)pr$xw##D9I8FgHSigT*7^9buD%e=WevS z5LT3^rwZFx;d^PzT`+eqeb z=VCGMF`t}=bOft!&qJOGgVdH%Ob3G0f-+1nA(sx8b8@bFryPMWJrP8Q`|u23T81F% zzW`(|4sy=`%iW<7N|zQO2F2uO$7lGEn(f$!EOl80@`2gvPnAeDVK((yjD6;v!fmDI zh9&H_Q?)L^9AF30QY=Ly^{nE88`ZojtnfvHdh1mb`Pg}X+`3W+c{WR4(#b%&7)XeL zbTg1p0}0oNUF!NC2BV$^5@jGU24Xdk-UjlJhuFPs?PDLV&NWEHfZ>HDfTo=73#LC?UV9eOVP7nM$y zhvMHkn^T+(Q4d*N|Jq@k<&4!gMJaWBsIk$cI$oh{w5kr3d?V9yEmpR@V){)=Qm6m> zxRh^r?q*zG+=vGPMu~ff9DdT&TE1>u%H3;q9oGhA#wH$+OX;ais2b?t3k7{X%oR>E zTJK$~u8D%2<=YqCX0jlm6ulXR;ZKPVIi#lx;vYbc&4_WIS5^N1!%2U($HJRsi6C?M zsTcBsAacI*3|^&zyd-(OZ19?|c~R~bbPlPIOc#1gY5o=rpd(vg^F+4!HIdRnmaT}5 zlxy&&mY1|{E~osh=-zvY6uEC1jB53gmTg5$vcKeBCsNk(Q*ZWqkFA$%6ok9;5_^Zp z)!DA6L~P>@-X-PY6e)WovR4qJ2?6 z$fpwdToAd6#|4qA*eJ-C!fP0x()l*53;&H$hEdLTbPt#*)|Qi;uEl(#i1~9`%x~Dv zG2f_uvi;s{I~t@QY2SAI^XYA}dTSRVfFufWVhI23a3TyTROIBPDn)#mQ#-rox?P&? XSDdVSs+RDmNNCa$GWQ_L$4!0*w)zhR diff --git a/CAN_Bridge.cydsn/main.c b/CAN_Bridge.cydsn/main.c index 9f96bdf..bd212d8 100644 --- a/CAN_Bridge.cydsn/main.c +++ b/CAN_Bridge.cydsn/main.c @@ -29,14 +29,15 @@ // LED stuff volatile uint8_t CAN_time_LED = 0; volatile uint8_t ERROR_time_LED = 0; +uint8 uart_rx_len = 0; // UART stuff char txData[TX_DATA_SIZE]; // CAN stuff -CANPacket can_recieve; -CANPacket can_send; -uint8 address = 0; +//CANPacket can_recieve; +// CANPacket can_send; +// uint8 address = 0; // from CAN packet char8 uart_tx[64]; @@ -44,18 +45,18 @@ char8 uart_rx[64]; CANPacket can_tx; CANPacket can_rx; -uint8 uart_rx_len = 0; + CY_ISR(Period_Reset_Handler) { CAN_time_LED++; ERROR_time_LED++; - if (ERROR_time_LED >= 3) { + /*if (ERROR_time_LED >= 3) { LED_ERR_Write(OFF); } if (CAN_time_LED >= 3) { LED_CAN_Write(OFF); - } + }*/ } /* @@ -96,7 +97,7 @@ void parseLine(CANPacket* p, char8 line[], int length) { p->dlc = i; } -uint32_t decodeFromBytes(int msb_index, int lsb_index, uint8_t data[]) { +/*uint32_t decodeFromBytes(int msb_index, int lsb_index, uint8_t data[]) { uint32_t result = 0; if (msb_index < lsb_index) for (int i = msb_index; i <= lsb_index; i++) @@ -105,13 +106,13 @@ uint32_t decodeFromBytes(int msb_index, int lsb_index, uint8_t data[]) { for (int i = msb_index; i >= lsb_index; i--) result = (result | data[i]) << 8; return result; -} +}*/ void sprintCANPacket(CANPacket* packet, char* buffer) { uint8 pri = (packet->id & 0x400) >> 10; uint8 dg = (packet->id & 0x3C0) >> 6; uint8 sn = (packet->id & 0x03F) >> 0; - + int len = sprintf(buffer, "%01X %02X %02X ", pri, dg, sn); for(int i = 0; i < packet->dlc; i++) len += sprintf(buffer+len," %02X", packet->data[i]); @@ -137,11 +138,12 @@ void DebugPrint(char input) { void DisplayErrorCode(uint8_t code) { ERROR_time_LED = 0; LED_ERR_Write(ON); - // LED_DBG_1_Write(ON); + + Print("check if code is entering this block"); sprintf(txData, "Error %X\r\n", code); Print(txData); - + switch(code) { case ERROR_INVALID_TTC: @@ -158,12 +160,13 @@ void Initialize(void) { CyGlobalIntEnable; /* Enable global interrupts. LED arrays need this first */ // address = getSerialAddress(); + InitCAN(0x04, 0xF5); CAN_Start(); CAN_1_Start(); DBG_UART_Start(); DBG_UART_1_Start(); - + Print(txData); // LED_DBG_Write(0); @@ -187,7 +190,7 @@ int main(void) Initialize(); // toggle for debugging - + // int err; // we can read CAN packets and pass it into uart first Print("format:\r\n"); @@ -199,12 +202,12 @@ int main(void) for(;;) { - if (CAN_time_LED > 0) { + /*if (CAN_time_LED > 0) { LED_CAN_Write(0); CAN_time_LED--; } else { LED_CAN_Write(0); - } + }*/ uint32 c = DBG_UART_UartGetChar(); if (c) { @@ -215,6 +218,9 @@ int main(void) Print("sent "); Print(uart_tx); uart_rx_len = 0; + LED_CAN_Write(0); + CyDelay(10); + LED_CAN_Write(1); } else { Print("Epic FAIL\r\n"); } @@ -225,6 +231,7 @@ int main(void) } if (PollAndReceiveCANPacket(&can_rx) == ERROR_NONE) { + LED_CAN_Write(0); sprintCANPacket(&can_rx, uart_tx); Print(uart_tx); } From 8bbc82bba815f31ac7cb101ea63f8511d175c097 Mon Sep 17 00:00:00 2001 From: FLinLan Date: Sun, 4 May 2025 13:36:46 -0700 Subject: [PATCH 06/10] added better packaging logic for parsing the CAN packets --- CAN_Bridge.cydsn/CAN_Bridge.cyprj | 848 +++++++++++------------------- CAN_Bridge.cydsn/main.c | 31 +- 2 files changed, 328 insertions(+), 551 deletions(-) diff --git a/CAN_Bridge.cydsn/CAN_Bridge.cyprj b/CAN_Bridge.cydsn/CAN_Bridge.cyprj index 1514486..a35a98e 100644 --- a/CAN_Bridge.cydsn/CAN_Bridge.cyprj +++ b/CAN_Bridge.cydsn/CAN_Bridge.cyprj @@ -457,35 +457,35 @@ - - + + - - + + - - + + - - + + - - + + @@ -497,35 +497,35 @@ - - + + - - + + - - + + - - + + - - + + @@ -537,35 +537,35 @@ - - + + - - + + - - + + - - + + - - + + @@ -577,35 +577,35 @@ - - + + - - + + - - + + - - + + - - + + @@ -617,39 +617,58 @@ - + - + - + - + - + + + + + + + + + + + + + - + + + + + + + + @@ -657,39 +676,102 @@ - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -697,34 +779,34 @@ - + - + - + - + - + @@ -737,27 +819,34 @@ - + - + - + - + + + + + + + + @@ -770,25 +859,39 @@ - + - + - + + + + + + + + + + + + + + + @@ -796,35 +899,42 @@ - - + + - - + + - - + + - - + + - + + + + + + + + - - + + @@ -836,25 +946,39 @@ - - + + - - + + - - + + + + + + + + + + + + + + + + @@ -928,6 +1052,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1020,318 +1170,25 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - + - - - - - - - @@ -1339,34 +1196,34 @@ - + - + - + - + - + @@ -1379,46 +1236,25 @@ - + - + - + - - - - - - - - - - - - - - - - - - - - - @@ -1426,34 +1262,34 @@ - + - + - + - + - + @@ -1518,206 +1354,170 @@ - + - - - - - - - - + - + - + - + - + - - - - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + - + - + - + - - - - - - - - + + - - + + + - + - + - + - + - + - + @@ -1727,34 +1527,20 @@ - + - - - - - - - - - - - - - - - + - + @@ -1767,39 +1553,25 @@ - + - + - - - - - - - - + - - - - - - - @@ -1807,20 +1579,20 @@ - + - + - + @@ -1831,32 +1603,34 @@ - - - + + - - + + + - + - + - + - + + + + + + + + - - - - - diff --git a/CAN_Bridge.cydsn/main.c b/CAN_Bridge.cydsn/main.c index bd212d8..3935fc4 100644 --- a/CAN_Bridge.cydsn/main.c +++ b/CAN_Bridge.cydsn/main.c @@ -179,14 +179,10 @@ void Initialize(void) { } + int main(void) { // intialize the two CAN blocks here - /*for (int i = 0; i < 10000; i++) { - LED_CAN_Write(0); - CyDelay(100); - LED_CAN_Write(1); - }*/ Initialize(); // toggle for debugging @@ -202,12 +198,12 @@ int main(void) for(;;) { - /*if (CAN_time_LED > 0) { + if (CAN_time_LED > 0) { LED_CAN_Write(0); CAN_time_LED--; } else { LED_CAN_Write(0); - }*/ + } uint32 c = DBG_UART_UartGetChar(); if (c) { @@ -217,10 +213,6 @@ int main(void) sprintCANPacket(&can_tx, uart_tx); Print("sent "); Print(uart_tx); - uart_rx_len = 0; - LED_CAN_Write(0); - CyDelay(10); - LED_CAN_Write(1); } else { Print("Epic FAIL\r\n"); } @@ -230,11 +222,22 @@ int main(void) } } - if (PollAndReceiveCANPacket(&can_rx) == ERROR_NONE) { - LED_CAN_Write(0); + int rx_result = PollAndReceiveCANPacket(&can_rx); + if (rx_result == ERROR_NONE) { + + LED_CAN_Write(1); // Turn LED OFF (active low) sprintCANPacket(&can_rx, uart_tx); Print(uart_tx); - } + + } /*else { + // Periodically show error code (not on every loop to avoid flooding UART) + static uint32_t error_print_counter = 0; + if (error_print_counter++ % 100 == 0) { // Print every 100th error + sprintf(uart_tx, "CAN RX Error: 0x%02X\r\n", rx_result); + Print(uart_tx); + } + }*/ + CyDelay(100); } } From f10ceeec36431d2b313b789c1d2628803f9df0d8 Mon Sep 17 00:00:00 2001 From: FLinLan Date: Tue, 6 May 2025 18:47:01 -0700 Subject: [PATCH 07/10] added print testers for data bytes sent, changed data order to little endian --- CAN_Bridge.cydsn/HindsightCAN/Port.h | 4 +- .../PortFiles/PortPSOC_CY8C4248AZI_L485.c | 13 ++++ CAN_Bridge.cydsn/TopDesign/TopDesign.cysch | Bin 111719 -> 111711 bytes CAN_Bridge.cydsn/main.c | 60 ++++++++++++++++-- 4 files changed, 71 insertions(+), 6 deletions(-) diff --git a/CAN_Bridge.cydsn/HindsightCAN/Port.h b/CAN_Bridge.cydsn/HindsightCAN/Port.h index 089efe1..71ddb52 100644 --- a/CAN_Bridge.cydsn/HindsightCAN/Port.h +++ b/CAN_Bridge.cydsn/HindsightCAN/Port.h @@ -17,8 +17,8 @@ #include "CANPacket.h" - -void InitCAN(int deviceGroup, int deviceAddress); +void InitCAN(); +// void InitCAN(int deviceGroup, int deviceAddress); //TODO: define constants for these error codes //Returns 0x0 for successful send diff --git a/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortPSOC_CY8C4248AZI_L485.c b/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortPSOC_CY8C4248AZI_L485.c index db7c81f..c31a319 100644 --- a/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortPSOC_CY8C4248AZI_L485.c +++ b/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortPSOC_CY8C4248AZI_L485.c @@ -37,6 +37,18 @@ CY_ISR_PROTO(CAN_FLAG_ISR); int deviceAddress; int deviceGroup; CAN_RX_CFG rxMailbox; + +void InitCAN() { + rxMailbox.rxmailbox = CAN_RX_MAILBOX_0; + rxMailbox.rxacr = 0x00000000; // acceptance code + rxMailbox.rxamr = 0xFFFFFFFF; // accept all IDs + CAN_RxBufConfig(&rxMailbox); + CAN_GlobalIntEnable(); + CyIntSetVector(CAN_ISR_NUMBER, CAN_FLAG_ISR); +} + + +/* void InitCAN(int deviceGroupInput, int deviceAddressInput) { CAN_Start();//must name CAN Top Design block as "CAN" @@ -71,6 +83,7 @@ void InitCAN(int deviceGroupInput, int deviceAddressInput) //CY_ISR_PROTO(CAN_FLAG_ISR); } +*/ int SendCANPacket(CANPacket *packetToSend) { if(!packetToSend) {return ERROR_NULL_POINTER;} diff --git a/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch b/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch index aabf7dc29422f36a70ad62de087e3ba576944795..3f688453020a66e6d5f9ff292eedf35ad10294d0 100644 GIT binary patch literal 111711 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 literal 111719 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 V(G<|T=#8Q1``U{hbhe5D{(t2N> (8*i)) & 0xFF; + } + // two extra zero bytes + cmd.data[4] = 0; + cmd.data[5] = 0; + + + + if (SendCANPacket(&cmd) == ERROR_NONE) { + int len = sprintf(odrivePacket, "ID=0x%03X DLC=%u DATA=", cmd.id, cmd.dlc); + // now append each data byte in hex + for (int i = 0; i < cmd.dlc; ++i) { + len += sprintf(odrivePacket + len, "%02X ", cmd.data[i]); + } + // print it out + Print(odrivePacket); + Print("\r\n"); + Print("ODrive velocity command sent\r\n"); + } else { + Print("Send error\r\n"); + } + + for(;;) { + // optionally poll for responses + if (PollAndReceiveCANPacket(&cmd) == ERROR_NONE) { + LED_CAN_1_Write(0); + sprintCANPacket(&cmd, uart_tx); + Print(uart_tx); + LED_CAN_1_Write(1); + } + } +} + + /* [] END OF FILE */ From d7ad501df9b713956514a4285d93c9aca6cdfb60 Mon Sep 17 00:00:00 2001 From: FLinLan Date: Sat, 10 May 2025 12:20:20 -0700 Subject: [PATCH 08/10] pushing right now because I'm about to make some major changes to the firmware --- CAN_Bridge.cydsn/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CAN_Bridge.cydsn/main.c b/CAN_Bridge.cydsn/main.c index 990e1f6..7222a76 100644 --- a/CAN_Bridge.cydsn/main.c +++ b/CAN_Bridge.cydsn/main.c @@ -265,8 +265,6 @@ int main() { cmd.data[4] = 0; cmd.data[5] = 0; - - if (SendCANPacket(&cmd) == ERROR_NONE) { int len = sprintf(odrivePacket, "ID=0x%03X DLC=%u DATA=", cmd.id, cmd.dlc); // now append each data byte in hex @@ -293,4 +291,4 @@ int main() { } -/* [] END OF FILE */ +/* [] END OF FILE */ \ No newline at end of file From 92403054f1fdd8da6bb938589915086b7d019533 Mon Sep 17 00:00:00 2001 From: FLinLan Date: Sun, 11 May 2025 12:34:37 -0700 Subject: [PATCH 09/10] changed baud rate of CAN blocks to 250kbps to fit the Odrive data rate --- .../PortFiles/PortPSOC_CY8C4248AZI_L485.c | 2 +- CAN_Bridge.cydsn/main.c | 290 +++--------------- 2 files changed, 43 insertions(+), 249 deletions(-) diff --git a/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortPSOC_CY8C4248AZI_L485.c b/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortPSOC_CY8C4248AZI_L485.c index c31a319..2869a37 100644 --- a/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortPSOC_CY8C4248AZI_L485.c +++ b/CAN_Bridge.cydsn/HindsightCAN/PortFiles/PortPSOC_CY8C4248AZI_L485.c @@ -105,7 +105,7 @@ int SendCANPacket(CANPacket *packetToSend) return ERROR_GENERIC_ERROR; } } -// + int PollAndReceiveCANPacket(CANPacket *receivedPacket) { if(!receivedPacket) { diff --git a/CAN_Bridge.cydsn/main.c b/CAN_Bridge.cydsn/main.c index 7222a76..58f4307 100644 --- a/CAN_Bridge.cydsn/main.c +++ b/CAN_Bridge.cydsn/main.c @@ -1,294 +1,88 @@ -/* ======================================== - * - * Copyright YOUR COMPANY, THE YEAR - * All Rights Reserved - * UNPUBLISHED, LICENSED SOFTWARE. - * - * CONFIDENTIAL AND PROPRIETARY INFORMATION - * WHICH IS THE PROPERTY OF your company. - * - * ======================================== -*/ - #include #include #include #include +#include #include "main.h" #include "cyapicallbacks.h" #include "CAN_Stuff.h" #include "FSM_Stuff.h" #include "HindsightCAN/CANLibrary.h" -#define UNKNOWN_PACKET 0xFFFF - -// testing out the headers -#include "cytypes.h" -#include "cyfitter.h" -#include "cydevice_trm.h" - -// LED stuff -volatile uint8_t CAN_time_LED = 0; -volatile uint8_t ERROR_time_LED = 0; -uint8 uart_rx_len = 0; - -// UART stuff -char txData[TX_DATA_SIZE]; -// CAN stuff -//CANPacket can_recieve; -// CANPacket can_send; -// uint8 address = 0; +// Define node_id as per Odrive configuration +#define NODE_ID 0x3F // 63 -// from CAN packet +// Buffer for UART output char8 uart_tx[64]; -char8 uart_rx[64]; -CANPacket can_tx; -CANPacket can_rx; - - - -CY_ISR(Period_Reset_Handler) { - CAN_time_LED++; - ERROR_time_LED++; - - /*if (ERROR_time_LED >= 3) { - LED_ERR_Write(OFF); - } - if (CAN_time_LED >= 3) { - LED_CAN_Write(OFF); - }*/ -} - -/* -CY_ISR(Button_1_Handler) { - LED_DBG_Write(!LED_DBG_Read()); -} -*/ - -uint8 s2x(char8 c) { - switch(c) { - case '1': return 1; case '2': return 2; - case '3': return 3; case '4': return 4; - case '5': return 5; case '6': return 6; - case '7': return 7; case '8': return 8; - case '9': return 9; case 'A': return 10; - case 'B': return 11;case 'C': return 12; - case 'D': return 13;case 'E': return 14; - case 'F': return 15;case 'a': return 10; - case 'b': return 11;case 'c': return 12; - case 'd': return 13;case 'e': return 14; - case 'f': return 15;default: return 0; - } -} - -void parseLine(CANPacket* p, char8 line[], int length) { - uint16 pr = (uint16) s2x(line[0]) << 10; - uint16 dg = (uint16) s2x(line[2]) << 6; - uint16 sn = (uint16) s2x(line[4]) << 4 | s2x(line[5]); - p->id = (pr | dg | sn); - - int i = 0; - int j = 8; - while (j < length && i < 8) { - p->data[i] = (s2x(line[j-1])<<4) | s2x(line[j]); - j += 3; - i++; - } - p->dlc = i; -} - -/*uint32_t decodeFromBytes(int msb_index, int lsb_index, uint8_t data[]) { - uint32_t result = 0; - if (msb_index < lsb_index) - for (int i = msb_index; i <= lsb_index; i++) - result = result << 8 | data[i]; - else - for (int i = msb_index; i >= lsb_index; i--) - result = (result | data[i]) << 8; - return result; -}*/ void sprintCANPacket(CANPacket* packet, char* buffer) { - uint8 pri = (packet->id & 0x400) >> 10; - uint8 dg = (packet->id & 0x3C0) >> 6; - uint8 sn = (packet->id & 0x03F) >> 0; + // Extract priority (bit 10), device group (bits 9:6), and serial number (bits 5:0) + uint8 pri = (packet->id & 0x400) >> 10; // Bit 10 + uint8 dg = (packet->id & 0x3C0) >> 6; // Bits 9:6 + uint8 sn = (packet->id & 0x03F); // Bits 5:0 + // Format ID components into buffer int len = sprintf(buffer, "%01X %02X %02X ", pri, dg, sn); - for(int i = 0; i < packet->dlc; i++) - len += sprintf(buffer+len," %02X", packet->data[i]); - - sprintf(buffer+len,"\r\n"); -} - -void DebugPrint(char input) { - switch(input) { - case 'f': - sprintf(txData, "Mode: %x State:%x \r\n", GetMode(), GetState()); - break; - case 'x': - sprintf(txData, "bruh\r\n"); - break; - default: - sprintf(txData, "what\r\n"); - break; - } - Print(txData); -} - -void DisplayErrorCode(uint8_t code) { - ERROR_time_LED = 0; - LED_ERR_Write(ON); - Print("check if code is entering this block"); - - sprintf(txData, "Error %X\r\n", code); - Print(txData); - - switch(code) - { - case ERROR_INVALID_TTC: - Print("Cannot Send That Data Type!\n\r"); - break; - default: - //some error - break; + // Append data bytes in hex format + for (int i = 0; i < packet->dlc; i++) { + len += sprintf(buffer + len, " %02X", packet->data[i]); } + + // Add newline + sprintf(buffer + len, "\r\n"); } -// remove a occurrences of serial address, since not mentioned on the board void Initialize(void) { - CyGlobalIntEnable; /* Enable global interrupts. LED arrays need this first */ - - // address = getSerialAddress(); - InitCAN(0x04, 0xF5); + CyGlobalIntEnable; // Enable global interrupts + InitCAN(); // Set up CAN interface CAN_Start(); CAN_1_Start(); - DBG_UART_Start(); DBG_UART_1_Start(); - - Print(txData); - - // LED_DBG_Write(0); - - // InitCAN(0x4, (int)address); - // InitCAN(); - - Timer_Period_Reset_Start(); - isr_Period_Reset_StartEx(Period_Reset_Handler); } -/*int main(void) -{ - // intialize the two CAN blocks here - - Initialize(); - // toggle for debugging - - // int err; - // we can read CAN packets and pass it into uart first - Print("format:\r\n"); - Print("X XX XX XX XX XX XX XX XX XX XX\r\n"); - Print("p | | | | | | | | | |\r\n"); - Print(" dg | | | | | | | | |\r\n"); - Print(" sn | | | | | | | |\r\n"); - Print(" 0 1 2 3 4 5 6 7 (data)\r\n"); - - for(;;) - { - if (CAN_time_LED > 0) { - LED_CAN_Write(0); - CAN_time_LED--; - } else { - LED_CAN_Write(0); - } - - uint32 c = DBG_UART_UartGetChar(); - if (c) { - if (c == '\r') { - parseLine(&can_tx, uart_rx+1, uart_rx_len-1); - if (SendCANPacket(&can_tx) == 0) { - sprintCANPacket(&can_tx, uart_tx); - Print("sent "); - Print(uart_tx); - } else { - Print("Epic FAIL\r\n"); - } - } else { - uart_rx[uart_rx_len] = c; - uart_rx_len++; - } - } - - int rx_result = PollAndReceiveCANPacket(&can_rx); - if (rx_result == ERROR_NONE) { - - LED_CAN_Write(1); // Turn LED OFF (active low) - sprintCANPacket(&can_rx, uart_tx); - Print(uart_tx); - - } /*else { - // Periodically show error code (not on every loop to avoid flooding UART) - static uint32_t error_print_counter = 0; - if (error_print_counter++ % 100 == 0) { // Print every 100th error - sprintf(uart_tx, "CAN RX Error: 0x%02X\r\n", rx_result); - Print(uart_tx); - } - } - - CyDelay(100); - } -} -*/ -char odrivePacket[64]; int main() { - CyGlobalIntEnable; - - // initialize the CAN block - CAN_Start(); // PSoC-Designer name for the CAN Top-Level - CAN_1_Start(); // if you have a second instance - InitCAN(); // our helper: sets up mailbox 0, mask=0, IRQ, etc. - - DBG_UART_Start(); // for debug prints + Initialize(); Print("CAN initialized\r\n"); - - // now send a test command + + // Send Set_Input_Vel command CANPacket cmd; - cmd.id = (0x04 << 4) | 0x0D; // node_id=0x01 (axis 0), cmd_id=0x0D (Set Input Velocity) - cmd.dlc = 6; // ODrive velocity packets use 6 bytes - // fill 6‐byte little endian velocity, e.g. 10000 → 0x002710 - int32_t velocity = 10000; - for (int i = 0; i < 4; ++i) { - cmd.data[i] = (velocity >> (8*i)) & 0xFF; - } - // two extra zero bytes - cmd.data[4] = 0; - cmd.data[5] = 0; + uint8_t cmd_id = 0x0D; // Set_Input_Vel + cmd.id = (NODE_ID << 5) | cmd_id; // CAN ID: (node_id << 5) | cmd_id + cmd.dlc = 8; // 8-byte payload + // Set velocity to 10.0 rev/s + float velocity = 10.0f; + memcpy(cmd.data, &velocity, 4); // First 4 bytes: velocity (float32) + + // Set Input_Torque_FF to 0.0 + float torque_ff = 0.0f; + memcpy(cmd.data + 4, &torque_ff, 4); // Next 4 bytes: torque feedforward (float32) + + // Send the packet if (SendCANPacket(&cmd) == ERROR_NONE) { + char odrivePacket[64]; int len = sprintf(odrivePacket, "ID=0x%03X DLC=%u DATA=", cmd.id, cmd.dlc); - // now append each data byte in hex for (int i = 0; i < cmd.dlc; ++i) { len += sprintf(odrivePacket + len, "%02X ", cmd.data[i]); } - // print it out Print(odrivePacket); Print("\r\n"); Print("ODrive velocity command sent\r\n"); } else { Print("Send error\r\n"); } - - for(;;) { - // optionally poll for responses - if (PollAndReceiveCANPacket(&cmd) == ERROR_NONE) { - LED_CAN_1_Write(0); - sprintCANPacket(&cmd, uart_tx); + + // Loop to receive responses + for (;;) { + CANPacket rx_cmd; + if (PollAndReceiveCANPacket(&rx_cmd) == ERROR_NONE) { + sprintCANPacket(&rx_cmd, uart_tx); + Print("Received: "); Print(uart_tx); - LED_CAN_1_Write(1); } } -} - -/* [] END OF FILE */ \ No newline at end of file + return 0; +} From a7f9975891abfc5c5339d5ad8f3235f77975230a Mon Sep 17 00:00:00 2001 From: FLinLan Date: Tue, 13 May 2025 11:27:05 -0700 Subject: [PATCH 10/10] added firmware that merely sends the Odrive CAN packets --- CAN_Bridge.cydsn/TopDesign/TopDesign.cysch | Bin 111711 -> 111721 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch b/CAN_Bridge.cydsn/TopDesign/TopDesign.cysch index 3f688453020a66e6d5f9ff292eedf35ad10294d0..7ff6da6d457a26c8195cc6703ce1de660d039c4b 100644 GIT binary patch literal 111721 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