From 9dce0dfa4cd90e7ce2131e1e5821f54eb3754b26 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 24 Aug 2015 14:18:19 +0200 Subject: 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. --- src/Makefile | 2 +- src/input-device/.gitignore | 1 + src/input-device/Makefile | 10 + src/input-device/input-device-interface.vala | 20 ++ src/input-device/input-device.vala | 317 +++++++++++++++++++++++++ src/input-device/main.vala | 47 ++++ src/scanner-session/Makefile | 2 +- src/scanner-session/scannersession.vala | 4 +- src/serial-device/Makefile | 2 +- src/serial-device/main.vala | 4 +- src/serial-device/serial-device-interface.vala | 20 -- src/serial-device/serial-device.vala | 2 +- 12 files changed, 403 insertions(+), 28 deletions(-) create mode 100644 src/input-device/.gitignore create mode 100644 src/input-device/Makefile create mode 100644 src/input-device/input-device-interface.vala create mode 100644 src/input-device/input-device.vala create mode 100644 src/input-device/main.vala delete mode 100644 src/serial-device/serial-device-interface.vala diff --git a/src/Makefile b/src/Makefile index 77ece0e..6c03867 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -DAEMONS=audio config curses-ui database pdf-invoice pdf-stock pgp scanner-session serial-device web +DAEMONS=audio config curses-ui database pdf-invoice pdf-stock pgp scanner-session serial-device input-device web all: @$(foreach dir,$(DAEMONS),cd $(dir) && echo "Building $(dir)..." && make --no-print-directory all && cd ..;) 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 + * + * 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 + * + * 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= '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 + * + * 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"); + } +} diff --git a/src/scanner-session/Makefile b/src/scanner-session/Makefile index 68a906a..5320025 100644 --- a/src/scanner-session/Makefile +++ b/src/scanner-session/Makefile @@ -1,7 +1,7 @@ all: scanner-session @echo > /dev/null -scanner-session: main.vala scannersession.vala scannersession-interface.vala ../database/db-interface.vala ../serial-device/serial-device-interface.vala ../cli/cli-interface.vala ../audio/audio-interface.vala ../price.vapi +scanner-session: main.vala scannersession.vala scannersession-interface.vala ../database/db-interface.vala ../input-device/input-device-interface.vala ../cli/cli-interface.vala ../audio/audio-interface.vala ../price.vapi valac -X -w -o $@ --pkg gio-2.0 $^ clean: diff --git a/src/scanner-session/scannersession.vala b/src/scanner-session/scannersession.vala index 2661179..002b7db 100644 --- a/src/scanner-session/scannersession.vala +++ b/src/scanner-session/scannersession.vala @@ -23,7 +23,7 @@ public class ScannerSessionImplementation { private Database db; private AudioPlayer audio; - private SerialDevice dev; + private InputDevice dev; private Cli cli; @@ -33,7 +33,7 @@ public class ScannerSessionImplementation { public ScannerSessionImplementation() { try { db = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Database", "/io/mainframe/shopsystem/database"); - dev = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.SerialDevice", "/io/mainframe/shopsystem/device"); + dev = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.InputDevice", "/io/mainframe/shopsystem/device"); cli = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Cli", "/io/mainframe/shopsystem/cli"); audio = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.AudioPlayer", "/io/mainframe/shopsystem/audio"); diff --git a/src/serial-device/Makefile b/src/serial-device/Makefile index b9ebaf4..d80279d 100644 --- a/src/serial-device/Makefile +++ b/src/serial-device/Makefile @@ -1,7 +1,7 @@ all: serial-device @echo > /dev/null -serial-device: main.vala serial-device.vala serial-device-interface.vala ../config/config-interface.vala +serial-device: main.vala serial-device.vala ../input-device/input-device-interface.vala ../config/config-interface.vala valac -X -w -o $@ --pkg linux --pkg posix --pkg gio-2.0 $^ clean: diff --git a/src/serial-device/main.vala b/src/serial-device/main.vala index e338842..ae1aa75 100644 --- a/src/serial-device/main.vala +++ b/src/serial-device/main.vala @@ -18,7 +18,7 @@ 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("SERIAL", "device"), 9600, 8, 1); + dev = new Device(cfg.get_string("INPUT", "device"), 9600, 8, 1); } catch(IOError e) { error("IOError: %s\n", e.message); } catch(KeyFileError e) { @@ -27,7 +27,7 @@ public static int main(string[] args) { Bus.own_name( BusType.SESSION, - "io.mainframe.shopsystem.SerialDevice", + "io.mainframe.shopsystem.InputDevice", BusNameOwnerFlags.NONE, on_bus_aquired, () => {}, diff --git a/src/serial-device/serial-device-interface.vala b/src/serial-device/serial-device-interface.vala deleted file mode 100644 index 572e810..0000000 --- a/src/serial-device/serial-device-interface.vala +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2013, Sebastian Reichel - * - * 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.SerialDevice")] -public interface SerialDevice : Object { - public abstract signal void received_barcode(string barcode); - public abstract void blink(uint duration) throws IOError; -} diff --git a/src/serial-device/serial-device.vala b/src/serial-device/serial-device.vala index c697a59..549cd74 100644 --- a/src/serial-device/serial-device.vala +++ b/src/serial-device/serial-device.vala @@ -13,7 +13,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -[DBus (name = "io.mainframe.shopsystem.SerialDevice")] +[DBus (name = "io.mainframe.shopsystem.InputDevice")] public class Device { private Posix.termios newtio; private Posix.termios restoretio; -- cgit v1.2.3