2019-05-27 01:32:21 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
2019-05-25 18:19:56 -05:00
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/Xutil.h>
|
2019-05-27 19:52:00 -05:00
|
|
|
#include <X11/extensions/Xdbe.h>
|
|
|
|
|
2019-05-25 18:19:56 -05:00
|
|
|
#include <cairo.h>
|
|
|
|
#include <cairo-xlib.h>
|
|
|
|
|
2019-05-27 01:32:21 -05:00
|
|
|
#include <hexagram/can.h>
|
2019-05-28 00:41:54 -05:00
|
|
|
#include <hexagram/window.h>
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-25 22:08:26 -05:00
|
|
|
static void draw_needle(cairo_t *cr,
|
|
|
|
double x,
|
|
|
|
double y,
|
|
|
|
double r,
|
|
|
|
double min_angle,
|
|
|
|
double max_angle,
|
|
|
|
double value) {
|
2019-05-26 11:18:31 -05:00
|
|
|
double angle = min_angle + ((max_angle - min_angle) * value) - (M_PI/2);
|
2019-05-25 22:08:26 -05:00
|
|
|
|
|
|
|
cairo_move_to(cr, x, y);
|
|
|
|
|
2019-05-25 22:11:26 -05:00
|
|
|
cairo_set_source_rgb(cr, 0, 0.25, 1.0);
|
|
|
|
|
2019-05-25 22:08:26 -05:00
|
|
|
cairo_line_to(cr,
|
2019-05-26 11:18:31 -05:00
|
|
|
x + r * cos(angle),
|
|
|
|
y + r * sin(angle));
|
2019-05-25 22:08:26 -05:00
|
|
|
|
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
|
|
|
|
2019-05-25 22:49:59 -05:00
|
|
|
static void draw_face_number(cairo_t *cr,
|
|
|
|
double x,
|
|
|
|
double y,
|
|
|
|
double r,
|
|
|
|
double min_angle,
|
|
|
|
double max_angle,
|
|
|
|
double value,
|
|
|
|
const char *text) {
|
2019-05-26 11:21:06 -05:00
|
|
|
double angle = min_angle + ((max_angle - min_angle) * value) - 1.658;
|
2019-05-25 22:49:59 -05:00
|
|
|
|
|
|
|
cairo_set_source_rgb(cr, 1, 1, 1);
|
|
|
|
|
|
|
|
cairo_move_to(cr,
|
2019-05-26 11:21:06 -05:00
|
|
|
x + r * cos(angle),
|
|
|
|
y + r * sin(angle));
|
2019-05-25 22:49:59 -05:00
|
|
|
|
|
|
|
cairo_save(cr);
|
2019-05-26 11:21:06 -05:00
|
|
|
cairo_rotate(cr, angle + 1.658);
|
2019-05-25 22:49:59 -05:00
|
|
|
cairo_show_text(cr, text);
|
2019-05-27 15:32:53 -05:00
|
|
|
cairo_stroke(cr);
|
2019-05-25 22:49:59 -05:00
|
|
|
cairo_restore(cr);
|
|
|
|
}
|
|
|
|
|
2019-05-27 15:32:53 -05:00
|
|
|
static void draw_tachometer_needle(cairo_t *cr,
|
|
|
|
double x,
|
|
|
|
double y,
|
|
|
|
double r,
|
|
|
|
double rpm) {
|
|
|
|
if (rpm > 8000) {
|
|
|
|
rpm = 8000;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Draw a tiny boi circle
|
|
|
|
*/
|
|
|
|
cairo_set_source_rgb(cr, 1, 1, 1);
|
|
|
|
cairo_arc(cr, x, y, 0.08 * r, 0, 2*M_PI);
|
|
|
|
cairo_fill(cr);
|
2019-05-27 16:00:39 -05:00
|
|
|
|
|
|
|
draw_needle(cr, x, y, 0.77 * r,
|
|
|
|
232 * (M_PI/180),
|
|
|
|
488 * (M_PI/180),
|
|
|
|
rpm / 8000);
|
2019-05-27 15:32:53 -05:00
|
|
|
}
|
|
|
|
|
2019-05-26 10:31:43 -05:00
|
|
|
static void draw_tachometer(cairo_t *cr,
|
|
|
|
double x,
|
|
|
|
double y,
|
2019-05-27 15:32:53 -05:00
|
|
|
double r) {
|
2019-05-25 22:49:59 -05:00
|
|
|
int i;
|
|
|
|
|
2019-05-26 10:38:24 -05:00
|
|
|
cairo_select_font_face(cr, "Helvetica",
|
|
|
|
CAIRO_FONT_SLANT_NORMAL,
|
|
|
|
CAIRO_FONT_WEIGHT_NORMAL);
|
|
|
|
|
2019-05-26 16:31:05 -05:00
|
|
|
cairo_set_font_size(cr, r * 0.125);
|
2019-05-26 10:38:24 -05:00
|
|
|
|
2019-05-25 22:49:59 -05:00
|
|
|
cairo_set_source_rgb(cr, 1, 1, 1);
|
2019-05-26 11:02:17 -05:00
|
|
|
cairo_arc(cr, x, y, r, 0, 2*M_PI);
|
2019-05-25 22:49:59 -05:00
|
|
|
cairo_stroke(cr);
|
|
|
|
|
|
|
|
/*
|
2019-05-26 10:05:46 -05:00
|
|
|
* Draw face numbers
|
2019-05-25 22:49:59 -05:00
|
|
|
*/
|
|
|
|
for (i=0; i<=80; i+=10) {
|
|
|
|
char text[4];
|
|
|
|
|
|
|
|
snprintf(text, 3, "%02d", i);
|
2019-05-26 11:21:06 -05:00
|
|
|
|
|
|
|
draw_face_number(cr, x, y,
|
|
|
|
0.85 * r,
|
|
|
|
232 * (M_PI/180),
|
|
|
|
488 * (M_PI/180),
|
|
|
|
i / 80.0,
|
|
|
|
text);
|
2019-05-25 22:49:59 -05:00
|
|
|
}
|
2019-05-26 10:08:20 -05:00
|
|
|
}
|
|
|
|
|
2019-05-26 10:32:59 -05:00
|
|
|
static void draw_speedometer(cairo_t *cr,
|
|
|
|
double x,
|
|
|
|
double y,
|
|
|
|
double r) {
|
2019-05-26 11:01:44 -05:00
|
|
|
cairo_arc(cr, x, y, r, 0, 2*M_PI);
|
2019-05-26 10:08:20 -05:00
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
|
|
|
|
2019-05-26 10:33:58 -05:00
|
|
|
static void draw_thermometer(cairo_t *cr,
|
|
|
|
double x,
|
|
|
|
double y,
|
|
|
|
double r) {
|
2019-05-26 11:01:44 -05:00
|
|
|
cairo_arc(cr, x, y, r, 0, 2*M_PI);
|
2019-05-25 22:49:59 -05:00
|
|
|
cairo_stroke(cr);
|
2019-05-26 10:13:42 -05:00
|
|
|
}
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-26 10:37:31 -05:00
|
|
|
static void draw_fuel_gauge(cairo_t *cr,
|
|
|
|
double x,
|
|
|
|
double y,
|
|
|
|
double r) {
|
2019-05-26 11:01:44 -05:00
|
|
|
cairo_arc(cr, x, y, r, 0, 2*M_PI);
|
2019-05-25 22:49:59 -05:00
|
|
|
cairo_stroke(cr);
|
2019-05-26 10:13:42 -05:00
|
|
|
}
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-26 10:23:24 -05:00
|
|
|
static void draw_mfd(cairo_t *cr,
|
|
|
|
double x,
|
|
|
|
double y,
|
|
|
|
double width,
|
|
|
|
double height) {
|
2019-05-25 22:49:59 -05:00
|
|
|
cairo_set_source_rgb(cr, 0.75, 0, 0);
|
2019-05-26 10:23:24 -05:00
|
|
|
cairo_move_to(cr, x, y);
|
|
|
|
cairo_line_to(cr, x + width, y);
|
|
|
|
cairo_line_to(cr, x + width, y + height);
|
|
|
|
cairo_line_to(cr, x, y + height);
|
|
|
|
cairo_line_to(cr, x, y);
|
2019-05-25 22:49:59 -05:00
|
|
|
cairo_fill(cr);
|
|
|
|
|
|
|
|
cairo_set_source_rgb(cr, 1, 1, 1);
|
2019-05-26 10:23:24 -05:00
|
|
|
cairo_move_to(cr, x, y);
|
|
|
|
cairo_line_to(cr, x + width, y);
|
|
|
|
cairo_line_to(cr, x + width, y + height);
|
|
|
|
cairo_line_to(cr, x, y + height);
|
|
|
|
cairo_line_to(cr, x, y);
|
2019-05-25 22:49:59 -05:00
|
|
|
cairo_stroke(cr);
|
2019-05-25 21:30:31 -05:00
|
|
|
}
|
|
|
|
|
2019-05-28 00:46:06 -05:00
|
|
|
static void draw_gauge_cluster_bg(hexagram_window *window,
|
2019-05-27 15:32:53 -05:00
|
|
|
double width,
|
|
|
|
double height) {
|
|
|
|
cairo_t *cr;
|
|
|
|
|
2019-05-28 00:50:38 -05:00
|
|
|
cr = hexagram_window_create_bg_context(window);
|
2019-05-27 01:32:21 -05:00
|
|
|
|
2019-05-26 10:13:42 -05:00
|
|
|
/*
|
|
|
|
* Paint canvas black
|
|
|
|
*/
|
|
|
|
cairo_set_source_rgb(cr, 0, 0, 0);
|
|
|
|
cairo_paint(cr);
|
|
|
|
|
2019-05-26 16:03:12 -05:00
|
|
|
draw_tachometer(cr,
|
2019-05-27 15:32:53 -05:00
|
|
|
width * 0.2,
|
|
|
|
height * 0.5,
|
|
|
|
height * 0.4);
|
2019-05-26 16:03:12 -05:00
|
|
|
|
2019-05-26 16:07:20 -05:00
|
|
|
draw_speedometer(cr,
|
2019-05-27 15:32:53 -05:00
|
|
|
width * 0.8,
|
|
|
|
height * 0.5,
|
|
|
|
height * 0.4);
|
2019-05-26 16:07:20 -05:00
|
|
|
|
2019-05-26 16:12:21 -05:00
|
|
|
draw_thermometer(cr,
|
2019-05-27 15:32:53 -05:00
|
|
|
width * 0.43,
|
|
|
|
height * 0.76,
|
|
|
|
height * 0.13);
|
2019-05-26 16:12:21 -05:00
|
|
|
|
2019-05-26 16:15:00 -05:00
|
|
|
draw_fuel_gauge(cr,
|
2019-05-27 15:32:53 -05:00
|
|
|
width * 0.57,
|
|
|
|
height * 0.76,
|
|
|
|
height * 0.13);
|
2019-05-26 16:15:00 -05:00
|
|
|
|
2019-05-26 16:21:03 -05:00
|
|
|
draw_mfd(cr,
|
2019-05-27 15:32:53 -05:00
|
|
|
width * 0.42,
|
|
|
|
height * 0.1,
|
|
|
|
width * 0.16,
|
|
|
|
height * 0.5);
|
|
|
|
|
|
|
|
cairo_destroy(cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_gauge_cluster(cairo_t *cr,
|
2019-05-28 00:54:05 -05:00
|
|
|
struct can_frame *frame,
|
|
|
|
double x,
|
|
|
|
double y,
|
|
|
|
double width,
|
|
|
|
double height) {
|
2019-05-27 15:32:53 -05:00
|
|
|
static double rpm = 0;
|
|
|
|
|
|
|
|
if (frame->can_id == 0x280) {
|
|
|
|
rpm = 0.25 * (double)(frame->data[2] | (frame->data[3] << 8));
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
draw_tachometer_needle(cr,
|
|
|
|
x + width * 0.2,
|
|
|
|
y + height * 0.5,
|
|
|
|
height * 0.4,
|
|
|
|
rpm);
|
2019-05-26 10:13:42 -05:00
|
|
|
}
|
|
|
|
|
2019-05-25 18:19:56 -05:00
|
|
|
int main(int argc, char **argv) {
|
|
|
|
Display *display;
|
2019-05-27 01:44:15 -05:00
|
|
|
fd_set rfds, rready;
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 01:32:21 -05:00
|
|
|
hexagram_can_if *can_if;
|
2019-05-28 00:41:54 -05:00
|
|
|
hexagram_window *window;
|
2019-05-27 01:32:21 -05:00
|
|
|
|
2019-05-28 00:48:28 -05:00
|
|
|
int fd, fd2,
|
2019-05-27 01:45:11 -05:00
|
|
|
width = 1024,
|
|
|
|
height = 480;
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-28 00:58:18 -05:00
|
|
|
cairo_t *fg;
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 01:32:21 -05:00
|
|
|
if ((can_if = hexagram_can_if_open("vcan0")) == NULL)
|
|
|
|
exit(1);
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-28 00:41:54 -05:00
|
|
|
if ((window = hexagram_window_new_x11(NULL, width, height)) == NULL)
|
2019-05-25 18:19:56 -05:00
|
|
|
exit(1);
|
|
|
|
|
2019-05-28 00:58:18 -05:00
|
|
|
display = hexagram_window_display(window);
|
2019-05-27 19:52:00 -05:00
|
|
|
|
2019-05-27 01:32:21 -05:00
|
|
|
fd = hexagram_can_if_fd(can_if);
|
2019-05-28 00:41:54 -05:00
|
|
|
fd2 = hexagram_window_display_fd(window);
|
2019-05-27 19:57:41 -05:00
|
|
|
|
2019-05-27 15:32:53 -05:00
|
|
|
/*
|
|
|
|
* Draw the background layer
|
|
|
|
*/
|
2019-05-28 00:46:06 -05:00
|
|
|
draw_gauge_cluster_bg(window, width, height);
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-28 00:41:54 -05:00
|
|
|
hexagram_window_show(window);
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 15:32:53 -05:00
|
|
|
/*
|
|
|
|
* Set up the foreground surface
|
|
|
|
*/
|
2019-05-28 00:58:18 -05:00
|
|
|
fg = hexagram_window_create_fg_context(window);
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 15:32:53 -05:00
|
|
|
/*
|
|
|
|
* Set up file descriptors to monitor
|
|
|
|
*/
|
2019-05-27 01:32:21 -05:00
|
|
|
FD_ZERO(&rfds);
|
|
|
|
|
|
|
|
FD_SET(fd, &rfds);
|
|
|
|
FD_SET(fd2, &rfds);
|
2019-05-25 18:19:56 -05:00
|
|
|
|
|
|
|
while (1) {
|
2019-05-27 01:44:15 -05:00
|
|
|
int pending;
|
2019-05-27 01:32:21 -05:00
|
|
|
|
|
|
|
while ((pending = XPending(display)) != 0) {
|
|
|
|
XEvent e;
|
|
|
|
|
|
|
|
XNextEvent(display, &e);
|
|
|
|
|
|
|
|
switch (e.type) {
|
|
|
|
case Expose:
|
|
|
|
fprintf(stderr, "Event %d\n", e.type);
|
|
|
|
|
2019-05-28 00:41:54 -05:00
|
|
|
hexagram_window_refresh_bg(window);
|
2019-05-27 01:32:21 -05:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ButtonPress:
|
|
|
|
case KeyPress:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "Dropping unhandled XEvent.type = %d.\n", e.type);
|
|
|
|
}
|
|
|
|
}
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 01:32:21 -05:00
|
|
|
memcpy(&rready, &rfds, sizeof(rfds));
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 01:32:21 -05:00
|
|
|
if (select(fd2, &rready, NULL, NULL, NULL) < 0) {
|
|
|
|
break;
|
|
|
|
}
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 01:32:21 -05:00
|
|
|
if (FD_ISSET(fd, &rready)) {
|
|
|
|
struct can_frame frame;
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 01:32:21 -05:00
|
|
|
hexagram_can_if_read(can_if, &frame);
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 15:32:53 -05:00
|
|
|
if (frame.can_id == 0x280) {
|
2019-05-28 00:41:54 -05:00
|
|
|
hexagram_window_refresh_bg(window);
|
2019-05-27 15:32:53 -05:00
|
|
|
|
2019-05-28 00:58:18 -05:00
|
|
|
update_gauge_cluster(fg, &frame, 0, 0, width, height);
|
2019-05-27 19:57:41 -05:00
|
|
|
|
2019-05-28 00:41:54 -05:00
|
|
|
hexagram_window_swap_buffer(window);
|
2019-05-27 15:32:53 -05:00
|
|
|
}
|
2019-05-25 18:19:56 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 00:54:05 -05:00
|
|
|
hexagram_window_destroy(window);
|
2019-05-25 18:19:56 -05:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|