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>
|
|
|
|
|
2019-06-06 23:31:26 -05:00
|
|
|
#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>
|
2019-06-09 14:03:56 -05:00
|
|
|
#include <hexagram/cluster.h>
|
2019-06-06 23:31:26 -05:00
|
|
|
|
2019-06-11 21:12:56 -05:00
|
|
|
static void handle_xevents(hexagram_window *window,
|
|
|
|
hexagram_cluster *cluster,
|
|
|
|
Display *display,
|
|
|
|
cairo_t *fg) {
|
|
|
|
while (XPending(display)) {
|
|
|
|
XEvent e;
|
|
|
|
|
|
|
|
XNextEvent(display, &e);
|
|
|
|
|
|
|
|
switch (e.type) {
|
|
|
|
case MapNotify:
|
|
|
|
case Expose:
|
|
|
|
hexagram_window_refresh_bg(window);
|
|
|
|
hexagram_cluster_draw_fg(cluster, fg);
|
|
|
|
hexagram_window_swap_buffer(window);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ButtonPress:
|
|
|
|
case KeyPress:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-09 16:05:06 -05:00
|
|
|
static void cluster_update(hexagram_cluster *cluster,
|
2019-06-09 19:36:19 -05:00
|
|
|
cairo_t *cr,
|
|
|
|
hexagram_window *window,
|
|
|
|
struct can_frame *frame,
|
|
|
|
struct timeval *last) {
|
|
|
|
struct timeval now;
|
|
|
|
|
2024-01-28 16:27:54 +00:00
|
|
|
switch (frame->can_id) {
|
|
|
|
case 0x280: {
|
|
|
|
double rpm = 0.25 * (float)(frame->data[2] | frame->data[3] << 8);
|
|
|
|
|
|
|
|
cluster->tacho.dial.value = rpm;
|
|
|
|
cluster->shift_indicator.rpm = rpm;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 0x288: {
|
|
|
|
cluster->thermo.dial.value = 0.75 * (float)(frame->data[1] - 48);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 0x320: {
|
|
|
|
cluster->fuel.dial.value = frame->data[2] & 0xf;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 0x5a0: {
|
|
|
|
double rps = 0.001 * (float)(frame->data[1] | (frame->data[2] << 8)),
|
|
|
|
kph = (2.00152 * rps * 3600) / 1000.0;
|
|
|
|
|
|
|
|
cluster->speedo.dial.value = kph;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-06-09 19:36:19 -05:00
|
|
|
|
|
|
|
gettimeofday(&now, NULL);
|
|
|
|
|
|
|
|
if (now.tv_sec - last->tv_sec || now.tv_usec - last->tv_usec > 16666) {
|
|
|
|
hexagram_window_refresh_bg(window);
|
|
|
|
hexagram_cluster_draw_fg(cluster, cr);
|
|
|
|
hexagram_window_swap_buffer(window);
|
|
|
|
|
|
|
|
memcpy(last, &now, sizeof(now));
|
2019-05-28 01:09:44 -05:00
|
|
|
}
|
2019-06-06 23:31:26 -05:00
|
|
|
}
|
2019-06-06 13:57:26 -04:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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-06-09 15:46:41 -05:00
|
|
|
hexagram_cluster *cluster;
|
2019-05-27 01:32:21 -05:00
|
|
|
|
2019-06-09 15:50:24 -05:00
|
|
|
int fd, fd2,
|
2024-01-11 17:39:52 -05:00
|
|
|
width = 1280,
|
2019-06-06 13:57:26 -04:00
|
|
|
height = 480;
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-06-09 19:36:19 -05:00
|
|
|
cairo_t *fg, *bg;
|
|
|
|
|
2019-06-07 02:15:48 -05:00
|
|
|
struct timeval last = {
|
2019-06-06 23:31:26 -05:00
|
|
|
.tv_sec = 0,
|
|
|
|
.tv_usec = 0
|
|
|
|
};
|
|
|
|
|
2019-06-07 15:34:13 -05:00
|
|
|
if (argc != 2) {
|
|
|
|
return usage(argc, argv, "No CAN interface specified");
|
|
|
|
}
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-06-07 15:34:13 -05:00
|
|
|
if ((can_if = hexagram_can_if_open(argv[1])) == NULL) {
|
2019-06-28 18:09:08 -05:00
|
|
|
perror("hexagram_can_if_open()");
|
|
|
|
|
2019-06-07 15:34:13 -05:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((window = hexagram_window_new_x11(NULL, width, height)) == NULL) {
|
2019-06-28 18:09:08 -05:00
|
|
|
perror("hexagram_window_new_x11()");
|
|
|
|
|
2019-06-07 15:34:13 -05:00
|
|
|
return 1;
|
|
|
|
}
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2024-01-18 12:59:54 -05:00
|
|
|
if ((cluster = hexagram_cluster_new()) == NULL) {
|
2019-06-28 18:09:08 -05:00
|
|
|
perror("hexagram_cluster_new()");
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hexagram_cluster_filter_can_if(can_if) < 0) {
|
|
|
|
perror("hexagram_cluster_filter_can_if()");
|
|
|
|
|
2019-06-09 15:46:41 -05:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-05-28 00:58:18 -05:00
|
|
|
display = hexagram_window_display(window);
|
2019-05-27 19:52:00 -05:00
|
|
|
|
2019-06-09 15:50:24 -05:00
|
|
|
fd = hexagram_can_if_fd(can_if);
|
|
|
|
fd2 = hexagram_window_display_fd(window);
|
2019-05-27 19:57:41 -05:00
|
|
|
|
2019-05-27 15:32:53 -05:00
|
|
|
/*
|
2019-05-28 01:00:48 -05:00
|
|
|
* Set up the rendering surfaces
|
2019-05-27 15:32:53 -05:00
|
|
|
*/
|
2019-06-13 16:55:37 -05:00
|
|
|
fg = hexagram_window_get_fg_context(window);
|
|
|
|
bg = hexagram_window_get_bg_context(window);
|
2019-05-25 18:19:56 -05:00
|
|
|
|
2019-05-27 15:32:53 -05:00
|
|
|
/*
|
2019-05-28 01:00:48 -05:00
|
|
|
* Draw the background layer
|
2019-05-27 15:32:53 -05:00
|
|
|
*/
|
2019-06-09 15:46:41 -05:00
|
|
|
hexagram_cluster_draw_bg(cluster, bg);
|
2019-05-28 01:00:48 -05:00
|
|
|
|
2019-06-06 23:42:43 -05:00
|
|
|
/*
|
|
|
|
* Present the background layer
|
|
|
|
*/
|
2019-06-07 00:06:35 -05:00
|
|
|
hexagram_window_show(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);
|
|
|
|
|
2019-06-09 15:50:24 -05:00
|
|
|
FD_SET(fd, &rfds);
|
|
|
|
FD_SET(fd2, &rfds);
|
2019-05-25 18:19:56 -05:00
|
|
|
|
|
|
|
while (1) {
|
2019-06-11 21:12:56 -05:00
|
|
|
int nfds = fd2 + 1;
|
2019-05-27 01:32:21 -05:00
|
|
|
|
2019-06-11 21:12:56 -05:00
|
|
|
handle_xevents(window, cluster, display, fg);
|
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-06-09 15:50:24 -05:00
|
|
|
if (select(nfds, &rready, NULL, NULL, NULL) < 0) {
|
2019-05-27 01:32:21 -05:00
|
|
|
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-06-09 19:36:19 -05:00
|
|
|
cluster_update(cluster, fg, window, &frame, &last);
|
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;
|
|
|
|
}
|