diff --git a/STM32_CO2_NODE/.cproject b/STM32_CO2_NODE/.cproject
index 24c3b77..dfaf178 100644
--- a/STM32_CO2_NODE/.cproject
+++ b/STM32_CO2_NODE/.cproject
@@ -212,5 +212,12 @@
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.cpp b/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.cpp
index e69de29..43bdf09 100644
--- a/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.cpp
+++ b/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.cpp
@@ -0,0 +1,31 @@
+#include "co2_can_protocol.hpp"
+
+CANProtocol::CANProtocol(CAN_HandleTypeDef* hcan)
+ : can(hcan)
+{
+ txHeader.StdId = 0x101;
+ txHeader.IDE = CAN_ID_STD;
+ txHeader.RTR = CAN_RTR_DATA;
+ txHeader.DLC = 2;
+}
+
+bool CANProtocol::sendCO2(uint16_t ppm) {
+ data[0] = ppm >> 8;
+ data[1] = ppm & 0xFF;
+
+ uint32_t mailbox;
+ return HAL_CAN_AddTxMessage(can, &txHeader, data, &mailbox) == HAL_OK;
+}
+
+bool CANProtocol::receiveCO2(uint16_t &ppm) {
+ CAN_RxHeaderTypeDef rxHeader;
+ uint8_t rxData[8];
+
+ if (HAL_CAN_GetRxFifoFillLevel(can, CAN_RX_FIFO0) == 0)
+ return false;
+
+ HAL_CAN_GetRxMessage(can, CAN_RX_FIFO0, &rxHeader, rxData);
+
+ ppm = (rxData[0] << 8) | rxData[1];
+ return true;
+}
diff --git a/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.hpp b/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.hpp
index e69de29..9ce41be 100644
--- a/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.hpp
+++ b/STM32_CO2_NODE/Drivers/CAN/co2_can_protocol.hpp
@@ -0,0 +1,22 @@
+#pragma once
+#include "stm32f1xx_hal.h"
+#include
+
+struct CO2Frame {
+ uint16_t ppm;
+ uint32_t timestamp;
+};
+
+class CANProtocol {
+public:
+ CANProtocol(CAN_HandleTypeDef* hcan);
+
+ bool sendCO2(uint16_t ppm);
+ bool receiveCO2(uint16_t &ppm);
+
+private:
+ CAN_HandleTypeDef* can;
+
+ CAN_TxHeaderTypeDef txHeader;
+ uint8_t data[8];
+};
diff --git a/STM32_CO2_NODE/FATFS/App/IPC/queues.cpp b/STM32_CO2_NODE/FATFS/App/IPC/queues.cpp
new file mode 100644
index 0000000..7186e96
--- /dev/null
+++ b/STM32_CO2_NODE/FATFS/App/IPC/queues.cpp
@@ -0,0 +1,4 @@
+#include "queues.hpp"
+
+QueueHandle_t g_sdQueue;
+QueueHandle_t g_canQueue;
diff --git a/STM32_CO2_NODE/FATFS/App/IPC/queues.hpp b/STM32_CO2_NODE/FATFS/App/IPC/queues.hpp
new file mode 100644
index 0000000..c08c6df
--- /dev/null
+++ b/STM32_CO2_NODE/FATFS/App/IPC/queues.hpp
@@ -0,0 +1,6 @@
+#pragma once
+#include "FreeRTOS.h"
+#include "queue.h"
+
+extern QueueHandle_t g_sdQueue;
+extern QueueHandle_t g_canQueue;
diff --git a/STM32_CO2_NODE/FATFS/App/Models/co2_data.hpp b/STM32_CO2_NODE/FATFS/App/Models/co2_data.hpp
new file mode 100644
index 0000000..ba5f803
--- /dev/null
+++ b/STM32_CO2_NODE/FATFS/App/Models/co2_data.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include
+
+struct CO2Data
+{
+ uint32_t timestamp;
+ uint16_t ppm;
+};
\ No newline at end of file
diff --git a/STM32_CO2_NODE/FATFS/App/Tasks/co2_task.cpp b/STM32_CO2_NODE/FATFS/App/Tasks/co2_task.cpp
new file mode 100644
index 0000000..62c19fd
--- /dev/null
+++ b/STM32_CO2_NODE/FATFS/App/Tasks/co2_task.cpp
@@ -0,0 +1,26 @@
+#include "co2_task.hpp"
+#include "mhz19c.hpp"
+#include "queues.hpp"
+#include "co2_data.hpp"
+
+extern MHZ19C sensor;
+
+void CO2Task_Run() {
+ uint16_t ppm;
+
+ while (1) {
+ sensor.requestCO2();
+ HAL_Delay(100);
+
+ if (sensor.readCO2(ppm)) {
+ CO2Data data;
+ data.ppm = ppm;
+ data.timestamp = HAL_GetTick();
+
+ xQueueSend(g_sdQueue, &data, 0);
+ xQueueSend(g_canQueue, &data, 0);
+ }
+
+ osDelay(1000);
+ }
+}
diff --git a/STM32_CO2_NODE/FATFS/App/Tasks/co2_task.hpp b/STM32_CO2_NODE/FATFS/App/Tasks/co2_task.hpp
new file mode 100644
index 0000000..532f1e3
--- /dev/null
+++ b/STM32_CO2_NODE/FATFS/App/Tasks/co2_task.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+void CO2Task_RunOnce();
diff --git a/STM32_CO2_NODE/FATFS/App/Tasks/sd_task.cpp b/STM32_CO2_NODE/FATFS/App/Tasks/sd_task.cpp
new file mode 100644
index 0000000..29c8983
--- /dev/null
+++ b/STM32_CO2_NODE/FATFS/App/Tasks/sd_task.cpp
@@ -0,0 +1,17 @@
+#include "sd_task.hpp"
+#include "sdcard.hpp"
+#include "queues.hpp"
+
+extern SDCardLogger sd;
+
+void SDTask_Run() {
+ CO2Data data;
+
+ while (1) {
+ if (xQueueReceive(g_sdQueue, &data, portMAX_DELAY)) {
+ char line[64];
+ sprintf(line, "CO2:%d t:%lu", data.ppm, data.timestamp);
+ sd.write(line);
+ }
+ }
+}
diff --git a/STM32_CO2_NODE/FATFS/App/Tasks/sd_task.hpp b/STM32_CO2_NODE/FATFS/App/Tasks/sd_task.hpp
new file mode 100644
index 0000000..5ee8e21
--- /dev/null
+++ b/STM32_CO2_NODE/FATFS/App/Tasks/sd_task.hpp
@@ -0,0 +1,13 @@
+#pragma once
+#include "fatfs.h"
+#include
+
+class SDCardLogger {
+public:
+ bool init();
+ bool write(const std::string &line);
+
+private:
+ FIL file;
+ FATFS fs;
+};