mirror of
https://github.com/adrigongv23/G26---Telemetry-Software.git
synced 2026-08-25 19:43:16 +02:00
Archivos iniciales añadidos
This commit is contained in:
parent
7b2267494e
commit
dd67d2afdd
8 changed files with 805 additions and 0 deletions
35
Escritorio_Boxes/diseño.py
Normal file
35
Escritorio_Boxes/diseño.py
Normal file
|
|
@ -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)
|
||||||
92
Escritorio_Boxes/monitor.py
Normal file
92
Escritorio_Boxes/monitor.py
Normal file
|
|
@ -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()
|
||||||
100
Firmware/G26-Telemetria/G26-Telemetria.ino
Normal file
100
Firmware/G26-Telemetria/G26-Telemetria.ino
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
49
Firmware/G26-Telemetria/include/can.hpp
Normal file
49
Firmware/G26-Telemetria/include/can.hpp
Normal file
|
|
@ -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<CAN*>(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
|
||||||
22
Firmware/G26-Telemetria/include/common_libraries.hpp
Normal file
22
Firmware/G26-Telemetria/include/common_libraries.hpp
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef COMMON_LIBRARIES_HPP
|
||||||
|
#define COMMON_LIBRARIES_HPP
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "time.h"
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//Librerías WiFi y HTTP ---
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
|
||||||
|
// --- 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
|
||||||
33
Firmware/G26-Telemetria/include/data_processor.hpp
Normal file
33
Firmware/G26-Telemetria/include/data_processor.hpp
Normal file
|
|
@ -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<float> data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
223
Firmware/G26-Telemetria/src/can.cpp
Normal file
223
Firmware/G26-Telemetria/src/can.cpp
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
251
Firmware/G26-Telemetria/src/data_processor.cpp
Normal file
251
Firmware/G26-Telemetria/src/data_processor.cpp
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
#include "../include/data_processor.hpp"
|
||||||
|
|
||||||
|
char* DataProcessor::process(std::vector<float> 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);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue