#include #include #include #define CLUSTER_WIDTH 1280 #define CLUSTER_HEIGHT 480 #define RPM_SHIFT_MIN 2000 #define RPM_SHIFT_MAX 6500 #define RPM_REDLINE 6500 #define RPM_MAX 8000 #define SHIFT_INDICATOR_X 392 #define SHIFT_INDICATOR_Y 24 #define SECTION_HEIGHT_TOP 64 #define SECTION_HEIGHT_BOTTOM 52 #define SPEEDO_MAX 322.0 #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"; int hexagram_cluster_filter_can_if(hexagram_can_if *can_if) { struct can_filter filters[4] = { { .can_id = 0x280, .can_mask = 0x3f0 }, { .can_id = 0x320, .can_mask = 0x320 }, { .can_id = 0x540, .can_mask = 0x540 }, { .can_id = 0x5a0, .can_mask = 0x5a0 } }; return setsockopt(hexagram_can_if_fd(can_if), SOL_CAN_RAW, CAN_RAW_FILTER, &filters, sizeof(filters)); } int hexagram_cluster_init(hexagram_cluster *cluster) { 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; } if (hexagram_speedo_init(&cluster->speedo, CLUSTER_HEIGHT / 2, CLUSTER_HEIGHT / 2, CLUSTER_HEIGHT / 2, SPEEDO_MAX) < 0) { goto error_speedo_init; } if (hexagram_fuel_init(&cluster->fuel, CLUSTER_HEIGHT / 2, CLUSTER_HEIGHT / 2, CLUSTER_HEIGHT / 2) < 0) { goto error_fuel_init; } 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; } if (hexagram_thermo_init(&cluster->thermo, CLUSTER_WIDTH - CLUSTER_HEIGHT / 2, CLUSTER_HEIGHT / 2, CLUSTER_HEIGHT / 2) < 0) { goto error_thermo_init; } if (hexagram_odo_init(&cluster->odo, 0.8 * CLUSTER_HEIGHT, CLUSTER_HEIGHT - (SECTION_HEIGHT_BOTTOM - HEXAGRAM_TEXT_FONT_SIZE) / 2, HEXAGRAM_TEXT_LEFT, HEXAGRAM_ODO_MILES) < 0) { goto error_odo_init; } if (hexagram_clock_init(&cluster->clock, CLUSTER_WIDTH / 2, CLUSTER_HEIGHT - (SECTION_HEIGHT_BOTTOM - HEXAGRAM_TEXT_FONT_SIZE) / 2, HEXAGRAM_TEXT_MIDDLE, HEXAGRAM_CLOCK_24H) < 0) { goto error_clock_init; } if (hexagram_temp_init(&cluster->temp, CLUSTER_WIDTH - 0.8 * CLUSTER_HEIGHT, CLUSTER_HEIGHT - (SECTION_HEIGHT_BOTTOM - HEXAGRAM_TEXT_FONT_SIZE) / 2, HEXAGRAM_TEXT_RIGHT) < 0) { goto error_temp_init; } if (hexagram_tacho_shift_indicator_init(&cluster->shift_indicator, SHIFT_INDICATOR_X, SHIFT_INDICATOR_Y, RPM_SHIFT_MIN, RPM_SHIFT_MAX) < 0) { goto error_tacho_shift_indicator_init; } 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; return 0; 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; } void hexagram_cluster_cleanup(hexagram_cluster *cluster) { hexagram_status_icon_box_cleanup(&cluster->status); hexagram_temp_cleanup(&cluster->temp); hexagram_pattern_cleanup(&cluster->pattern); } hexagram_cluster *hexagram_cluster_new(void) { hexagram_cluster *cluster; if ((cluster = malloc(sizeof(*cluster))) == NULL) { goto error_malloc_cluster; } hexagram_cluster_init(cluster); return cluster; 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; igauges[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; igauges[i]->draw_fg) { cluster->gauges[i]->draw_fg(cluster->gauges[i], cr); } } }