diff options
author | Sebastian Reichel <sre@ring0.de> | 2015-08-24 14:18:19 +0200 |
---|---|---|
committer | Sebastian Reichel <sre@ring0.de> | 2015-09-12 17:00:43 +0200 |
commit | 9dce0dfa4cd90e7ce2131e1e5821f54eb3754b26 (patch) | |
tree | 11806709f96f236c87575e7bfbde0d4b244f5863 /src/input-device | |
parent | b3464b4f908197fdb3cf17f25b82e9315f9734a2 (diff) | |
download | serial-barcode-scanner-9dce0dfa4cd90e7ce2131e1e5821f54eb3754b26.tar.bz2 |
input-device: add new daemon
The input-device daemon can be used instead of the serial-device daemon
for barcode scanners, that are connected as HID device.
Diffstat (limited to 'src/input-device')
-rw-r--r-- | src/input-device/.gitignore | 1 | ||||
-rw-r--r-- | src/input-device/Makefile | 10 | ||||
-rw-r--r-- | src/input-device/input-device-interface.vala | 20 | ||||
-rw-r--r-- | src/input-device/input-device.vala | 317 | ||||
-rw-r--r-- | src/input-device/main.vala | 47 |
5 files changed, 395 insertions, 0 deletions
diff --git a/src/input-device/.gitignore b/src/input-device/.gitignore new file mode 100644 index 0000000..3ba6df4 --- /dev/null +++ b/src/input-device/.gitignore @@ -0,0 +1 @@ +input-device diff --git a/src/input-device/Makefile b/src/input-device/Makefile new file mode 100644 index 0000000..aba6c73 --- /dev/null +++ b/src/input-device/Makefile @@ -0,0 +1,10 @@ +all: input-device + @echo > /dev/null + +input-device: main.vala input-device.vala input-device-interface.vala ../config/config-interface.vala + valac -X -w -o $@ --pkg linux --pkg posix --pkg gio-2.0 $^ + +clean: + rm -rf input-device + +.PHONY: all clean diff --git a/src/input-device/input-device-interface.vala b/src/input-device/input-device-interface.vala new file mode 100644 index 0000000..067b827 --- /dev/null +++ b/src/input-device/input-device-interface.vala @@ -0,0 +1,20 @@ +/* Copyright 2015, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.InputDevice")] +public interface InputDevice : Object { + public abstract signal void received_barcode(string barcode); + public abstract void blink(uint duration) throws IOError; +} diff --git a/src/input-device/input-device.vala b/src/input-device/input-device.vala new file mode 100644 index 0000000..9e2680c --- /dev/null +++ b/src/input-device/input-device.vala @@ -0,0 +1,317 @@ +/* Copyright 2015, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.InputDevice")] +public class Device { + private IOChannel io_read; + private string buffer; + private bool shift; + + public signal void received_barcode(string barcode); + + public Device(string device) { + try { + io_read = new IOChannel.file(device, "r"); + buffer = ""; + shift = false; + + int fd = io_read.unix_get_fd(); + int flags = Posix.fcntl(fd, Posix.F_GETFL, 0); + Posix.fcntl(fd, Posix.F_SETFL, flags | Posix.O_NONBLOCK); + + if(!(io_read.add_watch(IOCondition.IN | IOCondition.HUP, device_read) != 0)) { + error("Could not bind IOChannel"); + } + } catch(FileError e) { + error("FileError: %s", e.message); + } + } + + private char linux_event_lookup(uint16 code) { + int c = code; + + switch(c) { + case Linux.Input.KEY_0: + return '0'; + case Linux.Input.KEY_1: + return '1'; + case Linux.Input.KEY_2: + return '2'; + case Linux.Input.KEY_3: + return '3'; + case Linux.Input.KEY_4: + return '4'; + case Linux.Input.KEY_5: + return '5'; + case Linux.Input.KEY_6: + return '6'; + case Linux.Input.KEY_7: + return '7'; + case Linux.Input.KEY_8: + return '8'; + case Linux.Input.KEY_9: + return '9'; + case Linux.Input.KEY_A: + return 'a'; + case Linux.Input.KEY_B: + return 'b'; + case Linux.Input.KEY_C: + return 'c'; + case Linux.Input.KEY_D: + return 'd'; + case Linux.Input.KEY_E: + return 'e'; + case Linux.Input.KEY_F: + return 'f'; + case Linux.Input.KEY_G: + return 'g'; + case Linux.Input.KEY_H: + return 'h'; + case Linux.Input.KEY_I: + return 'i'; + case Linux.Input.KEY_J: + return 'j'; + case Linux.Input.KEY_K: + return 'k'; + case Linux.Input.KEY_L: + return 'l'; + case Linux.Input.KEY_M: + return 'm'; + case Linux.Input.KEY_N: + return 'n'; + case Linux.Input.KEY_O: + return 'o'; + case Linux.Input.KEY_P: + return 'p'; + case Linux.Input.KEY_Q: + return 'q'; + case Linux.Input.KEY_R: + return 'r'; + case Linux.Input.KEY_S: + return 's'; + case Linux.Input.KEY_T: + return 't'; + case Linux.Input.KEY_U: + return 'u'; + case Linux.Input.KEY_V: + return 'v'; + case Linux.Input.KEY_W: + return 'w'; + case Linux.Input.KEY_X: + return 'x'; + case Linux.Input.KEY_Y: + return 'y'; + case Linux.Input.KEY_Z: + return 'z'; + case Linux.Input.KEY_SPACE: + return ' '; + case Linux.Input.KEY_DOT: + return '.'; + case Linux.Input.KEY_MINUS: + return '-'; + case Linux.Input.KEY_SLASH: + return '/'; + case Linux.Input.KEY_ENTER: + return '\n'; + default: + return '\0'; + } + } + + private char linux_event_lookup_shift(uint16 code) { + int c = code; + + switch(c) { + case Linux.Input.KEY_EQUAL: + return '+'; + case Linux.Input.KEY_4: + return '$'; + case Linux.Input.KEY_5: + return '%'; + case Linux.Input.KEY_A: + return 'A'; + case Linux.Input.KEY_B: + return 'B'; + case Linux.Input.KEY_C: + return 'C'; + case Linux.Input.KEY_D: + return 'D'; + case Linux.Input.KEY_E: + return 'E'; + case Linux.Input.KEY_F: + return 'F'; + case Linux.Input.KEY_G: + return 'G'; + case Linux.Input.KEY_H: + return 'H'; + case Linux.Input.KEY_I: + return 'I'; + case Linux.Input.KEY_J: + return 'J'; + case Linux.Input.KEY_K: + return 'K'; + case Linux.Input.KEY_L: + return 'L'; + case Linux.Input.KEY_M: + return 'M'; + case Linux.Input.KEY_N: + return 'N'; + case Linux.Input.KEY_O: + return 'O'; + case Linux.Input.KEY_P: + return 'P'; + case Linux.Input.KEY_Q: + return 'Q'; + case Linux.Input.KEY_R: + return 'R'; + case Linux.Input.KEY_S: + return 'S'; + case Linux.Input.KEY_T: + return 'T'; + case Linux.Input.KEY_U: + return 'U'; + case Linux.Input.KEY_V: + return 'V'; + case Linux.Input.KEY_W: + return 'W'; + case Linux.Input.KEY_X: + return 'X'; + case Linux.Input.KEY_Y: + return 'Y'; + case Linux.Input.KEY_Z: + return 'Z'; + case Linux.Input.KEY_SPACE: + return ' '; + case Linux.Input.KEY_ENTER: + return '\n'; + default: + return '\0'; + + } + } + + private bool device_read(IOChannel source, IOCondition cond) { + Linux.Input.Event ev = {}; + char key = '\0'; + + if((cond & IOCondition.HUP) == IOCondition.HUP) + error("Lost device"); + + do { + int fd = source.unix_get_fd(); + ssize_t s = Posix.read(fd, &ev, sizeof(Linux.Input.Event)); + + /* short read */ + if (s != sizeof(Linux.Input.Event)) { + if(s > 0) + stdout.printf("short read!\n"); + return true; + } + + /* only handle key events */ + if (ev.type != Linux.Input.EV_KEY) + continue; + + if (ev.code == Linux.Input.KEY_LEFTSHIFT) { + shift = (ev.value == 1); + continue; + } + + /* ignore key-release */ + if (ev.value != 1) + continue; + + /* key event to ascii */ + key = shift ? linux_event_lookup_shift(ev.code) : linux_event_lookup(ev.code); + + /* add buffer */ + if (key != '\n') + buffer += "%c".printf(key); + } while(key != '\n'); + + stdout.printf("barcode: %s\n", buffer); + + if(buffer.has_prefix("USER ") || buffer.has_prefix("STOCK") || buffer.has_prefix("AMOUNT ")) { + if(!check_code39_checksum(buffer)) + received_barcode("SCANNER RETURNED INCORRECT DATA"); + else {/* remove checksum */ + buffer = buffer[0:-1]; + received_barcode(buffer); + } + } + else + received_barcode(buffer); + + buffer = ""; + return true; + } + + private bool check_code39_checksum(string data) { + int result = 0; + + for(int i = 0; i<data.length-1; i++) { + if(data[i] >= '0' && data[i] <= '9') + result += data[i] - '0'; + else if(data[i] >= 'A' && data[i] <= 'Z') + result += data[i] - 'A' + 10; + else + switch(data[i]) { + case '-': + result += 36; break; + case '.': + result += 37; break; + case ' ': + result += 38; break; + case '$': + result += 39; break; + case '/': + result += 40; break; + case '+': + result += 41; break; + case '%': + result += 42; break; + default: + /* invalid character */ + return false; + } + + result %= 43; + } + + if(result < 10) + result = result + '0'; + else if(result < 36) + result = result - 10 + 'A'; + else + switch(result) { + case 36: result = '-'; break; + case 37: result = '.'; break; + case 38: result = ' '; break; + case 39: result = '$'; break; + case 40: result = '/'; break; + case 41: result = '+'; break; + case 42: result = '%'; break; + } + + return (data[data.length-1] == result); + } + + /** + * @param duration duration of the blink in 0.1 seconds + */ + public void blink(uint duration) { + /* not supported */ + } +} diff --git a/src/input-device/main.vala b/src/input-device/main.vala new file mode 100644 index 0000000..e2dee27 --- /dev/null +++ b/src/input-device/main.vala @@ -0,0 +1,47 @@ +/* Copyright 2015, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +Device dev; + +public static int main(string[] args) { + try { + Config cfg = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Config", "/io/mainframe/shopsystem/config"); + dev = new Device(cfg.get_string("INPUT", "device")); + } catch(IOError e) { + error("IOError: %s\n", e.message); + } catch(KeyFileError e) { + error("Config Error: %s\n", e.message); + } + + Bus.own_name( + BusType.SESSION, + "io.mainframe.shopsystem.InputDevice", + BusNameOwnerFlags.NONE, + on_bus_aquired, + () => {}, + () => stderr.printf("Could not aquire name\n")); + + new MainLoop().run(); + + return 0; +} + +void on_bus_aquired(DBusConnection con) { + try { + con.register_object("/io/mainframe/shopsystem/device", dev); + } catch(IOError e) { + stderr.printf("Could not register service\n"); + } +} |