From 2b8208805ef45d93d22f555195e6441a401f29af Mon Sep 17 00:00:00 2001 From: ezra buchla Date: Tue, 5 Oct 2021 16:12:18 -0700 Subject: [PATCH] Decouple fb merge (#1444) * decouple linuxfb cairo implementation * screen backend for writing to json * fix writing to json * slow, wrong x11 backend draws something * rename json write functions * replace x11 fb with sdl * select screens to use via lua configuration * lua configuration for screen + input * lua boot config working on norns hw * unified input and screen data structures * update json screen * rename gpio input, add broken sdl input * restore battery_init and fix fprintf werror * require ./waf --desktop flag to include SDL * rm json screen for now, cleanup prints, matronrc fallback * fix matronrc fallback * restore vcgencmd polling * remove old input/fd.c * Remove TrigPhasor * Remove nova-simd * merge * bypass polling SDL input for now * scale up the SDL window Co-authored-by: Sam Boling Co-authored-by: Sam Boling Co-authored-by: Artem Popov --- .gitignore | 1 + crone/softcut | 2 +- matron/src/args.c | 30 ++-- matron/src/args.h | 1 - matron/src/config.c | 75 ++++++++++ matron/src/config.h | 4 + matron/src/device/device_common.h | 2 - matron/src/events.c | 1 - matron/src/hardware/gpio.c | 169 ++++++++++------------ matron/src/hardware/gpio.h | 6 - matron/src/hardware/input.c | 41 ++++++ matron/src/hardware/input.h | 9 ++ matron/src/hardware/input/gpio.c | 205 +++++++++++++++++++++++++++ matron/src/hardware/input/inputs.h | 7 + matron/src/hardware/input/sdl.c | 123 ++++++++++++++++ matron/src/hardware/io.c | 82 +++++++++++ matron/src/hardware/io.h | 70 +++++++++ matron/src/hardware/screen.c | 57 +++++--- matron/src/hardware/screen/fbdev.c | 166 ++++++++++++++++++++++ matron/src/hardware/screen/screens.h | 8 ++ matron/src/hardware/screen/sdl.c | 110 ++++++++++++++ matron/src/hardware/stat.c | 25 ++++ matron/src/lua_eval.c | 6 +- matron/src/lua_eval.h | 11 ++ matron/src/main.c | 17 +-- matron/src/weaver.c | 9 +- matron/wscript | 16 ++- matronrc.lua | 20 +++ wscript | 3 + 29 files changed, 1105 insertions(+), 171 deletions(-) create mode 100644 matron/src/config.c create mode 100644 matron/src/config.h delete mode 100644 matron/src/hardware/gpio.h create mode 100644 matron/src/hardware/input.c create mode 100644 matron/src/hardware/input.h create mode 100644 matron/src/hardware/input/gpio.c create mode 100644 matron/src/hardware/input/inputs.h create mode 100644 matron/src/hardware/input/sdl.c create mode 100644 matron/src/hardware/io.c create mode 100644 matron/src/hardware/io.h create mode 100644 matron/src/hardware/screen/fbdev.c create mode 100644 matron/src/hardware/screen/screens.h create mode 100644 matron/src/hardware/screen/sdl.c create mode 100644 matronrc.lua diff --git a/.gitignore b/.gitignore index 7f73c99a3..b04a03518 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ # ignore emacs cruft \#*\# +.\#* *.*~ # vim diff --git a/crone/softcut b/crone/softcut index a720f20f2..03ef80867 160000 --- a/crone/softcut +++ b/crone/softcut @@ -1 +1 @@ -Subproject commit a720f20f27a39a00c32de7dab351be0861c7205e +Subproject commit 03ef80867407100138598cbfb3cef089413ec761 diff --git a/matron/src/args.c b/matron/src/args.c index 033a1c06d..07ca313fb 100644 --- a/matron/src/args.c +++ b/matron/src/args.c @@ -10,7 +10,7 @@ struct args { char ext_port[ARG_BUF_SIZE]; char remote_port[ARG_BUF_SIZE]; char crone_port[ARG_BUF_SIZE]; - char framebuffer[ARG_BUF_SIZE]; + char framebuffer[ARG_BUF_SIZE]; }; static struct args a = { @@ -25,18 +25,6 @@ int args_parse(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, "o:e:l:c:f:h")) != -1) { switch (opt) { - case '?': - case 'h': - default: - fprintf(stdout, "Start matron with optional overrides:\n"); - fprintf(stdout, "-l override OSC local port [default %s]\n", a.loc_port); - fprintf(stdout, "-e override OSC ext port [default %s]\n", a.ext_port); - fprintf(stdout, "-o override OSC remote port [default %s]\n", a.remote_port); - fprintf(stdout, "-c override crone port [default %s]\n", a.crone_port); - fprintf(stdout, "-f override framebuffer file [default '%s']\n", a.framebuffer); - - exit(1); - ; case 'l': strncpy(a.loc_port, optarg, ARG_BUF_SIZE - 1); break; @@ -49,9 +37,15 @@ int args_parse(int argc, char **argv) { case 'c': strncpy(a.crone_port, optarg, ARG_BUF_SIZE - 1); break; - case 'f': - strncpy(a.framebuffer, optarg, ARG_BUF_SIZE - 1); - break; + case '?': + case 'h': + default: + fprintf(stdout, "Start matron with optional overrides:"); + fprintf(stdout, "-l override OSC local port [default %s]\n", a.loc_port); + fprintf(stdout, "-e override OSC ext port [default %s]\n", a.ext_port); + fprintf(stdout, "-c override crone port [default %s]\n", a.crone_port); + exit(1); + ; } } return 0; @@ -72,7 +66,3 @@ const char *args_remote_port(void) { const char *args_crone_port(void) { return a.crone_port; } - -const char *args_framebuffer(void) { - return a.framebuffer; -} diff --git a/matron/src/args.h b/matron/src/args.h index 0007ed149..7978fde27 100644 --- a/matron/src/args.h +++ b/matron/src/args.h @@ -7,4 +7,3 @@ extern const char *args_ext_port(void); extern const char *args_remote_port(void); extern const char *args_crone_port(void); extern const char *args_monome_path(void); -extern const char *args_framebuffer(void); diff --git a/matron/src/config.c b/matron/src/config.c new file mode 100644 index 000000000..d6d3ab699 --- /dev/null +++ b/matron/src/config.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +#include +#include + +#include "lua_eval.h" +#include "hardware/input.h" +#include "hardware/io.h" +#include "hardware/screen.h" + +lua_State *config_lvm; + +static inline void lua_register_func(lua_State *l, const char* name, lua_CFunction func) { + lua_pushcfunction(l, func); + lua_setfield(l, -2, name); +} + +static int _add_io(lua_State *l); + +int config_init(void) { + lua_State *l = config_lvm = luaL_newstate(); + luaL_openlibs(l); + lua_pcall(l, 0, 0, 0); + + lua_newtable(l); + + lua_register_func(l, "add_io", _add_io); + + lua_setglobal(l, "_boot"); + + char *home = getenv("HOME"); + char fname[256]; + snprintf(fname, 256, "%s/matronrc.lua", home); + if (access(fname, R_OK)) { + fprintf(stderr, "no user matronrc file (%s) found, using default\n", fname); + snprintf(fname, 256, "%s/norns/matronrc.lua", home); + } + fprintf(stderr, "loading matronrc file: %s\n", fname); + if (l_dofile(l, fname)) { + fprintf(stderr, "error evaluating matronrc.lua, stop.\n"); + return -1; + } + + lua_close(l); + + io_setup_all(); + screen_init(); + + return 0; +} + +void config_deinit(void) { + io_destroy_all(); +} + +int _add_io(lua_State *l) { + lua_check_num_args(2); + const char *type = luaL_checkstring(l, 1); + luaL_checktype(l, 2, LUA_TTABLE); + + io_ops_t **ops = io_types; + while (*ops != NULL) { + if (strcmp(type, (*ops)->name) == 0) { + return io_create(l, *ops); + } + ops++; + } + + fprintf(stderr, "ERROR (config) unknown io type: %s\n", type); + lua_settop(l, 0); + return luaL_error(l, "unknown input type"); +} diff --git a/matron/src/config.h b/matron/src/config.h new file mode 100644 index 000000000..95f1177a9 --- /dev/null +++ b/matron/src/config.h @@ -0,0 +1,4 @@ +#pragma once + +extern int config_init(void); +extern void config_deinit(void); diff --git a/matron/src/device/device_common.h b/matron/src/device/device_common.h index c5c0d4ea2..d75d6b4de 100644 --- a/matron/src/device/device_common.h +++ b/matron/src/device/device_common.h @@ -2,8 +2,6 @@ #include - - typedef enum { // libmonome devices DEV_TYPE_MONOME = 0, diff --git a/matron/src/events.c b/matron/src/events.c index fbf811983..350891c07 100644 --- a/matron/src/events.c +++ b/matron/src/events.c @@ -11,7 +11,6 @@ #include "battery.h" #include "device_monome.h" #include "events.h" -#include "gpio.h" #include "oracle.h" #include "stat.h" #include "weaver.h" diff --git a/matron/src/hardware/gpio.c b/matron/src/hardware/gpio.c index dbee2e64e..cfb5378ed 100644 --- a/matron/src/hardware/gpio.c +++ b/matron/src/hardware/gpio.c @@ -4,120 +4,97 @@ * keys and encoders */ -#include -#include -#include #include #include #include #include #include -#include -#include #include "events.h" - -int key_fd; -pthread_t key_p; - -int enc_fd[3]; -pthread_t enc_p[3]; - -void *key_check(void *); -void *enc_check(void *); +#include "hardware/input/matron_input.h" +#include "hardware/gpio.h" + +static int input_init(matron_input_t* input, input_config_t* cfg, input_ops_t* ops) { + input->data = malloc(ops->data_size); + if (!input->data) { + fprintf(stderr, "ERROR (input - %s) cannot allocate memory\n", ops->name); + return -1; + } + input->config = malloc(sizeof(input_config_t)); + if (!input->config) { + fprintf(stderr, "ERROR (input - %s) cannot allocate memory\n", ops->name); + return -1; + } + memcpy(input->config, cfg, sizeof(input_config_t)); + input->ops = ops; + return 0; +} // extern def - -static int open_and_grab(const char *pathname, int flags) { - int fd; - int open_attempts = 0, ioctl_attempts = 0; - while (open_attempts < 200) { - fd = open(pathname, flags); - if (fd > 0) { - if (ioctl(fd, EVIOCGRAB, 1) == 0) { - ioctl(fd, EVIOCGRAB, (void *)0); - goto done; - } - ioctl_attempts++; - close(fd); - } - open_attempts++; - usleep(50000); // 50ms sleep * 200 = 10s fail after 10s - }; -done: - if (open_attempts > 0) { - fprintf(stderr, "WARN open_and_grab GPIO '%s' required %d open attempts & %d ioctl attempts\n", pathname, - open_attempts, ioctl_attempts); +TAILQ_HEAD(tailhead, _matron_input) input_devs = TAILQ_HEAD_INITIALIZER(input_devs); + +int input_create(input_type_t type, const char* name, input_config_t* cfg) { + int err; + matron_input_t* input = malloc(sizeof(matron_input_t)); + input->name = malloc(strlen(name) + 1); + strcpy(input->name, name); + + (void)cfg; + + switch (type) { + case INPUT_TYPE_GPIO_KEY: + if ((err = input_init(input, cfg, &gpio_key_ops))) goto fail; + break; + case INPUT_TYPE_GPIO_ENC: + if ((err = input_init(input, cfg, &gpio_enc_ops))) goto fail; + break; + /* case INPUT_TYPE_KBM: */ + /* if ((err = input_init(input, &kbm_input_ops))) goto fail; */ + /* break; */ + /* case INPUT_TYPE_JSON: */ + /* if ((err = input_init(input, &json_input_ops))) goto fail; */ + /* break; */ + default: + goto fail; } - return fd; -} + + TAILQ_INSERT_TAIL(&input_devs, input, entries); + fprintf(stderr, "added input %s\n", name); + return 0; + +fail: + fprintf(stderr, "couldn't set up input %s\n", name); + free(input); + return -1; +} void gpio_init() { - key_fd = open_and_grab("/dev/input/by-path/platform-keys-event", O_RDONLY); // Keys - if (key_fd > 0) { - if (pthread_create(&key_p, NULL, key_check, 0)) { - fprintf(stderr, "ERROR (keys) pthread error\n"); + matron_input_t *input; + TAILQ_FOREACH(input, &input_devs, entries) { + input->data = malloc(input->ops->data_size); + if (!input->data) { + fprintf(stderr, "ERROR (input %s) couldn't allocate %zu\n", input->name, input->ops->data_size); + return; } - } - - char *enc_filenames[3] = {"/dev/input/by-path/platform-soc:knob1-event", - "/dev/input/by-path/platform-soc:knob2-event", - "/dev/input/by-path/platform-soc:knob3-event"}; - for (int i = 0; i < 3; i++) { - enc_fd[i] = open_and_grab(enc_filenames[i], O_RDONLY); - if (enc_fd[i] > 0) { - int *arg = malloc(sizeof(int)); - *arg = i; - if (pthread_create(&enc_p[i], NULL, enc_check, arg)) { - fprintf(stderr, "ERROR (enc%d) pthread error\n", i); - } + if (input->ops->setup(input)) { + fprintf(stderr, "ERROR (input %s) setup failed\n", input->name); + continue; + } + if (pthread_create(&input->poll_thread, NULL, input->ops->poll, input)) { + fprintf(stderr, "ERROR (input %s) pthread error\n", input->name); + continue; } } } void gpio_deinit() { - pthread_cancel(key_p); - pthread_cancel(enc_p[0]); - pthread_cancel(enc_p[1]); - pthread_cancel(enc_p[2]); -} - -void *enc_check(void *x) { - int n = *((int *)x); - free(x); - int rd; - unsigned int i; - struct input_event event[64]; - int dir[3] = {1, 1, 1}; - clock_t now[3]; - clock_t prev[3]; - clock_t diff; - prev[0] = prev[1] = prev[2] = clock(); - - while (1) { - rd = read(enc_fd[n], event, sizeof(struct input_event) * 64); - if (rd < (int)sizeof(struct input_event)) { - fprintf(stderr, "ERROR (enc) read error\n"); - } - - for (i = 0; i < rd / sizeof(struct input_event); i++) { - if (event[i].type) { // make sure it's not EV_SYN == 0 - now[i] = clock(); - diff = now[i] - prev[i]; - // fprintf(stderr, "%d\t%d\t%lu\n", n, event[i].value, diff); - prev[i] = now[i]; - if (diff > 100) { // filter out glitches - if (dir[i] != event[i].value && - diff > 500) { // only reverse direction if there is reasonable settling time - dir[i] = event[i].value; - } - union event_data *ev = event_data_new(EVENT_ENC); - ev->enc.n = n + 1; - ev->enc.delta = event[i].value; - event_post(ev); - } - } - } + matron_input_t* input; + while (!TAILQ_EMPTY(&input_devs)) { + input = TAILQ_FIRST(&input_devs); + pthread_cancel(input->poll_thread); + TAILQ_REMOVE(&input_devs, input, entries); + free(input->data); + free(input); } } diff --git a/matron/src/hardware/gpio.h b/matron/src/hardware/gpio.h deleted file mode 100644 index 09cade96f..000000000 --- a/matron/src/hardware/gpio.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include - -extern void gpio_init(void); -extern void gpio_deinit(void); diff --git a/matron/src/hardware/input.c b/matron/src/hardware/input.c new file mode 100644 index 000000000..3bd860a8e --- /dev/null +++ b/matron/src/hardware/input.c @@ -0,0 +1,41 @@ +/* + * gpio.c + * + * keys and encoders + */ + +#include +#include +#include +#include +#include + +#include "hardware/input.h" +#include "hardware/io.h" + +int input_setup(matron_io_t *io) { + if (io->ops->type != IO_INPUT) { + fprintf(stderr, "ERROR (%s) wrong IO type\n", io->ops->name); + return -1; + } + + int err = 0; + matron_input_t *input = (matron_input_t *)io; + input_ops_t *input_ops = (input_ops_t *)io->ops; + err = pthread_create(&input->poll_thread, NULL, input_ops->poll, input); + if (err) { + fprintf(stderr, "ERROR (input %s) pthread error\n", io->ops->name); + return err; + } + + return 0; +} + +void input_destroy(matron_io_t *io) { + if (io->ops->type != IO_INPUT) { + fprintf(stderr, "ERROR (%s) wrong IO type\n", io->ops->name); + return; + } + matron_input_t *input = (matron_input_t *)io; + pthread_cancel(input->poll_thread); +} diff --git a/matron/src/hardware/input.h b/matron/src/hardware/input.h new file mode 100644 index 000000000..53dd29603 --- /dev/null +++ b/matron/src/hardware/input.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +#include "hardware/io.h" + +extern int input_setup(matron_io_t *io); +extern void input_destroy(matron_io_t *io); diff --git a/matron/src/hardware/input/gpio.c b/matron/src/hardware/input/gpio.c new file mode 100644 index 000000000..30acd9e5c --- /dev/null +++ b/matron/src/hardware/input/gpio.c @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "events.h" +#include "hardware/input.h" +#include "hardware/io.h" + +typedef struct _input_gpio_priv { + int fd; + char* dev; +} input_gpio_priv_t; + +typedef struct _enc_gpio_priv { + input_gpio_priv_t base; + int index; +} enc_gpio_priv_t; + +static int input_gpio_config(matron_io_t* io, lua_State *l); +static int enc_gpio_config(matron_io_t* io, lua_State *l); +static int input_gpio_setup(matron_io_t* io); +static void input_gpio_destroy(matron_io_t* io); +static void* enc_gpio_poll(void* data); +static void* key_gpio_poll(void* data); +static int open_and_grab(const char *pathname, int flags); + +input_ops_t key_gpio_ops = { + .io_ops.name = "keys:gpio", + .io_ops.type = IO_INPUT, + .io_ops.data_size = sizeof(input_gpio_priv_t), + .io_ops.config = input_gpio_config, + .io_ops.setup = input_gpio_setup, + .io_ops.destroy = input_gpio_destroy, + + .poll = key_gpio_poll, +}; + +input_ops_t enc_gpio_ops = { + .io_ops.name = "enc:gpio", + .io_ops.type = IO_INPUT, + .io_ops.data_size = sizeof(enc_gpio_priv_t), + .io_ops.config = enc_gpio_config, + .io_ops.setup = input_gpio_setup, + .io_ops.destroy = input_gpio_destroy, + + .poll = enc_gpio_poll, +}; + +int input_gpio_config(matron_io_t* io, lua_State *l) { + input_gpio_priv_t* priv = io->data; + + lua_pushstring(l, "dev"); + lua_gettable(l, -2); + if (lua_isstring(l, -1)) { + const char *dev = lua_tostring(l, -1); + if (!(priv->dev = malloc(strlen(dev) + 1))) { + fprintf(stderr, "ERROR (%s) no memory\n", io->ops->name); + lua_settop(l, 0); + return -1; + } + strcpy(priv->dev, dev); + } else { + fprintf(stderr, "ERROR (%s) config option 'dev' should be a string\n", io->ops->name); + lua_settop(l, 0); + return -1; + } + lua_pop(l, 1); + return 0; +} + +int enc_gpio_config(matron_io_t* io, lua_State *l) { + int err = input_gpio_config(io, l); + if (err) { + return err; + } + + enc_gpio_priv_t *priv = io->data; + lua_pushstring(l, "index"); + lua_gettable(l, -2); + if (lua_isinteger(l, -1)) { + priv->index = lua_tointeger(l, -1); + } else { + fprintf(stderr, "ERROR (%s) config option 'index' should be an integer\n", io->ops->name); + free(priv->base.dev); + lua_settop(l, 0); + return -1; + } + lua_pop(l, 1); + return 0; +} + +int input_gpio_setup(matron_io_t* io) { + input_gpio_priv_t *priv = io->data; + priv->fd = open_and_grab(priv->dev, O_RDONLY); + if (priv->fd <= 0) { + fprintf(stderr, "ERROR (%s) device not available: %s\n", io->ops->name, priv->dev); + return priv->fd; + } + return input_setup(io); +} + +void input_gpio_destroy(matron_io_t *io) { + input_gpio_priv_t *priv = io->data; + free(priv->dev); + input_destroy(io); +} + +void* enc_gpio_poll(void* data) { + matron_input_t* input = data; + enc_gpio_priv_t* priv = input->io.data; + + int rd; + unsigned int i; + struct input_event event[64]; + int dir[3] = {1, 1, 1}; + clock_t now[3]; + clock_t prev[3]; + clock_t diff; + prev[0] = prev[1] = prev[2] = clock(); + + while (1) { + rd = read(priv->base.fd, event, sizeof(struct input_event) * 64); + if (rd < (int)sizeof(struct input_event)) { + fprintf(stderr, "ERROR (enc) read error\n"); + } + + for (i = 0; i < rd / sizeof(struct input_event); i++) { + if (event[i].type) { // make sure it's not EV_SYN == 0 + now[i] = clock(); + diff = now[i] - prev[i]; + // fprintf(stderr, "%d\t%d\t%lu\n", n, event[i].value, diff); + prev[i] = now[i]; + if (diff > 100) { // filter out glitches + if (dir[i] != event[i].value && + diff > 500) { // only reverse direction if there is reasonable settling time + dir[i] = event[i].value; + } + union event_data *ev = event_data_new(EVENT_ENC); + ev->enc.n = priv->index; + ev->enc.delta = event[i].value; + event_post(ev); + } + } + } + } + + return NULL; +} + +void* key_gpio_poll(void* data) { + matron_input_t* input = data; + input_gpio_priv_t* priv = input->io.data; + + int rd; + unsigned int i; + struct input_event event[64]; + + while (1) { + rd = read(priv->fd, event, sizeof(struct input_event) * 64); + if (rd < (int)sizeof(struct input_event)) { + fprintf(stderr, "ERROR (key) read error\n"); + } + + for (i = 0; i < rd / sizeof(struct input_event); i++) { + if (event[i].type) { // make sure it's not EV_SYN == 0 + // fprintf(stderr, "enc%d = %d\n", n, event[i].value); + union event_data *ev = event_data_new(EVENT_KEY); + ev->key.n = event[i].code; + ev->key.val = event[i].value; + event_post(ev); + } + } + } + + return NULL; +} + +int open_and_grab(const char *pathname, int flags) { + int fd; + int open_attempts = 0, ioctl_attempts = 0; + while (open_attempts < 200) { + fd = open(pathname, flags); + if (fd > 0) { + if (ioctl(fd, EVIOCGRAB, 1) == 0) { + ioctl(fd, EVIOCGRAB, (void *)0); + goto done; + } + ioctl_attempts++; + close(fd); + } + open_attempts++; + usleep(50000); // 50ms sleep * 200 = 10s fail after 10s + }; +done: + if (open_attempts > 0) { + fprintf(stderr, "WARN open_and_grab GPIO '%s' required %d open attempts & %d ioctl attempts\n", pathname, + open_attempts, ioctl_attempts); + } + return fd; +} diff --git a/matron/src/hardware/input/inputs.h b/matron/src/hardware/input/inputs.h new file mode 100644 index 000000000..d90e6d3df --- /dev/null +++ b/matron/src/hardware/input/inputs.h @@ -0,0 +1,7 @@ +#pragma once + +#include "hardware/io.h" + +extern input_ops_t key_gpio_ops; +extern input_ops_t enc_gpio_ops; +extern input_ops_t input_sdl_ops; diff --git a/matron/src/hardware/input/sdl.c b/matron/src/hardware/input/sdl.c new file mode 100644 index 000000000..17e82d07c --- /dev/null +++ b/matron/src/hardware/input/sdl.c @@ -0,0 +1,123 @@ +#include + +#include "events.h" +#include "event_types.h" +#include "hardware/io.h" +#include "hardware/input.h" +#include "hardware/input/inputs.h" + +typedef struct _input_sdl_priv { +} input_sdl_priv_t; + +static int input_sdl_config(matron_io_t* io, lua_State *l); +static int input_sdl_setup(matron_io_t* io); +static void input_sdl_destroy(matron_io_t* io); +static void* input_sdl_poll(void* data); + +input_ops_t input_sdl_ops = { + .io_ops.name = "input:sdl", + .io_ops.type = IO_INPUT, + .io_ops.data_size = sizeof(input_sdl_priv_t), + .io_ops.config = input_sdl_config, + .io_ops.setup = input_sdl_setup, + .io_ops.destroy = input_sdl_destroy, + .poll = input_sdl_poll, +}; + +int input_sdl_config(matron_io_t *io, lua_State *l) { + (void)io; + (void)l; + return 0; +} + +int input_sdl_setup(matron_io_t *io) { + return input_setup(io); +} + +void input_sdl_destroy(matron_io_t *io) { + input_destroy(io); +} + +static void* input_sdl_poll(void* data) { + (void)data; + // for now, we don't actually want to use keyboard input + // (leave it for scripts / menu) +#if 0 + SDL_Event event; + union event_data *ev; + fprintf(stderr, "starting SDL input loop\n"); + while (true) { + SDL_WaitEvent(&event); + fprintf(stderr, "got SDL input %d\n", event.type); + switch (event.type) { + case SDL_KEYDOWN: + case SDL_KEYUP: { + fprintf(stderr, "key event\n"); + int z = event.type == SDL_KEYDOWN ? 1 : 0; + switch (event.key.keysym.sym) { + case SDL_SCANCODE_Q: + ev = event_data_new(EVENT_KEY); + ev->key.n = 0; + ev->key.val = z; + event_post(ev); + break; + case SDL_SCANCODE_A: + ev = event_data_new(EVENT_KEY); + ev->key.n = 1; + ev->key.val = z; + event_post(ev); + break; + case SDL_SCANCODE_Z: + ev = event_data_new(EVENT_KEY); + ev->key.n = 2; + ev->key.val = z; + event_post(ev); + break; + case SDL_SCANCODE_W: + ev = event_data_new(EVENT_ENC); + ev->enc.n = 0; + ev->enc.delta = -1; + event_post(ev); + break; + case SDL_SCANCODE_E: + ev = event_data_new(EVENT_ENC); + ev->enc.n = 0; + ev->enc.delta = 1; + event_post(ev); + break; + case SDL_SCANCODE_S: + ev = event_data_new(EVENT_ENC); + ev->enc.n = 1; + ev->enc.delta = -1; + event_post(ev); + break; + case SDL_SCANCODE_D: + ev = event_data_new(EVENT_ENC); + ev->enc.n = 1; + ev->enc.delta = 1; + event_post(ev); + break; + case SDL_SCANCODE_X: + ev = event_data_new(EVENT_ENC); + ev->enc.n = 2; + ev->enc.delta = -1; + event_post(ev); + break; + case SDL_SCANCODE_C: + ev = event_data_new(EVENT_ENC); + ev->enc.n = 2; + ev->enc.delta = 1; + event_post(ev); + break; + default: + break; + } + break; + } + default: + break; + } + } + #endif + return NULL; +} diff --git a/matron/src/hardware/io.c b/matron/src/hardware/io.c new file mode 100644 index 000000000..c500cb7d3 --- /dev/null +++ b/matron/src/hardware/io.c @@ -0,0 +1,82 @@ +#include +#include + +#include + +#include "hardware/io.h" +#include "hardware/screen/screens.h" +#include "hardware/input/inputs.h" + +io_ops_t* io_types[] = { + (io_ops_t*)&screen_fbdev_ops, + (io_ops_t*)&enc_gpio_ops, + (io_ops_t*)&key_gpio_ops, + +#ifdef NORNS_DESKTOP + (io_ops_t*)&screen_sdl_ops, + (io_ops_t*)&input_sdl_ops, +#endif + (io_ops_t*)NULL, +}; + +struct io_head io_queue = TAILQ_HEAD_INITIALIZER(io_queue); + +int io_create(lua_State *l, io_ops_t *ops) { + matron_io_t* io; + switch (ops->type) { + case IO_SCREEN: + io = malloc(sizeof(matron_fb_t)); + break; + case IO_INPUT: + io = malloc(sizeof(matron_input_t)); + break; + default: + fprintf(stderr, "ERROR (%s) no such IO type\n", ops->name); + return -1; + } + if (!io) { + luaL_error(l, "out of memory"); + return -1; + } + + if (!(io->data = malloc(ops->data_size))) { + free(io); + return luaL_error(l, "out of memory"); + } + + io->ops = ops; + int err = io->ops->config(io, l); + if (err) { + free(io->data); + return err; + } + + TAILQ_INSERT_TAIL(&io_queue, io, entries); + return 0; +} + +int io_setup_all(void) { + int err; + matron_io_t* io; + TAILQ_FOREACH(io, &io_queue, entries) { + fprintf(stderr, "setup IO %s\n", io->ops->name); + err = io->ops->setup(io); + if (err) { + fprintf(stderr, "ERROR (%s) setup failed\n", io->ops->name); + return err; + } + } + fprintf(stderr, "IO setup OK.\n"); + return 0; +} + +void io_destroy_all(void) { + matron_io_t* io; + while (!TAILQ_EMPTY(&io_queue)) { + io = TAILQ_FIRST(&io_queue); + io->ops->destroy(io); + TAILQ_REMOVE(&io_queue, io, entries); + free(io->data); + free(io); + } +} diff --git a/matron/src/hardware/io.h b/matron/src/hardware/io.h new file mode 100644 index 000000000..cd6a77b03 --- /dev/null +++ b/matron/src/hardware/io.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include +#include + +typedef enum _matron_io_type { + IO_SCREEN, + IO_INPUT, + IO_END, +} matron_io_type_t; + +struct _matron_io; + +typedef struct _io_ops { + const char* name; + matron_io_type_t type; + size_t data_size; + + int (*config)(struct _matron_io* io, lua_State *l); + int (*setup)(struct _matron_io* io); + void (*destroy)(struct _matron_io* io); +} io_ops_t; + +extern io_ops_t* io_types[]; + +int io_create(lua_State *l, io_ops_t *ops); +int io_setup_all(void); +void io_destroy_all(void); + +typedef struct _matron_io { + void *data; + io_ops_t *ops; + + TAILQ_ENTRY(_matron_io) entries; +} matron_io_t; + +extern TAILQ_HEAD(io_head, _matron_io) io_queue; + +//// screen +struct _matron_fb; + +typedef struct _screen_ops { + io_ops_t io_ops; + + void (*paint)(struct _matron_fb *fb); + void (*bind)(struct _matron_fb *fb, cairo_surface_t *surface); +} screen_ops_t; + +typedef struct _matron_fb { + matron_io_t io; + + cairo_t *cairo; + cairo_surface_t *surface; +} matron_fb_t; + +//// keys & encs +struct _matron_input; + +typedef struct _input_ops { + io_ops_t io_ops; + + void* (*poll)(void* input); +} input_ops_t; + +typedef struct _matron_input { + matron_io_t io; + + pthread_t poll_thread; +} matron_input_t; diff --git a/matron/src/hardware/screen.c b/matron/src/hardware/screen.c index d1c0f536f..b922140cc 100644 --- a/matron/src/hardware/screen.c +++ b/matron/src/hardware/screen.c @@ -5,19 +5,18 @@ */ #include -#include #include +#include #include #include #include #include #include #include -#include -#include -#include #include "args.h" +#include "hardware/io.h" +#include "hardware/screen.h" // skip this if you don't want every screen module call to perform null checks #ifndef CHECK_CR @@ -73,17 +72,18 @@ static cairo_operator_t ops[NUM_OPS] = { }; static cairo_surface_t *surface; -static cairo_surface_t *surfacefb; static cairo_surface_t *image; - static cairo_t *cr; -static cairo_t *crfb; + static cairo_font_face_t *ct[NUM_FONTS]; static FT_Library value; static FT_Error status; static FT_Face face[NUM_FONTS]; static double text_xy[2]; +/* +//<<<<<<< HEAD +//======= typedef struct _cairo_linuxfb_device { int fb_fd; unsigned char *fb_data; @@ -92,7 +92,7 @@ typedef struct _cairo_linuxfb_device { struct fb_fix_screeninfo fb_finfo; } cairo_linuxfb_device_t; -/* Destroy a cairo surface */ +// Destroy a cairo surface void cairo_linuxfb_surface_destroy(void *device) { cairo_linuxfb_device_t *dev = (cairo_linuxfb_device_t *)device; @@ -105,7 +105,7 @@ void cairo_linuxfb_surface_destroy(void *device) { free(dev); } -/* Create a cairo surface using the specified framebuffer */ +// Create a cairo surface using the specified framebuffer cairo_surface_t *cairo_linuxfb_surface_create() { cairo_linuxfb_device_t *device; cairo_surface_t *surface; @@ -149,7 +149,7 @@ cairo_surface_t *cairo_linuxfb_surface_create() { goto handle_ioctl_error; } - /* Create the cairo surface which will be used to draw to */ + // Create the cairo surface which will be used to draw to surface = cairo_image_surface_create_for_data( device->fb_data, CAIRO_FORMAT_RGB16_565, device->fb_vinfo.xres, device->fb_vinfo.yres, cairo_format_stride_for_width(CAIRO_FORMAT_RGB16_565, device->fb_vinfo.xres)); @@ -164,6 +164,9 @@ cairo_surface_t *cairo_linuxfb_surface_create() { return NULL; } +//>>>>>>> main +*/ + void screen_display_png(const char *filename, double x, double y) { int img_w, img_h; // fprintf(stderr, "loading: %s\n", filename); @@ -185,12 +188,6 @@ void screen_display_png(const char *filename, double x, double y) { } void screen_init(void) { - surfacefb = cairo_linuxfb_surface_create(); - if (surfacefb == NULL) { - return; - } - crfb = cairo_create(surfacefb); - surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 128, 64); cr = cairo_create(surface); @@ -313,22 +310,38 @@ void screen_init(void) { cairo_set_font_face(cr, ct[0]); cairo_set_font_size(cr, 8.0); - // config buffer - cairo_set_operator(crfb, CAIRO_OPERATOR_SOURCE); - cairo_set_source_surface(crfb, surface, 0, 0); + fprintf(stderr, "font setup OK.\n"); + + matron_io_t *io; + TAILQ_FOREACH(io, &io_queue, entries) { + if (io->ops->type != IO_SCREEN) continue; + matron_fb_t *fb = (matron_fb_t *)io; + screen_ops_t *fb_ops = (screen_ops_t *)io->ops; + fb_ops->bind(fb, surface); + } } void screen_deinit(void) { CHECK_CR cairo_destroy(cr); cairo_surface_destroy(surface); - cairo_destroy(crfb); - cairo_surface_destroy(surfacefb); + + matron_io_t *io; + TAILQ_FOREACH(io, &io_queue, entries) { + if (io->ops->type != IO_SCREEN) continue; + io->ops->destroy(io); + } } void screen_update(void) { CHECK_CR - cairo_paint(crfb); + matron_io_t *io; + TAILQ_FOREACH(io, &io_queue, entries) { + if (io->ops->type != IO_SCREEN) continue; + matron_fb_t *fb = (matron_fb_t *)io; + screen_ops_t *fb_ops = (screen_ops_t *)io->ops; + fb_ops->paint(fb); + } } void screen_save(void) { diff --git a/matron/src/hardware/screen/fbdev.c b/matron/src/hardware/screen/fbdev.c new file mode 100644 index 000000000..bdb06aec3 --- /dev/null +++ b/matron/src/hardware/screen/fbdev.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "args.h" +#include "hardware/io.h" +#include "hardware/screen/screens.h" + +typedef struct _screen_fbdev_priv { + char *dev; + int fb_fd; + unsigned char *fb_data; + long fb_screensize; + struct fb_var_screeninfo fb_vinfo; + struct fb_fix_screeninfo fb_finfo; +} screen_fbdev_priv_t; + +static int screen_fbdev_config(matron_io_t *io, lua_State *l); +static int screen_fbdev_setup(matron_io_t *io); +static void screen_fbdev_destroy(matron_io_t *io); +static void screen_fbdev_paint(matron_fb_t *fb); +static void screen_fbdev_bind(matron_fb_t *fb, cairo_surface_t *surface); + +static void screen_fbdev_surface_destroy(void *device); +static cairo_surface_t *screen_fbdev_surface_create(screen_fbdev_priv_t *priv, const char *fb_name); + +screen_ops_t screen_fbdev_ops = { + .io_ops.name = "screen:fbdev", + .io_ops.type = IO_SCREEN, + .io_ops.data_size = sizeof(screen_fbdev_priv_t), + .io_ops.config = screen_fbdev_config, + .io_ops.setup = screen_fbdev_setup, + .io_ops.destroy = screen_fbdev_destroy, + + .paint = screen_fbdev_paint, + .bind = screen_fbdev_bind, +}; + +int screen_fbdev_config(matron_io_t *io, lua_State *l) { + screen_fbdev_priv_t *priv = io->data; + lua_pushstring(l, "dev"); + lua_gettable(l, -2); + if (lua_isstring(l, -1)) { + const char *dev = lua_tostring(l, -1); + if (!(priv->dev = malloc(strlen(dev) + 1))) { + fprintf(stderr, "ERROR (screen:fbdev) no memory\n"); + lua_settop(l, 0); + return -1; + } + strcpy(priv->dev, dev); + } else if (lua_isnil(l, -1)) { + if (!(priv->dev = malloc(9))) { + fprintf(stderr, "ERROR (screen:fbdev) no memory\n"); + free(priv->dev); + lua_settop(l, 0); + return -1; + } + strcpy(priv->dev, "/dev/fb0"); + fprintf(stderr, "screen:fbdev: no 'dev', using %s\n", priv->dev); + } else { + fprintf(stderr, "ERROR (screen:fbdev) config option 'dev' should be a string\n"); + lua_settop(l, 0); + return -1; + } + lua_pop(l, 1); + return 0; +} + +int screen_fbdev_setup(matron_io_t *io) { + matron_fb_t *fb = (matron_fb_t *)io; + screen_fbdev_priv_t *priv = io->data; + fb->surface = screen_fbdev_surface_create(priv, priv->dev); + if (!fb->surface) { + fprintf(stderr, "ERROR (screen:fbdev) failed to create surface '%s'\n", priv->dev); + free(priv->dev); + return -1; + } + fb->cairo = cairo_create(fb->surface); + return 0; +} + +static void screen_fbdev_destroy(matron_io_t *io) { + matron_fb_t *fb = (matron_fb_t *)io; + screen_fbdev_priv_t *priv = io->data; + cairo_destroy(fb->cairo); + cairo_surface_destroy(fb->surface); + free(priv->dev); +} + +static void screen_fbdev_paint(matron_fb_t *fb) { + cairo_paint(fb->cairo); +} + +static void screen_fbdev_bind(matron_fb_t *fb, cairo_surface_t *surface) { + cairo_set_operator(fb->cairo, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(fb->cairo, surface, 0, 0); +} + +static void screen_fbdev_surface_destroy(void *data) { + screen_fbdev_priv_t *priv = data; + + if (priv == NULL) { + return; + } + + munmap(priv->fb_data, priv->fb_screensize); + close(priv->fb_fd); + free(priv); +} + +static cairo_surface_t *screen_fbdev_surface_create(screen_fbdev_priv_t *priv, const char *dev) { + cairo_surface_t *surface; + + // Open the file for reading and writing + priv->fb_fd = open(dev, O_RDWR); + if (priv->fb_fd <= 0) { + fprintf(stderr, "ERROR (screen) cannot open framebuffer device\n"); + goto handle_allocate_error; + } + + // Get variable screen information + if (ioctl(priv->fb_fd, FBIOGET_VSCREENINFO, &priv->fb_vinfo) == -1) { + fprintf(stderr, "ERROR (screen) reading variable information\n"); + goto handle_ioctl_error; + } + + // Figure out the size of the screen in bytes + priv->fb_screensize = priv->fb_vinfo.xres * priv->fb_vinfo.yres * priv->fb_vinfo.bits_per_pixel / 8; + + // Map the device to memory + priv->fb_data = + (unsigned char *)mmap(0, priv->fb_screensize, PROT_READ | PROT_WRITE, MAP_SHARED, priv->fb_fd, 0); + + if (priv->fb_data == (unsigned char *)-1) { + fprintf(stderr, "ERROR (screen) failed to map framebuffer device to memory\n"); + goto handle_ioctl_error; + } + + // Get fixed screen information + if (ioctl(priv->fb_fd, FBIOGET_FSCREENINFO, &priv->fb_finfo) == -1) { + fprintf(stderr, "ERROR (screen) reading fixed information\n"); + goto handle_ioctl_error; + } + + // Create the cairo surface which will be used to draw to + surface = cairo_image_surface_create_for_data( + priv->fb_data, CAIRO_FORMAT_RGB16_565, priv->fb_vinfo.xres, priv->fb_vinfo.yres, + cairo_format_stride_for_width(CAIRO_FORMAT_RGB16_565, priv->fb_vinfo.xres)); + cairo_surface_set_user_data(surface, NULL, priv, &screen_fbdev_surface_destroy); + + return surface; + +handle_ioctl_error: + close(priv->fb_fd); +handle_allocate_error: + free(priv); + return NULL; +} + diff --git a/matron/src/hardware/screen/screens.h b/matron/src/hardware/screen/screens.h new file mode 100644 index 000000000..cd7cef5a1 --- /dev/null +++ b/matron/src/hardware/screen/screens.h @@ -0,0 +1,8 @@ +#pragma once + +#include "hardware/io.h" + +extern screen_ops_t screen_fbdev_ops; +#ifdef NORNS_DESKTOP +extern screen_ops_t screen_sdl_ops; +#endif diff --git a/matron/src/hardware/screen/sdl.c b/matron/src/hardware/screen/sdl.c new file mode 100644 index 000000000..f89440d69 --- /dev/null +++ b/matron/src/hardware/screen/sdl.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include + +#include +#include + +#include "hardware/io.h" +#include "hardware/screen/screens.h" + +typedef struct _screen_sdl_priv { + SDL_Window *window; + SDL_Surface *window_surface; + SDL_Surface *draw_surface; +} screen_sdl_priv_t; + +static int screen_sdl_config(matron_io_t *io, lua_State *l); +static int screen_sdl_setup(matron_io_t *io); +static void screen_sdl_destroy(matron_io_t *io); +static void screen_sdl_paint(matron_fb_t *fb); +static void screen_sdl_bind(matron_fb_t *fb, cairo_surface_t *surface); + +static void screen_sdl_surface_destroy(void *priv); +static cairo_surface_t *screen_sdl_surface_create(screen_sdl_priv_t *priv); + +static SDL_Rect windowSize = { + .x = 0, + .y = 0, + .w = 512, + .h = 256 +}; + +screen_ops_t screen_sdl_ops = { + .io_ops.name = "screen:sdl", + .io_ops.type = IO_SCREEN, + .io_ops.data_size = sizeof(screen_sdl_priv_t), + .io_ops.config = screen_sdl_config, + .io_ops.setup = screen_sdl_setup, + .io_ops.destroy = screen_sdl_destroy, + + .paint = screen_sdl_paint, + .bind = screen_sdl_bind, +}; + +int screen_sdl_config(matron_io_t *io, lua_State *l) { + (void)io; + (void)l; + return 0; +} + +int screen_sdl_setup(matron_io_t *io) { + matron_fb_t *fb = (matron_fb_t *)io; + fb->surface = screen_sdl_surface_create((screen_sdl_priv_t *)io->data); + if (!fb->surface) { + fprintf(stderr, "ERROR (%s) failed to create surface\n", io->ops->name); + return -1; + } + fb->cairo = cairo_create(fb->surface); + return 0; +} + +static void screen_sdl_destroy(matron_io_t *io) { + matron_fb_t *fb = (matron_fb_t *)io; + cairo_destroy(fb->cairo); + cairo_surface_destroy(fb->surface); +} + +static void screen_sdl_paint(matron_fb_t *fb) { + screen_sdl_priv_t *priv = fb->io.data; + cairo_paint(fb->cairo); + SDL_BlitScaled(priv->draw_surface, NULL, priv->window_surface, &windowSize); + SDL_UpdateWindowSurface(priv->window); +} + +static void screen_sdl_bind(matron_fb_t *fb, cairo_surface_t *surface) { + cairo_set_operator(fb->cairo, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(fb->cairo, surface, 0, 0); +} + +static void screen_sdl_surface_destroy(void *data) { + screen_sdl_priv_t *priv = data; + + if (priv == NULL) { + return; + } + SDL_FreeSurface(priv->draw_surface); + SDL_DestroyWindow(priv->window); + free(priv); +} + +static cairo_surface_t *screen_sdl_surface_create(screen_sdl_priv_t *priv) { + cairo_surface_t *surface; + + SDL_Init(SDL_INIT_VIDEO); + priv->window = SDL_CreateWindow("matron", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowSize.w, windowSize.h, + SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); + priv->window_surface = SDL_GetWindowSurface(priv->window); + priv->draw_surface = SDL_CreateRGBSurface(0, + 128, 64, + 16, 0xf800, 0x000007e0, 0x0000001f, + 0); + surface = cairo_image_surface_create_for_data((unsigned char *)priv->draw_surface->pixels, + CAIRO_FORMAT_RGB16_565, priv->draw_surface->w, priv->draw_surface->h, + cairo_format_stride_for_width(CAIRO_FORMAT_RGB16_565, priv->draw_surface->w)); + cairo_surface_set_user_data(surface, NULL, priv, &screen_sdl_surface_destroy); + + return surface; +} diff --git a/matron/src/hardware/stat.c b/matron/src/hardware/stat.c index c9b7202f5..08efc4408 100644 --- a/matron/src/hardware/stat.c +++ b/matron/src/hardware/stat.c @@ -78,6 +78,18 @@ void *stat_check(void *x) { } // check temp + /* +//<<<<<<< HEAD + if ((fd = popen("vcgencmd measure_temp", "r")) == NULL) { + fprintf(stderr, "Error opening pipe: temp read\n"); + } else { + while (fgets(buf, 16, fd) != NULL) { + bufsub[0] = buf[5]; + bufsub[1] = buf[6]; + bufsub[2] = 0; + temp = atoi(bufsub); + // fprintf(stderr,"temp: %d\r\n", temp); +//======= if (have_vcgencmd) { if ((fd = popen("vcgencmd measure_temp", "r")) == NULL) { fprintf(stderr, "Error opening pipe: temp read\n"); @@ -86,6 +98,19 @@ void *stat_check(void *x) { memcpy(bufsub, buf + 5, 2); temp = atoi(bufsub); } +//>>>>>>> main + */ + + if (have_vcgencmd) { + if ((fd = popen("vcgencmd measure_temp", "r")) == NULL) { + fprintf(stderr, "Error opening pipe: temp read\n"); + } else { + while (fgets(buf, 16, fd) != NULL) { + bufsub[0] = buf[5]; + bufsub[1] = buf[6]; + bufsub[2] = 0; + temp = atoi(bufsub); + } } pclose(fd); } diff --git a/matron/src/lua_eval.c b/matron/src/lua_eval.c index 8c237c90c..e36c220aa 100644 --- a/matron/src/lua_eval.c +++ b/matron/src/lua_eval.c @@ -163,9 +163,9 @@ static int dochunk(lua_State *L, int status) { return report(L, status); } -/* static int dofile (lua_State *L, const char *name) { */ -/* return dochunk(L, luaL_loadfile(L, name)); */ -/* } */ +int l_dofile (lua_State *L, const char *name) { + return dochunk(L, luaL_loadfile(L, name)); +} static int dostring(lua_State *L, const char *s, const char *name) { return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name)); diff --git a/matron/src/lua_eval.h b/matron/src/lua_eval.h index 2892c107d..5f4cab15b 100644 --- a/matron/src/lua_eval.h +++ b/matron/src/lua_eval.h @@ -1,9 +1,20 @@ #pragma once +#include + +#define STRING_NUM(n) #n +#define LUA_ARG_ERROR(n) "error: requires " STRING_NUM(n) " arguments" +#define lua_check_num_args(n) \ + if (lua_gettop(l) != n) { \ + return luaL_error(l, LUA_ARG_ERROR(n)); \ + } + extern int l_dostring(lua_State *L, const char *s, const char *name); extern int l_report(lua_State *L, int status); extern int l_docall(lua_State *L, int narg, int nres); +extern int l_dofile(lua_State *L, const char* filename); + extern int l_handle_line(lua_State *L, char *line); diff --git a/matron/src/main.c b/matron/src/main.c index 07c011785..0bc1632ce 100644 --- a/matron/src/main.c +++ b/matron/src/main.c @@ -12,6 +12,7 @@ #include "clocks/clock_internal.h" #include "clocks/clock_link.h" #include "clocks/clock_midi.h" +#include "config.h" #include "clocks/clock_scheduler.h" #include "device.h" #include "device_hid.h" @@ -20,7 +21,6 @@ #include "device_monitor.h" #include "device_monome.h" #include "events.h" -#include "gpio.h" #include "hello.h" #include "i2c.h" #include "input.h" @@ -40,9 +40,9 @@ void cleanup(void) { osc_deinit(); o_deinit(); w_deinit(); - gpio_deinit(); + + config_deinit(); i2c_deinit(); - screen_deinit(); battery_deinit(); stat_deinit(); clock_deinit(); @@ -59,16 +59,13 @@ int main(int argc, char **argv) { printf("platform: %d\n",platform()); events_init(); // <-- must come first! - screen_init(); + if (config_init()) { + fprintf(stderr, "configuration failed\n"); + return -1; + } metros_init(); -#ifdef __arm__ - // gpio_init() hangs for too long when cross-compiling norns - // desktop for dev - just disable on x86 for now - gpio_init(); -#endif - battery_init(); stat_init(); i2c_init(); diff --git a/matron/src/weaver.c b/matron/src/weaver.c index ecf5ed886..f7953beb7 100644 --- a/matron/src/weaver.c +++ b/matron/src/weaver.c @@ -267,7 +267,7 @@ static inline void _push_norns_func(const char *field, const char *func) { //// extern function definitions void w_init(void) { - fprintf(stderr, "starting lua vm\n"); + fprintf(stderr, "starting main lua vm\n"); lvm = luaL_newstate(); luaL_openlibs(lvm); lua_pcall(lvm, 0, 0, 0); @@ -511,13 +511,6 @@ void w_reset_lvm() { //---- static definitions // -#define STRING_NUM(n) #n -#define LUA_ARG_ERROR(n) "error: requires " STRING_NUM(n) " arguments" -#define lua_check_num_args(n) \ - if (lua_gettop(l) != n) { \ - return luaL_error(l, LUA_ARG_ERROR(n)); \ - } - int _reset_lvm(lua_State *l) { lua_check_num_args(0); lua_settop(l, 0); diff --git a/matron/wscript b/matron/wscript index 50e6d4f40..f142e27ce 100644 --- a/matron/wscript +++ b/matron/wscript @@ -2,6 +2,7 @@ top = '..' def build(bld): matron_sources = [ + 'src/config.c', 'src/device/device.c', 'src/device/device_hid.c', 'src/device/device_list.c', @@ -11,11 +12,14 @@ def build(bld): 'src/device/device_crow.c', 'src/osc.c', 'src/hardware/battery.c', - 'src/hardware/gpio.c', 'src/hardware/i2c.c', + 'src/hardware/input.c', + 'src/hardware/io.c', 'src/hardware/platform.c', 'src/hardware/screen.c', 'src/hardware/stat.c', + 'src/hardware/screen/fbdev.c', + 'src/hardware/input/gpio.c', 'src/args.c', 'src/events.c', 'src/hello.c', @@ -34,6 +38,12 @@ def build(bld): 'src/clocks/clock_scheduler.c', ] + if bld.options.desktop: + matron_sources += [ + 'src/hardware/screen/sdl.c', + 'src/hardware/input/sdl.c', + ] + matron_includes = [ 'src', 'src/device', @@ -60,6 +70,10 @@ def build(bld): 'JACK', ] + if bld.options.desktop: + matron_libs.append('SDL2') + matron_use.append('SDL2') + if bld.env.ENABLE_ABLETON_LINK: matron_sources += ['src/clocks/clock_link.c'] matron_includes += ['../third-party/link-c'] diff --git a/matronrc.lua b/matronrc.lua new file mode 100644 index 000000000..10aa96639 --- /dev/null +++ b/matronrc.lua @@ -0,0 +1,20 @@ +function init_norns() + _boot.add_io('screen:fbdev', {dev='/dev/fb0'}) + _boot.add_io('keys:gpio', {dev='/dev/input/by-path/platform-keys-event'}) + _boot.add_io('enc:gpio', {dev='/dev/input/by-path/platform-soc:knob1-event', index=1}) + _boot.add_io('enc:gpio', {dev='/dev/input/by-path/platform-soc:knob2-event', index=2}) + _boot.add_io('enc:gpio', {dev='/dev/input/by-path/platform-soc:knob3-event', index=3}) +end + +function init_desktop() + -- desktop window + _boot.add_io('screen:sdl', {}) + -- _boot.add_io('input:sdl', {}) + + -- i/o via maiden + -- _boot.add_io('screen:json', {}) + -- _boot.input_add('web_input', 'json', {}) +end + +init_norns() + diff --git a/wscript b/wscript index cd10b841d..9a54f8a4d 100644 --- a/wscript +++ b/wscript @@ -44,6 +44,9 @@ def configure(conf): conf.check_cfg(package='avahi-compat-libdns_sd', args=['--cflags', '--libs']) conf.check_cfg(package='sndfile', args=['--cflags', '--libs']) conf.check_cfg(package='jack', args=['--cflags', '--libs']) + + if conf.options.desktop: + conf.check_cfg(package='sdl2', args=['--cflags', '--libs']) conf.check_cc(msg='Checking for libmonome', define_name='HAVE_LIBMONOME',