12. Hardware Listener
All hardware peripherals (monome, griffin) are polled inside of a single listener thread. Anytime a message is received by a hardware interface, it is immediately handled by the corresponding virtual interface.
12.1. Thread hardware listener callback
The hardware listener runs as a POSIX thread, so the pthread header is included.
#ifdef MONOLITH_OSX
#include <pthread/pthread.h>
#endif
#ifdef MONOLITH_LINUX
#include <pthread.h>
#endif
#include <unistd.h>
The function usleep
is always implicitely declared when
enforcing c89 C mode. To remove this warning, the function
prototype is explicitely written.
This delcaration seems to cause problems when cross
compiling for norns because it can't seem to find the
useconds_t
. For now, I am using a ifndef
macro as a hack
for now.
#ifndef MONOLITH_NORNS
int usleep(useconds_t usec);
#endif
The listener itself is contained in a static pthread
function called listener
. Contained inside is a while loop
which periodically polls the peripherals for any new events.
Any new events found will be immediately processed with the
virtual hardware interface.
static void* listener(void *data);
void monolith_poll(monolith_d *m)
{
<<poll_the_monome>>
<<poll_the_griffin>>
<<poll_the_g430>>
<<poll_the_norns>>
}
static void* listener(void *data)
{
monolith_d *m;
m = data;
while (m->listener_running) {
monolith_poll(m);
usleep(800);
}
pthread_exit(NULL);
}
12.2. Monolith listener data
The listener thread has a pthread data type called
listener_thread
pthread_t listener_thread;
On init, this is set to be NULL.
m->listener_thread = 0;
There is also a flag that is used to break out of the while
loop called listener_running
.
int listener_running;
m->listener_running = 0;
By default, it's set to be 0.
12.3. Starting/Stopping the hardware listener
The hardware listener can be started with the callback
monolith_listener_start
. This will start the pthread
listener.
void monolith_listener_start(monolith_d *m);
void monolith_listener_start(monolith_d *m)
{
if(m->listener_running) {
fprintf(stderr, "Hardware listener seems to be running already\n");
return;
}
m->listener_running = 1;
pthread_create(&m->listener_thread, NULL, listener, m);
}
The hardware listener can be started from scheme using the
function monolith:listener-start
.
{"monolith:listener-start", pp_listener_start, 0, 0, {CHR,___,___}},
static cell pp_listener_start(cell x) {
monolith_listener_start(monolith_data_get());
return UNSPECIFIC;
}
{
"monolith/listener-start",
j_listener_start,
"Starts the main listener."
},
static Janet j_listener_start(int32_t argc, Janet *argv)
{
monolith_d *m;
janet_fixarity(argc, 0);
m = monolith_data_get();
monolith_listener_start(m);
return janet_wrap_nil();
}
The hardware listern can be stopped with the callback
monolith_listener_stop
.
void monolith_listener_stop(monolith_d *m);
void monolith_listener_stop(monolith_d *m)
{
if(m->listener_running == 0) return;
m->listener_running = 0;
pthread_join(m->listener_thread, NULL);
}
12.4. Stopping the listener at cleanup
At cleanup, monolith_listener_stop
is stopped. To prevent
segfaults, hardware must be explicitely stopped after that.
monolith_listener_stop(m);
<<hardware_cleanup>>
12.5. Single-threaded event polling
This will create a blocking event loop. On the norns, this should be able to allow Janet functions to be called by the norns aux menu.
SIGINT will be mapped so that a command line test will cleanly quit out of the listener loop.
void monolith_listener_loop(monolith_d *m);
#include <signal.h>
static int loop_running = 0;
static void close_eventloop(int dummy)
{
fprintf(stderr, "Stopping event loop.\n");
loop_running = 0;
}
void monolith_listener_loop(monolith_d *m)
{
signal(SIGINT, close_eventloop);
loop_running = 1;
m->listener_running = 1;
#ifdef MONOLITH_NORNS
while (loop_running && m->norns_running) {
monolith_poll(m);
usleep(800);
}
#else
while (loop_running) {
monolith_poll(m);
usleep(800);
}
#endif
m->listener_running = 0;
}
Call this from Janet with monolith/event-loop
.
{
"monolith/event-loop",
j_event_loop,
"A single-threaded event loop.\n"
},
static Janet j_event_loop(int32_t argc, Janet *argv)
{
janet_fixarity(argc, 0);
monolith_listener_loop(monolith_data_get());
return janet_wrap_nil();
}
prev | home | next