hexagram/examples/cluster.c

266 lines
6.4 KiB
C
Raw Normal View History

2019-05-27 01:32:21 -05:00
#include <stdio.h>
#include <stdlib.h>
2019-06-07 15:34:13 -05:00
#include <stdarg.h>
2019-05-27 01:32:21 -05:00
#include <string.h>
#include <math.h>
#include <sys/time.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>
#include <hexagram/gauge.h>
#include <hexagram/tacho.h>
#include <hexagram/speedo.h>
2019-06-09 13:52:59 -05:00
#include <hexagram/thermo.h>
#include <hexagram/fuel.h>
2019-06-09 13:57:57 -05:00
#include <hexagram/mfd.h>
typedef struct _hexagram_cluster_state {
2019-06-07 15:34:13 -05:00
double rpm, rps, temp, fuel;
} hexagram_cluster_state;
static hexagram_cluster_state state = {
0, 0, 0, 0
};
static void cluster_draw_bg(cairo_t *cr,
double width,
double height) {
2019-05-26 10:13:42 -05:00
/*
* Paint canvas black
*/
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
hexagram_tacho_draw_face(cr,
width * 0.2,
height * 0.5,
height * 0.4,
6500);
hexagram_speedo_draw_face(cr,
width * 0.8,
height * 0.5,
height * 0.4);
2019-06-09 13:52:59 -05:00
hexagram_thermo_draw_face(cr,
width * 0.43,
height * 0.76,
height * 0.13,
240.0);
2019-05-26 16:12:21 -05:00
hexagram_fuel_draw_face(cr,
width * 0.57,
height * 0.76,
height * 0.13,
0.125);
2019-05-26 16:15:00 -05:00
2019-06-09 13:57:57 -05:00
hexagram_mfd_draw(cr,
width * 0.42,
height * 0.1,
width * 0.16,
height * 0.5);
2019-05-27 15:32:53 -05:00
}
static void cluster_update(struct can_frame *frame) {
2019-05-28 01:09:44 -05:00
switch (frame->can_id) {
case 0x280: {
state.rpm = 0.25 *
(double)(frame->data[2] | (frame->data[3] << 8));
2019-05-27 15:32:53 -05:00
break;
}
case 0x288: {
state.temp = (double)(frame->data[1] - 48 * 0.75);
break;
}
case 0x320: {
2019-06-07 15:34:13 -05:00
state.fuel = (double)(frame->data[2] & 0xf) / 16.0;
break;
}
case 0x5a0: {
state.rps = 0.001 * (double)(frame->data[1]
| (frame->data[2] << 8));
2019-05-28 01:09:44 -05:00
break;
}
}
}
static void cluster_draw(cairo_t *cr,
double x,
double y,
double width,
double height) {
hexagram_tacho_draw_needle(cr,
x + width * 0.2,
y + height * 0.5,
height * 0.4,
state.rpm);
hexagram_speedo_draw_needle(cr,
width * 0.8,
height * 0.5,
height * 0.4,
(2.032 * state.rps * 3600) / 1000.0);
2019-06-09 13:52:59 -05:00
hexagram_thermo_draw_needle(cr,
width * 0.43,
height * 0.76,
height * 0.13,
state.temp);
hexagram_fuel_draw_needle(cr,
width * 0.57,
height * 0.76,
height * 0.13,
state.fuel);
2019-06-07 15:34:13 -05:00
}
static int usage(int argc, char **argv, const char *message, ...) {
if (message) {
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
fprintf(stderr, "\n");
va_end(args);
}
fprintf(stderr, "usage: %s canif\n", argv[0]);
return 1;
2019-05-26 10:13:42 -05:00
}
int main(int argc, char **argv) {
Display *display;
fd_set rfds, rready;
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
int fd,
width = 1024,
height = 480;
struct timeval last = {
.tv_sec = 0,
.tv_usec = 0
};
cairo_t *fg, *bg;
2019-06-07 15:34:13 -05:00
if (argc != 2) {
return usage(argc, argv, "No CAN interface specified");
}
2019-06-07 15:34:13 -05:00
if ((can_if = hexagram_can_if_open(argv[1])) == NULL) {
return 1;
}
if ((window = hexagram_window_new_x11(NULL, width, height)) == NULL) {
return 1;
}
2019-05-28 00:58:18 -05:00
display = hexagram_window_display(window);
fd = hexagram_can_if_fd(can_if);
2019-05-27 15:32:53 -05:00
/*
* Set up the rendering surfaces
2019-05-27 15:32:53 -05:00
*/
fg = hexagram_window_create_fg_context(window);
bg = hexagram_window_create_bg_context(window);
2019-05-27 15:32:53 -05:00
/*
* Draw the background layer
2019-05-27 15:32:53 -05:00
*/
cluster_draw_bg(bg, width, height);
/*
* Present the background layer
*/
hexagram_window_show(window);
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);
while (1) {
struct timeval timeout = {
.tv_sec = 0,
.tv_usec = 250000
}, now;
int pending,
nfds = fd + 1;
2019-05-27 01:32:21 -05:00
(void)gettimeofday(&now, NULL);
2019-05-27 01:32:21 -05:00
while ((pending = XPending(display)) != 0) {
XEvent e;
XNextEvent(display, &e);
switch (e.type) {
case MapNotify:
2019-05-27 01:32:21 -05:00
case Expose:
2019-05-28 00:41:54 -05:00
hexagram_window_refresh_bg(window);
cluster_draw(fg, 0, 0, width, height);
hexagram_window_swap_buffer(window);
2019-05-27 01:32:21 -05:00
break;
2019-05-28 01:09:44 -05:00
2019-05-27 01:32:21 -05:00
case ButtonPress:
case KeyPress:
break;
default:
break;
2019-05-27 01:32:21 -05:00
}
}
2019-05-27 01:32:21 -05:00
memcpy(&rready, &rfds, sizeof(rfds));
if (select(nfds, &rready, NULL, NULL, &timeout) < 0) {
2019-05-27 01:32:21 -05:00
break;
}
2019-05-27 01:32:21 -05:00
if (FD_ISSET(fd, &rready)) {
struct can_frame frame;
2019-05-27 01:32:21 -05:00
hexagram_can_if_read(can_if, &frame);
switch (frame.can_id) {
case 0x280:
case 0x288:
case 0x320:
case 0x5a0: {
cluster_update(&frame);
2019-05-27 15:32:53 -05:00
if (now.tv_sec - last.tv_sec
|| now.tv_usec - last.tv_usec > 16666) {
hexagram_window_refresh_bg(window);
cluster_draw(fg, 0, 0, width, height);
hexagram_window_swap_buffer(window);
(void)memcpy(&last, &now, sizeof(now));
}
}
2019-05-27 15:32:53 -05:00
}
}
}
hexagram_window_destroy(window);
return 0;
}