Skip to content
Permalink
main
Go to file
 
 
Cannot retrieve contributors at this time
308 lines (285 sloc) 8.54 KB
#include <assert.h>
#include <search.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "battery.h"
#include "device_monome.h"
#include "events.h"
#include "gpio.h"
#include "oracle.h"
#include "stat.h"
#include "weaver.h"
#include "event_types.h"
//----------------------------
//--- types and variables
struct ev_node {
struct ev_node *next;
struct ev_node *prev;
union event_data *ev;
};
struct ev_q {
struct ev_node *head;
struct ev_node *tail;
ssize_t size;
pthread_cond_t nonempty;
pthread_mutex_t lock;
};
struct ev_q evq;
bool quit;
//----------------------------
//--- static function declarations
//---- handlers
static void handle_event(union event_data *ev);
/// helpers
static void handle_engine_report(void);
// static void handle_command_report(void);
// static void handle_poll_report(void);
// add an event data struct to the end of the event queue
// *does* allocate queue node memory!
// *does not* allocate event data memory!
// call with the queue locked
static void evq_push(union event_data *ev) {
struct ev_node *evn = calloc(1, sizeof(struct ev_node));
evn->ev = ev;
if (evq.size == 0) {
insque(evn, NULL);
evq.head = evn;
} else {
insque(evn, evq.tail);
}
evq.tail = evn;
evq.size += 1;
}
// remove and return the event data struct from the top of the event queue
// call with the queue locked
// *does* free queue node memory!
// *does not* free the event data memory!
static union event_data *evq_pop() {
struct ev_node *evn = evq.head;
if (evn == NULL) {
return NULL;
}
union event_data *ev = evn->ev;
evq.head = evn->next;
if (evn == evq.tail) {
assert(evq.size == 1);
evq.tail = NULL;
}
remque(evn);
free(evn);
evq.size -= 1;
return ev;
}
//-------------------------------
//-- extern function definitions
void events_init(void) {
evq.size = 0;
evq.head = NULL;
evq.tail = NULL;
pthread_cond_init(&evq.nonempty, NULL);
}
union event_data *event_data_new(event_t type) {
// FIXME: better not to allocate here, use object pool
union event_data *ev = calloc(1, sizeof(union event_data));
ev->type = type;
return ev;
}
void event_data_free(union event_data *ev) {
switch (ev->type) {
case EVENT_EXEC_CODE_LINE:
free(ev->exec_code_line.line);
break;
case EVENT_OSC:
free(ev->osc_event.path);
free(ev->osc_event.from_host);
free(ev->osc_event.from_port);
lo_message_free(ev->osc_event.msg);
break;
case EVENT_POLL_DATA:
free(ev->poll_data.data);
break;
case EVENT_POLL_WAVE:
free(ev->poll_wave.data);
break;
case EVENT_SYSTEM_CMD:
free(ev->system_cmd.capture);
break;
case EVENT_SOFTCUT_RENDER:
free(ev->softcut_render.data);
break;
}
free(ev);
}
// add an event to the q and signal if necessary
void event_post(union event_data *ev) {
assert(ev != NULL);
pthread_mutex_lock(&evq.lock);
if (evq.size == 0) {
// signal handler thread to wake up...
pthread_cond_signal(&evq.nonempty);
}
evq_push(ev);
// ...handler actually wakes up once we release the lock
pthread_mutex_unlock(&evq.lock);
}
// main loop to read events!
void event_loop(void) {
union event_data *ev;
while (!quit) {
pthread_mutex_lock(&evq.lock);
// while() because contention may produce spurious wakeup
while (evq.size == 0) {
//// FIXME: if we have an input device thread running,
//// then we get segfaults here on SIGINT
//// need to set an explicit sigint handler
// atomically unlocks the mutex, sleeps on condvar, locks again on
// wakeup
pthread_cond_wait(&evq.nonempty, &evq.lock);
}
// fprintf(stderr, "evq.size : %d\n", (int) evq.size);
assert(evq.size > 0);
ev = evq_pop();
pthread_mutex_unlock(&evq.lock);
if (ev != NULL) {
handle_event(ev);
}
}
}
//------------------------------
//-- static function definitions
static void handle_event(union event_data *ev) {
switch (ev->type) {
case EVENT_EXEC_CODE_LINE:
w_handle_exec_code_line(ev->exec_code_line.line);
break;
case EVENT_METRO:
w_handle_metro(ev->metro.id, ev->metro.stage);
break;
case EVENT_CLOCK_RESUME:
w_handle_clock_resume(ev->clock_resume.thread_id);
break;
case EVENT_CLOCK_START:
w_handle_clock_start();
break;
case EVENT_CLOCK_STOP:
w_handle_clock_stop();
break;
case EVENT_KEY:
w_handle_key(ev->key.n, ev->key.val);
break;
case EVENT_ENC:
w_handle_enc(ev->enc.n, ev->enc.delta);
break;
case EVENT_BATTERY:
w_handle_battery(ev->battery.percent, ev->battery.current);
break;
case EVENT_POWER:
w_handle_power(ev->power.present);
break;
case EVENT_STAT:
w_handle_stat(ev->stat.disk, ev->stat.temp, ev->stat.cpu);
break;
case EVENT_MONOME_ADD:
w_handle_monome_add(ev->monome_add.dev);
break;
case EVENT_MONOME_REMOVE:
w_handle_monome_remove(ev->monome_remove.id);
break;
case EVENT_GRID_KEY:
w_handle_grid_key(ev->grid_key.id, ev->grid_key.x, ev->grid_key.y, ev->grid_key.state);
break;
case EVENT_ARC_ENCODER_DELTA:
w_handle_arc_encoder_delta(ev->arc_encoder_delta.id, ev->arc_encoder_delta.number, ev->arc_encoder_delta.delta);
break;
case EVENT_ARC_ENCODER_KEY:
w_handle_arc_encoder_key(ev->arc_encoder_key.id, ev->arc_encoder_key.number, ev->arc_encoder_key.state);
break;
case EVENT_HID_ADD:
w_handle_hid_add(ev->hid_add.dev);
break;
case EVENT_HID_REMOVE:
w_handle_hid_remove(ev->hid_remove.id);
break;
case EVENT_HID_EVENT:
w_handle_hid_event(ev->hid_event.id, ev->hid_event.type, ev->hid_event.code, ev->hid_event.value);
break;
case EVENT_MIDI_ADD:
w_handle_midi_add(ev->midi_add.dev);
break;
case EVENT_MIDI_REMOVE:
w_handle_midi_remove(ev->midi_remove.id);
break;
case EVENT_MIDI_EVENT:
w_handle_midi_event(ev->midi_event.id, ev->midi_event.data, ev->midi_event.nbytes);
break;
case EVENT_OSC:
w_handle_osc_event(ev->osc_event.from_host, ev->osc_event.from_port, ev->osc_event.path, ev->osc_event.msg);
break;
case EVENT_ENGINE_REPORT:
handle_engine_report();
break;
/* case EVENT_COMMAND_REPORT: */
/* handle_command_report(); */
/* break; */
/* case EVENT_POLL_REPORT: */
/* handle_poll_report(); */
/* break; */
case EVENT_ENGINE_LOADED:
w_handle_engine_loaded();
break;
case EVENT_POLL_VALUE:
w_handle_poll_value(ev->poll_value.idx, ev->poll_value.value);
break;
case EVENT_POLL_DATA:
w_handle_poll_data(ev->poll_data.idx, ev->poll_data.size, ev->poll_data.data);
break;
case EVENT_POLL_IO_LEVELS:
w_handle_poll_io_levels(ev->poll_io_levels.value.bytes);
break;
case EVENT_POLL_SOFTCUT_PHASE:
w_handle_poll_softcut_phase(ev->softcut_phase.idx, ev->softcut_phase.value);
break;
case EVENT_STARTUP_READY_OK:
w_handle_startup_ready_ok();
break;
case EVENT_STARTUP_READY_TIMEOUT:
w_handle_startup_ready_timeout();
break;
case EVENT_SYSTEM_CMD:
w_handle_system_cmd(ev->system_cmd.capture);
break;
case EVENT_RESET_LVM:
w_reset_lvm();
break;
case EVENT_QUIT:
quit = true;
break;
case EVENT_CROW_ADD:
w_handle_crow_add(ev->crow_add.dev);
break;
case EVENT_CROW_REMOVE:
w_handle_crow_remove(ev->crow_remove.id);
break;
case EVENT_CROW_EVENT:
w_handle_crow_event(ev->crow_event.dev, ev->crow_event.id);
break;
case EVENT_SOFTCUT_RENDER:
w_handle_softcut_render(ev->softcut_render.idx, ev->softcut_render.sec_per_sample, ev->softcut_render.start, ev->softcut_render.size, ev->softcut_render.data);
break;
} /* switch */
event_data_free(ev);
}
//---------------------------------
//---- helpers
//--- reports
void handle_engine_report(void) {
o_lock_descriptors();
const char **p = o_get_engine_names();
const int n = o_get_num_engines();
w_handle_engine_report(p, n);
o_unlock_descriptors();
}