Files
RTOS/applications/dashboard/src/gauge_control.c
T
root ca13734bf0 Add full automotive RTOS project
Add kernel (Cortex-M0/M3/M4, Tricore, S32K, RISC-V ports), drivers,
middleware (CAN stack, diagnostics, safety), applications, board
support, build/test tooling, and documentation.
2026-08-23 03:35:29 -04:00

201 lines
5.5 KiB
C

/**
* @file gauge_control.c
* @brief Analog gauge control for dashboard
*/
#include "kernel.h"
#include "pwm_driver.h"
#include "adc_driver.h"
#include "can_driver.h"
#include <string.h>
#include <math.h>
/* Gauge Control State */
typedef struct {
bool initialized;
uint16_t speed_gauge_position;
uint16_t rpm_gauge_position;
uint16_t fuel_gauge_position;
uint16_t temp_gauge_position;
uint16_t target_positions[4];
Mutex_t mutex;
} GaugeControlState_t;
static GaugeControlState_t gauge_control;
/* Initialize Gauge Control */
KernelStatus_t gauge_control_init(void) {
if (gauge_control.initialized) {
return KERNEL_ERROR;
}
memset(&gauge_control, 0, sizeof(GaugeControlState_t));
/* Initialize PWM for gauges */
pwm_init(3, &(PwmConfig_t){
.frequency_hz = 100, /* 100 Hz for smooth gauge movement */
.channel_count = 4,
.channels = {
{.channel = 0, .duty_cycle = 0}, /* Speedometer */
{.channel = 1, .duty_cycle = 0}, /* Tachometer */
{.channel = 2, .duty_cycle = 0}, /* Fuel gauge */
{.channel = 3, .duty_cycle = 0} /* Temperature gauge */
}
});
mutex_create(&gauge_control.mutex, false);
gauge_control.initialized = true;
return KERNEL_OK;
}
/* Gauge Control Task */
void gauge_control_task(void* parameters) {
(void)parameters;
while (1) {
/* Read CAN messages for gauge data */
CanMessage_t message;
while (can_receive_message(&message, 0) == KERNEL_OK) {
process_gauge_message(&message);
}
/* Smooth gauge movement */
smooth_gauge_movement();
/* 10ms update rate */
kernel_delay(10);
}
}
/* Process Gauge Message */
static void process_gauge_message(const CanMessage_t* message) {
mutex_lock(&gauge_control.mutex, 100);
switch (message->id.id) {
case 0x300: /* Engine data */
/* RPM: 0-8000 RPM maps to 0-10000 duty cycle */
gauge_control.target_positions[1] =
((message->data[0] << 8) | message->data[1]) * 10000 / 8000;
/* Temperature: -40 to 120°C maps to 0-10000 */
int16_t temp = (message->data[2] << 8) | message->data[3];
gauge_control.target_positions[3] =
(temp + 40) * 10000 / 160;
break;
case 0x301: /* Vehicle speed */
/* Speed: 0-240 km/h maps to 0-10000 */
gauge_control.target_positions[0] =
((message->data[0] << 8) | message->data[1]) * 10000 / 240;
break;
case 0x302: /* Fuel level */
/* Fuel: 0-100% maps to 0-10000 */
gauge_control.target_positions[2] = message->data[0] * 100;
break;
}
mutex_unlock(&gauge_control.mutex);
}
/* Smooth Gauge Movement */
static void smooth_gauge_movement(void) {
mutex_lock(&gauge_control.mutex, 100);
/* Smooth movement for each gauge */
for (int i = 0; i < 4; i++) {
uint16_t current = 0;
uint16_t target = gauge_control.target_positions[i];
/* Get current position */
switch (i) {
case 0:
current = gauge_control.speed_gauge_position;
break;
case 1:
current = gauge_control.rpm_gauge_position;
break;
case 2:
current = gauge_control.fuel_gauge_position;
break;
case 3:
current = gauge_control.temp_gauge_position;
break;
}
/* Calculate new position with smoothing */
int32_t delta = target - current;
uint16_t new_position = current + (delta / 10); /* 10% movement per update */
/* Update position */
switch (i) {
case 0:
gauge_control.speed_gauge_position = new_position;
break;
case 1:
gauge_control.rpm_gauge_position = new_position;
break;
case 2:
gauge_control.fuel_gauge_position = new_position;
break;
case 3:
gauge_control.temp_gauge_position = new_position;
break;
}
/* Update PWM output */
pwm_set_duty_cycle(3, i, new_position);
}
mutex_unlock(&gauge_control.mutex);
}
/* Calibrate Gauges */
KernelStatus_t gauge_calibrate(uint8_t gauge, uint16_t min_position,
uint16_t max_position) {
if (!gauge_control.initialized || gauge >= 4) {
return KERNEL_ERROR;
}
mutex_lock(&gauge_control.mutex, 100);
/* Set gauge to minimum position */
pwm_set_duty_cycle(3, gauge, min_position);
kernel_delay(1000); /* Wait 1 second */
/* Set gauge to maximum position */
pwm_set_duty_cycle(3, gauge, max_position);
kernel_delay(1000); /* Wait 1 second */
/* Return to zero */
pwm_set_duty_cycle(3, gauge, min_position);
mutex_unlock(&gauge_control.mutex);
return KERNEL_OK;
}
/* Self-Test Gauges */
KernelStatus_t gauge_self_test(void) {
if (!gauge_control.initialized) {
return KERNEL_ERROR;
}
/* Perform gauge sweep */
for (uint16_t position = 0; position <= 10000; position += 100) {
for (int i = 0; i < 4; i++) {
pwm_set_duty_cycle(3, i, position);
}
kernel_delay(10);
}
/* Return to zero */
for (int i = 0; i < 4; i++) {
pwm_set_duty_cycle(3, i, 0);
}
return KERNEL_OK;
}