From 977734b00b3cbcd66627f6cb44eeb3d3db34ae79 Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Mon, 8 Jan 2024 21:32:30 -0500 Subject: [PATCH] GOT THE PYTHON RENDERING TO AN X WINDOW --- bin/hexagram-app | 5 ++ py/hexagram/app.pyx | 104 ++++++++++++++++++++++++++++++++++++++ py/hexagram/can.pxd | 28 ++++++++++ py/hexagram/cluster_c.pyx | 41 --------------- py/hexagram/window.pxd | 54 ++++++++++++++++++++ setup.py | 17 ++++--- 6 files changed, 202 insertions(+), 47 deletions(-) create mode 100755 bin/hexagram-app create mode 100755 py/hexagram/app.pyx create mode 100644 py/hexagram/can.pxd delete mode 100644 py/hexagram/cluster_c.pyx create mode 100644 py/hexagram/window.pxd diff --git a/bin/hexagram-app b/bin/hexagram-app new file mode 100755 index 0000000..3bb2a73 --- /dev/null +++ b/bin/hexagram-app @@ -0,0 +1,5 @@ +#! /usr/bin/env python3 + +from hexagram.app import main + +exit(main()) diff --git a/py/hexagram/app.pyx b/py/hexagram/app.pyx new file mode 100755 index 0000000..c22341d --- /dev/null +++ b/py/hexagram/app.pyx @@ -0,0 +1,104 @@ +import sys +import cairo + +from Xlib.X import MapNotify, Expose + +from libc.stdio cimport printf +from libc.string cimport memcpy +from posix.select cimport * + +from hexagram.can cimport * +from hexagram.window cimport * + +from hexagram.cluster import Cluster + +CLUSTER_WIDTH = 1280 +CLUSTER_HEIGHT = 480 +CLUSTER_RPM_MIN = 1200 +CLUSTER_RPM_REDLINE = 6500 +CLUSTER_RPM_MAX = 8000 + +def usage(message=None): + if message: + print(message, file=sys.stderr) + + print("usage: %s canif" % sys.argv[0], file=sys.stderr) + +cdef handle_xevents(hexagram_window *window, + cluster: Cluster, + Display *display, + fg: cairo.Context): + cdef XEvent e + + while XPending(display) > 0: + XNextEvent(display, &e) + if e.type == MapNotify or e.type == Expose: + hexagram_window_refresh_bg(window) + cluster.draw_fg(fg) + hexagram_window_swap_buffer(window) + +def main(): + cdef fd_set rfds, rready + cdef can_frame frame + + import_cairo() + + if len(sys.argv) != 2: + usage("No CAN interface specified") + + can_if = hexagram_can_if_open(bytes(sys.argv[1], 'utf8')) + + if can_if is NULL: + raise Exception("hexagram_can_if_open()") + + window = hexagram_window_new_x11(NULL, CLUSTER_WIDTH, CLUSTER_HEIGHT) + + if window is NULL: + raise Exception("hexagram_window_new_x11()") + + cluster = Cluster(CLUSTER_RPM_MIN, CLUSTER_RPM_REDLINE, CLUSTER_RPM_MAX) + + if hexagram_cluster_filter_can_if(can_if) < 0: + raise Exception("hexagram_cluster_filter_can_if()") + + display = hexagram_window_display(window) + + fd = hexagram_can_if_fd(can_if) + fd2 = hexagram_window_display_fd(window) + + # + # Set up rendering surfaces + # + fg = PycairoContext_FromContext(hexagram_window_get_fg_context(window), + ctx_type(), + NULL) + + bg = PycairoContext_FromContext(hexagram_window_get_bg_context(window), + ctx_type(), + NULL) + + cluster.draw_bg(bg) + + hexagram_window_show(window) + + FD_ZERO(&rfds) + + FD_SET(fd, &rfds) + FD_SET(fd2, &rfds) + + while True: + 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): + hexagram_can_if_read(can_if, &frame) + + hexagram_window_destroy(window) + + return 0 diff --git a/py/hexagram/can.pxd b/py/hexagram/can.pxd new file mode 100644 index 0000000..222d259 --- /dev/null +++ b/py/hexagram/can.pxd @@ -0,0 +1,28 @@ +cdef extern from "sys/select.h": + ctypedef struct fd_set: + pass + +cdef extern from "linux/can.h": + cdef struct can_frame: + pass + +cdef extern from "hexagram/can.h": + ctypedef struct hexagram_can_if: + pass + + hexagram_can_if *hexagram_can_if_open(const char *name) + + void hexagram_can_if_close(hexagram_can_if *can_if) + + int hexagram_can_if_read(hexagram_can_if *can_if, can_frame *frame) + + int hexagram_can_if_write(hexagram_can_if *can_if, can_frame *frame) + + int hexagram_can_if_fd(hexagram_can_if *can_if); + + void hexagram_can_if_fd_set(hexagram_can_if *can_if, fd_set *fds) + + int hexagram_can_if_fd_isset(hexagram_can_if *can_if, fd_set *fds) + +cdef extern from "hexagram/cluster.h": + int hexagram_cluster_filter_can_if(hexagram_can_if *can_if) diff --git a/py/hexagram/cluster_c.pyx b/py/hexagram/cluster_c.pyx deleted file mode 100644 index eedbd4a..0000000 --- a/py/hexagram/cluster_c.pyx +++ /dev/null @@ -1,41 +0,0 @@ -from cpython.ref cimport PyObject, PyTypeObject, Py_INCREF - -from hexagram.cluster import Cluster - -cdef extern from "linux/can.h": - cdef struct can_frame: - pass - -cdef extern from "cairo.h": - ctypedef struct cairo_t: - pass - -cdef extern from "py3cairo.h": - cdef PyObject *PycairoContext_FromContext(cairo_t *ctx, PyTypeObject *type, PyObject *base) - - ctypedef struct Pycairo_CAPI_t: - pass - - cdef extern Pycairo_CAPI_t *Pycairo_CAPI - -cdef extern from *: - """ - #define ctx_type (Pycairo_CAPI->Context_Type) - """ - cdef extern PyTypeObject *ctx_type - -cdef class Cluster_py: - cdef object _obj - - def __cinit__(self, double rpm_min, double rpm_redline, double rpm_max): - self._obj = Cluster(rpm_min, rpm_redline, rpm_max) - - cdef draw_bg(self, cairo_t *cr): - ctx = PycairoContext_FromContext(cr, ctx_type, NULL) - - self._obj.draw_bg(ctx) - - cdef draw_fg(self, cairo_t *cr): - ctx = PycairoContext_FromContext(cr, ctx_type, NULL) - - self._obj.draw_fg(ctx) diff --git a/py/hexagram/window.pxd b/py/hexagram/window.pxd new file mode 100644 index 0000000..ea88c8c --- /dev/null +++ b/py/hexagram/window.pxd @@ -0,0 +1,54 @@ +from cpython.ref cimport PyObject, PyTypeObject, Py_INCREF + +cdef extern from "X11/Xlib.h": + ctypedef struct Display: + pass + + ctypedef struct XEvent: + int type + long pad[24] + + int XPending(Display *display) + + int XNextEvent(Display *display, XEvent *event_return) + +cdef extern from "cairo.h": + ctypedef struct cairo_t: + pass + +cdef extern from "py3cairo.h": + cdef PyObject *PycairoContext_FromContext(cairo_t *ctx, PyTypeObject *type, PyObject *base) + +cdef extern from *: + """ + #define ctx_api() (Pycairo_CAPI) + #define ctx_type() (Pycairo_CAPI->Context_Type) + """ + + cdef int import_cairo() + cdef void *ctx_api() + cdef PyTypeObject *ctx_type() + +cdef extern from "hexagram/window.h": + ctypedef struct hexagram_window: + pass + + hexagram_window *hexagram_window_new_x11(const char *display, + int width, + int height) + + void hexagram_window_destroy(hexagram_window *window) + + Display *hexagram_window_display(hexagram_window *window) + + int hexagram_window_display_fd(hexagram_window *window) + + int hexagram_window_show(hexagram_window *window) + + int hexagram_window_refresh_bg(hexagram_window *window) + + int hexagram_window_swap_buffer(hexagram_window *window) + + cairo_t *hexagram_window_get_bg_context(hexagram_window *window) + + cairo_t *hexagram_window_get_fg_context(hexagram_window *window) diff --git a/setup.py b/setup.py index 73a52b1..ba4efba 100644 --- a/setup.py +++ b/setup.py @@ -11,10 +11,15 @@ setup( packages = [ 'hexagram' ], - ext_modules = cythonize( - Extension( - "*", ["py/hexagram/*.pyx"], - include_dirs = ["./include", "/usr/include/cairo", "/usr/include/pycairo"] - ), language_level = 3, - ) + ext_modules = cythonize(Extension("*", [ + "py/hexagram/*.pyx" + ], include_dirs = [ + "./include", + "/usr/include/cairo", + "/usr/include/pycairo" + ], library_dirs = [ + "src" + ], libraries = [ + "hexagram" + ]), language_level = 3, gdb_debug = True) )