Compare commits
No commits in common. "a0825d1d5854d56f9f3f892f05a5f71697949e1d" and "65769a7442c734cad6cf82db5a29cfb5c5896ea0" have entirely different histories.
a0825d1d58
...
65769a7442
6
Makefile
6
Makefile
|
@ -1,6 +1,4 @@
|
||||||
DEPS =
|
DEPS = libevdev
|
||||||
DEPS += libevdev
|
|
||||||
DEPS += libconfig
|
|
||||||
CFLAGS = -Wall -Wextra
|
CFLAGS = -Wall -Wextra
|
||||||
ifdef DEBUG
|
ifdef DEBUG
|
||||||
CFLAGS += -Og -gdwarf-2
|
CFLAGS += -Og -gdwarf-2
|
||||||
|
@ -12,7 +10,7 @@ CPPFLAGS += $(shell pkg-config --cflags $(DEPS))
|
||||||
LDLIBS += $(shell pkg-config --libs $(DEPS))
|
LDLIBS += $(shell pkg-config --libs $(DEPS))
|
||||||
INTERP ?=
|
INTERP ?=
|
||||||
MAIN = main
|
MAIN = main
|
||||||
OBJS = main.o events.o processing.o graph.o config.o nodes/getchar.o nodes/print.o nodes/evdev.o
|
OBJS = main.o events.o processing.o graph.o nodes/getchar.o nodes/print.o nodes/evdev.o
|
||||||
|
|
||||||
all: $(MAIN)
|
all: $(MAIN)
|
||||||
|
|
||||||
|
|
137
config.c
137
config.c
|
@ -1,137 +0,0 @@
|
||||||
#include <string.h>
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
static GraphNodeConfig
|
|
||||||
load_single_node_config(const config_setting_t *config_member)
|
|
||||||
{
|
|
||||||
GraphNodeConfig result = {
|
|
||||||
.name = NULL,
|
|
||||||
.type = NULL,
|
|
||||||
.options = NULL,
|
|
||||||
};
|
|
||||||
if (!config_member) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result.name = config_setting_name(config_member);
|
|
||||||
if (!result.name) {
|
|
||||||
config_setting_lookup_string(config_member, "namd", &result.name);
|
|
||||||
}
|
|
||||||
config_setting_lookup_string(config_member, "type", &result.type);
|
|
||||||
result.options = config_setting_get_member(config_member, "options");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GraphNodeConfigSection
|
|
||||||
load_nodes_section(const config_setting_t *config_section)
|
|
||||||
{
|
|
||||||
GraphNodeConfigSection result = {
|
|
||||||
.length = 0,
|
|
||||||
.items = NULL,
|
|
||||||
};
|
|
||||||
if (!config_section) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
ssize_t length = config_setting_length(config_section);
|
|
||||||
if (length <= 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result.items = calloc(length, sizeof(GraphNodeConfig));
|
|
||||||
if (!result.items) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
for (ssize_t i = 0; i < length; ++i) {
|
|
||||||
result.items[i] = load_single_node_config(config_setting_get_elem(config_section, i));
|
|
||||||
}
|
|
||||||
result.length = length;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void
|
|
||||||
load_channel_end_config(const config_setting_t *config_member, const char **name_ptr, size_t *index_ptr)
|
|
||||||
{
|
|
||||||
ssize_t length = config_setting_length(config_member);
|
|
||||||
if (length < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (length == 1) {
|
|
||||||
config_setting_t *kv = config_setting_get_elem(config_member, 0);
|
|
||||||
if (!kv) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*name_ptr = config_setting_name(config_member);
|
|
||||||
*index_ptr = config_setting_get_int64(config_member);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*name_ptr = config_setting_get_string_elem(config_member, 0);
|
|
||||||
*index_ptr = config_setting_get_int64_elem(config_member, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GraphChannelConfig
|
|
||||||
load_single_channel_config(const config_setting_t *config_member)
|
|
||||||
{
|
|
||||||
GraphChannelConfig result = {
|
|
||||||
.from = {NULL, 0},
|
|
||||||
.to = {NULL, 0},
|
|
||||||
};
|
|
||||||
if (!config_member) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
config_setting_t *ends[2];
|
|
||||||
bool flip = true;
|
|
||||||
const char *flip_keys[2] = {"to", "from"};
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
|
||||||
if (!(ends[i] = config_setting_get_elem(config_member, i))) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
const char *name = config_setting_name(ends[i]);
|
|
||||||
if (!name || strcmp(name, flip_keys[i]) != 0) {
|
|
||||||
flip = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flip) {
|
|
||||||
config_setting_t *tmp = ends[0];
|
|
||||||
ends[0] = ends[1];
|
|
||||||
ends[1] = tmp;
|
|
||||||
}
|
|
||||||
load_channel_end_config(ends[0], &result.from.name, &result.from.index);
|
|
||||||
load_channel_end_config(ends[1], &result.to.name, &result.to.index);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GraphChannelConfigSection
|
|
||||||
load_channels_section(const config_setting_t *config_section)
|
|
||||||
{
|
|
||||||
GraphChannelConfigSection result = {
|
|
||||||
.length = 0,
|
|
||||||
.items = NULL,
|
|
||||||
};
|
|
||||||
if (!config_section) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
ssize_t length = config_setting_length(config_section);
|
|
||||||
if (length <= 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result.items = calloc(length, sizeof(GraphChannelConfig));
|
|
||||||
if (!result.items) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
for (ssize_t i = 0; i < length; ++i) {
|
|
||||||
result.items[i] = load_single_channel_config(config_setting_get_elem(config_section, i));
|
|
||||||
}
|
|
||||||
result.length = length;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
load_config(const config_setting_t *config_root, FullConfig *config)
|
|
||||||
{
|
|
||||||
if (!config_root || !config) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const config_setting_t *node_config = config_setting_get_member(config_root, "nodes");
|
|
||||||
const config_setting_t *channel_config = config_setting_get_member(config_root, "channels");
|
|
||||||
config->nodes = load_nodes_section(node_config);
|
|
||||||
config->channels = load_channels_section(channel_config);
|
|
||||||
return true;
|
|
||||||
}
|
|
29
config.cfg
29
config.cfg
|
@ -1,29 +0,0 @@
|
||||||
nodes = {
|
|
||||||
stdin = {
|
|
||||||
type = "getchar";
|
|
||||||
options = {
|
|
||||||
namespace = 0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
print = {
|
|
||||||
type = "print";
|
|
||||||
options = {};
|
|
||||||
};
|
|
||||||
clickpad = {
|
|
||||||
type = "evdev";
|
|
||||||
options = {
|
|
||||||
file = "/dev/input/event7";
|
|
||||||
namespace = 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
channels = ({
|
|
||||||
from: ("stdin", 0);
|
|
||||||
to: ("print", 0);
|
|
||||||
}, {
|
|
||||||
from: ("clickpad", 0);
|
|
||||||
to: ("print", 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
// vim: ft=libconfig
|
|
37
config.h
37
config.h
|
@ -1,37 +0,0 @@
|
||||||
#ifndef CONFIG_H_
|
|
||||||
#define CONFIG_H_
|
|
||||||
|
|
||||||
#include <libconfig.h>
|
|
||||||
#include "defs.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char *name;
|
|
||||||
const char *type;
|
|
||||||
config_setting_t *options;
|
|
||||||
} GraphNodeConfig;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
size_t length;
|
|
||||||
GraphNodeConfig *items;
|
|
||||||
} GraphNodeConfigSection;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
struct {
|
|
||||||
const char *name;
|
|
||||||
size_t index;
|
|
||||||
} from, to;
|
|
||||||
} GraphChannelConfig;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
size_t length;
|
|
||||||
GraphChannelConfig *items;
|
|
||||||
} GraphChannelConfigSection;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
GraphNodeConfigSection nodes;
|
|
||||||
GraphChannelConfigSection channels;
|
|
||||||
} FullConfig;
|
|
||||||
|
|
||||||
bool load_config(const config_setting_t *config_root, FullConfig *config);
|
|
||||||
|
|
||||||
#endif /* end of include guard: CONFIG_H_ */
|
|
1
defs.h
1
defs.h
|
@ -10,7 +10,6 @@
|
||||||
// Assuming child type has a field for the base type
|
// Assuming child type has a field for the base type
|
||||||
// So for structs it is usually actual downcast, but for unions it is an upcast
|
// So for structs it is usually actual downcast, but for unions it is an upcast
|
||||||
#define DOWNCAST(contype, basename, ptr) containerof(ptr, contype, as_##basename)
|
#define DOWNCAST(contype, basename, ptr) containerof(ptr, contype, as_##basename)
|
||||||
#define lengthof(arr) (sizeof(arr) / sizeof(*arr))
|
|
||||||
|
|
||||||
#define DEBUG_PRINT_VALUE(x, fmt) fprintf(stderr, #x " = " fmt "\n", x); fflush(stderr)
|
#define DEBUG_PRINT_VALUE(x, fmt) fprintf(stderr, #x " = " fmt "\n", x); fflush(stderr)
|
||||||
|
|
||||||
|
|
3
events.h
3
events.h
|
@ -9,8 +9,7 @@ typedef uint32_t EventNamespace;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
EventNamespace ns;
|
EventNamespace ns;
|
||||||
uint16_t major;
|
uint32_t value;
|
||||||
uint16_t minor;
|
|
||||||
} EventCode;
|
} EventCode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
190
filters.c
190
filters.c
|
@ -1,190 +0,0 @@
|
||||||
#include <limits.h>
|
|
||||||
#include "filters.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
size_t capacity;
|
|
||||||
size_t length;
|
|
||||||
EventFilter *values;
|
|
||||||
} EventFilterList;
|
|
||||||
|
|
||||||
static EventFilterList filters = {
|
|
||||||
.length = 0,
|
|
||||||
.capacity = 0,
|
|
||||||
.values = NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool
|
|
||||||
event_filter_list_extend(EventFilterList * lst)
|
|
||||||
{
|
|
||||||
size_t capacity = lst->capacity;
|
|
||||||
capacity = capacity + (capacity >> 1) + 1;
|
|
||||||
|
|
||||||
EventFilter *new_values;
|
|
||||||
if (lst->values) {
|
|
||||||
new_values = reallocarray(lst->values, capacity, sizeof(EventFilter));
|
|
||||||
} else {
|
|
||||||
new_values = calloc(capacity, sizeof(EventFilter));
|
|
||||||
}
|
|
||||||
if (!new_values) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
lst->values = new_values;
|
|
||||||
|
|
||||||
lst->capacity = capacity;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
event_filter_list_clear(EventFilterList * lst)
|
|
||||||
{
|
|
||||||
if (lst->values) {
|
|
||||||
free(lst->values);
|
|
||||||
lst->values = NULL;
|
|
||||||
}
|
|
||||||
lst->capacity = 0;
|
|
||||||
lst->length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EventFilterHandle
|
|
||||||
event_filter_register(EventFilter filter)
|
|
||||||
{
|
|
||||||
size_t i = filters.length;
|
|
||||||
if (i >= INT32_MAX) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
while (i <= filters.capacity) {
|
|
||||||
event_filter_list_extend(&filters);
|
|
||||||
}
|
|
||||||
filters.values[i] = filter;
|
|
||||||
filters.length = i + 1;
|
|
||||||
return (EventFilterHandle) i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static EventFilter*
|
|
||||||
event_filter_get_ptr(EventFilterHandle handle)
|
|
||||||
{
|
|
||||||
if (handle < 0 || (size_t) handle >= filters.length) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return &filters.values[handle];
|
|
||||||
}
|
|
||||||
|
|
||||||
EventFilter
|
|
||||||
event_filter_get(EventFilterHandle handle)
|
|
||||||
{
|
|
||||||
EventFilter *ptr = event_filter_get_ptr(handle);
|
|
||||||
if (ptr) {
|
|
||||||
return *ptr;
|
|
||||||
} else {
|
|
||||||
return (EventFilter) {
|
|
||||||
.type = EVFILTER_INVALID,
|
|
||||||
.enabled = false,
|
|
||||||
.inverted = false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EventFilterResult
|
|
||||||
event_filter_apply(EventFilterHandle handle, EventNode * event)
|
|
||||||
{
|
|
||||||
EventFilter *ptr = event_filter_get_ptr(handle);
|
|
||||||
if (!ptr) {
|
|
||||||
return EVFILTERRES_DISABLED;
|
|
||||||
}
|
|
||||||
if (!ptr->enabled) {
|
|
||||||
return EVFILTERRES_DISABLED;
|
|
||||||
}
|
|
||||||
bool accepted = false;
|
|
||||||
switch (ptr->type) {
|
|
||||||
case EVFILTER_INVALID:
|
|
||||||
return EVFILTERRES_DISABLED;
|
|
||||||
case EVFILTER_ACCEPT:
|
|
||||||
accepted = true;
|
|
||||||
break;
|
|
||||||
case EVFILTER_CODE_NS...EVFILTER_PAYLOAD:
|
|
||||||
if (!event) {
|
|
||||||
return EVFILTERRES_DISABLED;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
int64_t actual;
|
|
||||||
switch (ptr->type) {
|
|
||||||
case EVFILTER_CODE_NS:
|
|
||||||
actual = event->data.code.ns;
|
|
||||||
break;
|
|
||||||
case EVFILTER_CODE_MAJOR:
|
|
||||||
actual = event->data.code.major;
|
|
||||||
break;
|
|
||||||
case EVFILTER_CODE_MINOR:
|
|
||||||
actual = event->data.code.minor;
|
|
||||||
break;
|
|
||||||
case EVFILTER_PAYLOAD:
|
|
||||||
actual = event->data.payload;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return EVFILTERRES_DISABLED;
|
|
||||||
}
|
|
||||||
accepted = ptr->range_data.min_value <= actual && actual <= ptr->range_data.max_value;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVFILTER_CONJUNCTION:
|
|
||||||
case EVFILTER_DISJUNCTION:
|
|
||||||
if (!ptr->aggregate_data.handles) {
|
|
||||||
return EVFILTERRES_DISABLED;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bool disjunction = ptr->type == EVFILTER_DISJUNCTION;
|
|
||||||
accepted = !disjunction;
|
|
||||||
for (size_t i = 0; i < ptr->aggregate_data.length; ++i) {
|
|
||||||
EventFilterResult child_result = event_filter_apply(ptr->aggregate_data.handles[i], event); // TODO protect from stack overflow
|
|
||||||
bool should_stop = false;
|
|
||||||
switch (child_result) {
|
|
||||||
case EVFILTERRES_DISABLED:
|
|
||||||
continue;
|
|
||||||
case EVFILTERRES_ACCEPTED:
|
|
||||||
should_stop = false;
|
|
||||||
break;
|
|
||||||
case EVFILTERRES_REJECTED:
|
|
||||||
should_stop = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (disjunction) {
|
|
||||||
should_stop = !should_stop;
|
|
||||||
}
|
|
||||||
if (should_stop) {
|
|
||||||
accepted = disjunction;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ptr->inverted) {
|
|
||||||
accepted = !accepted;
|
|
||||||
}
|
|
||||||
return accepted ? EVFILTERRES_ACCEPTED : EVFILTERRES_REJECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_filter_set_enabled(EventFilterHandle handle, bool enabled)
|
|
||||||
{
|
|
||||||
EventFilter *ptr = event_filter_get_ptr(handle);
|
|
||||||
if (!ptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ptr->enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void event_filter_set_inverted(EventFilterHandle handle, bool inverted)
|
|
||||||
{
|
|
||||||
EventFilter *ptr = event_filter_get_ptr(handle);
|
|
||||||
if (!ptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ptr->inverted = inverted;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_filter_reset()
|
|
||||||
{
|
|
||||||
event_filter_list_clear(&filters);
|
|
||||||
}
|
|
51
filters.h
51
filters.h
|
@ -1,51 +0,0 @@
|
||||||
#ifndef FILTERS_H_
|
|
||||||
#define FILTERS_H_
|
|
||||||
|
|
||||||
#include "events.h"
|
|
||||||
|
|
||||||
typedef struct event_filter EventFilter;
|
|
||||||
typedef int32_t EventFilterHandle;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EVFILTER_INVALID,
|
|
||||||
EVFILTER_ACCEPT,
|
|
||||||
// Range
|
|
||||||
EVFILTER_CODE_NS,
|
|
||||||
EVFILTER_CODE_MAJOR,
|
|
||||||
EVFILTER_CODE_MINOR,
|
|
||||||
EVFILTER_PAYLOAD,
|
|
||||||
// Aggregation
|
|
||||||
EVFILTER_CONJUNCTION,
|
|
||||||
EVFILTER_DISJUNCTION,
|
|
||||||
} EventFilterType;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EVFILTERRES_DISABLED = -1,
|
|
||||||
EVFILTERRES_REJECTED = 0,
|
|
||||||
EVFILTERRES_ACCEPTED = 1,
|
|
||||||
} EventFilterResult;
|
|
||||||
|
|
||||||
struct event_filter {
|
|
||||||
EventFilterType type;
|
|
||||||
bool enabled;
|
|
||||||
bool inverted;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
int64_t min_value;
|
|
||||||
int64_t max_value;
|
|
||||||
} range_data;
|
|
||||||
struct {
|
|
||||||
size_t length;
|
|
||||||
EventFilterHandle *handles;
|
|
||||||
} aggregate_data;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
EventFilterHandle event_filter_register(EventFilter filter);
|
|
||||||
EventFilter event_filter_get(EventFilterHandle handle);
|
|
||||||
EventFilterResult event_filter_apply(EventFilterHandle handle, EventNode * event);
|
|
||||||
void event_filter_set_enabled(EventFilterHandle handle, bool enabled);
|
|
||||||
void event_filter_set_inverted(EventFilterHandle handle, bool inverted);
|
|
||||||
void event_filter_reset();
|
|
||||||
|
|
||||||
#endif /* end of include guard: FILTERS_H_ */
|
|
4
graph.c
4
graph.c
|
@ -88,12 +88,12 @@ graph_channel_init(GraphChannel * ch, GraphNode * start, size_t start_idx, Graph
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphNode *
|
GraphNode *
|
||||||
graph_node_new(GraphNodeSpecification * spec, GraphNodeConfig * config)
|
graph_node_new(GraphNodeSpecification * spec)
|
||||||
{
|
{
|
||||||
if (!spec || !spec->create) {
|
if (!spec || !spec->create) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return spec->create(spec, config);
|
return spec->create(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
5
graph.h
5
graph.h
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
#include "processing.h"
|
#include "processing.h"
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
typedef struct graph_node GraphNode;
|
typedef struct graph_node GraphNode;
|
||||||
typedef struct graph_channel GraphChannel;
|
typedef struct graph_channel GraphChannel;
|
||||||
|
@ -29,14 +28,14 @@ struct graph_channel {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct graph_node_specification {
|
struct graph_node_specification {
|
||||||
GraphNode * (*create)(GraphNodeSpecification * self, GraphNodeConfig * config);
|
GraphNode * (*create)(GraphNodeSpecification * self);
|
||||||
void (*destroy)(GraphNodeSpecification * self, GraphNode * target);
|
void (*destroy)(GraphNodeSpecification * self, GraphNode * target);
|
||||||
void (*register_io)(GraphNodeSpecification * self, GraphNode * target, ProcessingState * state);
|
void (*register_io)(GraphNodeSpecification * self, GraphNode * target, ProcessingState * state);
|
||||||
char *name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
void graph_channel_init(GraphChannel * ch, GraphNode * start, size_t start_idx, GraphNode * end, size_t end_idx);
|
void graph_channel_init(GraphChannel * ch, GraphNode * start, size_t start_idx, GraphNode * end, size_t end_idx);
|
||||||
GraphNode *graph_node_new(GraphNodeSpecification * spec, GraphNodeConfig * config);
|
GraphNode *graph_node_new(GraphNodeSpecification * spec);
|
||||||
void graph_node_delete(GraphNode * self);
|
void graph_node_delete(GraphNode * self);
|
||||||
void graph_node_register_io(GraphNode * self, ProcessingState * state);
|
void graph_node_register_io(GraphNode * self, ProcessingState * state);
|
||||||
void graph_channel_list_init(GraphChannelList * lst);
|
void graph_channel_list_init(GraphChannelList * lst);
|
||||||
|
|
87
main.c
87
main.c
|
@ -3,12 +3,6 @@
|
||||||
#include "nodes/getchar.h"
|
#include "nodes/getchar.h"
|
||||||
#include "nodes/evdev.h"
|
#include "nodes/evdev.h"
|
||||||
|
|
||||||
GraphNodeSpecification *node_specifications[] = {
|
|
||||||
&nodespec_getchar,
|
|
||||||
&nodespec_print,
|
|
||||||
&nodespec_evdev,
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char ** argv)
|
main(int argc, char ** argv)
|
||||||
{
|
{
|
||||||
|
@ -22,80 +16,23 @@ main(int argc, char ** argv)
|
||||||
io_subscription_list_init(&state.wait_input, 5);
|
io_subscription_list_init(&state.wait_input, 5);
|
||||||
io_subscription_list_init(&state.wait_output, 5);
|
io_subscription_list_init(&state.wait_output, 5);
|
||||||
|
|
||||||
config_t config_tree;
|
GraphNode * input_node = graph_node_new(&nodespec_getchar);
|
||||||
FullConfig loaded_config;
|
GraphNode * output_node = graph_node_new(&nodespec_print);
|
||||||
config_init(&config_tree);
|
GraphNode * evdev_node = graph_node_new(&nodespec_evdev);
|
||||||
config_read_file(&config_tree, "config.cfg");
|
GraphChannel chan[2];
|
||||||
config_set_auto_convert(&config_tree, CONFIG_TRUE);
|
graph_channel_init(&chan[0], input_node, 0, output_node, 0);
|
||||||
if (!load_config(config_root_setting(&config_tree), &loaded_config)) {
|
graph_channel_init(&chan[1], evdev_node, 0, output_node, 1);
|
||||||
perror("Failed to load config");
|
graph_node_register_io(input_node, &state);
|
||||||
exit(1);
|
graph_node_register_io(output_node, &state);
|
||||||
}
|
graph_node_register_io(evdev_node, &state);
|
||||||
|
|
||||||
GraphNode **nodes = calloc(loaded_config.nodes.length, sizeof(GraphNode*));
|
|
||||||
for (size_t i = 0; i < loaded_config.nodes.length; ++i) {
|
|
||||||
const char* type_name = loaded_config.nodes.items[i].type;
|
|
||||||
if (!type_name) {
|
|
||||||
fprintf(stderr, "No node type for node %ld \"%s\"\n", i, loaded_config.nodes.items[i].name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
GraphNodeSpecification *spec = NULL;
|
|
||||||
for (size_t j = 0; j < lengthof(node_specifications); ++j) {
|
|
||||||
if (strcmp(type_name, node_specifications[j]->name) == 0) {
|
|
||||||
spec = node_specifications[j];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!spec) {
|
|
||||||
fprintf(stderr, "Unknown node type \"%s\" for node %ld \"%s\"\n", type_name, i, loaded_config.nodes.items[i].name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (!(nodes[i] = graph_node_new(spec, &loaded_config.nodes.items[i]))) {
|
|
||||||
perror("Failed to create node");
|
|
||||||
fprintf(stderr, "%ld \"%s\"\n", i, loaded_config.nodes.items[i].name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GraphChannel *channels = calloc(loaded_config.channels.length, sizeof(GraphChannel));
|
|
||||||
for (size_t i = 0; i < loaded_config.channels.length; ++i) {
|
|
||||||
const char *node_names[2];
|
|
||||||
GraphNode *end_nodes[2] = {NULL, NULL};
|
|
||||||
node_names[0] = loaded_config.channels.items[i].from.name;
|
|
||||||
node_names[1] = loaded_config.channels.items[i].to.name;
|
|
||||||
for (int j = 0; j < 2; ++j) {
|
|
||||||
for (size_t k = 0; k < loaded_config.nodes.length; ++k) {
|
|
||||||
if (strcmp(loaded_config.nodes.items[k].name, node_names[j]) == 0) {
|
|
||||||
end_nodes[j] = nodes[k];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!end_nodes[j]) {
|
|
||||||
fprintf(stderr, "No node named \"%s\"\n", node_names[j]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
graph_channel_init(&channels[i],
|
|
||||||
end_nodes[0], loaded_config.channels.items[i].from.index,
|
|
||||||
end_nodes[1], loaded_config.channels.items[i].to.index
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < loaded_config.nodes.length; ++i) {
|
|
||||||
graph_node_register_io(nodes[i], &state);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
process_iteration(&state);
|
process_iteration(&state);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ssize_t i = loaded_config.nodes.length - 1; i >= 0; --i) {
|
graph_node_delete(evdev_node);
|
||||||
graph_node_delete(nodes[i]);
|
graph_node_delete(output_node);
|
||||||
}
|
graph_node_delete(input_node);
|
||||||
free(channels);
|
|
||||||
free(nodes);
|
|
||||||
|
|
||||||
config_destroy(&config_tree);
|
|
||||||
|
|
||||||
io_subscription_list_deinit(&state.wait_output);
|
io_subscription_list_deinit(&state.wait_output);
|
||||||
io_subscription_list_deinit(&state.wait_input);
|
io_subscription_list_deinit(&state.wait_input);
|
||||||
|
|
|
@ -13,7 +13,6 @@ typedef struct {
|
||||||
IOHandling subscription;
|
IOHandling subscription;
|
||||||
struct libevdev *dev;
|
struct libevdev *dev;
|
||||||
int fd;
|
int fd;
|
||||||
int namespace;
|
|
||||||
} EvdevGraphNode;
|
} EvdevGraphNode;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -47,8 +46,7 @@ handle_io(EventPositionBase * self, int fd, bool is_output)
|
||||||
EventData data = {
|
EventData data = {
|
||||||
.code = {
|
.code = {
|
||||||
.ns = 1,
|
.ns = 1,
|
||||||
.major = buf.type,
|
.value = (((int32_t) buf.type) << 16) | buf.code,
|
||||||
.minor = buf.code,
|
|
||||||
},
|
},
|
||||||
.ttl = 100,
|
.ttl = 100,
|
||||||
.priority = 10,
|
.priority = 10,
|
||||||
|
@ -68,22 +66,13 @@ handle_io(EventPositionBase * self, int fd, bool is_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GraphNode *
|
static GraphNode *
|
||||||
create(GraphNodeSpecification * spec, GraphNodeConfig * config)
|
create(GraphNodeSpecification * spec)
|
||||||
{
|
{
|
||||||
EvdevGraphNode * node = calloc(1, sizeof(EvdevGraphNode));
|
EvdevGraphNode * node = calloc(1, sizeof(EvdevGraphNode));
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const char *filename = NULL;
|
int fd = open("/dev/input/event7", O_RDONLY | O_NONBLOCK);
|
||||||
if (config) {
|
|
||||||
config_setting_lookup_int(config->options, "namespace", &node->namespace);
|
|
||||||
config_setting_lookup_string(config->options, "file", &filename);
|
|
||||||
}
|
|
||||||
if (filename == NULL) {
|
|
||||||
free(node);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
int fd = open(filename, O_RDONLY | O_NONBLOCK);
|
|
||||||
int err;
|
int err;
|
||||||
if ((err = libevdev_new_from_fd(fd, &node->dev)) < 0) {
|
if ((err = libevdev_new_from_fd(fd, &node->dev)) < 0) {
|
||||||
errno = -err;
|
errno = -err;
|
||||||
|
@ -107,7 +96,6 @@ create(GraphNodeSpecification * spec, GraphNodeConfig * config)
|
||||||
},
|
},
|
||||||
.dev = node->dev,
|
.dev = node->dev,
|
||||||
.fd = fd,
|
.fd = fd,
|
||||||
.namespace = node->namespace,
|
|
||||||
};
|
};
|
||||||
return &node->as_GraphNode;
|
return &node->as_GraphNode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GraphNode as_GraphNode;
|
GraphNode as_GraphNode;
|
||||||
IOHandling subscription;
|
IOHandling subscription;
|
||||||
int32_t namespace;
|
|
||||||
} GetcharGraphNode;
|
} GetcharGraphNode;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -23,8 +22,7 @@ handle_io(EventPositionBase * self, int fd, bool is_output)
|
||||||
EventData data = {
|
EventData data = {
|
||||||
.code = {
|
.code = {
|
||||||
.ns = 0,
|
.ns = 0,
|
||||||
.major = 0,
|
.value = 1,
|
||||||
.minor = 1,
|
|
||||||
},
|
},
|
||||||
.ttl = 100,
|
.ttl = 100,
|
||||||
.priority = 10,
|
.priority = 10,
|
||||||
|
@ -34,7 +32,7 @@ handle_io(EventPositionBase * self, int fd, bool is_output)
|
||||||
};
|
};
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
node->subscription.enabled = false;
|
node->subscription.enabled = false;
|
||||||
data.code.minor = 2;
|
data.code.value = 2;
|
||||||
data.payload = 0;
|
data.payload = 0;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < node->as_GraphNode.outputs.length; ++i) {
|
for (size_t i = 0; i < node->as_GraphNode.outputs.length; ++i) {
|
||||||
|
@ -48,7 +46,7 @@ handle_io(EventPositionBase * self, int fd, bool is_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GraphNode *
|
static GraphNode *
|
||||||
create(GraphNodeSpecification * spec, GraphNodeConfig * config)
|
create(GraphNodeSpecification * spec)
|
||||||
{
|
{
|
||||||
GetcharGraphNode * node = calloc(1, sizeof(GetcharGraphNode));
|
GetcharGraphNode * node = calloc(1, sizeof(GetcharGraphNode));
|
||||||
if (!node) {
|
if (!node) {
|
||||||
|
@ -69,11 +67,7 @@ create(GraphNodeSpecification * spec, GraphNodeConfig * config)
|
||||||
.handle_io = handle_io,
|
.handle_io = handle_io,
|
||||||
.enabled = true,
|
.enabled = true,
|
||||||
},
|
},
|
||||||
.namespace = 0,
|
|
||||||
};
|
};
|
||||||
if (config) {
|
|
||||||
config_setting_lookup_int(config->options, "namespace", &node->namespace);
|
|
||||||
}
|
|
||||||
return &node->as_GraphNode;
|
return &node->as_GraphNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,7 @@ handle_event(EventPositionBase * self, EventNode * event)
|
||||||
EventData data = event->data;
|
EventData data = event->data;
|
||||||
printf("Event from connector %ld:\n", event->input_index);
|
printf("Event from connector %ld:\n", event->input_index);
|
||||||
PRINT_FIELD("%d", code.ns);
|
PRINT_FIELD("%d", code.ns);
|
||||||
PRINT_FIELD("%d", code.major);
|
PRINT_FIELD("%d", code.value);
|
||||||
PRINT_FIELD("%d", code.minor);
|
|
||||||
PRINT_FIELD("%d", ttl);
|
PRINT_FIELD("%d", ttl);
|
||||||
PRINT_FIELD("%d", priority);
|
PRINT_FIELD("%d", priority);
|
||||||
PRINT_FIELD("%ld", payload);
|
PRINT_FIELD("%ld", payload);
|
||||||
|
@ -27,9 +26,8 @@ handle_event(EventPositionBase * self, EventNode * event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GraphNode *
|
static GraphNode *
|
||||||
create(GraphNodeSpecification * spec, GraphNodeConfig * config)
|
create(GraphNodeSpecification * spec)
|
||||||
{
|
{
|
||||||
(void) config;
|
|
||||||
GraphNode * node = calloc(1, sizeof(GraphNode));
|
GraphNode * node = calloc(1, sizeof(GraphNode));
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return node;
|
return node;
|
||||||
|
|
Loading…
Reference in New Issue