hexagram/examples/cluster.c

306 lines
7.9 KiB
C
Raw Normal View History

2019-05-27 01:32:21 -05:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <cairo.h>
#include <cairo-xlib.h>
2019-05-27 01:32:21 -05:00
#include <hexagram/can.h>
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) {
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,
x + r * cos(angle),
y + r * sin(angle));
2019-05-25 22:08:26 -05:00
cairo_stroke(cr);
}
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;
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));
cairo_save(cr);
2019-05-26 11:21:06 -05:00
cairo_rotate(cr, angle + 1.658);
cairo_show_text(cr, text);
cairo_restore(cr);
}
static void draw_tachometer(cairo_t *cr,
double x,
double y,
2019-05-27 01:32:21 -05:00
double r,
double rpm) {
int i;
2019-05-27 01:32:21 -05:00
if (rpm > 8000) {
rpm = 8000;
}
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
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_arc(cr, x, y, r, 0, 2*M_PI);
cairo_stroke(cr);
/*
* Draw face numbers
*/
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:08:26 -05:00
/*
* Draw a gauge needle
*/
draw_needle(cr, x, y, 0.77 * r,
232 * (M_PI/180),
2019-05-27 01:32:21 -05:00
488 * (M_PI/180),
rpm / 8000);
2019-05-25 22:08:26 -05:00
/*
* Draw a tiny boi circle
2019-05-25 22:08:26 -05:00
*/
cairo_set_source_rgb(cr, 1, 1, 1);
2019-05-26 11:01:44 -05:00
cairo_arc(cr, x, y, 0.08 * r, 0, 2*M_PI);
cairo_fill(cr);
}
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);
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);
cairo_stroke(cr);
2019-05-26 10:13:42 -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);
cairo_stroke(cr);
2019-05-26 10:13:42 -05:00
}
static void draw_mfd(cairo_t *cr,
double x,
double y,
double width,
double height) {
cairo_set_source_rgb(cr, 0.75, 0, 0);
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);
cairo_fill(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
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);
cairo_stroke(cr);
}
2019-05-26 15:55:54 -05:00
static void draw_gauge_cluster(cairo_t *cr,
2019-05-27 01:32:21 -05:00
struct can_frame *frame,
2019-05-26 15:55:54 -05:00
double x,
double y,
double width,
double height) {
2019-05-27 01:32:21 -05:00
static double rpm = 0;
if (frame->can_id == 0x280) {
rpm = 0.25 * (double)(frame->data[2] | (frame->data[3] << 8));
}
2019-05-26 10:13:42 -05:00
/*
* Paint canvas black
*/
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
draw_tachometer(cr,
x + width * 0.2,
y + height * 0.5,
2019-05-27 01:32:21 -05:00
height * 0.4,
rpm);
draw_speedometer(cr,
x + width * 0.8,
y + height * 0.5,
height * 0.4);
2019-05-26 16:12:21 -05:00
draw_thermometer(cr,
x + width * 0.43,
y + height * 0.76,
height * 0.13);
2019-05-26 16:15:00 -05:00
draw_fuel_gauge(cr,
x + width * 0.57,
y + height * 0.76,
height * 0.13);
draw_mfd(cr,
x + width * 0.42,
y + height * 0.1,
width * 0.16,
height * 0.5);
2019-05-26 10:13:42 -05:00
}
int main(int argc, char **argv) {
Display *display;
Window win;
Pixmap buf;
GC gc;
fd_set rfds, rready;
2019-05-27 01:32:21 -05:00
hexagram_can_if *can_if;
int screen, fd, fd2,
width = 1024,
height = 480;
XGCValues values = {
.foreground = 0x000000,
.background = 0xffffff,
.graphics_exposures = 0
};
cairo_surface_t *sfc;
cairo_t *cr;
2019-05-27 01:32:21 -05:00
if ((can_if = hexagram_can_if_open("vcan0")) == NULL)
exit(1);
if ((display = XOpenDisplay(NULL)) == NULL)
exit(1);
2019-05-27 01:32:21 -05:00
fd = hexagram_can_if_fd(can_if);
fd2 = ConnectionNumber(display);
screen = DefaultScreen(display);
2019-05-26 15:55:54 -05:00
win = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, width, height, 0, 0, 0);
gc = XCreateGC(display, win, GCForeground | GCBackground | GCGraphicsExposures, &values);
2019-05-26 15:55:54 -05:00
buf = XCreatePixmap(display, win, width, height, 24);
XSelectInput(display, win, ExposureMask | ButtonPressMask | KeyPressMask);
XMapWindow(display, win);
2019-05-26 15:55:54 -05:00
sfc = cairo_xlib_surface_create(display, buf, DefaultVisual(display, screen), width, height);
cairo_xlib_surface_set_size(sfc, width, height);
cr = cairo_create(sfc);
2019-05-27 01:32:21 -05:00
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
FD_SET(fd2, &rfds);
while (1) {
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);
XCopyArea(display, buf, win, gc,
e.xexpose.x,
e.xexpose.y,
e.xexpose.width,
e.xexpose.height,
e.xexpose.x,
e.xexpose.y);
break;
case ButtonPress:
case KeyPress:
break;
default:
fprintf(stderr, "Dropping unhandled XEvent.type = %d.\n", e.type);
}
}
2019-05-27 01:32:21 -05:00
memcpy(&rready, &rfds, sizeof(rfds));
2019-05-27 01:32:21 -05:00
if (select(fd2, &rready, NULL, NULL, NULL) < 0) {
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);
draw_gauge_cluster(cr, &frame, 0, 0, width, height);
2019-05-27 01:32:21 -05:00
XCopyArea(display, buf, win, gc, 0, 0,
width, height,
2019-05-27 01:32:21 -05:00
0, 0);
}
}
cairo_destroy(cr);
cairo_surface_destroy(sfc);
XCloseDisplay(display);
return 0;
}