Skip to content

Commit

Permalink
Decouple fb merge (#1444)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: Sam Boling <[email protected]>
Co-authored-by: Artem Popov <[email protected]>
  • Loading branch information
4 people authored Oct 5, 2021
1 parent 0fc9606 commit 2b82088
Show file tree
Hide file tree
Showing 29 changed files with 1,105 additions and 171 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

# ignore emacs cruft
\#*\#
.\#*
*.*~

# vim
Expand Down
2 changes: 1 addition & 1 deletion crone/softcut
30 changes: 10 additions & 20 deletions matron/src/args.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}
1 change: 0 additions & 1 deletion matron/src/args.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
75 changes: 75 additions & 0 deletions matron/src/config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <lauxlib.h>
#include <lualib.h>

#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");
}
4 changes: 4 additions & 0 deletions matron/src/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

extern int config_init(void);
extern void config_deinit(void);
2 changes: 0 additions & 2 deletions matron/src/device/device_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

#include <stdint.h>



typedef enum {
// libmonome devices
DEV_TYPE_MONOME = 0,
Expand Down
1 change: 0 additions & 1 deletion matron/src/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
169 changes: 73 additions & 96 deletions matron/src/hardware/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,120 +4,97 @@
* keys and encoders
*/

#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#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);
}
}

Expand Down
6 changes: 0 additions & 6 deletions matron/src/hardware/gpio.h

This file was deleted.

Loading

0 comments on commit 2b82088

Please sign in to comment.