2019-06-09 15:46:41 -05:00
|
|
|
#include <stdlib.h>
|
2019-06-09 16:05:06 -05:00
|
|
|
#include <string.h>
|
2019-06-09 15:46:41 -05:00
|
|
|
|
2019-06-09 14:03:56 -05:00
|
|
|
#include <hexagram/cluster.h>
|
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
#define CLUSTER_WIDTH 1280
|
|
|
|
#define CLUSTER_HEIGHT 480
|
|
|
|
|
|
|
|
#define SHIFT_INDICATOR_X 392
|
|
|
|
#define SHIFT_INDICATOR_Y 24
|
|
|
|
|
|
|
|
#define SECTION_HEIGHT_TOP 64
|
|
|
|
#define SECTION_HEIGHT_BOTTOM 52
|
|
|
|
|
|
|
|
#define SPEEDO_MAX 200.0
|
|
|
|
#define SPEEDO_UNITS HEXAGRAM_SPEEDO_MPH
|
|
|
|
|
|
|
|
#define PATTERN_WIDTH 100
|
|
|
|
#define PATTERN_HEIGHT 87
|
|
|
|
|
|
|
|
static const double hexagon_pattern_color[3] = { 0.3, 0.1, 0.3 };
|
|
|
|
|
|
|
|
static const double hexagon_pattern_matrix[6] = {
|
|
|
|
0.21213203, 0.21213203, 0.21213203, -0.21213203, 1, 1
|
|
|
|
};
|
|
|
|
|
|
|
|
static const double hexagon_pattern_scale[2] = { 3, 3 };
|
|
|
|
|
|
|
|
static const char *hexagon_pattern =
|
|
|
|
"M 23.246093 0,"
|
|
|
|
" 0 13.382812,"
|
|
|
|
"V 44.689453"
|
|
|
|
"L 0.0839844 44.640625,"
|
|
|
|
" 24.033203 58.505859,"
|
|
|
|
" 24.001953 86.332031,"
|
|
|
|
" 22.841796 87"
|
|
|
|
"h 4.478516"
|
|
|
|
"L 26.068359 86.275391,"
|
|
|
|
" 26.099609 58.449219,"
|
|
|
|
" 50.083984 44.640625,"
|
|
|
|
" 74.033203 58.505859,"
|
|
|
|
" 74.001953 86.332031,"
|
|
|
|
" 72.841796 87"
|
|
|
|
"h 4.478516"
|
|
|
|
"L 76.068359 86.275391,"
|
|
|
|
" 76.099609 58.449219,"
|
|
|
|
" 100 44.689453,"
|
|
|
|
"V 13.365234"
|
|
|
|
"L 76.919921 0"
|
|
|
|
"H 73.246093"
|
|
|
|
"L 50.015625 13.373047,"
|
|
|
|
" 26.919921 0"
|
|
|
|
"Z"
|
|
|
|
"M 25.083984 1.25,"
|
|
|
|
" 49.033203 15.115234,"
|
|
|
|
" 49.001953, 42.941406,"
|
|
|
|
" 25.017578 56.75,"
|
|
|
|
" 1.0019531 42.845703,"
|
|
|
|
"l 0.033203 -27.75"
|
|
|
|
"z"
|
|
|
|
"m 50 0,"
|
|
|
|
" 24.017576 13.904297,"
|
|
|
|
" -0.0352 27.75"
|
|
|
|
"L 75.017578 56.75,"
|
|
|
|
" 51.068359 42.884766,"
|
|
|
|
" 51.099609 15.058594"
|
|
|
|
"Z";
|
2019-06-09 15:46:41 -05:00
|
|
|
|
2019-06-28 18:12:29 -05:00
|
|
|
int hexagram_cluster_filter_can_if(hexagram_can_if *can_if) {
|
2024-01-09 22:15:59 -05:00
|
|
|
struct can_filter filters[4] = {
|
2019-06-28 18:12:29 -05:00
|
|
|
{ .can_id = 0x280, .can_mask = 0x3f0 },
|
|
|
|
{ .can_id = 0x320, .can_mask = 0x320 },
|
2024-01-09 22:15:59 -05:00
|
|
|
{ .can_id = 0x540, .can_mask = 0x540 },
|
2019-06-28 18:12:29 -05:00
|
|
|
{ .can_id = 0x5a0, .can_mask = 0x5a0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
return setsockopt(hexagram_can_if_fd(can_if),
|
|
|
|
SOL_CAN_RAW,
|
|
|
|
CAN_RAW_FILTER,
|
|
|
|
&filters,
|
|
|
|
sizeof(filters));
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
int hexagram_cluster_init(hexagram_cluster *cluster,
|
|
|
|
double rpm_min,
|
|
|
|
double rpm_redline,
|
|
|
|
double rpm_max) {
|
|
|
|
cluster->width = CLUSTER_WIDTH;
|
|
|
|
cluster->height = CLUSTER_HEIGHT;
|
|
|
|
|
|
|
|
if (hexagram_pattern_init(&cluster->pattern,
|
|
|
|
PATTERN_WIDTH,
|
|
|
|
PATTERN_HEIGHT,
|
|
|
|
hexagon_pattern_color,
|
|
|
|
HEXAGRAM_PATTERN_STROKE,
|
|
|
|
hexagon_pattern,
|
|
|
|
strlen(hexagon_pattern)) < 0) {
|
|
|
|
goto error_pattern_init;
|
|
|
|
}
|
2019-06-13 16:54:55 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
if (hexagram_speedo_init(&cluster->speedo,
|
|
|
|
CLUSTER_HEIGHT / 2,
|
|
|
|
CLUSTER_HEIGHT / 2,
|
|
|
|
CLUSTER_HEIGHT / 2,
|
|
|
|
SPEEDO_MAX,
|
|
|
|
SPEEDO_UNITS) < 0) {
|
|
|
|
goto error_speedo_init;
|
|
|
|
}
|
2019-06-13 16:54:55 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
if (hexagram_fuel_init(&cluster->fuel,
|
|
|
|
CLUSTER_HEIGHT / 2,
|
|
|
|
CLUSTER_HEIGHT / 2,
|
|
|
|
CLUSTER_HEIGHT / 2) < 0) {
|
|
|
|
goto error_fuel_init;
|
|
|
|
}
|
2019-06-13 16:54:55 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
if (hexagram_tacho_init(&cluster->tacho,
|
|
|
|
CLUSTER_WIDTH - CLUSTER_HEIGHT / 2,
|
|
|
|
CLUSTER_HEIGHT / 2,
|
|
|
|
CLUSTER_HEIGHT / 2,
|
|
|
|
rpm_redline,
|
|
|
|
rpm_max) < 0) {
|
|
|
|
goto error_tacho_init;
|
|
|
|
}
|
2019-06-13 16:54:55 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
if (hexagram_thermo_init(&cluster->thermo,
|
|
|
|
CLUSTER_WIDTH - CLUSTER_HEIGHT / 2,
|
|
|
|
CLUSTER_HEIGHT / 2,
|
|
|
|
CLUSTER_HEIGHT / 2) < 0) {
|
|
|
|
goto error_thermo_init;
|
|
|
|
}
|
2019-06-13 16:54:55 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
if (hexagram_odo_init(&cluster->odo,
|
|
|
|
0.8 * CLUSTER_HEIGHT,
|
|
|
|
CLUSTER_HEIGHT - 16,
|
|
|
|
HEXAGRAM_TEXT_LEFT,
|
|
|
|
HEXAGRAM_ODO_MILES) < 0) {
|
|
|
|
goto error_odo_init;
|
|
|
|
}
|
2019-06-13 16:54:55 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
if (hexagram_clock_init(&cluster->clock,
|
|
|
|
CLUSTER_WIDTH / 2,
|
|
|
|
CLUSTER_HEIGHT - 16,
|
|
|
|
HEXAGRAM_TEXT_MIDDLE,
|
|
|
|
HEXAGRAM_CLOCK_24H) < 0) {
|
|
|
|
goto error_clock_init;
|
|
|
|
}
|
2019-06-13 16:54:55 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
if (hexagram_temp_init(&cluster->temp,
|
|
|
|
CLUSTER_WIDTH - 0.8 * CLUSTER_HEIGHT,
|
|
|
|
CLUSTER_HEIGHT - 16,
|
|
|
|
HEXAGRAM_TEXT_RIGHT,
|
|
|
|
HEXAGRAM_TEMP_CELSIUS) < 0) {
|
|
|
|
goto error_temp_init;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hexagram_tacho_shift_indicator_init(&cluster->shift_indicator,
|
|
|
|
SHIFT_INDICATOR_X,
|
|
|
|
SHIFT_INDICATOR_Y,
|
|
|
|
rpm_min,
|
|
|
|
rpm_redline) < 0) {
|
|
|
|
goto error_tacho_shift_indicator_init;
|
2019-06-13 16:54:55 -05:00
|
|
|
}
|
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
if (hexagram_status_icon_box_init(&cluster->status,
|
|
|
|
CLUSTER_WIDTH / 2 - HEXAGRAM_STATUS_ICON_WIDTH * 3.5,
|
|
|
|
CLUSTER_HEIGHT - SECTION_HEIGHT_BOTTOM - 16 - HEXAGRAM_STATUS_ICON_HEIGHT * 3,
|
|
|
|
HEXAGRAM_STATUS_ICON_WIDTH * 7,
|
|
|
|
HEXAGRAM_STATUS_ICON_HEIGHT * 3) < 0) {
|
|
|
|
goto error_status_icon_box_init;
|
|
|
|
}
|
|
|
|
|
|
|
|
cluster->gauges[0] = &cluster->speedo.dial.gauge;
|
|
|
|
cluster->gauges[1] = &cluster->fuel.dial.gauge;
|
|
|
|
cluster->gauges[2] = &cluster->tacho.dial.gauge;
|
|
|
|
cluster->gauges[3] = &cluster->thermo.dial.gauge;
|
|
|
|
cluster->gauges[4] = &cluster->odo.text.gauge;
|
|
|
|
cluster->gauges[5] = &cluster->temp.text.gauge;
|
|
|
|
cluster->gauges[6] = &cluster->clock.text.gauge;
|
|
|
|
cluster->gauges[7] = &cluster->status.gauge;
|
|
|
|
cluster->gauges[8] = &cluster->shift_indicator.gauge;
|
|
|
|
|
2019-06-13 16:54:55 -05:00
|
|
|
return 0;
|
2024-01-11 17:39:52 -05:00
|
|
|
|
|
|
|
error_status_icon_box_init:
|
|
|
|
error_tacho_shift_indicator_init:
|
|
|
|
hexagram_temp_cleanup(&cluster->temp);
|
|
|
|
|
|
|
|
error_temp_init:
|
|
|
|
error_clock_init:
|
|
|
|
error_odo_init:
|
|
|
|
error_thermo_init:
|
|
|
|
error_tacho_init:
|
|
|
|
error_fuel_init:
|
|
|
|
error_speedo_init:
|
|
|
|
hexagram_pattern_cleanup(&cluster->pattern);
|
|
|
|
|
|
|
|
error_pattern_init:
|
|
|
|
return -1;
|
2019-06-13 16:54:55 -05:00
|
|
|
}
|
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
void hexagram_cluster_cleanup(hexagram_cluster *cluster) {
|
|
|
|
hexagram_status_icon_box_cleanup(&cluster->status);
|
|
|
|
hexagram_temp_cleanup(&cluster->temp);
|
|
|
|
hexagram_pattern_cleanup(&cluster->pattern);
|
2019-06-09 14:03:56 -05:00
|
|
|
}
|
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
hexagram_cluster *hexagram_cluster_new(double rpm_min,
|
|
|
|
double rpm_redline,
|
|
|
|
double rpm_max) {
|
|
|
|
hexagram_cluster *cluster;
|
2019-06-09 15:46:41 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
if ((cluster = malloc(sizeof(*cluster))) == NULL) {
|
|
|
|
goto error_malloc_cluster;
|
|
|
|
}
|
|
|
|
|
|
|
|
hexagram_cluster_init(cluster, rpm_min, rpm_redline, rpm_max);
|
2019-06-09 14:03:56 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
return cluster;
|
2019-06-09 14:03:56 -05:00
|
|
|
|
2024-01-11 17:39:52 -05:00
|
|
|
error_malloc_cluster:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hexagram_cluster_destroy(hexagram_cluster *cluster) {
|
|
|
|
hexagram_cluster_cleanup(cluster);
|
|
|
|
free(cluster);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hexagram_cluster_draw_bg(hexagram_cluster *cluster, cairo_t *cr) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
|
|
|
|
cairo_rectangle(cr, 0, 0, CLUSTER_WIDTH, CLUSTER_HEIGHT);
|
|
|
|
cairo_fill(cr);
|
|
|
|
|
|
|
|
cairo_rectangle(cr, 0, 0, CLUSTER_WIDTH, CLUSTER_HEIGHT);
|
|
|
|
hexagram_pattern_fill(&cluster->pattern,
|
|
|
|
cr,
|
|
|
|
hexagon_pattern_matrix,
|
|
|
|
hexagon_pattern_scale);
|
|
|
|
|
|
|
|
/* Top dark area */
|
|
|
|
cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
|
|
|
|
cairo_rectangle(cr, 0, 0, CLUSTER_WIDTH, SECTION_HEIGHT_TOP);
|
|
|
|
cairo_fill(cr);
|
|
|
|
|
|
|
|
cairo_set_source_rgba(cr, 1, 1, 1, 0.25);
|
|
|
|
cairo_move_to(cr, 0, SECTION_HEIGHT_TOP);
|
|
|
|
cairo_line_to(cr, CLUSTER_WIDTH, SECTION_HEIGHT_TOP);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
|
|
|
|
/* Bottom dark area */
|
|
|
|
cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
|
|
|
|
cairo_rectangle(cr,
|
|
|
|
0,
|
|
|
|
CLUSTER_HEIGHT - SECTION_HEIGHT_BOTTOM,
|
|
|
|
CLUSTER_WIDTH,
|
|
|
|
SECTION_HEIGHT_BOTTOM);
|
|
|
|
cairo_fill(cr);
|
|
|
|
|
|
|
|
cairo_set_source_rgba(cr, 1, 1, 1, 0.25);
|
|
|
|
cairo_move_to(cr, 0, CLUSTER_HEIGHT - SECTION_HEIGHT_BOTTOM);
|
|
|
|
cairo_line_to(cr, CLUSTER_WIDTH, CLUSTER_HEIGHT - SECTION_HEIGHT_BOTTOM);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
|
|
|
|
for (i=0; i<HEXAGRAM_CLUSTER_GAUGE_COUNT; i++) {
|
|
|
|
if (cluster->gauges[i]->draw_bg) {
|
|
|
|
cluster->gauges[i]->draw_bg(cluster->gauges[i], cr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void hexagram_cluster_draw_fg(hexagram_cluster *cluster, cairo_t *cr) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<HEXAGRAM_CLUSTER_GAUGE_COUNT; i++) {
|
|
|
|
if (cluster->gauges[i]->draw_fg) {
|
|
|
|
cluster->gauges[i]->draw_fg(cluster->gauges[i], cr);
|
|
|
|
}
|
|
|
|
}
|
2019-06-09 14:03:56 -05:00
|
|
|
}
|