summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2015-09-01 22:48:51 +0200
committerNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2015-09-01 22:48:51 +0200
commit1af58bb8886673ac115f019094853fa763e79187 (patch)
treec2ab030898e74288f82c557287272546a990e932
Initial commit.
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt16
-rw-r--r--LICENSE24
-rw-r--r--conf/space_navigator.conf8
-rw-r--r--src/CMakeLists.txt10
-rw-r--r--src/axis.c99
-rw-r--r--src/axis.h23
-rw-r--r--src/config.c256
-rw-r--r--src/config.h49
-rw-r--r--src/error.h123
-rw-r--r--src/input.c150
-rw-r--r--src/input.h28
-rw-r--r--src/main.c110
-rw-r--r--src/pervasive.h13
-rw-r--r--src/relabsd_device.c137
-rw-r--r--src/relabsd_device.h31
16 files changed, 1078 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..567609b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+build/
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..a1ca449
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+
+project("relabsd")
+
+include(FindPkgConfig)
+
+add_subdirectory(src)
+
+# ${SRC_FILES} is recursively defined in the subdirectories.
+# Each subdirectory only adds the source files that are present at its level.
+
+add_executable(relabsd ${SRC_FILES})
+
+pkg_search_module(LIBEVDEV REQUIRED libevdev)
+include_directories(${LIBEVDEV_INCLUDE_DIRS})
+target_link_libraries(relabsd ${LIBEVDEV_LIBRARIES})
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5692bf1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2015, Nathanael Sensfelder
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL NATHANAEL SENSFELDER BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/conf/space_navigator.conf b/conf/space_navigator.conf
new file mode 100644
index 0000000..07a5ae0
--- /dev/null
+++ b/conf/space_navigator.conf
@@ -0,0 +1,8 @@
+# 3DConnexion SpaceNavigator
+# AXIS MIN MAX FUZZ FLAT RESOLUTION
+X -350 350 1 1 1
+Y -350 350 1 1 1
+Z -350 350 1 1 1
+RX -350 350 1 1 1
+RY -350 350 1 1 1
+RZ -350 350 1 1 1
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..98af72c
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(
+ SRC_FILES ${SRC_FILES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/config.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/input.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/axis.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/relabsd_device.c
+)
+
+set(SRC_FILES ${SRC_FILES} PARENT_SCOPE)
diff --git a/src/axis.c b/src/axis.c
new file mode 100644
index 0000000..1ba09f0
--- /dev/null
+++ b/src/axis.c
@@ -0,0 +1,99 @@
+#include <libevdev/libevdev.h>
+
+#include "pervasive.h"
+
+#include "axis.h"
+
+enum relabsd_axis relabsd_axis_name_to_enum (char * const name)
+{
+ if (_IS_PREFIX("X", name))
+ {
+ return RELABSD_X;
+ }
+ else if (_IS_PREFIX("Y", name))
+ {
+ return RELABSD_Y;
+ }
+ else if (_IS_PREFIX("Z", name))
+ {
+ return RELABSD_Z;
+ }
+ else if (_IS_PREFIX("RX", name))
+ {
+ return RELABSD_RX;
+ }
+ else if (_IS_PREFIX("RY", name))
+ {
+ return RELABSD_RY;
+ }
+ else if (_IS_PREFIX("RZ", name))
+ {
+ return RELABSD_RZ;
+ }
+
+ return RELABSD_UNKNOWN;
+}
+
+char * relabsd_axis_enum_to_name (enum relabsd_axis const e)
+{
+ switch (e)
+ {
+ case RELABSD_X:
+ return "X";
+
+ case RELABSD_Y:
+ return "Y";
+
+ case RELABSD_Z:
+ return "Z";
+
+ case RELABSD_RX:
+ return "RX";
+
+ case RELABSD_RY:
+ return "RY";
+
+ case RELABSD_RZ:
+ return "RZ";
+
+ case RELABSD_UNKNOWN:
+ return "??";
+ }
+}
+
+enum relabsd_axis relabsd_axis_convert_evdev_rel
+(
+ unsigned int const rel_code,
+ unsigned int * const abs_code
+)
+{
+ switch (rel_code)
+ {
+ case REL_X:
+ *abs_code = ABS_X;
+ return RELABSD_X;
+
+ case REL_Y:
+ *abs_code = ABS_Y;
+ return RELABSD_Y;
+
+ case REL_Z:
+ *abs_code = ABS_Z;
+ return RELABSD_Z;
+
+ case REL_RX:
+ *abs_code = ABS_RX;
+ return RELABSD_RX;
+
+ case REL_RY:
+ *abs_code = ABS_RY;
+ return RELABSD_RY;
+
+ case REL_RZ:
+ *abs_code = ABS_RZ;
+ return RELABSD_RZ;
+
+ default:
+ return RELABSD_UNKNOWN;
+ }
+}
diff --git a/src/axis.h b/src/axis.h
new file mode 100644
index 0000000..6d4f7f5
--- /dev/null
+++ b/src/axis.h
@@ -0,0 +1,23 @@
+#ifndef RELABSD_AXIS_H
+#define RELABSD_AXIS_H
+
+enum relabsd_axis
+{
+ RELABSD_X,
+ RELABSD_Y,
+ RELABSD_Z,
+ RELABSD_RX,
+ RELABSD_RY,
+ RELABSD_RZ,
+ RELABSD_UNKNOWN
+};
+
+enum relabsd_axis relabsd_axis_name_to_enum (char * const name);
+char * relabsd_axis_enum_to_name (enum relabsd_axis const e);
+enum relabsd_axis relabsd_axis_convert_evdev_rel
+(
+ unsigned int const rel_code,
+ unsigned int * const abs_code
+);
+
+#endif
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..1699811
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,256 @@
+#include <errno.h>
+#include <string.h>
+
+#include "error.h"
+#include "pervasive.h"
+#include "axis.h"
+#include "config.h"
+
+static int reach_next_line_or_eof (FILE * const f)
+{
+ char c;
+ c = getc(f);
+
+ while ((c != '\n') && c != EOF)
+ {
+ c = getc(f);
+ }
+
+ if (c == EOF)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int all_axis_are_configured (const int * const axis_is_configured)
+{
+ int i;
+
+ for (i = 0; i < 6; ++i)
+ {
+ if (axis_is_configured[i] == 0)
+ {
+ _FATAL
+ (
+ "[CONFIG] Axis '%s' is not configured.",
+ relabsd_axis_enum_to_name((enum relabsd_axis) i)
+ );
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int parse_axis_configuration_line
+(
+ struct relabsd_config * const conf,
+ FILE * const f,
+ int * const axis_is_configured,
+ char * const buffer
+)
+{
+ int valc;
+ enum relabsd_axis axis;
+
+ axis = relabsd_axis_name_to_enum(buffer);
+
+ if (axis == RELABSD_UNKNOWN)
+ {
+ _FATAL
+ (
+ "[CONFIG] Unknown axis '%s'.",
+ buffer
+ );
+
+ return -1;
+ }
+
+ valc =
+ fscanf
+ (
+ f,
+ "%d %d %d %d %d",
+ &(conf->axis[axis].min),
+ &(conf->axis[axis].max),
+ &(conf->axis[axis].fuzz),
+ &(conf->axis[axis].flat),
+ &(conf->axis[axis].resolution)
+ );
+
+ if (valc == EOF)
+ {
+ _FATAL
+ (
+ "[CONFIG] Unexpected end of file while reading axis '%s'.",
+ buffer
+ );
+
+ return -1;
+ }
+ else if (valc < 5)
+ {
+ _FATAL
+ (
+ "[CONFIG] Invalid parameter count for axis '%s'.",
+ buffer
+ );
+
+ return -1;
+ }
+
+ axis_is_configured[axis] = 1;
+ return 0;
+}
+
+static int read_config_file
+(
+ struct relabsd_config * const conf,
+ char * const filename
+)
+{
+ FILE * f;
+ int axis_is_configured[6];
+ char buffer[3];
+ int test;
+
+ buffer[2] = '\0';
+
+ memset(axis_is_configured, 0, 6 * sizeof(int));
+
+ f = fopen(filename, "r");
+
+ if (f == (FILE *) NULL)
+ {
+ _FATAL
+ (
+ "[CONFIG] Could not open file: %s.",
+ strerror(errno)
+ );
+
+ return -1;
+ }
+
+ errno = 0;
+
+ while ((test = fscanf(f, "%2s", buffer)) > 0)
+ {
+ if (_IS_PREFIX("#", buffer))
+ {
+ if (reach_next_line_or_eof(f) < 0)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if
+ (
+ parse_axis_configuration_line
+ (
+ conf,
+ f,
+ axis_is_configured,
+ buffer
+ )
+ < 0
+ )
+ {
+ break;
+ }
+
+ if (reach_next_line_or_eof(f) < 0)
+ {
+ break;
+ }
+ }
+ }
+
+ if (test < 0 && errno != 0)
+ {
+ _FATAL
+ (
+ "[CONFIG] Error while reading file: %s, last read '%s'.",
+ strerror(errno),
+ buffer
+ );
+
+ fclose(f);
+
+ return -1;
+ }
+
+ fclose(f);
+
+ if (all_axis_are_configured(axis_is_configured) < 0)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+int relabsd_config_parse
+(
+ struct relabsd_config * const conf,
+ int const argc,
+ char ** const argv
+)
+{
+ if ((argc < 3) || (argc > 4))
+ {
+ _FATAL
+ (
+ "Usage: %s input_device config_file [<relabsd_device_name>]",
+ argv[0]
+ );
+
+ return -1;
+ }
+
+ if (argc == 3)
+ {
+ conf->device_name = "relabsd device";
+ }
+ else
+ {
+ conf->device_name = argv[3];
+ }
+
+ conf->input_file = argv[1];
+
+ if (read_config_file(conf, argv[2]) < 0)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+int relabsd_config_allows
+(
+ const struct relabsd_config * const conf,
+ enum relabsd_axis const axis,
+ int const value
+)
+{
+ return 1;
+};
+
+void relabsd_config_get_absinfo
+(
+ const struct relabsd_config * const conf,
+ enum relabsd_axis const axis,
+ struct input_absinfo * const absinfo
+)
+{
+ absinfo->value = (__s32) 0;
+ absinfo->minimum = (__s32) conf->axis[axis].min;
+ absinfo->maximum = (__s32) conf->axis[axis].max;
+ absinfo->fuzz = (__s32) conf->axis[axis].fuzz;
+ absinfo->flat = (__s32) conf->axis[axis].flat;
+ absinfo->resolution = (__s32) conf->axis[axis].resolution;
+}
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..ffdfebb
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,49 @@
+#ifndef RELABSD_CONFIG_H
+#define RELABSD_CONFIG_H
+
+#include <libevdev/libevdev.h>
+
+#include "axis.h"
+
+struct relabsd_config_axis
+{
+ int min;
+ int max;
+ int fuzz;
+ int flat;
+ int resolution;
+};
+
+/*
+ * There are no relabsd_config_free function so be careful about using dynamic
+ * memory for input_file or device_name.
+ */
+struct relabsd_config
+{
+ char * input_file;
+ char * device_name;
+ struct relabsd_config_axis axis[6];
+};
+
+int relabsd_config_parse
+(
+ struct relabsd_config * const conf,
+ int const argc,
+ char ** const argv
+);
+
+int relabsd_config_allows
+(
+ const struct relabsd_config * const conf,
+ enum relabsd_axis const axis,
+ int const value
+);
+
+void relabsd_config_get_absinfo
+(
+ const struct relabsd_config * const conf,
+ enum relabsd_axis const axis,
+ struct input_absinfo * const absinfo
+);
+
+#endif
diff --git a/src/error.h b/src/error.h
new file mode 100644
index 0000000..aa85e63
--- /dev/null
+++ b/src/error.h
@@ -0,0 +1,123 @@
+#ifndef RELABSD_ERROR_H
+#define RELABSD_ERROR_H
+
+#include <stdio.h>
+
+#include "config.h"
+#include "pervasive.h"
+
+#define _HIGHEST_DEBUG_LVL 100
+
+#define _DEBUG_LVL _HIGHEST_DEBUG_LVL
+#define _ENABLE_WARNINGS_OUTPUT 1
+#define _ENABLE_RUNTIME_ERRORS_OUTPUT 1
+#define _ENABLE_PROGRAMMING_ERRORS_OUTPUT 1
+#define _ENABLE_FATAL_ERROR_OUTPUT 1
+#define _ENABLE_ERROR_LOCATION 0
+
+#if _ENABLE_ERROR_LOCATION
+ #define _LOCATION "[" __FILE__ "][" _TO_STRING(__LINE__) "]"
+#else
+ #define _LOCATION ""
+#endif
+
+#define _PRINT_STDERR(symbol, str, ...)\
+ fprintf(stderr, "[" symbol "]" _LOCATION " " str "\n", __VA_ARGS__);
+
+#define _DEBUG(level, str, ...)\
+ _ISOLATE\
+ (\
+ if (level < _DEBUG_LVL)\
+ {\
+ _PRINT_STDERR("D", str, __VA_ARGS__);\
+ }\
+ )
+
+
+#define _WARNING(str, ...)\
+ _ISOLATE\
+ (\
+ if (_ENABLE_WARNINGS_OUTPUT)\
+ {\
+ _PRINT_STDERR("W", str, __VA_ARGS__);\
+ }\
+ )
+
+#define _ERROR(str, ...)\
+ _ISOLATE\
+ (\
+ if (_ENABLE_RUNTIME_ERRORS_OUTPUT)\
+ {\
+ _PRINT_STDERR("E", str, __VA_ARGS__);\
+ }\
+ )
+
+#define _PROG_ERROR(str, ...)\
+ _ISOLATE\
+ (\
+ if (_ENABLE_PROGRAMMING_ERRORS_OUTPUT)\
+ {\
+ _PRINT_STDERR("P", str, __VA_ARGS__);\
+ }\
+ )
+
+#define _FATAL(str, ...)\
+ _ISOLATE\
+ (\
+ if (_ENABLE_FATAL_ERROR_OUTPUT)\
+ {\
+ _PRINT_STDERR("F", str, __VA_ARGS__);\
+ }\
+ )
+
+/* For outputs without dynamic content (static). ******************************/
+
+#define _PRINT_S_STDERR(symbol, str)\
+ fprintf(stderr, "[" symbol "]" _LOCATION " " str "\n");
+
+#define _S_DEBUG(level, str)\
+ _ISOLATE\
+ (\
+ if (level < _DEBUG_LVL)\
+ {\
+ _PRINT_S_STDERR("D", str);\
+ }\
+ )
+
+#define _S_WARNING(str)\
+ _ISOLATE\
+ (\
+ if (_ENABLE_WARNINGS_OUTPUT)\
+ {\
+ _PRINT_S_STDERR("W", str);\
+ }\
+ )
+
+#define _S_ERROR(str)\
+ _ISOLATE\
+ (\
+ if (_ENABLE_RUNTIME_ERRORS_OUTPUT)\
+ {\
+ _PRINT_S_STDERR("E", str);\
+ }\
+ )
+
+#define _S_PROG_ERROR(str)\
+ _ISOLATE\
+ (\
+ if (_ENABLE_PROGRAMMING_ERRORS_OUTPUT)\
+ {\
+ _PRINT_S_STDERR("P", str);\
+ }\
+ )
+
+#define _S_FATAL(str)\
+ _ISOLATE\
+ (\
+ if (_ENABLE_FATAL_ERROR_OUTPUT)\
+ {\
+ _PRINT_S_STDERR("F", str);\
+ }\
+ )
+
+#endif
diff --git a/src/input.c b/src/input.c
new file mode 100644
index 0000000..eb7b013
--- /dev/null
+++ b/src/input.c
@@ -0,0 +1,150 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <libevdev/libevdev.h>
+
+#include "error.h"
+
+#include "input.h"
+
+static int check_for_axis
+(
+ const struct libevdev * const dev,
+ const char * axis_name,
+ const unsigned int axis_id
+)
+{
+ if (!libevdev_has_event_code(dev, EV_REL, axis_id))
+ {
+ _FATAL("Input device has no %s axis.", axis_name);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static int device_is_compatible (const struct libevdev * const dev)
+{
+ if (!libevdev_has_event_type(dev, EV_REL))
+ {
+ _S_FATAL("Input device has no relative axis.");
+
+ return -1;
+ }
+
+ if
+ (
+ (check_for_axis(dev, "X", REL_X) < 0)
+ | (check_for_axis(dev, "Y", REL_Y) < 0)
+ | (check_for_axis(dev, "Z", REL_Z) < 0)
+ | (check_for_axis(dev, "RX", REL_RX) < 0)
+ | (check_for_axis(dev, "RY", REL_RY) < 0)
+ | (check_for_axis(dev, "RZ", REL_RZ) < 0)
+ )
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+int relabsd_input_open
+(
+ struct relabsd_input * const input,
+ const char * const filename
+)
+{
+ input->fd = open(filename, O_RDONLY);
+
+ if (input->fd < 0)
+ {
+ _FATAL
+ (
+ "Could not open device %s in read only mode:",
+ filename,
+ strerror(errno)
+ );
+
+ return -1;
+ }
+
+ if
+ (
+ libevdev_new_from_fd(input->fd, &(input->dev)) < 0
+ )
+ {
+ _FATAL
+ (
+ "libevdev could not open %s:",
+ filename,
+ strerror(errno)
+ );
+
+ close(input->fd);
+
+ return -1;
+ }
+
+ if (device_is_compatible(input->dev) < 0)
+ {
+ _FATAL("%s is not compatible with relabsd.", filename);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+void relabsd_input_close (const struct relabsd_input * const input)
+{
+ libevdev_free(input->dev);
+ close(input->fd);
+}
+
+int relabsd_input_read
+(
+ const struct relabsd_input * const input,
+ unsigned int * const input_type,
+ unsigned int * const input_code,
+ int * const input_value
+)
+{
+ int rc;
+ struct input_event event;
+
+ rc =
+ libevdev_next_event
+ (
+ input->dev,
+ (LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_BLOCKING),
+ &event
+ );
+
+ /*if (rc == LIBEVDEV_READ_STATUS_SYNC)
+ {
+ handle_syn_dropped(input->dev);
+ }
+ else*/ if (rc != LIBEVDEV_READ_STATUS_SUCCESS)
+ {
+ _WARNING("[INPUT] Could not get next event: %s.", strerror(-rc));
+
+ return -1;
+ }
+
+ _DEBUG
+ (
+ 90,
+ "[INPUT] Valid event received: {type = %s; code = %s; value = %d}.",
+ libevdev_event_type_get_name(event.type),
+ libevdev_event_code_get_name(event.type, event.code),
+ event.value
+ );
+
+ *input_type = event.type;
+ *input_code = event.code;
+ *input_value = event.value;
+
+ return 0;
+}
diff --git a/src/input.h b/src/input.h
new file mode 100644
index 0000000..03b5c5a
--- /dev/null
+++ b/src/input.h
@@ -0,0 +1,28 @@
+#ifndef RELABSD_INPUT_H
+#define RELABSD_INPUT_H
+
+#include <libevdev/libevdev.h>
+
+struct relabsd_input
+{
+ struct libevdev * dev;
+ int fd;
+};
+
+int relabsd_input_open
+(
+ struct relabsd_input * const input,
+ const char * const filename
+);
+
+void relabsd_input_close (const struct relabsd_input * const input);
+
+int relabsd_input_read
+(
+ const struct relabsd_input * const input,
+ unsigned int * const input_type,
+ unsigned int * const input_code,
+ int * const input_value
+);
+
+#endif
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..b60a074
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,110 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "pervasive.h"
+#include "error.h"
+#include "config.h"
+#include "input.h"
+#include "relabsd_device.h"
+
+static int RELABSD_RUN = 1;
+
+static void interrupt (int signal_id)
+{
+ RELABSD_RUN = 0;
+
+ _S_WARNING("Interrupted, will exit at the next input device event.");
+}
+
+static void convert_input
+(
+ const struct relabsd_config * const conf,
+ const struct relabsd_input * const input,
+ const struct relabsd_device * const dev
+)
+{
+ unsigned int input_type, input_code, abs_code;
+ enum relabsd_axis rad_code;
+ int value;
+
+ while (RELABSD_RUN == 1)
+ {
+ if (relabsd_input_read(input, &input_type, &input_code, &value) < 0)
+ {
+ continue;
+ }
+
+ if (input_type == EV_REL)
+ {
+ rad_code = relabsd_axis_convert_evdev_rel(input_code, &abs_code);
+
+ if (rad_code == RELABSD_UNKNOWN)
+ {
+ relabsd_device_write_evdev_event
+ (
+ dev,
+ input_type,
+ input_code,
+ value
+ );
+ }
+ else if (relabsd_config_allows(conf, rad_code, value))
+ {
+ relabsd_device_write_evdev_event(dev, EV_ABS, abs_code, value);
+ }
+ }
+ else
+ {
+ relabsd_device_write_evdev_event
+ (
+ dev,
+ input_type,
+ input_code,
+ value
+ );
+ }
+ }
+}
+
+int main (int argc, char ** argv)
+{
+ struct relabsd_config conf;
+ struct relabsd_input input;
+ struct relabsd_device dev;
+
+ if (signal(SIGINT, interrupt) == SIG_ERR)
+ {
+ _S_FATAL("Unable to set the SIGINT signal handler.");
+
+ return -1;
+ }
+
+ if (relabsd_config_parse(&conf, argc, argv) < 0)
+ {
+ return -2;
+ }
+
+ if (relabsd_input_open(&input, conf.input_file) < 0)
+ {
+ return -3;
+ }
+
+ if (relabsd_device_create(&dev, &conf) < 0)
+ {
+ return -4;
+ }
+
+ _S_DEBUG(10, "Converting inputs...");
+
+ convert_input(&conf, &input, &dev);
+
+ _S_DEBUG(10, "Terminating...");
+
+ relabsd_device_destroy(&dev);
+ relabsd_input_close(&input);
+
+ return 0;
+}
diff --git a/src/pervasive.h b/src/pervasive.h
new file mode 100644
index 0000000..8a8449a
--- /dev/null
+++ b/src/pervasive.h
@@ -0,0 +1,13 @@
+#ifndef RELABSD_PERVASIVE_H
+#define RELABSD_PERVASIVE_H
+
+#include <string.h>
+
+#define __TO_STRING(x) #x
+#define _TO_STRING(x) __TO_STRING(x)
+
+#define _ISOLATE(a) do {a} while (0)
+
+#define _IS_PREFIX(a, b) (strncmp(a, b, strlen(a)) == 0)
+
+#endif
diff --git a/src/relabsd_device.c b/src/relabsd_device.c
new file mode 100644
index 0000000..7d2b761
--- /dev/null
+++ b/src/relabsd_device.c
@@ -0,0 +1,137 @@
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "error.h"
+#include "axis.h"
+#include "config.h"
+
+#include "relabsd_device.h"
+
+/* LIBEVDEV_UINPUT_OPEN_MANAGED is not defined on my machine. */
+#ifndef LIBEVDEV_UINPUT_OPEN_MANAGED
+ #warning "libevdev did not define LIBEVDEV_UINPUT_OPEN_MANAGED, "\
+ "using value '-2' instead."
+ #define LIBEVDEV_UINPUT_OPEN_MANAGED -2
+#endif
+
+static void replace_rel_axis
+(
+ struct relabsd_device * const dev,
+ const struct relabsd_config * const config,
+ struct input_absinfo * const absinfo,
+ unsigned int rel_code
+)
+{
+ enum relabsd_axis rad_code;
+ unsigned int abs_code;
+
+ rad_code = relabsd_axis_convert_evdev_rel(rel_code, &abs_code);
+
+ relabsd_config_get_absinfo(config, rad_code, absinfo);
+ libevdev_disable_event_code(dev->dev, EV_REL, rel_code);
+ libevdev_enable_event_code(dev->dev, EV_ABS, abs_code, absinfo);
+}
+
+int relabsd_device_create
+(
+ struct relabsd_device * const dev,
+ const struct relabsd_config * const config
+)
+{
+ struct input_absinfo absinfo;
+ int fd;
+
+ fd = open(config->input_file, O_RDONLY);
+
+ if (fd < 0)
+ {
+ _FATAL
+ (
+ "Could not open device %s in read only mode:",
+ config->input_file,
+ strerror(errno)
+ );
+
+ return -1;
+ }
+
+ if
+ (
+ libevdev_new_from_fd(fd, &(dev->dev)) < 0
+ )
+ {
+ _FATAL
+ (
+ "libevdev could not open %s:",
+ config->input_file,
+ strerror(errno)
+ );
+
+ close(fd);
+
+ return -1;
+ }
+
+ libevdev_set_name(dev->dev, config->device_name);
+
+ libevdev_enable_event_type(dev->dev, EV_ABS);
+
+ replace_rel_axis(dev, config, &absinfo, REL_X);
+ replace_rel_axis(dev, config, &absinfo, REL_Y);
+ replace_rel_axis(dev, config, &absinfo, REL_Z);
+ replace_rel_axis(dev, config, &absinfo, REL_RX);
+ replace_rel_axis(dev, config, &absinfo, REL_RY);
+ replace_rel_axis(dev, config, &absinfo, REL_RZ);
+
+ if
+ (
+ libevdev_uinput_create_from_device
+ (
+ dev->dev,
+ LIBEVDEV_UINPUT_OPEN_MANAGED,
+ &(dev->uidev)
+ )
+ < 0
+ )
+ {
+ _FATAL("Could not create relabsd device: %s.", strerror(errno));
+
+ libevdev_free(dev->dev);
+
+ close(fd);
+
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+void relabsd_device_destroy (const struct relabsd_device * const dev)
+{
+ libevdev_uinput_destroy(dev->uidev);
+ libevdev_free(dev->dev);
+}
+
+int relabsd_device_write_evdev_event
+(
+ const struct relabsd_device * const dev,
+ unsigned int const type,
+ unsigned int const code,
+ int const value
+)
+{
+ if
+ (
+ (libevdev_uinput_write_event(dev->uidev, type, code, value) == 0)
+ && (libevdev_uinput_write_event(dev->uidev, EV_SYN, SYN_REPORT, 0) == 0)
+ )
+ {
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/src/relabsd_device.h b/src/relabsd_device.h
new file mode 100644
index 0000000..35a4830
--- /dev/null
+++ b/src/relabsd_device.h
@@ -0,0 +1,31 @@
+#ifndef RELABSD_RELABSD_DEVICE_H
+#define RELABSD_RELABSD_DEVICE_H
+
+#include <libevdev/libevdev.h>
+
+#include "config.h"
+#include "input.h"
+
+struct relabsd_device
+{
+ struct libevdev * dev;
+ struct libevdev_uinput * uidev;
+};
+
+int relabsd_device_create
+(
+ struct relabsd_device * const dev,
+ const struct relabsd_config * const config
+);
+
+void relabsd_device_destroy (const struct relabsd_device * const dev);
+
+int relabsd_device_write_evdev_event
+(
+ const struct relabsd_device * const dev,
+ unsigned int const type,
+ unsigned int const code,
+ int const value
+);
+
+#endif