#include #include #include #include #include #include #include #include #include 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; } } } static void cluster_update(hexagram_cluster *cluster, cairo_t *cr, hexagram_window *window, struct can_frame *frame, struct timeval *last) { struct timeval now; 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 0x420: { double temp = ((double)frame->data[1] - 100) / 2.0; cluster->temp.value = temp; break; } case 0x540: { int value = ((frame->data[7] & 0xf0) >> 4) - 2; if ((frame->data[7] & 0xc) == 0xc) { cluster->tacho.gear = value; } else { cluster->tacho.gear = HEXAGRAM_TRANS_GEAR_D; } 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; } } 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)); } } 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; } int main(int argc, char **argv) { Display *display; fd_set rfds, rready; hexagram_can_if *can_if; hexagram_window *window; hexagram_cluster *cluster; int fd, fd2, width = 1280, height = 480; cairo_t *fg, *bg; struct timeval last = { .tv_sec = 0, .tv_usec = 0 }; if (argc != 2) { return usage(argc, argv, "No CAN interface specified"); } if ((can_if = hexagram_can_if_open(argv[1])) == NULL) { perror("hexagram_can_if_open()"); return 1; } if ((window = hexagram_window_new_x11(NULL, width, height)) == NULL) { perror("hexagram_window_new_x11()"); return 1; } if ((cluster = hexagram_cluster_new()) == NULL) { perror("hexagram_cluster_new()"); return 1; } if (hexagram_cluster_filter_can_if(can_if) < 0) { perror("hexagram_cluster_filter_can_if()"); return 1; } display = hexagram_window_display(window); fd = hexagram_can_if_fd(can_if); fd2 = hexagram_window_display_fd(window); /* * Set up the rendering surfaces */ fg = hexagram_window_get_fg_context(window); bg = hexagram_window_get_bg_context(window); /* * Draw the background layer */ hexagram_cluster_draw_bg(cluster, bg); /* * Present the background layer */ hexagram_window_show(window); /* * Set up file descriptors to monitor */ FD_ZERO(&rfds); FD_SET(fd, &rfds); FD_SET(fd2, &rfds); while (1) { int nfds = fd2 + 1; handle_xevents(window, cluster, display, fg); memcpy(&rready, &rfds, sizeof(rfds)); if (select(nfds, &rready, NULL, NULL, NULL) < 0) { break; } if (FD_ISSET(fd, &rready)) { struct can_frame frame; hexagram_can_if_read(can_if, &frame); cluster_update(cluster, fg, window, &frame, &last); } } hexagram_window_destroy(window); return 0; }