From dd67d2afddb576376f54b7f6b937e44b9e419ce1 Mon Sep 17 00:00:00 2001 From: adrigongv23 Date: Tue, 10 Feb 2026 15:00:39 +0100 Subject: [PATCH] =?UTF-8?q?Archivos=20iniciales=20a=C3=B1adidos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Escritorio_Boxes/diseño.py | 35 +++ Escritorio_Boxes/monitor.py | 92 +++++++ Firmware/G26-Telemetria/G26-Telemetria.ino | 100 +++++++ Firmware/G26-Telemetria/include/can.hpp | 49 ++++ .../include/common_libraries.hpp | 22 ++ .../G26-Telemetria/include/data_processor.hpp | 33 +++ Firmware/G26-Telemetria/src/can.cpp | 223 ++++++++++++++++ .../G26-Telemetria/src/data_processor.cpp | 251 ++++++++++++++++++ 8 files changed, 805 insertions(+) create mode 100644 Escritorio_Boxes/diseño.py create mode 100644 Escritorio_Boxes/monitor.py create mode 100644 Firmware/G26-Telemetria/G26-Telemetria.ino create mode 100644 Firmware/G26-Telemetria/include/can.hpp create mode 100644 Firmware/G26-Telemetria/include/common_libraries.hpp create mode 100644 Firmware/G26-Telemetria/include/data_processor.hpp create mode 100644 Firmware/G26-Telemetria/src/can.cpp create mode 100644 Firmware/G26-Telemetria/src/data_processor.cpp diff --git a/Escritorio_Boxes/diseño.py b/Escritorio_Boxes/diseño.py new file mode 100644 index 0000000..094772d --- /dev/null +++ b/Escritorio_Boxes/diseño.py @@ -0,0 +1,35 @@ +import socket +import time +import math +import random +from datetime import datetime # <--- IMPORTANTE: Nueva librería + +UDP_IP = "127.0.0.1" +UDP_PORT = 4210 + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + +print("TELEMETRÍA SIMULADA - ENVÍO DE DATOS") +print(" Formato: ECT | RPM | BATT | SPEED | HH:MM:SS") + +t = 0 +while True: + # Generación de datos (Igual que antes) + ect = 85 + (5 * math.sin(t / 5.0)) + random.uniform(-0.2, 0.2) + rpm = 3000 + (1000 * math.sin(t / 2.0)) + batt = 13.8 + random.uniform(-0.1, 0.1) + speed = 90 + (30 * math.sin(t / 3.0)) + + # --- CAMBIO AQUÍ: OBTENER HORA REAL --- + # Obtenemos hora actual y la convertimos a texto + hora_real = datetime.now().strftime("%H:%M:%S.%f")[:-3] # Hora con milisegundos + + # Mensaje con la hora legible al final + mensaje = f"{ect:.2f}|{int(rpm)}|{batt:.2f}|{int(speed)}|{hora_real}" + + sock.sendto(mensaje.encode(), (UDP_IP, UDP_PORT)) + + print(f"TX: {mensaje}") + + t += 0.1 + time.sleep(0.002) \ No newline at end of file diff --git a/Escritorio_Boxes/monitor.py b/Escritorio_Boxes/monitor.py new file mode 100644 index 0000000..b78278d --- /dev/null +++ b/Escritorio_Boxes/monitor.py @@ -0,0 +1,92 @@ +import socket +import matplotlib.pyplot as plt +import matplotlib.animation as animation +from collections import deque + +# --- CONFIGURACIÓN --- +UDP_IP = "0.0.0.0" +UDP_PORT = 4210 +MAX_PUNTOS = 150 + +data_ect = deque([0]*MAX_PUNTOS, maxlen=MAX_PUNTOS) +data_rpm = deque([0]*MAX_PUNTOS, maxlen=MAX_PUNTOS) +data_bat = deque([0]*MAX_PUNTOS, maxlen=MAX_PUNTOS) +data_spd = deque([0]*MAX_PUNTOS, maxlen=MAX_PUNTOS) + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +sock.bind((UDP_IP, UDP_PORT)) +sock.setblocking(False) + +# --- DISEÑO GRÁFICO --- +plt.style.use('dark_background') +fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, sharex=True, figsize=(8, 10)) + +# Título principal + RELOJ +fig.suptitle('GADES TELEMETRY SYSTEM', fontsize=16, fontweight='bold', color='white') +# Creamos un texto vacío arriba a la derecha para la hora +texto_reloj = fig.text(0.85, 0.97, "--:--:--", fontsize=12, color='cyan', ha='center', fontweight='bold') + +def setup_plot(ax, color, label, y_min, y_max): + line, = ax.plot([], [], color=color, lw=2) + ax.set_ylabel(label) + ax.set_ylim(y_min, y_max) + ax.grid(True, alpha=0.3, linestyle='--') + props = dict(boxstyle='round', facecolor='black', alpha=0.7, edgecolor=color) + text = ax.text(0.03, 0.85, '', transform=ax.transAxes, + fontsize=14, color=color, fontweight='bold', bbox=props) + return line, text + +line_ect, txt_ect = setup_plot(ax1, '#ff3333', 'ECT (°C)', 50, 110) +line_rpm, txt_rpm = setup_plot(ax2, '#ffff33', 'RPM', 0, 5000) +line_bat, txt_bat = setup_plot(ax3, '#33ffff', 'BATT (V)', 12, 15) +line_spd, txt_spd = setup_plot(ax4, '#33ff33', 'SPEED', 0, 140) + +def update(frame): + try: + while True: + data, addr = sock.recvfrom(1024) + msg = data.decode('utf-8') + partes = msg.split('|') + + # Extraer valores numéricos + val_ect = float(partes[0]) + val_rpm = float(partes[1]) + val_bat = float(partes[2]) + val_spd = float(partes[3]) + + # --- EXTRAER LA HORA (Es el elemento 4) --- + val_time = partes[4] + + # Guardar datos + data_ect.append(val_ect) + data_rpm.append(val_rpm) + data_bat.append(val_bat) + data_spd.append(val_spd) + + # Actualizar textos gráficas + txt_ect.set_text(f"TEMP: {val_ect:.1f} °C") + txt_rpm.set_text(f"RPM: {int(val_rpm)}") + txt_bat.set_text(f"BATT: {val_bat:.2f} V") + txt_spd.set_text(f"VEL: {int(val_spd)} Km/h") + + # --- ACTUALIZAR EL RELOJ DE ARRIBA --- + texto_reloj.set_text(f"{val_time}") + + except BlockingIOError: + pass + except Exception as e: + print(f"Error: {e}") + + x_range = range(len(data_ect)) + line_ect.set_data(x_range, data_ect) + line_rpm.set_data(x_range, data_rpm) + line_bat.set_data(x_range, data_bat) + line_spd.set_data(x_range, data_spd) + + ax1.set_xlim(0, len(data_ect)) + + return line_ect, line_rpm, line_bat, line_spd, txt_ect, txt_rpm, txt_bat, txt_spd, texto_reloj + +plt.tight_layout(rect=[0, 0, 1, 0.96]) # Dejar hueco arriba para el reloj +ani = animation.FuncAnimation(fig, update, interval=20, blit=False, cache_frame_data=False) +plt.show() \ No newline at end of file diff --git a/Firmware/G26-Telemetria/G26-Telemetria.ino b/Firmware/G26-Telemetria/G26-Telemetria.ino new file mode 100644 index 0000000..cf3649e --- /dev/null +++ b/Firmware/G26-Telemetria/G26-Telemetria.ino @@ -0,0 +1,100 @@ +#include "include/data_processor.hpp" +#include "include/can.hpp" +#include "include/common_libraries.hpp" //Librerias Wifi y credenciales + +DataProcessor dataProcessor; +CAN canController; + +// Cliente seguro para HTTPS +WiFiClientSecure wifiClient; + +// --- ENVIO DE DATOS A TRAVÉS DE WIFI --- +// Esta función se ejecutará en paralelo sin bloquear el CAN +void TaskWifiSender(void *pvParameters) { + + Serial.println("[WIFI-TASK] Iniciando tarea de envío..."); + + while (true) { + // 1. Verificamos conexión WiFi + if (WiFi.status() == WL_CONNECTED) { + + HTTPClient http; + wifiClient.setInsecure(); // Importante para Firebase sin certificados complejos + + // 2. Preparamos el JSON + // Leemos la variable 'volatile' del dataProcessor + int tempActual = dataProcessor.current_ect_value; + + // Creamos la URL completa + String url = String(FIREBASE_HOST) + String(FIREBASE_PATH); + + // Creamos el payload JSON: {"valor": 95, "ts": 123456...} + String jsonPayload = "{\"valor\":" + String(tempActual) + "}"; + + // 3. Enviamos PUT o POST + http.begin(wifiClient, url); + int httpResponseCode = http.PUT(jsonPayload); // Usamos PUT para sobreescribir el valor actual + + if (httpResponseCode > 0) { + Serial.printf("[WIFI] Enviado ECT: %d C° | Resp: %d\n", tempActual, httpResponseCode); + } else { + Serial.printf("[WIFI] Error envío: %s\n", http.errorToString(httpResponseCode).c_str()); + } + http.end(); + + } else { + Serial.println("[WIFI] Desconectado. Reintentando..."); + // Si se desconecta, intentar reconectar (opcionalmente) + WiFi.disconnect(); + WiFi.reconnect(); + } + + // 4. Esperar X tiempo antes del siguiente envío (ej. 1000ms = 1seg) + // Usamos vTaskDelay en lugar de delay() para no bloquear + vTaskDelay(1000 / portTICK_PERIOD_MS); + } +} + +void setup() { + Serial.begin(115200); + + // 1. INICIAR CAN Y PANTALLA + // Pasamos el puntero de dataProcessor al controlador CAN + canController.set_data_proccessor(&dataProcessor); + canController.start(); + canController.start_listening_task(); + + // 2. INICIAR WIFI + Serial.println("--- CONECTANDO WIFI ---"); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + int intentos = 0; + while (WiFi.status() != WL_CONNECTED && intentos < 20) { + delay(500); + Serial.print("."); + intentos++; + } + if(WiFi.status() == WL_CONNECTED){ + Serial.println("\n[OK] WiFi Conectado."); + } else { + Serial.println("\n[ERR] No se pudo conectar WiFi (Continuando offline)."); + } + + // 3. CREAR TAREA WIFI (Multitasking) + // Esto lanza la función TaskWifiSender en un núcleo aparte o hilo paralelo + xTaskCreatePinnedToCore( + TaskWifiSender, // Función de la tarea + "WifiSender", // Nombre + 8192, // Tamaño de pila (Stack size) + NULL, // Parámetros + 1, // Prioridad (Baja, para que el CAN tenga prioridad) + NULL, // Handle + 0 // Núcleo (0 o 1) + ); + + Serial.println("[OK] Sistema ONLINE (CAN + Pantalla + WiFi)."); +} + +void loop(){ + // El loop se queda SOLO para la interfaz gráfica (LVGL) + vTaskDelay(5 / portTICK_PERIOD_MS); +} \ No newline at end of file diff --git a/Firmware/G26-Telemetria/include/can.hpp b/Firmware/G26-Telemetria/include/can.hpp new file mode 100644 index 0000000..65dead5 --- /dev/null +++ b/Firmware/G26-Telemetria/include/can.hpp @@ -0,0 +1,49 @@ +#ifndef CAN_HPP +#define CAN_HPP + +#define RX_PIN 13 +#define TX_PIN 38 +#define POLLING_RATE_MS 1000 +#define TRANSMIT_RATE_MS 1000 + +#include "driver/twai.h" +#include "common_libraries.hpp" +#include "data_processor.hpp" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/task.h" + +class CAN { +public: + CAN(): _mutex(xSemaphoreCreateMutex()), _listen_task_handle(NULL), _should_stop_listening(false) {} + ~CAN(); + void start(); + void listen(); + void start_listening_task(); + void stop_listening_task(); + void send_frame(twai_message_t message); + twai_message_t createBoolMessage(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7); + + void set_data_proccessor(DataProcessor *data_processor) { + _data_processor = data_processor; + } + + SemaphoreHandle_t get_mutex() { + return _mutex; + } + + static void listenTask(void *arg) { + CAN *controller = static_cast(arg); + controller->listen(); + } + +private: + twai_message_t _rx_message; + DataProcessor *_data_processor; + SemaphoreHandle_t _mutex; + TaskHandle_t _listen_task_handle; + volatile bool _should_stop_listening; + int test = 0; +}; + +#endif diff --git a/Firmware/G26-Telemetria/include/common_libraries.hpp b/Firmware/G26-Telemetria/include/common_libraries.hpp new file mode 100644 index 0000000..693fe0f --- /dev/null +++ b/Firmware/G26-Telemetria/include/common_libraries.hpp @@ -0,0 +1,22 @@ +#ifndef COMMON_LIBRARIES_HPP +#define COMMON_LIBRARIES_HPP + +#include +#include "time.h" +#include +#include + +//Librerías WiFi y HTTP --- +#include +#include +#include + +// --- CONFIGURACIÓN WIFI Y FIREBASE --- +#define WIFI_SSID "test" +#define WIFI_PASSWORD "12345678" + +#define FIREBASE_HOST "https://iot-formula-gades-default-rtdb.europe-west1.firebasedatabase.app" +// La ruta dentro de la base de datos donde guardaremos la temperatura +#define FIREBASE_PATH "/telemetria/temperatura.json" + +#endif \ No newline at end of file diff --git a/Firmware/G26-Telemetria/include/data_processor.hpp b/Firmware/G26-Telemetria/include/data_processor.hpp new file mode 100644 index 0000000..95e95ae --- /dev/null +++ b/Firmware/G26-Telemetria/include/data_processor.hpp @@ -0,0 +1,33 @@ +#ifndef DATAPROCESSOR_HPP +#define DATAPROCESSOR_HPP + +#include "common_libraries.hpp" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + + +class DataProcessor { +public: + DataProcessor() = default; + + //Variable publica para el CAN + volatile int current_ect_value = 0; + + //Métodos de recepción de CAN + + void send_serial_frame_0(int rpmh, int rpml, int tpsh, int tpsl, int ecth, int ectl, int gear); + //void send_serial_frame_1(int lfws, int rfws, int lrws, int rrws, int maph, int mapl, int ect); + //void send_serial_frame_2(int lambh, int lambl, int lamth, int lamtl, int bvolth, int bvoltl, int iat); + //void send_serial_frame_3(int aux1, int aux2, int aux3, int aux4, int aux5, int aux6, int aux7); + //void send_serial_frame_4(int aux1, int aux2, int aux3, int aux4, int aux5, int aux6, int aux7); + + + //Métodos extras + void send_serial(byte type, unsigned int value); + + char* process(std::vector data); + +private: +}; + +#endif \ No newline at end of file diff --git a/Firmware/G26-Telemetria/src/can.cpp b/Firmware/G26-Telemetria/src/can.cpp new file mode 100644 index 0000000..1e4b29e --- /dev/null +++ b/Firmware/G26-Telemetria/src/can.cpp @@ -0,0 +1,223 @@ +/** + * @file can.cpp + * @author Raúl Arcos Herrera + * @brief This file contains the implementation of the CAN Controller class for Link G4+ ECU. + */ + +#include "../include/can.hpp" + +static bool driver_installed = false; + +void CAN::start() { + Serial.println("Starting CAN Controller..."); + twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TX_PIN, (gpio_num_t)RX_PIN, TWAI_MODE_NORMAL); + twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS(); + twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); + + esp_err_t install_status = twai_driver_install(&g_config, &t_config, &f_config); + if (install_status != ESP_OK) { + Serial.println("Failed to install TWAI driver"); + driver_installed = false; + return; + } else { + Serial.println("TWAI driver installed"); + } + + esp_err_t start_status = twai_start(); + if (start_status != ESP_OK) { + Serial.println("Failed to start TWAI driver"); + driver_installed = false; + return; + } else { + Serial.println("TWAI driver started"); + } + + uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR | TWAI_ALERT_RX_QUEUE_FULL; + if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) { + Serial.println("CAN Alerts reconfigured"); + } else { + Serial.println("Failed to reconfigure alerts"); + driver_installed = false; + return; + } + + // TWAI driver is now successfully installed and started + driver_installed = true; +} + +CAN::~CAN() { + stop_listening_task(); + if (driver_installed) { + twai_stop(); + twai_driver_uninstall(); + driver_installed = false; + } +} + +void CAN::start_listening_task() { + if (_listen_task_handle == NULL) { + _should_stop_listening = false; + + BaseType_t result = xTaskCreate( + listenTask, // Task function + "CAN_Listen_Task", // Task name + 4096, // Stack size (words) + this, // Task parameter (this CAN instance) + 1, // Priority (lowered from 5 to 1) + &_listen_task_handle // Task handle + ); + + // BaseType_t result = xTaskCreatePinnedToCore( + // listenTask, // Task function + // "CAN_Listen_Task", // Task name + // 4096, // Stack size (words) + // this, // Task parameter (this CAN instance) + // 1, // Priority + // &_listen_task_handle, // Task handle + // 0 // Core 0 (main loop typically runs on Core 1) + // ); + + if (result == pdPASS) { + Serial.println("CAN listening task created successfully"); + } else { + Serial.println("Failed to create CAN listening task"); + _listen_task_handle = NULL; + } + } else { + Serial.println("CAN listening task already running"); + } +} + +void CAN::stop_listening_task() { + if (_listen_task_handle != NULL) { + _should_stop_listening = true; + + // Wait for task to finish (max 1 second) + for (int i = 0; i < 100; i++) { + if (_listen_task_handle == NULL) { + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + + // Force delete if still running + if (_listen_task_handle != NULL) { + vTaskDelete(_listen_task_handle); + _listen_task_handle = NULL; + } + + Serial.println("CAN listening task stopped"); + } +} + +void CAN::send_frame(twai_message_t message) { + while (xSemaphoreTake(_mutex, portMAX_DELAY) != pdTRUE) { + Serial.println("Retrying to take mutex in send_frame"); + } + twai_transmit(&message, pdMS_TO_TICKS(TRANSMIT_RATE_MS)); + xSemaphoreGive(_mutex); +} + +twai_message_t CAN::createBoolMessage(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7) { + twai_message_t message; + memset(&message, 0, sizeof(message)); + message.identifier = 0x001; + message.data[0] = (b7 << 7) | (b6 << 6) | (b5 << 5) | (b4 << 4) | + (b3 << 3) | (b2 << 2) | (b1 << 1) | b0; + message.data_length_code = 8; + message.flags = TWAI_MSG_FLAG_NONE; + return message; +} + +void CAN::listen() { + Serial.println("CAN listening task started"); + + // Continuous loop for the thread + while (!_should_stop_listening) { + if (!driver_installed) { + // Driver not installed + vTaskDelay(pdMS_TO_TICKS(1000)); + continue; + } + + // Check if alert happened + uint32_t alerts_triggered; + twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(1000)); // Reduced timeout for more responsiveness + twai_status_info_t twaistatus; + twai_get_status_info(&twaistatus); + + // Handle alerts + if (alerts_triggered & TWAI_ALERT_ERR_PASS) { + Serial.println("Alert: TWAI controller has become error passive."); + } + if (alerts_triggered & TWAI_ALERT_BUS_ERROR) { + Serial.println("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus."); + Serial.printf("Bus error count: %lu\n", twaistatus.bus_error_count); + } + if (alerts_triggered & TWAI_ALERT_RX_QUEUE_FULL) { + Serial.println("Alert: The RX queue is full causing a received frame to be lost."); + Serial.printf("RX buffered: %lu\t", twaistatus.msgs_to_rx); + Serial.printf("RX missed: %lu\t", twaistatus.rx_missed_count); + Serial.printf("RX overrun %lu\n", twaistatus.rx_overrun_count); + } + + if (alerts_triggered & TWAI_ALERT_RX_DATA) { + twai_message_t message; + int message_count = 0; + while (twai_receive(&message, 0) == ESP_OK && !_should_stop_listening) { + bool all_zeros = true; + for (int i = 0; i < message.data_length_code; i++) { + if (message.data[i] != 0) { + all_zeros = false; + break; + } + } + + if (all_zeros) { + Serial.println("Ignoring message with all zero data"); + taskYIELD(); + continue; + } + + if (message.extd) { + Serial.println("Extended Format"); + } else { + Serial.println("Standard Format"); + } + Serial.printf("ID: %lx\nByte:", message.identifier); + if (!(message.rtr)) { + for (int i = 0; i < message.data_length_code; i++) { + Serial.printf(" %d = %02x,", i, message.data[i]); + } + Serial.println(""); + + // Send to data processor based on first byte (maintaining original logic) + switch (message.data[0]) { + case 0: + _data_processor->send_serial_frame_0(message.data[1], message.data[2], message.data[3], message.data[4], message.data[5], message.data[6], message.data[7]); + break; + case 1: + //_data_processor->send_serial_frame_1(message.data[1], message.data[2], message.data[3], message.data[4], message.data[5], message.data[6], message.data[7]); + break; + case 2: + //_data_processor->send_serial_frame_2(message.data[1], message.data[2], message.data[3], message.data[4], message.data[5], message.data[6], message.data[7]); + break; + case 3: + //_data_processor->send_serial_frame_3(message.data[1], message.data[2], message.data[3], message.data[4], message.data[5], message.data[6], message.data[7]); + default: + break; + } + } + + taskYIELD(); + } + } + + taskYIELD(); + vTaskDelay(pdMS_TO_TICKS(5)); + } + + Serial.println("CAN listening task ending"); + _listen_task_handle = NULL; + vTaskDelete(NULL); // Delete this task +} diff --git a/Firmware/G26-Telemetria/src/data_processor.cpp b/Firmware/G26-Telemetria/src/data_processor.cpp new file mode 100644 index 0000000..7ba1c64 --- /dev/null +++ b/Firmware/G26-Telemetria/src/data_processor.cpp @@ -0,0 +1,251 @@ +#include "../include/data_processor.hpp" + +char* DataProcessor::process(std::vector data) { + // Implementación del procesamiento de datos si es necesario + return nullptr; // Placeholder +} + +void DataProcessor::send_serial(byte type, unsigned int value) { //Como parámetros se pasan el ID (type), que es el ID establecido al inicio del código para el dato que se quiera enviar. Ej: RPM_ID -> 0x51; y se envía el valor de dicho dato. + byte dato[8] = { 0x5A, 0xA5, 0x05, 0x82, 0x00, 0x00, 0x00, 0x00 }; //Se establece un arreglo de bytes con los primeros datos necesarios para que la pantalla lo interprete como mensaje (En la Wiki hay tutoriales que lo explican a fondo), como ser la longitud y el tipo de mensaje. + dato[4] = type; //Se configura en el mensaje el ID correspondiente al dato a enviar. + dato[6] = (value >> 8) & 0xFF; //Se configura el dato en los últimos 2 bytes. + dato[7] = value & 0xFF; + + Serial.write(dato, 8); //Se envía serialmente el mensaje, indicando su longituden bytes para ello. +} + +//RPM + TPS + vBatt + ECT +void DataProcessor::send_serial_frame_0(int rpmh, int rpml, int tpsh, int tpsl, int vbatth, int vbattl, int ect){ + Serial.println("send_serial_frame_0"); + + this -> current_ect_value = ect; //Actualizamos el valor de ECT para que pueda ser usado por otras clases + //Serial.printf("CAN RX -> ECT: %d \n", ect); +} + +/* + +//LAMB + LAMBTRG + FUEL + GEAR +void DataProcessor::send_serial_frame_1(int lmbh, int lmbl, int lmbth, int lmbtl, int fuelh, int fuell, int gear){ + Serial.println("send_serial_frame_1"); + int lmb = (lmbh * 256) + lmbl; + int lmbtrg = (lmbth * 256) + lmbtl; + int fuel = (fuelh * 256) + fuell; + _crow_panel_controller->set_value_to_label(ui_lambda, lmb); + _crow_panel_controller->set_value_to_label(ui_lambdatarget, lmbtrg); + _crow_panel_controller->set_value_to_label(ui_fuel, fuel); +// _crow_panel_controller->set_value_to_label(ui_gear, gear); + +} + + +void DataProcessor::send_serial_frame_2(int shut, int fan, int lmbch, int lmbcl, int brakeh, int brakel, int aux1){ + Serial.println("send_serial_frame_2"); + int lmbcorrect = (lmbch * 256) + lmbcl; + int brake = (brakeh * 256) + brakel; + + char shut_str[10]; + char fan_str[10]; + char aux1_str[10]; + + if (shut == 3){ + strcpy(shut_str, "ON"); + } else { + strcpy(shut_str, "OFF"); + } + + if (fan == 1){ + strcpy(fan_str, "ON"); + } else { + strcpy(fan_str, "OFF"); + } + + if (aux1 == 1){ + strcpy(aux1_str, "N"); + _crow_panel_controller->set_label_color(ui_PanelGear, CrowPanelController::COLOR_GOOD); + } else { + strcpy(aux1_str, "D"); + _crow_panel_controller->set_label_color(ui_PanelGear, CrowPanelController::COLOR_PANEL_DEFAULT); + } + + + + _crow_panel_controller->set_string_to_label(ui_shutdown, shut_str); + _crow_panel_controller->set_string_to_label(ui_fan, fan_str); + _crow_panel_controller->set_value_to_label(ui_correctionlambda, lmbcorrect); + _crow_panel_controller->set_value_to_label(ui_auxstatus9, brake); + _crow_panel_controller->set_string_to_label(ui_gear, aux1_str); + + // Shutdown status color + if (shut == 3) { + _crow_panel_controller->set_label_color(ui_shutdown, CrowPanelController::COLOR_CRITICAL); // Red when shutdown is ON (emergency) + } else { + _crow_panel_controller->set_label_color(ui_shutdown, CrowPanelController::COLOR_GOOD); // Green when shutdown is OFF (normal) + } + + // Fan status color + if (fan == 1) { + _crow_panel_controller->set_label_color(ui_fan, CrowPanelController::COLOR_BLUE); // Blue when fan is ON (cooling) + } else { + _crow_panel_controller->set_label_color(ui_fan, CrowPanelController::COLOR_NORMAL); // White when fan is OFF + } + + // Brake pressure color (assuming brake > 0 means brakes applied) + if (brake > 100) { // Adjust threshold as needed + _crow_panel_controller->set_label_color(ui_auxstatus9, CrowPanelController::COLOR_WARNING); // Yellow for heavy braking + } else if (brake > 0) { + _crow_panel_controller->set_label_color(ui_auxstatus9, CrowPanelController::COLOR_NORMAL); // White for light braking + } else { + _crow_panel_controller->set_label_color(ui_auxstatus9, CrowPanelController::COLOR_GOOD); // Green for no braking + } +} + +void DataProcessor::send_serial_frame_3(int aux3, int aux4, int aux5, int aux6, int aux7, int aux8, int dig1){ + Serial.println("send_serial_frame_3"); + + char aux3_str[10]; + char aux4_str[10]; + char aux5_str[10]; + char aux6_str[10]; + char aux7_str[10]; + char aux8_str[10]; + char dig1_str[10]; + + if (aux3 == 1){ + strcpy(aux3_str, "ON"); + } else { + strcpy(aux3_str, "OFF"); + } + + if (aux4 == 1){ + + strcpy(aux4_str, "ON"); + } else { + strcpy(aux4_str, "OFF"); + } + + if (aux5 == 1){ + strcpy(aux5_str, "ON"); + } else { + strcpy(aux5_str, "OFF"); + } + + if (aux6 == 1){ + strcpy(aux6_str, "ON"); + } else { + strcpy(aux6_str, "OFF"); + } + + if (aux7 == 1){ + strcpy(aux7_str, "ON"); + } else { + strcpy(aux7_str, "OFF"); + } + + if (aux8 == 1){ + strcpy(aux8_str, "ON"); + } else { + strcpy(aux8_str, "OFF"); + } + + if (dig1 == 1){ + strcpy(dig1_str, "ON"); + } else { + strcpy(dig1_str, "OFF"); + } + + _crow_panel_controller -> set_string_to_label(ui_auxstatus3, aux3_str); + if(aux3 == 1 && change_screen_requested == false){ + switch(current_display){ + case 0: + _crow_panel_controller->change_screen(ui_Screen1); + break; + case 1: + _crow_panel_controller->change_screen(ui_Screen2); + break; + case 2: + _crow_panel_controller->change_screen(ui_Screen3); + break; + case 3: + _crow_panel_controller->change_screen(ui_Screen4); + break; + } + current_display++; + change_screen_requested = true; + if(current_display > 3){ + current_display = 0; + } + }else if(aux3 == 0 && change_screen_requested == true){ + change_screen_requested = false; + } + + _crow_panel_controller -> set_string_to_label(ui_auxstatus4, aux4_str); + _crow_panel_controller -> set_string_to_label(ui_auxstatus5, aux5_str); + _crow_panel_controller -> set_string_to_label(ui_auxstatus6, aux6_str); + _crow_panel_controller -> set_string_to_label(ui_auxstatus7, aux7_str); + _crow_panel_controller -> set_string_to_label(ui_auxstatus8, aux8_str); + _crow_panel_controller -> set_string_to_label(ui_digitalstatus1, dig1_str); +} + +void DataProcessor::send_serial_frame_4(int dig3, int dig4, int dig5, int dig6, int dig7, int dig8, int dig9){ + Serial.println("send_serial_frame_4"); + char dig3_str[10]; + char dig4_str[10]; + char dig5_str[10]; + char dig6_str[10]; + char dig7_str[10]; + char dig8_str[10]; + char dig9_str[10]; + + if (dig3 == 1){ + strcpy(dig3_str, "ON"); + } else { + strcpy(dig3_str, "OFF"); + } + + if (dig4 == 1){ + strcpy(dig4_str, "ON"); + } else { + strcpy(dig4_str, "OFF"); + } + + if (dig5 == 1){ + strcpy(dig5_str, "ON"); + } else { + strcpy(dig5_str, "OFF"); + } + + if (dig6 == 1){ + strcpy(dig6_str, "ON"); + } else { + strcpy(dig6_str, "OFF"); + } + + if (dig7 == 1){ + strcpy(dig7_str, "ON"); + } else { + strcpy(dig7_str, "OFF"); + } + + if (dig8 == 1){ + strcpy(dig8_str, "ON"); + } else { + strcpy(dig8_str, "OFF"); + } + + if (dig9 == 1){ + strcpy(dig9_str, "ON"); + } else { + strcpy(dig9_str, "OFF"); + } + + _crow_panel_controller -> set_string_to_label(ui_digitalstatus3, dig3_str); + _crow_panel_controller -> set_string_to_label(ui_digitalstatus4, dig4_str); + _crow_panel_controller -> set_string_to_label(ui_digitalstatus5, dig5_str); + _crow_panel_controller -> set_string_to_label(ui_digitalstatus6, dig6_str); + _crow_panel_controller -> set_string_to_label(ui_digitalstatus7, dig7_str); + _crow_panel_controller -> set_string_to_label(ui_digitalstatus8, dig8_str); + _crow_panel_controller -> set_string_to_label(ui_digitalstatus9, dig9_str); +} +*/ + +