diff --git a/firmware/mcal/linux/CMakeLists.txt b/firmware/mcal/linux/CMakeLists.txt
new file mode 100644
index 000000000..1bd55f91c
--- /dev/null
+++ b/firmware/mcal/linux/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_library(mcal-linux STATIC)
+
+target_include_directories(mcal-linux PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../..)
+
+add_subdirectory(periph)
+target_link_libraries(mcal-linux INTERFACE shared)
diff --git a/firmware/mcal/linux/PostBuild.cmake b/firmware/mcal/linux/PostBuild.cmake
new file mode 100644
index 000000000..7e21caabb
--- /dev/null
+++ b/firmware/mcal/linux/PostBuild.cmake
@@ -0,0 +1 @@
+# No special postbuild actions
\ No newline at end of file
diff --git a/firmware/mcal/linux/README.md b/firmware/mcal/linux/README.md
new file mode 100644
index 000000000..283a4846f
--- /dev/null
+++ b/firmware/mcal/linux/README.md
@@ -0,0 +1,11 @@
+# Linux MCAL
+
+A more advanced CLI. CAN messages are sent over virtual can (vcan) to enable true CAN communication between processes.
+
+## Note on Namespace Name
+
+The namespace is `mcal::lnx`, not `mcal::linux` as one might expect. This is because g++ defines `linux=1`, preventing `linux` from being used as an identifier.
+
+## WSL Compatability
+
+You can run this platform through the Windows Subsystem for Linux but must recompile your WSL kernel to include the CAN modules. See .
diff --git a/firmware/mcal/linux/Toolchain.cmake b/firmware/mcal/linux/Toolchain.cmake
new file mode 100644
index 000000000..954bbc632
--- /dev/null
+++ b/firmware/mcal/linux/Toolchain.cmake
@@ -0,0 +1,3 @@
+# Blake Freer
+# November 8, 2024
+# No cmake instructions as the default Linux compiler should work.
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/CMakeLists.txt b/firmware/mcal/linux/periph/CMakeLists.txt
new file mode 100644
index 000000000..987ed1410
--- /dev/null
+++ b/firmware/mcal/linux/periph/CMakeLists.txt
@@ -0,0 +1,10 @@
+target_sources(mcal-linux
+ PRIVATE
+ adc.cc
+ can.cc
+ digital_input.cc
+ digital_output.cc
+)
+
+add_subdirectory(vcan)
+target_link_libraries(mcal-linux PUBLIC vcan pthread)
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/adc.cc b/firmware/mcal/linux/periph/adc.cc
new file mode 100644
index 000000000..215b5396c
--- /dev/null
+++ b/firmware/mcal/linux/periph/adc.cc
@@ -0,0 +1,26 @@
+#include
+#include
+#include
+
+#include "adc.h"
+
+namespace mcal::lnx::periph {
+
+ADCInput::ADCInput(std::string name) : name_(name) {}
+
+void ADCInput::Start() {
+ std::cout << std::format("Reading ADC \"{}\"\n", name_);
+}
+
+uint32_t ADCInput::Read() {
+ Start();
+
+ uint32_t adc_val;
+ std::cout << " | Enter an unsigned 32-bit value: ";
+ std::cin >> adc_val;
+ std::cout << " | Obtained value " << adc_val << std::endl;
+
+ return adc_val;
+}
+
+} // namespace mcal::lnx::periph
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/adc.h b/firmware/mcal/linux/periph/adc.h
new file mode 100644
index 000000000..02d4eb7fb
--- /dev/null
+++ b/firmware/mcal/linux/periph/adc.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+#include
+
+#include "shared/periph/adc.h"
+
+namespace mcal::lnx::periph {
+
+class ADCInput : public shared::periph::ADCInput {
+public:
+ ADCInput(std::string name);
+
+ void Start() override;
+ uint32_t Read() override;
+
+private:
+ std::string name_;
+};
+
+} // namespace mcal::lnx::periph
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/can.cc b/firmware/mcal/linux/periph/can.cc
new file mode 100644
index 000000000..50005a70a
--- /dev/null
+++ b/firmware/mcal/linux/periph/can.cc
@@ -0,0 +1,101 @@
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "can.h"
+#include "shared/comms/can/raw_can_msg.h"
+#include "vcan/vcan.h"
+
+static std::string message_to_string(const shared::can::RawCanMsg& msg) {
+ std::string str = std::format("[{:02X}]", msg.header.id);
+ for (int i = 0; i < sizeof(msg.header.data_len); ++i) {
+ str += std::format(" {:02X}", msg.data[i]);
+ }
+ return str;
+}
+
+static can_frame to_can_frame(const shared::can::RawCanMsg& msg) {
+ struct can_frame frame{.can_id = msg.header.id,
+ .can_dlc = msg.header.data_len};
+ std::memcpy(&frame.data, msg.data, 8);
+ return frame;
+}
+
+static shared::can::RawCanMsg from_can_frame(const can_frame& frame) {
+ shared::can::RawCanMsg msg;
+ msg.header = {
+ .id = frame.can_id,
+ .data_len = frame.can_dlc,
+ .is_extended_frame = static_cast(frame.can_id & CAN_EFF_FLAG),
+ };
+ msg.tick_timestamp = 0;
+
+ std::copy(frame.data, frame.data + 8, msg.data);
+
+ return msg;
+}
+
+namespace mcal::lnx::periph {
+
+CanBase::CanBase(std::string iface) : socket_(iface) {}
+
+void CanBase::Setup() {
+ socket_.Open();
+
+ // Another thread handles reading
+ reader_thread_ = std::thread(&CanBase::StartReading, this);
+}
+
+void CanBase::Send(const shared::can::RawCanMsg& can_tx_msg) {
+ std::cout << std::format("CanBase {}: Sending\n| {}", socket_.GetIface(),
+ message_to_string(can_tx_msg))
+ << std::endl;
+
+ auto frame = to_can_frame(can_tx_msg);
+ socket_.Write(&frame);
+}
+
+void CanBase::ReadQueue(shared::can::RawCanMsg can_rx_msgs[], size_t len) {
+ uint16_t msg_idx = 0;
+ std::lock_guard lock(queue_access_);
+ while (!can_queue_.empty() && msg_idx < len) {
+ can_rx_msgs[msg_idx] = can_queue_.front();
+
+ std::cout << std::format("CanBase {}: Received\n| {}",
+ socket_.GetIface(),
+ message_to_string(can_rx_msgs[msg_idx]))
+ << std::endl;
+
+ can_queue_.pop();
+ msg_idx++;
+ }
+}
+
+void CanBase::StartReading() {
+ struct can_frame frame;
+ shared::can::RawCanMsg raw_msg;
+
+ while (true) {
+ // Block until a frame arrives
+ ssize_t bytes_read = socket_.Read(&frame);
+ if (bytes_read == -1) {
+ perror("Error reading from CAN socket.");
+ exit(1);
+ }
+
+ raw_msg = from_can_frame(frame);
+
+ { // push RawCanMsg to queue
+ std::lock_guard lock(queue_access_);
+ can_queue_.push(raw_msg);
+ }
+ }
+}
+
+} // namespace mcal::lnx::periph
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/can.h b/firmware/mcal/linux/periph/can.h
new file mode 100644
index 000000000..02086c820
--- /dev/null
+++ b/firmware/mcal/linux/periph/can.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include "mcal/linux/periph/vcan/vcan.h"
+#include "shared/comms/can/raw_can_msg.h"
+#include "shared/periph/can.h"
+#include "vcan/vcan.h"
+
+namespace mcal::lnx::periph {
+
+class CanBase : public shared::periph::CanBase {
+public:
+ CanBase(std::string can_iface);
+
+ void Setup();
+ void Send(const shared::can::RawCanMsg&);
+ void ReadQueue(shared::can::RawCanMsg[], size_t len);
+
+private:
+ struct vcan::VcanSocket socket_;
+
+ std::queue can_queue_;
+ std::mutex queue_access_;
+ std::thread reader_thread_;
+
+ void StartReading();
+};
+} // namespace mcal::lnx::periph
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/digital_input.cc b/firmware/mcal/linux/periph/digital_input.cc
new file mode 100644
index 000000000..e38f43fa5
--- /dev/null
+++ b/firmware/mcal/linux/periph/digital_input.cc
@@ -0,0 +1,23 @@
+#include
+#include
+#include
+
+#include "digital_input.h"
+
+namespace mcal::lnx::periph {
+
+DigitalInput::DigitalInput(std::string name) : name_(name) {};
+
+bool DigitalInput::Read() {
+ int value;
+
+ std::cout << std::format("Reading DigitalInput \"{}\"", name_) << std::endl;
+ std::cout << "| Enter 0 for False, 1 for True: ";
+ std::cin >> value;
+ std::cout << std::format("| Value was {}", value ? "true" : "false")
+ << std::endl;
+
+ return value;
+}
+
+} // namespace mcal::lnx::periph
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/digital_input.h b/firmware/mcal/linux/periph/digital_input.h
new file mode 100644
index 000000000..a8697523e
--- /dev/null
+++ b/firmware/mcal/linux/periph/digital_input.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+
+#include "shared/periph/gpio.h"
+
+namespace mcal::lnx::periph {
+
+class DigitalInput : public shared::periph::DigitalInput {
+public:
+ DigitalInput(std::string name);
+
+ bool Read() override;
+
+private:
+ std::string name_;
+};
+
+} // namespace mcal::lnx::periph
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/digital_output.cc b/firmware/mcal/linux/periph/digital_output.cc
new file mode 100644
index 000000000..13375ab57
--- /dev/null
+++ b/firmware/mcal/linux/periph/digital_output.cc
@@ -0,0 +1,25 @@
+#include
+#include
+#include
+
+#include "digital_output.h"
+
+namespace mcal::lnx::periph {
+
+DigitalOutput::DigitalOutput(std::string name) : name_(name) {}
+
+void DigitalOutput::Set(bool value) {
+ std::cout << std::format("DigitalOutput \"{}\" => {}", name_,
+ value ? "true" : "false")
+ << std::endl;
+}
+
+void DigitalOutput::SetHigh() {
+ Set(true);
+}
+
+void DigitalOutput::SetLow() {
+ Set(false);
+}
+
+} // namespace mcal::lnx::periph
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/digital_output.h b/firmware/mcal/linux/periph/digital_output.h
new file mode 100644
index 000000000..845be46ed
--- /dev/null
+++ b/firmware/mcal/linux/periph/digital_output.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+#include
+
+#include "shared/periph/gpio.h"
+
+namespace mcal::lnx::periph {
+class DigitalOutput : public shared::periph::DigitalOutput {
+public:
+ DigitalOutput(std::string name);
+
+ void Set(bool value) override;
+ void SetHigh() override;
+ void SetLow() override;
+
+private:
+ std::string name_;
+};
+
+} // namespace mcal::lnx::periph
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/vcan/CMakeLists.txt b/firmware/mcal/linux/periph/vcan/CMakeLists.txt
new file mode 100644
index 000000000..31a032644
--- /dev/null
+++ b/firmware/mcal/linux/periph/vcan/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(vcan STATIC vcan.cc)
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/vcan/vcan.cc b/firmware/mcal/linux/periph/vcan/vcan.cc
new file mode 100644
index 000000000..b8cfa433b
--- /dev/null
+++ b/firmware/mcal/linux/periph/vcan/vcan.cc
@@ -0,0 +1,60 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "vcan.h"
+
+namespace mcal::lnx::periph::vcan {
+
+VcanSocket::VcanSocket(std::string iface) : iface_(iface) {}
+
+int VcanSocket::Open() {
+ socket_ = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+ if (socket_ == -1) {
+ perror("Error while opening socket.");
+ return -1;
+ }
+ strcpy(ifr_.ifr_name, iface_.c_str());
+ ioctl(socket_, SIOGIFINDEX, &ifr_);
+
+ addr_.can_family = AF_CAN;
+ addr_.can_ifindex = ifr_.ifr_ifindex;
+
+ int bind_status = bind(socket_, (struct sockaddr*)&addr_, sizeof(addr_));
+ if (bind_status == -1) {
+ perror("Error in socket bind.");
+ return -1;
+ }
+
+ std::cout << std::format("Opened \"{}\" at index {}.\n", iface_,
+ addr_.can_ifindex);
+
+ return 0;
+}
+
+VcanSocket::~VcanSocket() {
+ close(socket_);
+}
+
+int VcanSocket::Write(struct can_frame* frame) {
+ return write(socket_, frame, sizeof(struct can_frame));
+}
+
+int VcanSocket::Read(struct can_frame* frame) {
+ return read(socket_, frame, sizeof(struct can_frame));
+}
+
+std::string VcanSocket::GetIface() const {
+ return iface_;
+}
+
+} // namespace mcal::lnx::periph::vcan
\ No newline at end of file
diff --git a/firmware/mcal/linux/periph/vcan/vcan.h b/firmware/mcal/linux/periph/vcan/vcan.h
new file mode 100644
index 000000000..1a3dc7b51
--- /dev/null
+++ b/firmware/mcal/linux/periph/vcan/vcan.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include
+
+namespace mcal::lnx::periph::vcan {
+
+class VcanSocket {
+public:
+ VcanSocket(std::string iface);
+ ~VcanSocket();
+
+ int Open();
+ int Write(struct can_frame* frame);
+ int Read(struct can_frame* frame);
+ std::string GetIface() const;
+
+private:
+ std::string iface_;
+ int socket_;
+ struct sockaddr_can addr_;
+ struct ifreq ifr_;
+};
+
+} // namespace mcal::lnx::periph::vcan
\ No newline at end of file
diff --git a/firmware/projects/Demo/Blink/platforms/linux/CMakeLists.txt b/firmware/projects/Demo/Blink/platforms/linux/CMakeLists.txt
new file mode 100644
index 000000000..b9b7a2e6e
--- /dev/null
+++ b/firmware/projects/Demo/Blink/platforms/linux/CMakeLists.txt
@@ -0,0 +1,4 @@
+target_sources(bindings PRIVATE bindings.cc)
+target_include_directories(bindings PRIVATE ${DIR_PROJECT})
+
+target_link_libraries(bindings PRIVATE mcal-linux)
\ No newline at end of file
diff --git a/firmware/projects/Demo/Blink/platforms/linux/bindings.cc b/firmware/projects/Demo/Blink/platforms/linux/bindings.cc
new file mode 100644
index 000000000..ae74aa0ea
--- /dev/null
+++ b/firmware/projects/Demo/Blink/platforms/linux/bindings.cc
@@ -0,0 +1,27 @@
+#include
+
+#include "bindings.h"
+#include "mcal/linux/periph/digital_output.h"
+#include "shared/periph/gpio.h"
+
+namespace mcal {
+
+using namespace lnx::periph;
+
+DigitalOutput indicator{"Indicator"};
+
+} // namespace mcal
+
+namespace bindings {
+
+shared::periph::DigitalOutput& indicator = mcal::indicator;
+
+void DelayMS(unsigned int ms) {
+ usleep(1000 * ms);
+}
+
+void Initialize() {
+ std::cout << "Initializing Linux" << std::endl;
+}
+
+} // namespace bindings
\ No newline at end of file
diff --git a/firmware/projects/Demo/Blink/platforms/linux/mcal_conf.cmake b/firmware/projects/Demo/Blink/platforms/linux/mcal_conf.cmake
new file mode 100644
index 000000000..009913775
--- /dev/null
+++ b/firmware/projects/Demo/Blink/platforms/linux/mcal_conf.cmake
@@ -0,0 +1 @@
+set(MCAL linux)
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Bar/README.md b/firmware/projects/Demo/CAN/Bar/README.md
deleted file mode 100644
index 4cf08e5ca..000000000
--- a/firmware/projects/Demo/CAN/Bar/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# DemoCanBar Project
-
-The DemoCanBar project is best suited for the `raspi` and the `stm32f767` platform. It reads a dummy message and sends a reply with the same data back (created for testing purposes). To observe the full system at work, run alongside the DemoCanFoo project.
-
-### Nodes:
-`Bar` (this ecu)
-
-`Foo` (some other ecu)
-
-### Messages:
-
-`Foo` sends `Bar` the `TempSensors` message.
-`Bar` reads `TempSensors` message and replies with the `TempSensorsReply` message.
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Bar/config.yaml b/firmware/projects/Demo/CAN/Bar/config.yaml
deleted file mode 100644
index 2599bb986..000000000
--- a/firmware/projects/Demo/CAN/Bar/config.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-canGen:
- busses:
- - name: veh
- node: bar
- dbcFiles:
- - "../demo.dbc"
diff --git a/firmware/projects/Demo/CAN/Bar/main.cc b/firmware/projects/Demo/CAN/Bar/main.cc
deleted file mode 100644
index 8a3359bca..000000000
--- a/firmware/projects/Demo/CAN/Bar/main.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-/// @author Samuel Parent
-/// @date 2024-01-16
-
-#include
-
-#include "generated/can/veh_can_messages.h"
-#include "generated/can/veh_msg_registry.h"
-#include "shared/comms/can/can_bus.h"
-
-namespace bindings {
-extern shared::periph::CanBase& veh_can_base;
-extern void Initialize();
-extern void TickBlocking(uint32_t);
-} // namespace bindings
-
-generated::can::VehMsgRegistry veh_can_registry{};
-
-shared::can::CanBus veh_can_bus{
- bindings::veh_can_base,
- veh_can_registry,
-};
-
-int main(void) {
- bindings::Initialize();
- uint32_t tick_duration = 100;
-
- generated::can::TempSensors temp_sens_msg{};
- generated::can::TempSensorsReply temp_sens_msg_reply{};
-
- while (true) {
- veh_can_bus.Update();
- veh_can_bus.Read(temp_sens_msg);
-
- temp_sens_msg_reply.sensor1 = temp_sens_msg.sensor1;
- temp_sens_msg_reply.sensor2 = temp_sens_msg.sensor2;
- temp_sens_msg_reply.sensor3 = temp_sens_msg.sensor3;
- temp_sens_msg_reply.sensor4 = temp_sens_msg.sensor4;
- temp_sens_msg_reply.sensor5 = temp_sens_msg.sensor5;
- temp_sens_msg_reply.sensor6 = temp_sens_msg.sensor6;
-
- veh_can_bus.Send(temp_sens_msg_reply);
-
- bindings::TickBlocking(tick_duration);
- }
-
- return 0;
-}
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Foo/README.md b/firmware/projects/Demo/CAN/Foo/README.md
deleted file mode 100644
index cf92755ef..000000000
--- a/firmware/projects/Demo/CAN/Foo/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# DemoCanFoo Project
-
-The DemoCanFoo project is best suited for the `raspi` and the `stm32f767` platform. It sends dummy messages created for testing purposes. To observe the full system at work, run alongside the DemoCanBar project.
-
-### Nodes:
-`Foo` (this ecu)
-
-`Bar` (some other ecu)
-
-### Messages:
-
-`Foo` sends `Bar` the `TempSensors` message.
-
diff --git a/firmware/projects/Demo/CAN/Foo/config.yaml b/firmware/projects/Demo/CAN/Foo/config.yaml
deleted file mode 100644
index 4ef5a0ddc..000000000
--- a/firmware/projects/Demo/CAN/Foo/config.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-canGen:
- busses:
- - name: veh
- node: foo
- dbcFiles:
- - "../demo.dbc"
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Foo/main.cc b/firmware/projects/Demo/CAN/Foo/main.cc
deleted file mode 100644
index 3c66d4721..000000000
--- a/firmware/projects/Demo/CAN/Foo/main.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-/// @author Samuel Parent
-/// @date 2024-01-16
-
-#include
-
-#include "generated/can/veh_can_messages.h"
-#include "generated/can/veh_msg_registry.h"
-#include "shared/comms/can/can_bus.h"
-
-namespace bindings {
-extern shared::periph::CanBase& veh_can_base;
-extern void Initialize();
-extern void TickBlocking(uint32_t);
-} // namespace bindings
-
-generated::can::VehMsgRegistry veh_can_registry{};
-
-shared::can::CanBus veh_can_bus{
- bindings::veh_can_base,
- veh_can_registry,
-};
-
-int main(void) {
- bindings::Initialize();
- uint32_t tick_duration = 100;
-
- generated::can::TempSensors temp_sens_msg{};
-
- while (true) {
- veh_can_bus.Update();
-
- temp_sens_msg.sensor1++;
- temp_sens_msg.sensor2++;
- temp_sens_msg.sensor3++;
- temp_sens_msg.sensor4++;
- temp_sens_msg.sensor5++;
- temp_sens_msg.sensor6++;
-
- veh_can_bus.Send(temp_sens_msg);
-
- bindings::TickBlocking(tick_duration);
- }
-
- return 0;
-}
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/README.md b/firmware/projects/Demo/CAN/README.md
new file mode 100644
index 000000000..d5adae06f
--- /dev/null
+++ b/firmware/projects/Demo/CAN/README.md
@@ -0,0 +1,57 @@
+# CAN Demo Projects
+
+Control an LED with a button over CAN.
+
+The `Send` node reads a button input then sends the input over CAN to the `Receive` node which then sets turns on an LED if the button is pressed.
+
+## DBC
+
+The DBC file is very simple. It contains a single message `ButtonStatus` with one signal fields:
+
+- Bit 0: State (boolean) - 1 if pressed, 0 if not
+
+C++ code for the DBC is generated using `scripts/cangen`. The code is placed into `Send/generated/can/` and `Receive/generated/can/`.
+
+## Platforms
+
+### Linux
+
+The projects communicate over virtual CAN (vcan). If using WSL, you need to recompile your kernel to enable vcan (instructions coming soon).
+
+Run `source vcan_setup.sh` to load the required modules.
+
+Run the `Send` program in one shell and `Receive` in another. `Send` will read the "button" state by prompting you for a 1 or 0, then will send the state over vcan to `Receive` which will turn on the "led" by printing its new state to the screen.
+
+```bash
+$ ./build/Demo/CAN/Send/linux/main
+Initializing Linux
+Opened vcan0 at index 4
+Reading DigitalInput "Button"
+| Enter 0 for False, 1 for True: 1
+| Value was true
+CanBase vcan0: Sending
+| [3AC] 01
+Reading DigitalInput "Button"
+| Enter 0 for False, 1 for True: 0
+| Value was false
+CanBase vcan0: Sending
+| [3AC] 00
+```
+
+```bash
+$ ./build/Demo/CAN/Receive/linux/main
+Initializing Linux
+Opened vcan0 at index 4
+CanBase vcan0: Received
+| [3AC] 01
+DigitalOutput "Indicator" => true
+CanBase vcan0: Received
+| [3AC] 00
+DigitalOutput "Indicator" => false
+```
+
+### stm32f767 Nucleo
+
+Both Send and Receive have CAN RX and TX on pins PB3 and PB4, respectively. See the nucleo pinouts (`racecar/datasheets/nucleo/`) for the physical pin. For a complete circuit, you will also need 2 CAN drivers like the AD MAX33042E (see datasheets folder).
+
+The `Send` node polls its built-in button every 50 ms and sends a message to the `Receive` node which sets its on-board LED to match the button.
diff --git a/firmware/projects/Demo/CAN/Bar/CMakeLists.txt b/firmware/projects/Demo/CAN/Receive/CMakeLists.txt
similarity index 77%
rename from firmware/projects/Demo/CAN/Bar/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Receive/CMakeLists.txt
index f47c88a9c..6d212da49 100644
--- a/firmware/projects/Demo/CAN/Bar/CMakeLists.txt
+++ b/firmware/projects/Demo/CAN/Receive/CMakeLists.txt
@@ -6,15 +6,7 @@
include("${CMAKE_SOURCE_DIR}/cmake/cangen.cmake")
-target_sources(main
- PRIVATE
- main.cc
-)
-
-target_include_directories(main
- PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/inc
-)
+target_sources(main PRIVATE main.cc)
# Notice that we don't include any mcal/ subdirectory in this CMake file.
# The master CMakeLists handles platform selection and library linking.
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Receive/README.md b/firmware/projects/Demo/CAN/Receive/README.md
new file mode 100644
index 000000000..63efc837c
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Receive/README.md
@@ -0,0 +1,5 @@
+# Demo CAN Receive Project
+
+This project is a minimal CAN message receiver. It should be executed alongside the `Demo/CAN/Send` project.
+
+See [Demo/CAN/README](../README.md).
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Receive/bindings.h b/firmware/projects/Demo/CAN/Receive/bindings.h
new file mode 100644
index 000000000..a890996bb
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Receive/bindings.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "shared/periph/can.h"
+#include "shared/periph/gpio.h"
+
+namespace bindings {
+
+extern shared::periph::CanBase& veh_can_base;
+extern shared::periph::DigitalOutput& indicator;
+
+extern void Initialize();
+} // namespace bindings
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Receive/config.yaml b/firmware/projects/Demo/CAN/Receive/config.yaml
new file mode 100644
index 000000000..6e00c0dfc
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Receive/config.yaml
@@ -0,0 +1,5 @@
+canGen:
+ busses:
+ - name: demobus
+ node: RECV
+ dbcFile: "../demo.dbc"
diff --git a/firmware/projects/Demo/CAN/Receive/main.cc b/firmware/projects/Demo/CAN/Receive/main.cc
new file mode 100644
index 000000000..41c9f5f80
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Receive/main.cc
@@ -0,0 +1,31 @@
+/// @author Samuel Parent
+/// @date 2024-01-16
+
+#include
+
+#include "bindings.h"
+#include "generated/can/demobus_can_messages.h"
+#include "generated/can/demobus_msg_registry.h"
+#include "shared/comms/can/can_bus.h"
+
+generated::can::DemobusMsgRegistry veh_can_registry{};
+
+shared::can::CanBus veh_can_bus{
+ bindings::veh_can_base,
+ veh_can_registry,
+};
+
+int main(void) {
+ bindings::Initialize();
+
+ generated::can::ButtonStatus btn_msg{};
+
+ while (true) {
+ veh_can_bus.Update();
+ veh_can_bus.Read(btn_msg);
+
+ bindings::indicator.Set(btn_msg.state);
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/cli/CMakeLists.txt b/firmware/projects/Demo/CAN/Receive/platforms/cli/CMakeLists.txt
similarity index 100%
rename from firmware/projects/Demo/CAN/Bar/platforms/cli/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Receive/platforms/cli/CMakeLists.txt
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/cli/bindings.cc b/firmware/projects/Demo/CAN/Receive/platforms/cli/bindings.cc
similarity index 54%
rename from firmware/projects/Demo/CAN/Foo/platforms/cli/bindings.cc
rename to firmware/projects/Demo/CAN/Receive/platforms/cli/bindings.cc
index bda69c104..c67b96b87 100644
--- a/firmware/projects/Demo/CAN/Foo/platforms/cli/bindings.cc
+++ b/firmware/projects/Demo/CAN/Receive/platforms/cli/bindings.cc
@@ -2,28 +2,31 @@
/// @date 2024-01-16
#include
+#include
#include
#include "mcal/cli/periph/can.h"
+#include "mcal/cli/periph/gpio.h"
#include "shared/periph/can.h"
namespace mcal {
using namespace cli::periph;
CanBase veh_can_base{"vcan0"};
+DigitalOutput indicator{"Indicator"};
} // namespace mcal
namespace bindings {
shared::periph::CanBase& veh_can_base = mcal::veh_can_base;
-
-void TickBlocking(uint32_t ticks) {
- std::chrono::milliseconds duration(ticks);
-
- std::this_thread::sleep_for(duration);
-}
+shared::periph::DigitalOutput& indicator = mcal::indicator;
void Initialize() {
- mcal::veh_can_base.Setup();
std::cout << "Initializing CLI..." << std::endl;
+ mcal::veh_can_base.Setup();
+ std::cerr << "The CLI platform has no way to receive messages from "
+ "CAN/Send. Consider using the linux platform instead."
+ << std::endl;
+ std::cerr << "Exiting..." << std::endl;
+ exit(1);
}
} // namespace bindings
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/cli/mcal_conf.cmake b/firmware/projects/Demo/CAN/Receive/platforms/cli/mcal_conf.cmake
similarity index 100%
rename from firmware/projects/Demo/CAN/Bar/platforms/cli/mcal_conf.cmake
rename to firmware/projects/Demo/CAN/Receive/platforms/cli/mcal_conf.cmake
diff --git a/firmware/projects/Demo/CAN/Receive/platforms/linux/CMakeLists.txt b/firmware/projects/Demo/CAN/Receive/platforms/linux/CMakeLists.txt
new file mode 100644
index 000000000..b9b7a2e6e
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Receive/platforms/linux/CMakeLists.txt
@@ -0,0 +1,4 @@
+target_sources(bindings PRIVATE bindings.cc)
+target_include_directories(bindings PRIVATE ${DIR_PROJECT})
+
+target_link_libraries(bindings PRIVATE mcal-linux)
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Receive/platforms/linux/bindings.cc b/firmware/projects/Demo/CAN/Receive/platforms/linux/bindings.cc
new file mode 100644
index 000000000..516427fca
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Receive/platforms/linux/bindings.cc
@@ -0,0 +1,27 @@
+#include
+
+#include
+
+#include "bindings.h"
+#include "mcal/linux/periph/can.h"
+#include "mcal/linux/periph/digital_output.h"
+
+namespace mcal {
+using namespace lnx::periph;
+
+CanBase veh_can_base{"vcan0"};
+DigitalOutput indicator{"Indicator"};
+
+} // namespace mcal
+
+namespace bindings {
+
+shared::periph::CanBase& veh_can_base = mcal::veh_can_base;
+shared::periph::DigitalOutput& indicator = mcal::indicator;
+
+void Initialize() {
+ std::cout << "Initializing Linux" << std::endl;
+ mcal::veh_can_base.Setup();
+}
+
+} // namespace bindings
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Receive/platforms/linux/mcal_conf.cmake b/firmware/projects/Demo/CAN/Receive/platforms/linux/mcal_conf.cmake
new file mode 100644
index 000000000..009913775
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Receive/platforms/linux/mcal_conf.cmake
@@ -0,0 +1 @@
+set(MCAL linux)
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/raspi/CMakeLists.txt b/firmware/projects/Demo/CAN/Receive/platforms/raspi/CMakeLists.txt
similarity index 100%
rename from firmware/projects/Demo/CAN/Bar/platforms/raspi/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Receive/platforms/raspi/CMakeLists.txt
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/raspi/bindings.cc b/firmware/projects/Demo/CAN/Receive/platforms/raspi/bindings.cc
similarity index 78%
rename from firmware/projects/Demo/CAN/Foo/platforms/raspi/bindings.cc
rename to firmware/projects/Demo/CAN/Receive/platforms/raspi/bindings.cc
index 6e55e5f16..f5b031560 100644
--- a/firmware/projects/Demo/CAN/Foo/platforms/raspi/bindings.cc
+++ b/firmware/projects/Demo/CAN/Receive/platforms/raspi/bindings.cc
@@ -16,12 +16,6 @@ CanBase veh_can_base{"vcan0"};
namespace bindings {
shared::periph::CanBase& veh_can_base = mcal::veh_can_base;
-void TickBlocking(uint32_t ticks) {
- std::chrono::milliseconds duration(ticks);
-
- std::this_thread::sleep_for(duration);
-}
-
void Initialize() {
mcal::veh_can_base.Setup();
std::cout << "Initializing raspi..." << std::endl;
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/raspi/mcal_conf.cmake b/firmware/projects/Demo/CAN/Receive/platforms/raspi/mcal_conf.cmake
similarity index 100%
rename from firmware/projects/Demo/CAN/Bar/platforms/raspi/mcal_conf.cmake
rename to firmware/projects/Demo/CAN/Receive/platforms/raspi/mcal_conf.cmake
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/stm32f767/CMakeLists.txt b/firmware/projects/Demo/CAN/Receive/platforms/stm32f767/CMakeLists.txt
similarity index 100%
rename from firmware/projects/Demo/CAN/Bar/platforms/stm32f767/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Receive/platforms/stm32f767/CMakeLists.txt
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/stm32f767/bindings.cc b/firmware/projects/Demo/CAN/Receive/platforms/stm32f767/bindings.cc
similarity index 82%
rename from firmware/projects/Demo/CAN/Foo/platforms/stm32f767/bindings.cc
rename to firmware/projects/Demo/CAN/Receive/platforms/stm32f767/bindings.cc
index 34736d32f..4c833b385 100644
--- a/firmware/projects/Demo/CAN/Foo/platforms/stm32f767/bindings.cc
+++ b/firmware/projects/Demo/CAN/Receive/platforms/stm32f767/bindings.cc
@@ -8,7 +8,9 @@
// fw includes
#include "mcal/stm32f767/periph/can.h"
+#include "mcal/stm32f767/periph/gpio.h"
#include "shared/periph/can.h"
+#include "shared/periph/gpio.h"
extern "C" {
/**
@@ -22,10 +24,12 @@ namespace mcal {
using namespace stm32f767::periph;
CanBase veh_can_base{&hcan3};
+DigitalOutput indicator{LedPin_GPIO_Port, LedPin_Pin};
} // namespace mcal
namespace bindings {
shared::periph::CanBase& veh_can_base = mcal::veh_can_base;
+shared::periph::DigitalOutput& indicator = mcal::indicator;
void Initialize() {
SystemClock_Config();
@@ -35,10 +39,6 @@ void Initialize() {
mcal::veh_can_base.Setup();
}
-void TickBlocking(uint32_t ticks) {
- HAL_Delay(ticks);
-}
-
extern "C" {
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* hcan) {
if (hcan == &hcan3) {
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/stm32f767/cubemx/.gitignore b/firmware/projects/Demo/CAN/Receive/platforms/stm32f767/cubemx/.gitignore
similarity index 100%
rename from firmware/projects/Demo/CAN/Bar/platforms/stm32f767/cubemx/.gitignore
rename to firmware/projects/Demo/CAN/Receive/platforms/stm32f767/cubemx/.gitignore
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/stm32f767/cubemx/CMakeLists.txt b/firmware/projects/Demo/CAN/Receive/platforms/stm32f767/cubemx/CMakeLists.txt
similarity index 100%
rename from firmware/projects/Demo/CAN/Bar/platforms/stm32f767/cubemx/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Receive/platforms/stm32f767/cubemx/CMakeLists.txt
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/stm32f767/cubemx/board_config.ioc b/firmware/projects/Demo/CAN/Receive/platforms/stm32f767/cubemx/board_config.ioc
similarity index 93%
rename from firmware/projects/Demo/CAN/Bar/platforms/stm32f767/cubemx/board_config.ioc
rename to firmware/projects/Demo/CAN/Receive/platforms/stm32f767/cubemx/board_config.ioc
index 3638f0255..0a40e8432 100644
--- a/firmware/projects/Demo/CAN/Bar/platforms/stm32f767/cubemx/board_config.ioc
+++ b/firmware/projects/Demo/CAN/Receive/platforms/stm32f767/cubemx/board_config.ioc
@@ -1,192 +1,181 @@
-#MicroXplorer Configuration settings - do not modify
-CAD.formats=
-CAD.pinconfig=
-CAD.provider=
-CAN3.ABOM=ENABLE
-CAN3.BS1=CAN_BS1_13TQ
-CAN3.BS2=CAN_BS2_2TQ
-CAN3.CalculateBaudRate=500000
-CAN3.CalculateTimeBit=2000
-CAN3.CalculateTimeQuantum=125.0
-CAN3.IPParameters=CalculateTimeQuantum,CalculateBaudRate,Prescaler,CalculateTimeBit,BS1,BS2,ABOM,Mode
-CAN3.Mode=CAN_MODE_NORMAL
-CAN3.Prescaler=6
-File.Version=6
-GPIO.groupedBy=Group By Peripherals
-KeepUserPlacement=false
-Mcu.CPN=STM32F767ZIT6
-Mcu.Family=STM32F7
-Mcu.IP0=CAN3
-Mcu.IP1=CORTEX_M7
-Mcu.IP2=NVIC
-Mcu.IP3=RCC
-Mcu.IP4=SYS
-Mcu.IPNb=5
-Mcu.Name=STM32F767ZITx
-Mcu.Package=LQFP144
-Mcu.Pin0=PC13
-Mcu.Pin1=PA6
-Mcu.Pin2=PA8
-Mcu.Pin3=PA15
-Mcu.Pin4=PB7
-Mcu.Pin5=VP_SYS_VS_Systick
-Mcu.PinsNb=6
-Mcu.ThirdPartyNb=0
-Mcu.UserConstants=
-Mcu.UserName=STM32F767ZITx
-MxCube.Version=6.12.0
-MxDb.Version=DB.6.0.120
-NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.CAN3_RX0_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
-NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.ForceEnableDMAVector=true
-NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
-NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:false
-NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-PA15.Locked=true
-PA15.Mode=CAN_Activate
-PA15.Signal=CAN3_TX
-PA6.GPIOParameters=PinState,GPIO_Label
-PA6.GPIO_Label=DASHBOARD_EN
-PA6.Locked=true
-PA6.PinState=GPIO_PIN_SET
-PA6.Signal=GPIO_Output
-PA8.Mode=CAN_Activate
-PA8.Signal=CAN3_RX
-PB7.GPIOParameters=GPIO_Label
-PB7.GPIO_Label=LedPin
-PB7.Locked=true
-PB7.Signal=GPIO_Output
-PC13.GPIOParameters=GPIO_PuPd,GPIO_Label
-PC13.GPIO_Label=ButtonPin
-PC13.GPIO_PuPd=GPIO_PULLDOWN
-PC13.Locked=true
-PC13.Signal=GPIO_Input
-PinOutPanel.RotationAngle=0
-ProjectManager.AskForMigrate=true
-ProjectManager.BackupPrevious=false
-ProjectManager.CompilerOptimize=6
-ProjectManager.ComputerToolchain=false
-ProjectManager.CoupleFile=true
-ProjectManager.CustomerFirmwarePackage=
-ProjectManager.DefaultFWLocation=true
-ProjectManager.DeletePrevious=true
-ProjectManager.DeviceId=STM32F767ZITx
-ProjectManager.FirmwarePackage=STM32Cube FW_F7 V1.17.2
-ProjectManager.FreePins=false
-ProjectManager.HalAssertFull=false
-ProjectManager.HeapSize=0x200
-ProjectManager.KeepUserCode=false
-ProjectManager.LastFirmware=true
-ProjectManager.LibraryCopy=1
-ProjectManager.MainLocation=Src
-ProjectManager.NoMain=true
-ProjectManager.PreviousToolchain=
-ProjectManager.ProjectBuild=false
-ProjectManager.ProjectFileName=board_config.ioc
-ProjectManager.ProjectName=board_config
-ProjectManager.ProjectStructure=
-ProjectManager.RegisterCallBack=
-ProjectManager.StackSize=0x400
-ProjectManager.TargetToolchain=Makefile
-ProjectManager.ToolChainLocation=
-ProjectManager.UAScriptAfterPath=
-ProjectManager.UAScriptBeforePath=
-ProjectManager.UnderRoot=false
-ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_CAN3_Init-CAN3-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
-RCC.48MHZClocksFreq_Value=24000000
-RCC.ADC12outputFreq_Value=72000000
-RCC.ADC34outputFreq_Value=72000000
-RCC.AHBFreq_Value=96000000
-RCC.APB1CLKDivider=RCC_HCLK_DIV2
-RCC.APB1Freq_Value=48000000
-RCC.APB1TimFreq_Value=96000000
-RCC.APB2Freq_Value=96000000
-RCC.APB2TimFreq_Value=96000000
-RCC.CECFreq_Value=32786.88524590164
-RCC.CortexFreq_Value=96000000
-RCC.DFSDMAudioFreq_Value=192000000
-RCC.DFSDMFreq_Value=96000000
-RCC.EthernetFreq_Value=96000000
-RCC.FCLKCortexFreq_Value=96000000
-RCC.FamilyName=M
-RCC.HCLKFreq_Value=96000000
-RCC.HSE_VALUE=8000000
-RCC.HSI_VALUE=16000000
-RCC.I2C1Freq_Value=48000000
-RCC.I2C2Freq_Value=48000000
-RCC.I2C3Freq_Value=48000000
-RCC.I2C4Freq_Value=48000000
-RCC.I2SClocksFreq_Value=48000000
-RCC.I2SFreq_Value=192000000
-RCC.IPParameters=48MHZClocksFreq_Value,ADC12outputFreq_Value,ADC34outputFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CECFreq_Value,CortexFreq_Value,DFSDMAudioFreq_Value,DFSDMFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SClocksFreq_Value,I2SFreq_Value,LCDTFTFreq_Value,LCDTFToutputFreq_Value,LPTIM1Freq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,MCO2PinFreq_Value,MCOFreq_Value,PLLCLKFreq_Value,PLLI2SPCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLI2SRoutputFreq_Value,PLLM,PLLMCOFreq_Value,PLLMUL,PLLN,PLLQ,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLRFreq_Value,PLLSAIPCLKFreq_Value,PLLSAIQCLKFreq_Value,PLLSAIRCLKFreq_Value,PLLSAIoutputFreq_Value,PRESCALERUSB,RNGFreq_Value,RTCFreq_Value,RTCHSEDivFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMC2Freq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,SYSCLKSourceVirtual,TIM15Freq_Value,TIM16Freq_Value,TIM17Freq_Value,TIM1Freq_Value,TIM20Freq_Value,TIM2Freq_Value,TIM3Freq_Value,TIM8Freq_Value,UART4Freq_Value,UART5Freq_Value,UART7Freq_Value,UART8Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,USBFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutput2Freq_Value,VCOOutputFreq_Value,VCOSAIOutputFreq_Value,VcooutputI2S,WatchDogFreq_Value
-RCC.LCDTFTFreq_Value=96000000
-RCC.LCDTFToutputFreq_Value=96000000
-RCC.LPTIM1Freq_Value=48000000
-RCC.LSE_VALUE=32768
-RCC.LSI_VALUE=32000
-RCC.MCO1PinFreq_Value=16000000
-RCC.MCO2PinFreq_Value=96000000
-RCC.MCOFreq_Value=72000000
-RCC.PLLCLKFreq_Value=96000000
-RCC.PLLI2SPCLKFreq_Value=192000000
-RCC.PLLI2SQCLKFreq_Value=192000000
-RCC.PLLI2SRCLKFreq_Value=192000000
-RCC.PLLI2SRoutputFreq_Value=192000000
-RCC.PLLM=8
-RCC.PLLMCOFreq_Value=72000000
-RCC.PLLMUL=RCC_PLL_MUL9
-RCC.PLLN=96
-RCC.PLLQ=4
-RCC.PLLQCLKFreq_Value=48000000
-RCC.PLLQoutputFreq_Value=48000000
-RCC.PLLRFreq_Value=96000000
-RCC.PLLSAIPCLKFreq_Value=192000000
-RCC.PLLSAIQCLKFreq_Value=192000000
-RCC.PLLSAIRCLKFreq_Value=192000000
-RCC.PLLSAIoutputFreq_Value=192000000
-RCC.PRESCALERUSB=RCC_USBCLKSOURCE_PLL_DIV1_5
-RCC.RNGFreq_Value=48000000
-RCC.RTCFreq_Value=32000
-RCC.RTCHSEDivFreq_Value=4000000
-RCC.SAI1Freq_Value=192000000
-RCC.SAI2Freq_Value=192000000
-RCC.SDMMC2Freq_Value=96000000
-RCC.SDMMCFreq_Value=96000000
-RCC.SPDIFRXFreq_Value=192000000
-RCC.SYSCLKFreq_VALUE=96000000
-RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
-RCC.SYSCLKSourceVirtual=RCC_SYSCLKSOURCE_PLLCLK
-RCC.TIM15Freq_Value=72000000
-RCC.TIM16Freq_Value=72000000
-RCC.TIM17Freq_Value=72000000
-RCC.TIM1Freq_Value=72000000
-RCC.TIM20Freq_Value=72000000
-RCC.TIM2Freq_Value=72000000
-RCC.TIM3Freq_Value=72000000
-RCC.TIM8Freq_Value=72000000
-RCC.UART4Freq_Value=48000000
-RCC.UART5Freq_Value=48000000
-RCC.UART7Freq_Value=48000000
-RCC.UART8Freq_Value=48000000
-RCC.USART1Freq_Value=96000000
-RCC.USART2Freq_Value=48000000
-RCC.USART3Freq_Value=48000000
-RCC.USART6Freq_Value=96000000
-RCC.USBFreq_Value=48000000
-RCC.VCOI2SOutputFreq_Value=384000000
-RCC.VCOInputFreq_Value=2000000
-RCC.VCOOutput2Freq_Value=8000000
-RCC.VCOOutputFreq_Value=192000000
-RCC.VCOSAIOutputFreq_Value=384000000
-RCC.VcooutputI2S=48000000
-RCC.WatchDogFreq_Value=32000
-VP_SYS_VS_Systick.Mode=SysTick
-VP_SYS_VS_Systick.Signal=SYS_VS_Systick
-board=NUCLEO-F767ZI
-boardIOC=true
+#MicroXplorer Configuration settings - do not modify
+CAD.formats=
+CAD.pinconfig=
+CAD.provider=
+CAN3.ABOM=ENABLE
+CAN3.BS1=CAN_BS1_13TQ
+CAN3.BS2=CAN_BS2_2TQ
+CAN3.CalculateBaudRate=500000
+CAN3.CalculateTimeBit=2000
+CAN3.CalculateTimeQuantum=125.0
+CAN3.IPParameters=CalculateTimeQuantum,CalculateBaudRate,Prescaler,CalculateTimeBit,BS1,BS2,ABOM,Mode
+CAN3.Mode=CAN_MODE_NORMAL
+CAN3.Prescaler=6
+File.Version=6
+GPIO.groupedBy=Group By Peripherals
+KeepUserPlacement=false
+Mcu.CPN=STM32F767ZIT6
+Mcu.Family=STM32F7
+Mcu.IP0=CAN3
+Mcu.IP1=CORTEX_M7
+Mcu.IP2=NVIC
+Mcu.IP3=RCC
+Mcu.IP4=SYS
+Mcu.IPNb=5
+Mcu.Name=STM32F767ZITx
+Mcu.Package=LQFP144
+Mcu.Pin0=PB3
+Mcu.Pin1=PB4
+Mcu.Pin2=PB7
+Mcu.Pin3=VP_SYS_VS_Systick
+Mcu.PinsNb=4
+Mcu.ThirdPartyNb=0
+Mcu.UserConstants=
+Mcu.UserName=STM32F767ZITx
+MxCube.Version=6.12.0
+MxDb.Version=DB.6.0.120
+NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.CAN3_RX0_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
+NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.ForceEnableDMAVector=true
+NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
+NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:false
+NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+PB3.Locked=true
+PB3.Mode=CAN_Activate
+PB3.Signal=CAN3_RX
+PB4.Locked=true
+PB4.Mode=CAN_Activate
+PB4.Signal=CAN3_TX
+PB7.GPIOParameters=GPIO_Label
+PB7.GPIO_Label=LedPin
+PB7.Locked=true
+PB7.Signal=GPIO_Output
+PinOutPanel.RotationAngle=0
+ProjectManager.AskForMigrate=true
+ProjectManager.BackupPrevious=false
+ProjectManager.CompilerOptimize=6
+ProjectManager.ComputerToolchain=false
+ProjectManager.CoupleFile=true
+ProjectManager.CustomerFirmwarePackage=
+ProjectManager.DefaultFWLocation=true
+ProjectManager.DeletePrevious=true
+ProjectManager.DeviceId=STM32F767ZITx
+ProjectManager.FirmwarePackage=STM32Cube FW_F7 V1.17.2
+ProjectManager.FreePins=false
+ProjectManager.HalAssertFull=false
+ProjectManager.HeapSize=0x200
+ProjectManager.KeepUserCode=false
+ProjectManager.LastFirmware=true
+ProjectManager.LibraryCopy=1
+ProjectManager.MainLocation=Src
+ProjectManager.NoMain=true
+ProjectManager.PreviousToolchain=
+ProjectManager.ProjectBuild=false
+ProjectManager.ProjectFileName=board_config.ioc
+ProjectManager.ProjectName=board_config
+ProjectManager.ProjectStructure=
+ProjectManager.RegisterCallBack=
+ProjectManager.StackSize=0x400
+ProjectManager.TargetToolchain=Makefile
+ProjectManager.ToolChainLocation=
+ProjectManager.UAScriptAfterPath=
+ProjectManager.UAScriptBeforePath=
+ProjectManager.UnderRoot=false
+ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_CAN3_Init-CAN3-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
+RCC.48MHZClocksFreq_Value=24000000
+RCC.ADC12outputFreq_Value=72000000
+RCC.ADC34outputFreq_Value=72000000
+RCC.AHBFreq_Value=96000000
+RCC.APB1CLKDivider=RCC_HCLK_DIV2
+RCC.APB1Freq_Value=48000000
+RCC.APB1TimFreq_Value=96000000
+RCC.APB2Freq_Value=96000000
+RCC.APB2TimFreq_Value=96000000
+RCC.CECFreq_Value=32786.88524590164
+RCC.CortexFreq_Value=96000000
+RCC.DFSDMAudioFreq_Value=192000000
+RCC.DFSDMFreq_Value=96000000
+RCC.EthernetFreq_Value=96000000
+RCC.FCLKCortexFreq_Value=96000000
+RCC.FamilyName=M
+RCC.HCLKFreq_Value=96000000
+RCC.HSE_VALUE=8000000
+RCC.HSI_VALUE=16000000
+RCC.I2C1Freq_Value=48000000
+RCC.I2C2Freq_Value=48000000
+RCC.I2C3Freq_Value=48000000
+RCC.I2C4Freq_Value=48000000
+RCC.I2SClocksFreq_Value=48000000
+RCC.I2SFreq_Value=192000000
+RCC.IPParameters=48MHZClocksFreq_Value,ADC12outputFreq_Value,ADC34outputFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CECFreq_Value,CortexFreq_Value,DFSDMAudioFreq_Value,DFSDMFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SClocksFreq_Value,I2SFreq_Value,LCDTFTFreq_Value,LCDTFToutputFreq_Value,LPTIM1Freq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,MCO2PinFreq_Value,MCOFreq_Value,PLLCLKFreq_Value,PLLI2SPCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLI2SRoutputFreq_Value,PLLM,PLLMCOFreq_Value,PLLMUL,PLLN,PLLQ,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLRFreq_Value,PLLSAIPCLKFreq_Value,PLLSAIQCLKFreq_Value,PLLSAIRCLKFreq_Value,PLLSAIoutputFreq_Value,PRESCALERUSB,RNGFreq_Value,RTCFreq_Value,RTCHSEDivFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMC2Freq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,SYSCLKSourceVirtual,TIM15Freq_Value,TIM16Freq_Value,TIM17Freq_Value,TIM1Freq_Value,TIM20Freq_Value,TIM2Freq_Value,TIM3Freq_Value,TIM8Freq_Value,UART4Freq_Value,UART5Freq_Value,UART7Freq_Value,UART8Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,USBFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutput2Freq_Value,VCOOutputFreq_Value,VCOSAIOutputFreq_Value,VcooutputI2S,WatchDogFreq_Value
+RCC.LCDTFTFreq_Value=96000000
+RCC.LCDTFToutputFreq_Value=96000000
+RCC.LPTIM1Freq_Value=48000000
+RCC.LSE_VALUE=32768
+RCC.LSI_VALUE=32000
+RCC.MCO1PinFreq_Value=16000000
+RCC.MCO2PinFreq_Value=96000000
+RCC.MCOFreq_Value=72000000
+RCC.PLLCLKFreq_Value=96000000
+RCC.PLLI2SPCLKFreq_Value=192000000
+RCC.PLLI2SQCLKFreq_Value=192000000
+RCC.PLLI2SRCLKFreq_Value=192000000
+RCC.PLLI2SRoutputFreq_Value=192000000
+RCC.PLLM=8
+RCC.PLLMCOFreq_Value=72000000
+RCC.PLLMUL=RCC_PLL_MUL9
+RCC.PLLN=96
+RCC.PLLQ=4
+RCC.PLLQCLKFreq_Value=48000000
+RCC.PLLQoutputFreq_Value=48000000
+RCC.PLLRFreq_Value=96000000
+RCC.PLLSAIPCLKFreq_Value=192000000
+RCC.PLLSAIQCLKFreq_Value=192000000
+RCC.PLLSAIRCLKFreq_Value=192000000
+RCC.PLLSAIoutputFreq_Value=192000000
+RCC.PRESCALERUSB=RCC_USBCLKSOURCE_PLL_DIV1_5
+RCC.RNGFreq_Value=48000000
+RCC.RTCFreq_Value=32000
+RCC.RTCHSEDivFreq_Value=4000000
+RCC.SAI1Freq_Value=192000000
+RCC.SAI2Freq_Value=192000000
+RCC.SDMMC2Freq_Value=96000000
+RCC.SDMMCFreq_Value=96000000
+RCC.SPDIFRXFreq_Value=192000000
+RCC.SYSCLKFreq_VALUE=96000000
+RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
+RCC.SYSCLKSourceVirtual=RCC_SYSCLKSOURCE_PLLCLK
+RCC.TIM15Freq_Value=72000000
+RCC.TIM16Freq_Value=72000000
+RCC.TIM17Freq_Value=72000000
+RCC.TIM1Freq_Value=72000000
+RCC.TIM20Freq_Value=72000000
+RCC.TIM2Freq_Value=72000000
+RCC.TIM3Freq_Value=72000000
+RCC.TIM8Freq_Value=72000000
+RCC.UART4Freq_Value=48000000
+RCC.UART5Freq_Value=48000000
+RCC.UART7Freq_Value=48000000
+RCC.UART8Freq_Value=48000000
+RCC.USART1Freq_Value=96000000
+RCC.USART2Freq_Value=48000000
+RCC.USART3Freq_Value=48000000
+RCC.USART6Freq_Value=96000000
+RCC.USBFreq_Value=48000000
+RCC.VCOI2SOutputFreq_Value=384000000
+RCC.VCOInputFreq_Value=2000000
+RCC.VCOOutput2Freq_Value=8000000
+RCC.VCOOutputFreq_Value=192000000
+RCC.VCOSAIOutputFreq_Value=384000000
+RCC.VcooutputI2S=48000000
+RCC.WatchDogFreq_Value=32000
+VP_SYS_VS_Systick.Mode=SysTick
+VP_SYS_VS_Systick.Signal=SYS_VS_Systick
+board=NUCLEO-F767ZI
+boardIOC=true
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/stm32f767/mcal_conf.cmake b/firmware/projects/Demo/CAN/Receive/platforms/stm32f767/mcal_conf.cmake
similarity index 100%
rename from firmware/projects/Demo/CAN/Bar/platforms/stm32f767/mcal_conf.cmake
rename to firmware/projects/Demo/CAN/Receive/platforms/stm32f767/mcal_conf.cmake
diff --git a/firmware/projects/Demo/CAN/Foo/CMakeLists.txt b/firmware/projects/Demo/CAN/Send/CMakeLists.txt
similarity index 77%
rename from firmware/projects/Demo/CAN/Foo/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Send/CMakeLists.txt
index f47c88a9c..6d212da49 100644
--- a/firmware/projects/Demo/CAN/Foo/CMakeLists.txt
+++ b/firmware/projects/Demo/CAN/Send/CMakeLists.txt
@@ -6,15 +6,7 @@
include("${CMAKE_SOURCE_DIR}/cmake/cangen.cmake")
-target_sources(main
- PRIVATE
- main.cc
-)
-
-target_include_directories(main
- PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/inc
-)
+target_sources(main PRIVATE main.cc)
# Notice that we don't include any mcal/ subdirectory in this CMake file.
# The master CMakeLists handles platform selection and library linking.
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Send/README.md b/firmware/projects/Demo/CAN/Send/README.md
new file mode 100644
index 000000000..0a1ab5847
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Send/README.md
@@ -0,0 +1,5 @@
+# Demo CAN Send Project
+
+This project is a minimal CAN message sender. It should be executed alongside the `Demo/CAN/Receive` project.
+
+See [Demo/CAN/README](../README.md).
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Send/bindings.h b/firmware/projects/Demo/CAN/Send/bindings.h
new file mode 100644
index 000000000..f6b6645fe
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Send/bindings.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include
+
+#include "shared/periph/can.h"
+#include "shared/periph/gpio.h"
+
+namespace bindings {
+
+extern shared::periph::CanBase& veh_can_base;
+extern shared::periph::DigitalInput& button;
+
+extern void Initialize();
+extern void TickBlocking(uint32_t);
+
+} // namespace bindings
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Send/config.yaml b/firmware/projects/Demo/CAN/Send/config.yaml
new file mode 100644
index 000000000..7a3d5b3e8
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Send/config.yaml
@@ -0,0 +1,5 @@
+canGen:
+ busses:
+ - name: demobus
+ node: SEND
+ dbcFile: "../demo.dbc"
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Send/main.cc b/firmware/projects/Demo/CAN/Send/main.cc
new file mode 100644
index 000000000..10416274c
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Send/main.cc
@@ -0,0 +1,34 @@
+/// @author Samuel Parent
+/// @date 2024-01-16
+
+#include
+
+#include "bindings.h"
+#include "generated/can/demobus_can_messages.h"
+#include "generated/can/demobus_msg_registry.h"
+#include "shared/comms/can/can_bus.h"
+
+generated::can::DemobusMsgRegistry veh_can_registry{};
+
+shared::can::CanBus veh_can_bus{
+ bindings::veh_can_base,
+ veh_can_registry,
+};
+
+int main(void) {
+ bindings::Initialize();
+ uint32_t interval_ms = 50;
+
+ generated::can::ButtonStatus btn_msg{};
+
+ while (true) {
+ veh_can_bus.Update();
+
+ btn_msg.state = bindings::button.Read();
+
+ veh_can_bus.Send(btn_msg);
+ bindings::TickBlocking(interval_ms);
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/cli/CMakeLists.txt b/firmware/projects/Demo/CAN/Send/platforms/cli/CMakeLists.txt
similarity index 100%
rename from firmware/projects/Demo/CAN/Foo/platforms/cli/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Send/platforms/cli/CMakeLists.txt
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/cli/bindings.cc b/firmware/projects/Demo/CAN/Send/platforms/cli/bindings.cc
similarity index 79%
rename from firmware/projects/Demo/CAN/Bar/platforms/cli/bindings.cc
rename to firmware/projects/Demo/CAN/Send/platforms/cli/bindings.cc
index bda69c104..64d3fdc72 100644
--- a/firmware/projects/Demo/CAN/Bar/platforms/cli/bindings.cc
+++ b/firmware/projects/Demo/CAN/Send/platforms/cli/bindings.cc
@@ -5,16 +5,20 @@
#include
#include "mcal/cli/periph/can.h"
+#include "mcal/cli/periph/gpio.h"
#include "shared/periph/can.h"
+#include "shared/periph/gpio.h"
namespace mcal {
using namespace cli::periph;
CanBase veh_can_base{"vcan0"};
+DigitalInput button{"Button"};
} // namespace mcal
namespace bindings {
shared::periph::CanBase& veh_can_base = mcal::veh_can_base;
+shared::periph::DigitalInput& button = mcal::button;
void TickBlocking(uint32_t ticks) {
std::chrono::milliseconds duration(ticks);
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/cli/mcal_conf.cmake b/firmware/projects/Demo/CAN/Send/platforms/cli/mcal_conf.cmake
similarity index 100%
rename from firmware/projects/Demo/CAN/Foo/platforms/cli/mcal_conf.cmake
rename to firmware/projects/Demo/CAN/Send/platforms/cli/mcal_conf.cmake
diff --git a/firmware/projects/Demo/CAN/Send/platforms/linux/CMakeLists.txt b/firmware/projects/Demo/CAN/Send/platforms/linux/CMakeLists.txt
new file mode 100644
index 000000000..b9b7a2e6e
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Send/platforms/linux/CMakeLists.txt
@@ -0,0 +1,4 @@
+target_sources(bindings PRIVATE bindings.cc)
+target_include_directories(bindings PRIVATE ${DIR_PROJECT})
+
+target_link_libraries(bindings PRIVATE mcal-linux)
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Send/platforms/linux/bindings.cc b/firmware/projects/Demo/CAN/Send/platforms/linux/bindings.cc
new file mode 100644
index 000000000..a164e557e
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Send/platforms/linux/bindings.cc
@@ -0,0 +1,31 @@
+#include
+
+#include
+
+#include "bindings.h"
+#include "mcal/linux/periph/can.h"
+#include "mcal/linux/periph/digital_input.h"
+
+namespace mcal {
+using namespace lnx::periph;
+
+CanBase veh_can_base{"vcan0"};
+DigitalInput button{"Button"};
+
+} // namespace mcal
+
+namespace bindings {
+
+shared::periph::CanBase& veh_can_base = mcal::veh_can_base;
+shared::periph::DigitalInput& button = mcal::button;
+
+void TickBlocking(uint32_t ms) {
+ usleep(1000 * ms);
+}
+
+void Initialize() {
+ std::cout << "Initializing Linux" << std::endl;
+ mcal::veh_can_base.Setup();
+}
+
+} // namespace bindings
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Send/platforms/linux/mcal_conf.cmake b/firmware/projects/Demo/CAN/Send/platforms/linux/mcal_conf.cmake
new file mode 100644
index 000000000..009913775
--- /dev/null
+++ b/firmware/projects/Demo/CAN/Send/platforms/linux/mcal_conf.cmake
@@ -0,0 +1 @@
+set(MCAL linux)
\ No newline at end of file
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/raspi/CMakeLists.txt b/firmware/projects/Demo/CAN/Send/platforms/raspi/CMakeLists.txt
similarity index 100%
rename from firmware/projects/Demo/CAN/Foo/platforms/raspi/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Send/platforms/raspi/CMakeLists.txt
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/raspi/bindings.cc b/firmware/projects/Demo/CAN/Send/platforms/raspi/bindings.cc
similarity index 100%
rename from firmware/projects/Demo/CAN/Bar/platforms/raspi/bindings.cc
rename to firmware/projects/Demo/CAN/Send/platforms/raspi/bindings.cc
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/raspi/mcal_conf.cmake b/firmware/projects/Demo/CAN/Send/platforms/raspi/mcal_conf.cmake
similarity index 100%
rename from firmware/projects/Demo/CAN/Foo/platforms/raspi/mcal_conf.cmake
rename to firmware/projects/Demo/CAN/Send/platforms/raspi/mcal_conf.cmake
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/stm32f767/CMakeLists.txt b/firmware/projects/Demo/CAN/Send/platforms/stm32f767/CMakeLists.txt
similarity index 100%
rename from firmware/projects/Demo/CAN/Foo/platforms/stm32f767/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Send/platforms/stm32f767/CMakeLists.txt
diff --git a/firmware/projects/Demo/CAN/Bar/platforms/stm32f767/bindings.cc b/firmware/projects/Demo/CAN/Send/platforms/stm32f767/bindings.cc
similarity index 81%
rename from firmware/projects/Demo/CAN/Bar/platforms/stm32f767/bindings.cc
rename to firmware/projects/Demo/CAN/Send/platforms/stm32f767/bindings.cc
index 34736d32f..3f32659d0 100644
--- a/firmware/projects/Demo/CAN/Bar/platforms/stm32f767/bindings.cc
+++ b/firmware/projects/Demo/CAN/Send/platforms/stm32f767/bindings.cc
@@ -7,8 +7,11 @@
#include "main.h"
// fw includes
+#include "../../bindings.h"
#include "mcal/stm32f767/periph/can.h"
+#include "mcal/stm32f767/periph/gpio.h"
#include "shared/periph/can.h"
+#include "shared/periph/gpio.h"
extern "C" {
/**
@@ -22,10 +25,12 @@ namespace mcal {
using namespace stm32f767::periph;
CanBase veh_can_base{&hcan3};
+DigitalInput button{ButtonPin_GPIO_Port, ButtonPin_Pin};
} // namespace mcal
namespace bindings {
shared::periph::CanBase& veh_can_base = mcal::veh_can_base;
+shared::periph::DigitalInput& button = mcal::button;
void Initialize() {
SystemClock_Config();
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/stm32f767/cubemx/.gitignore b/firmware/projects/Demo/CAN/Send/platforms/stm32f767/cubemx/.gitignore
similarity index 100%
rename from firmware/projects/Demo/CAN/Foo/platforms/stm32f767/cubemx/.gitignore
rename to firmware/projects/Demo/CAN/Send/platforms/stm32f767/cubemx/.gitignore
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/stm32f767/cubemx/CMakeLists.txt b/firmware/projects/Demo/CAN/Send/platforms/stm32f767/cubemx/CMakeLists.txt
similarity index 100%
rename from firmware/projects/Demo/CAN/Foo/platforms/stm32f767/cubemx/CMakeLists.txt
rename to firmware/projects/Demo/CAN/Send/platforms/stm32f767/cubemx/CMakeLists.txt
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/stm32f767/cubemx/board_config.ioc b/firmware/projects/Demo/CAN/Send/platforms/stm32f767/cubemx/board_config.ioc
similarity index 94%
rename from firmware/projects/Demo/CAN/Foo/platforms/stm32f767/cubemx/board_config.ioc
rename to firmware/projects/Demo/CAN/Send/platforms/stm32f767/cubemx/board_config.ioc
index 831d5b0de..ff4f59ecb 100644
--- a/firmware/projects/Demo/CAN/Foo/platforms/stm32f767/cubemx/board_config.ioc
+++ b/firmware/projects/Demo/CAN/Send/platforms/stm32f767/cubemx/board_config.ioc
@@ -1,192 +1,182 @@
-#MicroXplorer Configuration settings - do not modify
-CAD.formats=
-CAD.pinconfig=
-CAD.provider=
-CAN3.ABOM=ENABLE
-CAN3.BS1=CAN_BS1_13TQ
-CAN3.BS2=CAN_BS2_2TQ
-CAN3.CalculateBaudRate=500000
-CAN3.CalculateTimeBit=2000
-CAN3.CalculateTimeQuantum=125.0
-CAN3.IPParameters=CalculateTimeQuantum,CalculateBaudRate,Prescaler,CalculateTimeBit,BS1,BS2,ABOM,Mode
-CAN3.Mode=CAN_MODE_NORMAL
-CAN3.Prescaler=6
-File.Version=6
-GPIO.groupedBy=Group By Peripherals
-KeepUserPlacement=false
-Mcu.CPN=STM32F767ZIT6
-Mcu.Family=STM32F7
-Mcu.IP0=CAN3
-Mcu.IP1=CORTEX_M7
-Mcu.IP2=NVIC
-Mcu.IP3=RCC
-Mcu.IP4=SYS
-Mcu.IPNb=5
-Mcu.Name=STM32F767ZITx
-Mcu.Package=LQFP144
-Mcu.Pin0=PC13
-Mcu.Pin1=PG2
-Mcu.Pin2=PA8
-Mcu.Pin3=PA15
-Mcu.Pin4=PB7
-Mcu.Pin5=VP_SYS_VS_Systick
-Mcu.PinsNb=6
-Mcu.ThirdPartyNb=0
-Mcu.UserConstants=
-Mcu.UserName=STM32F767ZITx
-MxCube.Version=6.12.0
-MxDb.Version=DB.6.0.120
-NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.CAN3_RX0_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
-NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.ForceEnableDMAVector=true
-NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
-NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:false
-NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
-PA15.Locked=true
-PA15.Mode=CAN_Activate
-PA15.Signal=CAN3_TX
-PA8.Mode=CAN_Activate
-PA8.Signal=CAN3_RX
-PB7.GPIOParameters=GPIO_Label
-PB7.GPIO_Label=LedPin
-PB7.Locked=true
-PB7.Signal=GPIO_Output
-PC13.GPIOParameters=GPIO_PuPd,GPIO_Label
-PC13.GPIO_Label=ButtonPin
-PC13.GPIO_PuPd=GPIO_PULLDOWN
-PC13.Locked=true
-PC13.Signal=GPIO_Input
-PG2.GPIOParameters=PinState,GPIO_Label
-PG2.GPIO_Label=FC_ENABLE
-PG2.Locked=true
-PG2.PinState=GPIO_PIN_SET
-PG2.Signal=GPIO_Output
-PinOutPanel.RotationAngle=0
-ProjectManager.AskForMigrate=true
-ProjectManager.BackupPrevious=false
-ProjectManager.CompilerOptimize=6
-ProjectManager.ComputerToolchain=false
-ProjectManager.CoupleFile=true
-ProjectManager.CustomerFirmwarePackage=
-ProjectManager.DefaultFWLocation=true
-ProjectManager.DeletePrevious=true
-ProjectManager.DeviceId=STM32F767ZITx
-ProjectManager.FirmwarePackage=STM32Cube FW_F7 V1.17.2
-ProjectManager.FreePins=false
-ProjectManager.HalAssertFull=false
-ProjectManager.HeapSize=0x200
-ProjectManager.KeepUserCode=false
-ProjectManager.LastFirmware=true
-ProjectManager.LibraryCopy=1
-ProjectManager.MainLocation=Src
-ProjectManager.NoMain=true
-ProjectManager.PreviousToolchain=
-ProjectManager.ProjectBuild=false
-ProjectManager.ProjectFileName=board_config.ioc
-ProjectManager.ProjectName=board_config
-ProjectManager.ProjectStructure=
-ProjectManager.RegisterCallBack=
-ProjectManager.StackSize=0x400
-ProjectManager.TargetToolchain=Makefile
-ProjectManager.ToolChainLocation=
-ProjectManager.UAScriptAfterPath=
-ProjectManager.UAScriptBeforePath=
-ProjectManager.UnderRoot=false
-ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_CAN3_Init-CAN3-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
-RCC.48MHZClocksFreq_Value=24000000
-RCC.ADC12outputFreq_Value=72000000
-RCC.ADC34outputFreq_Value=72000000
-RCC.AHBFreq_Value=96000000
-RCC.APB1CLKDivider=RCC_HCLK_DIV2
-RCC.APB1Freq_Value=48000000
-RCC.APB1TimFreq_Value=96000000
-RCC.APB2Freq_Value=96000000
-RCC.APB2TimFreq_Value=96000000
-RCC.CECFreq_Value=32786.88524590164
-RCC.CortexFreq_Value=96000000
-RCC.DFSDMAudioFreq_Value=192000000
-RCC.DFSDMFreq_Value=96000000
-RCC.EthernetFreq_Value=96000000
-RCC.FCLKCortexFreq_Value=96000000
-RCC.FamilyName=M
-RCC.HCLKFreq_Value=96000000
-RCC.HSE_VALUE=8000000
-RCC.HSI_VALUE=16000000
-RCC.I2C1Freq_Value=48000000
-RCC.I2C2Freq_Value=48000000
-RCC.I2C3Freq_Value=48000000
-RCC.I2C4Freq_Value=48000000
-RCC.I2SClocksFreq_Value=48000000
-RCC.I2SFreq_Value=192000000
-RCC.IPParameters=48MHZClocksFreq_Value,ADC12outputFreq_Value,ADC34outputFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CECFreq_Value,CortexFreq_Value,DFSDMAudioFreq_Value,DFSDMFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SClocksFreq_Value,I2SFreq_Value,LCDTFTFreq_Value,LCDTFToutputFreq_Value,LPTIM1Freq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,MCO2PinFreq_Value,MCOFreq_Value,PLLCLKFreq_Value,PLLI2SPCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLI2SRoutputFreq_Value,PLLM,PLLMCOFreq_Value,PLLMUL,PLLN,PLLQ,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLRFreq_Value,PLLSAIPCLKFreq_Value,PLLSAIQCLKFreq_Value,PLLSAIRCLKFreq_Value,PLLSAIoutputFreq_Value,PRESCALERUSB,RNGFreq_Value,RTCFreq_Value,RTCHSEDivFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMC2Freq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,SYSCLKSourceVirtual,TIM15Freq_Value,TIM16Freq_Value,TIM17Freq_Value,TIM1Freq_Value,TIM20Freq_Value,TIM2Freq_Value,TIM3Freq_Value,TIM8Freq_Value,UART4Freq_Value,UART5Freq_Value,UART7Freq_Value,UART8Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,USBFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutput2Freq_Value,VCOOutputFreq_Value,VCOSAIOutputFreq_Value,VcooutputI2S,WatchDogFreq_Value
-RCC.LCDTFTFreq_Value=96000000
-RCC.LCDTFToutputFreq_Value=96000000
-RCC.LPTIM1Freq_Value=48000000
-RCC.LSE_VALUE=32768
-RCC.LSI_VALUE=32000
-RCC.MCO1PinFreq_Value=16000000
-RCC.MCO2PinFreq_Value=96000000
-RCC.MCOFreq_Value=72000000
-RCC.PLLCLKFreq_Value=96000000
-RCC.PLLI2SPCLKFreq_Value=192000000
-RCC.PLLI2SQCLKFreq_Value=192000000
-RCC.PLLI2SRCLKFreq_Value=192000000
-RCC.PLLI2SRoutputFreq_Value=192000000
-RCC.PLLM=8
-RCC.PLLMCOFreq_Value=72000000
-RCC.PLLMUL=RCC_PLL_MUL9
-RCC.PLLN=96
-RCC.PLLQ=4
-RCC.PLLQCLKFreq_Value=48000000
-RCC.PLLQoutputFreq_Value=48000000
-RCC.PLLRFreq_Value=96000000
-RCC.PLLSAIPCLKFreq_Value=192000000
-RCC.PLLSAIQCLKFreq_Value=192000000
-RCC.PLLSAIRCLKFreq_Value=192000000
-RCC.PLLSAIoutputFreq_Value=192000000
-RCC.PRESCALERUSB=RCC_USBCLKSOURCE_PLL_DIV1_5
-RCC.RNGFreq_Value=48000000
-RCC.RTCFreq_Value=32000
-RCC.RTCHSEDivFreq_Value=4000000
-RCC.SAI1Freq_Value=192000000
-RCC.SAI2Freq_Value=192000000
-RCC.SDMMC2Freq_Value=96000000
-RCC.SDMMCFreq_Value=96000000
-RCC.SPDIFRXFreq_Value=192000000
-RCC.SYSCLKFreq_VALUE=96000000
-RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
-RCC.SYSCLKSourceVirtual=RCC_SYSCLKSOURCE_PLLCLK
-RCC.TIM15Freq_Value=72000000
-RCC.TIM16Freq_Value=72000000
-RCC.TIM17Freq_Value=72000000
-RCC.TIM1Freq_Value=72000000
-RCC.TIM20Freq_Value=72000000
-RCC.TIM2Freq_Value=72000000
-RCC.TIM3Freq_Value=72000000
-RCC.TIM8Freq_Value=72000000
-RCC.UART4Freq_Value=48000000
-RCC.UART5Freq_Value=48000000
-RCC.UART7Freq_Value=48000000
-RCC.UART8Freq_Value=48000000
-RCC.USART1Freq_Value=96000000
-RCC.USART2Freq_Value=48000000
-RCC.USART3Freq_Value=48000000
-RCC.USART6Freq_Value=96000000
-RCC.USBFreq_Value=48000000
-RCC.VCOI2SOutputFreq_Value=384000000
-RCC.VCOInputFreq_Value=2000000
-RCC.VCOOutput2Freq_Value=8000000
-RCC.VCOOutputFreq_Value=192000000
-RCC.VCOSAIOutputFreq_Value=384000000
-RCC.VcooutputI2S=48000000
-RCC.WatchDogFreq_Value=32000
-VP_SYS_VS_Systick.Mode=SysTick
-VP_SYS_VS_Systick.Signal=SYS_VS_Systick
-board=NUCLEO-F767ZI
-boardIOC=true
+#MicroXplorer Configuration settings - do not modify
+CAD.formats=
+CAD.pinconfig=
+CAD.provider=
+CAN3.ABOM=ENABLE
+CAN3.BS1=CAN_BS1_13TQ
+CAN3.BS2=CAN_BS2_2TQ
+CAN3.CalculateBaudRate=500000
+CAN3.CalculateTimeBit=2000
+CAN3.CalculateTimeQuantum=125.0
+CAN3.IPParameters=CalculateTimeQuantum,CalculateBaudRate,Prescaler,CalculateTimeBit,BS1,BS2,ABOM,Mode
+CAN3.Mode=CAN_MODE_NORMAL
+CAN3.Prescaler=6
+File.Version=6
+GPIO.groupedBy=Group By Peripherals
+KeepUserPlacement=false
+Mcu.CPN=STM32F767ZIT6
+Mcu.Family=STM32F7
+Mcu.IP0=CAN3
+Mcu.IP1=CORTEX_M7
+Mcu.IP2=NVIC
+Mcu.IP3=RCC
+Mcu.IP4=SYS
+Mcu.IPNb=5
+Mcu.Name=STM32F767ZITx
+Mcu.Package=LQFP144
+Mcu.Pin0=PC13
+Mcu.Pin1=PB3
+Mcu.Pin2=PB4
+Mcu.Pin3=VP_SYS_VS_Systick
+Mcu.PinsNb=4
+Mcu.ThirdPartyNb=0
+Mcu.UserConstants=
+Mcu.UserName=STM32F767ZITx
+MxCube.Version=6.12.0
+MxDb.Version=DB.6.0.120
+NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.CAN3_RX0_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
+NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.ForceEnableDMAVector=true
+NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
+NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:false
+NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false
+PB3.Locked=true
+PB3.Mode=CAN_Activate
+PB3.Signal=CAN3_RX
+PB4.Locked=true
+PB4.Mode=CAN_Activate
+PB4.Signal=CAN3_TX
+PC13.GPIOParameters=GPIO_PuPd,GPIO_Label
+PC13.GPIO_Label=ButtonPin
+PC13.GPIO_PuPd=GPIO_PULLDOWN
+PC13.Locked=true
+PC13.Signal=GPIO_Input
+PinOutPanel.RotationAngle=0
+ProjectManager.AskForMigrate=true
+ProjectManager.BackupPrevious=false
+ProjectManager.CompilerOptimize=6
+ProjectManager.ComputerToolchain=false
+ProjectManager.CoupleFile=true
+ProjectManager.CustomerFirmwarePackage=
+ProjectManager.DefaultFWLocation=true
+ProjectManager.DeletePrevious=true
+ProjectManager.DeviceId=STM32F767ZITx
+ProjectManager.FirmwarePackage=STM32Cube FW_F7 V1.17.2
+ProjectManager.FreePins=false
+ProjectManager.HalAssertFull=false
+ProjectManager.HeapSize=0x200
+ProjectManager.KeepUserCode=false
+ProjectManager.LastFirmware=true
+ProjectManager.LibraryCopy=1
+ProjectManager.MainLocation=Src
+ProjectManager.NoMain=true
+ProjectManager.PreviousToolchain=
+ProjectManager.ProjectBuild=false
+ProjectManager.ProjectFileName=board_config.ioc
+ProjectManager.ProjectName=board_config
+ProjectManager.ProjectStructure=
+ProjectManager.RegisterCallBack=
+ProjectManager.StackSize=0x400
+ProjectManager.TargetToolchain=Makefile
+ProjectManager.ToolChainLocation=
+ProjectManager.UAScriptAfterPath=
+ProjectManager.UAScriptBeforePath=
+ProjectManager.UnderRoot=false
+ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_CAN3_Init-CAN3-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
+RCC.48MHZClocksFreq_Value=24000000
+RCC.ADC12outputFreq_Value=72000000
+RCC.ADC34outputFreq_Value=72000000
+RCC.AHBFreq_Value=96000000
+RCC.APB1CLKDivider=RCC_HCLK_DIV2
+RCC.APB1Freq_Value=48000000
+RCC.APB1TimFreq_Value=96000000
+RCC.APB2Freq_Value=96000000
+RCC.APB2TimFreq_Value=96000000
+RCC.CECFreq_Value=32786.88524590164
+RCC.CortexFreq_Value=96000000
+RCC.DFSDMAudioFreq_Value=192000000
+RCC.DFSDMFreq_Value=96000000
+RCC.EthernetFreq_Value=96000000
+RCC.FCLKCortexFreq_Value=96000000
+RCC.FamilyName=M
+RCC.HCLKFreq_Value=96000000
+RCC.HSE_VALUE=8000000
+RCC.HSI_VALUE=16000000
+RCC.I2C1Freq_Value=48000000
+RCC.I2C2Freq_Value=48000000
+RCC.I2C3Freq_Value=48000000
+RCC.I2C4Freq_Value=48000000
+RCC.I2SClocksFreq_Value=48000000
+RCC.I2SFreq_Value=192000000
+RCC.IPParameters=48MHZClocksFreq_Value,ADC12outputFreq_Value,ADC34outputFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CECFreq_Value,CortexFreq_Value,DFSDMAudioFreq_Value,DFSDMFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SClocksFreq_Value,I2SFreq_Value,LCDTFTFreq_Value,LCDTFToutputFreq_Value,LPTIM1Freq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,MCO2PinFreq_Value,MCOFreq_Value,PLLCLKFreq_Value,PLLI2SPCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLI2SRoutputFreq_Value,PLLM,PLLMCOFreq_Value,PLLMUL,PLLN,PLLQ,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLRFreq_Value,PLLSAIPCLKFreq_Value,PLLSAIQCLKFreq_Value,PLLSAIRCLKFreq_Value,PLLSAIoutputFreq_Value,PRESCALERUSB,RNGFreq_Value,RTCFreq_Value,RTCHSEDivFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMC2Freq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,SYSCLKSourceVirtual,TIM15Freq_Value,TIM16Freq_Value,TIM17Freq_Value,TIM1Freq_Value,TIM20Freq_Value,TIM2Freq_Value,TIM3Freq_Value,TIM8Freq_Value,UART4Freq_Value,UART5Freq_Value,UART7Freq_Value,UART8Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,USBFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutput2Freq_Value,VCOOutputFreq_Value,VCOSAIOutputFreq_Value,VcooutputI2S,WatchDogFreq_Value
+RCC.LCDTFTFreq_Value=96000000
+RCC.LCDTFToutputFreq_Value=96000000
+RCC.LPTIM1Freq_Value=48000000
+RCC.LSE_VALUE=32768
+RCC.LSI_VALUE=32000
+RCC.MCO1PinFreq_Value=16000000
+RCC.MCO2PinFreq_Value=96000000
+RCC.MCOFreq_Value=72000000
+RCC.PLLCLKFreq_Value=96000000
+RCC.PLLI2SPCLKFreq_Value=192000000
+RCC.PLLI2SQCLKFreq_Value=192000000
+RCC.PLLI2SRCLKFreq_Value=192000000
+RCC.PLLI2SRoutputFreq_Value=192000000
+RCC.PLLM=8
+RCC.PLLMCOFreq_Value=72000000
+RCC.PLLMUL=RCC_PLL_MUL9
+RCC.PLLN=96
+RCC.PLLQ=4
+RCC.PLLQCLKFreq_Value=48000000
+RCC.PLLQoutputFreq_Value=48000000
+RCC.PLLRFreq_Value=96000000
+RCC.PLLSAIPCLKFreq_Value=192000000
+RCC.PLLSAIQCLKFreq_Value=192000000
+RCC.PLLSAIRCLKFreq_Value=192000000
+RCC.PLLSAIoutputFreq_Value=192000000
+RCC.PRESCALERUSB=RCC_USBCLKSOURCE_PLL_DIV1_5
+RCC.RNGFreq_Value=48000000
+RCC.RTCFreq_Value=32000
+RCC.RTCHSEDivFreq_Value=4000000
+RCC.SAI1Freq_Value=192000000
+RCC.SAI2Freq_Value=192000000
+RCC.SDMMC2Freq_Value=96000000
+RCC.SDMMCFreq_Value=96000000
+RCC.SPDIFRXFreq_Value=192000000
+RCC.SYSCLKFreq_VALUE=96000000
+RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
+RCC.SYSCLKSourceVirtual=RCC_SYSCLKSOURCE_PLLCLK
+RCC.TIM15Freq_Value=72000000
+RCC.TIM16Freq_Value=72000000
+RCC.TIM17Freq_Value=72000000
+RCC.TIM1Freq_Value=72000000
+RCC.TIM20Freq_Value=72000000
+RCC.TIM2Freq_Value=72000000
+RCC.TIM3Freq_Value=72000000
+RCC.TIM8Freq_Value=72000000
+RCC.UART4Freq_Value=48000000
+RCC.UART5Freq_Value=48000000
+RCC.UART7Freq_Value=48000000
+RCC.UART8Freq_Value=48000000
+RCC.USART1Freq_Value=96000000
+RCC.USART2Freq_Value=48000000
+RCC.USART3Freq_Value=48000000
+RCC.USART6Freq_Value=96000000
+RCC.USBFreq_Value=48000000
+RCC.VCOI2SOutputFreq_Value=384000000
+RCC.VCOInputFreq_Value=2000000
+RCC.VCOOutput2Freq_Value=8000000
+RCC.VCOOutputFreq_Value=192000000
+RCC.VCOSAIOutputFreq_Value=384000000
+RCC.VcooutputI2S=48000000
+RCC.WatchDogFreq_Value=32000
+VP_SYS_VS_Systick.Mode=SysTick
+VP_SYS_VS_Systick.Signal=SYS_VS_Systick
+board=NUCLEO-F767ZI
+boardIOC=true
diff --git a/firmware/projects/Demo/CAN/Foo/platforms/stm32f767/mcal_conf.cmake b/firmware/projects/Demo/CAN/Send/platforms/stm32f767/mcal_conf.cmake
similarity index 100%
rename from firmware/projects/Demo/CAN/Foo/platforms/stm32f767/mcal_conf.cmake
rename to firmware/projects/Demo/CAN/Send/platforms/stm32f767/mcal_conf.cmake
diff --git a/firmware/projects/Demo/CAN/demo.dbc b/firmware/projects/Demo/CAN/demo.dbc
index 24a09bcbd..ece2a342a 100644
--- a/firmware/projects/Demo/CAN/demo.dbc
+++ b/firmware/projects/Demo/CAN/demo.dbc
@@ -1,54 +1,8 @@
-
VERSION ""
-
-NS_ :
- NS_DESC_
- CM_
- BA_DEF_
- BA_
- VAL_
- CAT_DEF_
- CAT_
- FILTER
- BA_DEF_DEF_
- EV_DATA_
- ENVVAR_DATA_
- SGTYPE_
- SGTYPE_VAL_
- BA_DEF_SGTYPE_
- BA_SGTYPE_
- SIG_TYPE_REF_
- VAL_TABLE_
- SIG_GROUP_
- SIG_VALTYPE_
- SIGTYPE_VALTYPE_
- BO_TX_BU_
- BA_DEF_REL_
- BA_REL_
- BA_DEF_DEF_REL_
- BU_SG_REL_
- BU_EV_REL_
- BU_BO_REL_
- SG_MUL_VAL_
-
BS_:
-BU_: FOO BAR
-
-
-BO_ 940 TempSensors: 8 FOO
- SG_ Sensor1 : 54|10@1- (0.2,0) [0|0] "degC" BAR
- SG_ Sensor2 : 44|10@1- (0.2,0) [0|0] "degC" BAR
- SG_ Sensor3 : 34|10@1- (0.2,0) [0|0] "degC" BAR
- SG_ Sensor4 : 24|10@1- (0.2,0) [0|0] "degC" BAR
- SG_ Sensor5 : 14|10@1- (0.2,0) [0|0] "degC" BAR
- SG_ Sensor6 : 4|10@1- (0.2,0) [0|0] "degC" BAR
-
-BO_ 941 TempSensorsReply: 8 BAR
- SG_ Sensor1 : 54|10@1- (0.2,0) [0|0] "degC" FOO
- SG_ Sensor2 : 44|10@1- (0.2,0) [0|0] "degC" FOO
- SG_ Sensor3 : 34|10@1- (0.2,0) [0|0] "degC" FOO
- SG_ Sensor4 : 24|10@1- (0.2,0) [0|0] "degC" FOO
- SG_ Sensor5 : 14|10@1- (0.2,0) [0|0] "degC" FOO
- SG_ Sensor6 : 4|10@1- (0.2,0) [0|0] "degC" FOO
\ No newline at end of file
+BU_: SEND RECV
+
+BO_ 940 ButtonStatus: 1 SEND
+ SG_ State : 0|1@1+ (1,0) [0|1] "bool" RECV
diff --git a/firmware/projects/Demo/CAN/vcan_setup.sh b/firmware/projects/Demo/CAN/vcan_setup.sh
new file mode 100644
index 000000000..dcd426e81
--- /dev/null
+++ b/firmware/projects/Demo/CAN/vcan_setup.sh
@@ -0,0 +1,4 @@
+sudo modprobe -a can can_raw vcan
+sudo ip link add dev vcan0 type vcan
+sudo ip link set up vcan0
+ip link show vcan0
\ No newline at end of file