summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2015-08-15 22:43:32 +0200
committerDavid Härdeman <david@hardeman.nu>2015-08-15 22:43:32 +0200
commitc420b38a5a4bac32b1086e0359e5f5646880d9f4 (patch)
treeffcf65dcc3d2e905665f82f57fcc48bccefa4a58
parent6d12cb6b9e9d7b67521f6ca999c933e1555a3226 (diff)
Add basic transmit support (WIP)
-rw-r--r--RemoteControlManager.xml3
-rw-r--r--rcm-client-hardware-list.c76
-rw-r--r--rcm-client.ui77
-rw-r--r--rcm-server-evdev.c4
-rw-r--r--rcm-server-keymap.c55
-rw-r--r--rcm-server-main.c163
-rw-r--r--rcm-server-main.h2
-rw-r--r--shared.c92
-rw-r--r--shared.h11
9 files changed, 407 insertions, 76 deletions
diff --git a/RemoteControlManager.xml b/RemoteControlManager.xml
index c4cb500..8f80b19 100644
--- a/RemoteControlManager.xml
+++ b/RemoteControlManager.xml
@@ -23,6 +23,9 @@
<arg type='aa{sv}' name='keymap_entries' direction='in'/>
<arg type='aa{sv}' name='layout_entries' direction='in'/>
</method>
+ <method name='Transmit'>
+ <arg type='au' name='data' direction='in'/>
+ </method>
<signal name='KeyPressed'>
<arg type='s' name='protocol'/>
<arg type='t' name='scancode'/>
diff --git a/rcm-client-hardware-list.c b/rcm-client-hardware-list.c
index 662dbf3..2c47ee5 100644
--- a/rcm-client-hardware-list.c
+++ b/rcm-client-hardware-list.c
@@ -6,6 +6,7 @@
#include <gtk/gtk.h>
#include "generated.h"
+#include "shared.h"
#include "rcm-client-main.h"
#include "rcm-client-hardware-list.h"
#include "rcm-client-receive.h"
@@ -84,12 +85,84 @@ hardware_properties_cb(GtkButton *button, gpointer user_data)
gtk_widget_hide(dialog);
}
+static GVariant *
+encode_nec(uint32_t scancode_raw)
+{
+ GVariantBuilder *builder;
+ GVariant *r;
+ unsigned i;
+ uint32_t scancode;
+
+ scancode = ((((scancode_raw >> 24) & 0xff) << 0) |
+ (((scancode_raw >> 16) & 0xff) << 8) |
+ (((scancode_raw >> 8) & 0xff) << 16) |
+ (((scancode_raw >> 0) & 0xff) << 24));
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add(builder, "u", 9000);
+ g_variant_builder_add(builder, "u", 4500);
+
+ for (i = 0; i < 32; i++) {
+ g_variant_builder_add(builder, "u", 560);
+ if (scancode & 0x1)
+ g_variant_builder_add(builder, "u", 3 * 560);
+ else
+ g_variant_builder_add(builder, "u", 1 * 560);
+ scancode >>= 1;
+ }
+
+ g_variant_builder_add(builder, "u", 560);
+
+ r = g_variant_builder_end(builder);
+ g_variant_builder_unref(builder);
+ return r;
+}
+
+static void
+advanced_transmit_cb(GtkButton *button, gpointer user_data)
+{
+ RCDevice *object = user_data;
+ GtkComboBoxText *protocolw;
+ GtkEntry *scancodew;
+ gchar *protocol;
+ const gchar *scancode;
+ uint64_t sc;
+ GError *error = NULL;
+ gboolean r;
+
+ protocolw = GTK_COMBO_BOX_TEXT(gtk_builder_get_object(global->builder, "advanced_main_transmit_protocol"));
+ scancodew = GTK_ENTRY(gtk_builder_get_object(global->builder, "advanced_main_transmit_scancode"));
+
+ protocol = gtk_combo_box_text_get_active_text(protocolw);
+ scancode = gtk_entry_get_text(scancodew);
+ printf("Asked to transmit: protocol %s scancode %s\n", protocol, scancode);
+ g_free(protocol);
+
+ if (!strcmp(protocol, "NEC")) {
+ printf("Invalid protocol: %s\n", protocol);
+ return;
+ }
+
+ r = strtoull_strict(scancode, &sc);
+ if (r < 0 || sc > UINT32_MAX) {
+ printf("Invalid scancode: %s\n", scancode);
+ return;
+ }
+
+ if (!rcdevice_call_transmit_sync(object, encode_nec(sc), NULL, &error)) {
+ printf("rcdevice_call_transmit_sync failed: %s\n",
+ error ? error->message : "no error reported");
+ g_error_free(error);
+ }
+}
+
static void
advanced_cb(GtkButton *button, gpointer user_data)
{
RCDevice *object = user_data;
GtkWidget *dialog;
GtkWidget *title;
+ GtkWidget *transmit;
gchar *titlestr;
dialog = GTK_WIDGET(gtk_builder_get_object(global->builder, "advanced"));
@@ -100,6 +173,9 @@ advanced_cb(GtkButton *button, gpointer user_data)
gtk_label_set_markup(GTK_LABEL(title), titlestr);
g_free(titlestr);
+ transmit = GTK_WIDGET(gtk_builder_get_object(global->builder, "advanced_main_transmit_button"));
+ g_signal_connect(transmit, "clicked", G_CALLBACK(advanced_transmit_cb), object);
+
g_signal_connect_swapped(dialog, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), dialog);
gtk_widget_show(dialog);
}
diff --git a/rcm-client.ui b/rcm-client.ui
index ba5c893..8384abd 100644
--- a/rcm-client.ui
+++ b/rcm-client.ui
@@ -61,10 +61,10 @@
<child>
<object class="GtkButton" id="advanced_main_transmit_button">
<property name="visible">True</property>
- <property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">end</property>
+ <property name="valign">start</property>
<property name="image">advanced_button_transmit_image</property>
</object>
<packing>
@@ -98,11 +98,80 @@
</packing>
</child>
<child>
- <object class="GtkLabel" id="advanced_main_transmit_label">
+ <object class="GtkGrid" id="advanced_main_transmit_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Transmit raw commands</property>
- <property name="xalign">0</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="advanced_main_transmit_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">&lt;b&gt;Transmit raw command&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="advanced_main_transmit_protocol_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">6</property>
+ <property name="label" translatable="yes">Protocol</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="advanced_main_transmit_scancode_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">6</property>
+ <property name="label" translatable="yes">Scancode</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="advanced_main_transmit_protocol">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="active">0</property>
+ <items>
+ <item translatable="yes">NEC</item>
+ </items>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="advanced_main_transmit_scancode">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="max_length">10</property>
+ <property name="text" translatable="yes">0x01FE0FF0</property>
+ <property name="input_hints">GTK_INPUT_HINT_UPPERCASE_CHARS | GTK_INPUT_HINT_NONE</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="left_attach">1</property>
diff --git a/rcm-server-evdev.c b/rcm-server-evdev.c
index 1c04864..ab5ac0e 100644
--- a/rcm-server-evdev.c
+++ b/rcm-server-evdev.c
@@ -173,10 +173,10 @@ evdev_read(sd_event_source *s, int fd, uint32_t revents, void *userdata)
if (r != LIBEVDEV_READ_STATUS_SUCCESS)
continue;
- printf("Event: %s %s %d\n",
+ printf("Event: %s %s %u (0x%08x)\n",
libevdev_event_type_get_name(ev.type),
libevdev_event_code_get_name(ev.type, ev.code),
- ev.value);
+ ev.value, ev.value);
switch (ev.type) {
case EV_KEY:
diff --git a/rcm-server-keymap.c b/rcm-server-keymap.c
index 15b7fe8..56e17f6 100644
--- a/rcm-server-keymap.c
+++ b/rcm-server-keymap.c
@@ -11,7 +11,6 @@
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
-#include <limits.h>
#include "utils.h"
#include "shared.h"
@@ -37,60 +36,6 @@ struct inis iniss[] = {
{ .name = NULL, .value = INI_SECTION_UNDEFINED },
};
-static int strtol_strict(const char *str, int *result)
-{
- char *end;
- long val;
-
- errno = 0;
- val = strtol(str, &end, 10);
-
- if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
- return -EINVAL;
-
- if (errno != 0 && val == 0)
- return -EINVAL;
-
- if (end == str)
- return -EINVAL;
-
- if (*end != '\0')
- return -EINVAL;
-
- if (val < 1 || val > UINT16_MAX)
- return -EINVAL;
-
- *result = val;
- return 0;
-}
-
-static int strtoull_strict(const char *str, uint64_t *result)
-{
- char *end;
- unsigned long long val;
-
- errno = 0;
- val = strtoull(str, &end, 16);
-
- if (errno == ERANGE && (val == ULLONG_MAX || val == 0))
- return -EINVAL;
-
- if (errno != 0 && val == 0)
- return -EINVAL;
-
- if (end == str)
- return -EINVAL;
-
- if (*end != '\0')
- return -EINVAL;
-
- if (val > UINT64_MAX)
- return -EINVAL;
-
- *result = val;
- return 0;
-}
-
static int
keymap_parse(FILE *fp, char **line, size_t *buf_size, struct keymap *keymap,
uint16_t *rows_return, uint16_t *cols_return,
diff --git a/rcm-server-main.c b/rcm-server-main.c
index 4a0adbc..4d23f89 100644
--- a/rcm-server-main.c
+++ b/rcm-server-main.c
@@ -649,6 +649,58 @@ out:
return sd_bus_error_set_errno(error, r);
}
+static void
+lirc_write(int fd, const uint32_t *v, unsigned count)
+{
+ unsigned nv[count];
+ unsigned i;
+ size_t l = count * sizeof(uint32_t);
+
+ for (i = 0; i < count; i++)
+ nv[i] = v[i];
+
+ printf("Write to lirc fd of %zu bytes returned %zi errno is %i aka %s\n",
+ l, write(fd, nv, l), errno, strerror(errno));
+}
+
+static int
+method_transmit(sd_bus_message *m, void *userdata, sd_bus_error *error)
+{
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ struct manager *mgr = userdata;
+ struct device *dev;
+ const void *v;
+ size_t l;
+ int r;
+ const uint32_t *values;
+ size_t count;
+
+ printf("Transmit method called\n");
+ dev = find_device_by_path(mgr, sd_bus_message_get_path(m));
+ if (!dev) {
+ sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device");
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_read_array(m, SD_BUS_TYPE_UINT32, &v, &l);
+ if (r < 0) {
+ goto out;
+ } else if (r == 0 || l % sizeof(uint32_t) != 0) {
+ r = -EBADMSG;
+ goto out;
+ }
+
+ values = v;
+ count = l / sizeof(uint32_t);
+ lirc_write(dev->lirc_fd, values, count);
+
+
+ return sd_bus_reply_method_return(m, NULL);
+
+out:
+ return sd_bus_error_set_errno(error, r);
+}
+
static const sd_bus_vtable device_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("SysName", "s", property_get, 0, 0),
@@ -660,6 +712,7 @@ static const sd_bus_vtable device_vtable[] = {
SD_BUS_METHOD("ListKeymaps", NULL, "as", method_listkeymaps, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetKeymap", "s", "ssqqaa{sv}aa{sv}", method_getkeymap, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetKeymap", "sssqqaa{sv}aa{sv}", NULL, method_setkeymap, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Transmit", "au", NULL, method_transmit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("KeyPressed", "sts", 0),
SD_BUS_SIGNAL("KeyReleased", "s", 0),
SD_BUS_VTABLE_END
@@ -684,6 +737,63 @@ remove_device(struct manager *mgr, struct udev_device *udev)
}
}
+static int
+lirc_read(sd_event_source *s, int fd, uint32_t revents, void *userdata)
+{
+ struct device *device = userdata;
+ uint8_t buf[100];
+ ssize_t bytes_read;
+
+ if (fd != device->lirc_fd)
+ fprintf(stderr, "lirc fd mismatch: %i != %i\n", device->lirc_fd, fd);
+
+ if (revents & EPOLLHUP) {
+ fprintf(stderr, "lirc connection closed!\n");
+ close(fd);
+ device->lirc_fd = -1;
+ return 0;
+ }
+
+ if (!(revents & EPOLLIN)) {
+ fprintf(stderr, "unexpected lirc event: %" PRIu32 "\n", revents);
+ return 0;
+ }
+
+ while ((bytes_read = read(fd, buf, sizeof(buf))) > 0)
+ printf("Read %zi bytes from lirc dev\n", bytes_read);
+
+ return 0;
+}
+
+static int
+lirc_setup(struct device *device, const char *path)
+{
+ if (!device)
+ return -EINVAL;
+
+ if (device->lirc_fd >= 0) {
+ printf("Multiple lirc devices!?\n");
+ return 0;
+ }
+
+ device->lirc_fd = open(path, O_RDWR | O_NONBLOCK);
+ if (device->lirc_fd < 0) {
+ printf("Failed to open lirc device %s: %s\n", path, strerror(errno));
+ return -errno;
+ }
+
+ if (sd_event_add_io(device->mgr->event, &device->lirc_ev,
+ device->lirc_fd, EPOLLIN, lirc_read, device) < 0) {
+ printf("Failed to add event source for lirc device %s: %s\n",
+ path, strerror(errno));
+ close(device->lirc_fd);
+ device->lirc_fd = -1;
+ return -errno;
+ }
+
+ return 0;
+}
+
static void
add_device(struct manager *mgr, struct udev_device *udev)
{
@@ -693,7 +803,6 @@ add_device(struct manager *mgr, struct udev_device *udev)
struct device *device;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *dev_list_entry;
- struct udev_device *evdev;
int r;
name = udev_device_get_sysname(udev);
@@ -714,7 +823,9 @@ add_device(struct manager *mgr, struct udev_device *udev)
device->path = path;
device->name = device->path + strlen("/org/gnome/RemoteControlManager/");
device->evdev_fd = -1;
+ device->lirc_fd = -1;
device->error = NULL;
+ device->input_name = NULL;
if (keymaps_load(device) < 0) {
fprintf(stderr, "failed to load keymaps: %m\n");
@@ -726,12 +837,15 @@ add_device(struct manager *mgr, struct udev_device *udev)
enumerate = udev_enumerate_new(mgr->udev);
udev_enumerate_add_match_parent(enumerate, udev);
udev_enumerate_add_match_sysname(enumerate, "event*");
+ udev_enumerate_add_match_sysname(enumerate, "lirc*");
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(dev_list_entry, devices) {
const char *path;
+ struct udev_device *udev_dev;
const char *devnode;
+ const char *subsys;
path = udev_list_entry_get_name(dev_list_entry);
if (!path) {
@@ -739,29 +853,47 @@ add_device(struct manager *mgr, struct udev_device *udev)
continue;
}
- evdev = udev_device_new_from_syspath(mgr->udev, path);
- if (!evdev) {
+ udev_dev = udev_device_new_from_syspath(mgr->udev, path);
+ if (!udev_dev) {
printf("Failed to create udev device\n");
continue;
}
- devnode = udev_device_get_devnode(evdev);
+ devnode = udev_device_get_devnode(udev_dev);
if (!devnode) {
- printf("Failed to determine evdev devnode\n");
- udev_device_unref(evdev);
- continue;
+ printf("Failed to determine udev_dev devnode\n");
+ goto next;
}
- r = evdev_setup(device, devnode);
- if (r < 0) {
- printf("Failed to setup evdev: %s\n", devnode);
- device->error = "Error: Failed to setup evdev";
- device->input_name = NULL;
- udev_device_unref(evdev);
- continue;
+ subsys = udev_device_get_subsystem(udev_dev);
+ if (!subsys) {
+ printf("Failed to determine udev_dev subsystem\n");
+ goto next;
+ }
+
+ if (!strcmp(subsys, "input")) {
+ r = evdev_setup(device, devnode);
+ if (r < 0) {
+ printf("Failed to setup evdev: %s\n", devnode);
+ device->error = "Error: Failed to setup evdev";
+ goto next;
+ }
+
+ } else if (!strcmp(subsys, "lirc")) {
+ r = lirc_setup(device, devnode);
+ if (r < 0) {
+ printf("Failed to setup lirc: %s\n", devnode);
+ device->error = "Error: Failed to setup lirc";
+ goto next;
+ }
+
+ } else {
+ printf("Unknown subsystem, ignored %s\n", devnode);
+ goto next;
}
- udev_device_unref(evdev);
+next:
+ udev_device_unref(udev_dev);
}
udev_enumerate_unref(enumerate);
@@ -793,6 +925,7 @@ add_device(struct manager *mgr, struct udev_device *udev)
printf("\tDriver : %s\n", device->driver_name);
printf("\tKernel map: %s\n", device->keymap_name);
printf("\tDevnode fd: %i\n", device->evdev_fd);
+ printf("\tLIRC fd : %i\n", device->lirc_fd);
printf("\tDBUS path : %s\n", device->path);
printf("\tProtocols : %s\n",
udev_device_get_sysattr_value(udev, "protocols"));
diff --git a/rcm-server-main.h b/rcm-server-main.h
index 689c4fd..4d2b57b 100644
--- a/rcm-server-main.h
+++ b/rcm-server-main.h
@@ -8,6 +8,8 @@ struct device {
char *driver_name;
char *keymap_name;
char *error;
+ int lirc_fd;
+ sd_event_source *lirc_ev;
int evdev_fd;
sd_event_source *evdev_ev;
struct libevdev *evdev_dev;
diff --git a/shared.c b/shared.c
index b07d8c0..a9875bc 100644
--- a/shared.c
+++ b/shared.c
@@ -1,5 +1,7 @@
#include <stdlib.h>
#include <strings.h>
+#include <errno.h>
+#include <limits.h>
#include "shared.h"
@@ -43,3 +45,93 @@ get_linux_keycode_by_name(const char *name)
return NULL;
}
+int
+strtol_strict(const char *str, int *result)
+{
+ char *end;
+ long val;
+
+ errno = 0;
+ val = strtol(str, &end, 10);
+
+ if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+ return -EINVAL;
+
+ if (errno != 0 && val == 0)
+ return -EINVAL;
+
+ if (end == str)
+ return -EINVAL;
+
+ if (*end != '\0')
+ return -EINVAL;
+
+ if (val < 1 || val > UINT16_MAX)
+ return -EINVAL;
+
+ *result = val;
+ return 0;
+}
+
+int
+strtoull_strict(const char *str, uint64_t *result)
+{
+ char *end;
+ unsigned long long val;
+
+ errno = 0;
+ val = strtoull(str, &end, 16);
+
+ if (errno == ERANGE && (val == ULLONG_MAX || val == 0))
+ return -EINVAL;
+
+ if (errno != 0 && val == 0)
+ return -EINVAL;
+
+ if (end == str)
+ return -EINVAL;
+
+ if (*end != '\0')
+ return -EINVAL;
+
+ if (val > UINT64_MAX)
+ return -EINVAL;
+
+ *result = val;
+ return 0;
+}
+
+uint8_t const byte_rev_table[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
diff --git a/shared.h b/shared.h
index 7dfcfca..1857555 100644
--- a/shared.h
+++ b/shared.h
@@ -22,4 +22,15 @@ extern struct linux_input_keycode linux_input_keycodes[];
struct linux_input_keycode *get_linux_keycode_by_name(const char *name);
+int strtol_strict(const char *str, int *result);
+
+int strtoull_strict(const char *str, uint64_t *result);
+
+extern uint8_t const byte_rev_table[256];
+
+static inline uint8_t bitrev8(uint8_t byte)
+{
+ return byte_rev_table[byte];
+}
+
#endif