summaryrefslogtreecommitdiffstats
path: root/src/device.vala
diff options
context:
space:
mode:
authorSebastian Reichel <sre@ring0.de>2012-10-02 01:05:51 +0200
committerSebastian Reichel <sre@ring0.de>2012-10-02 01:05:51 +0200
commit186049b3ed33f025eeb87eb34c19a28e1d5ba70a (patch)
tree5d892564001404fe979e18eac0e65dfcad65ed5e /src/device.vala
parent9713c98dbceb54d8d00c186ba8f41f3a5befcfd1 (diff)
downloadserial-barcode-scanner-186049b3ed33f025eeb87eb34c19a28e1d5ba70a.tar.bz2
restructure code, switch from GTK to Web based UI
- move barcode generation scripts into generation/ - move code to src/ - remove database analysis from invoice/graph - put database creation sql files into sql/ - remove glade builder file - add new templates/ directory, which contains files used by the Web-UI
Diffstat (limited to 'src/device.vala')
-rw-r--r--src/device.vala280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/device.vala b/src/device.vala
new file mode 100644
index 0000000..5d7fc09
--- /dev/null
+++ b/src/device.vala
@@ -0,0 +1,280 @@
+/* Copyright 2012, 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.
+ */
+
+public class Device {
+ private Posix.termios newtio;
+ private Posix.termios restoretio;
+ public int fd=-1;
+ private IOChannel io_read;
+ public int byterate;
+ private File lockfile;
+
+ public signal void received_barcode(string barcode);
+
+ public Device(string device, int rate, int bits, int stopbits) {
+ Posix.speed_t baudrate = Posix.B9600;
+
+ try {
+ /* check lock file */
+ lockfile = File.new_for_path("/var/lock/LCK.." + device.replace("/dev/", ""));
+ if(lockfile.query_exists()) {
+ int pid = -1;
+ uint8[] data;
+ if(lockfile.load_contents(null, out data, null)) {
+ pid = int.parse((string) data);
+ } else {
+ error("Can't read lock file!\n");
+ }
+
+ if(Posix.kill(pid, 0) == 0) {
+ error("serial device is locked!\n");
+ }
+ }
+
+ var pid = "%d\n".printf(Posix.getpid());
+ lockfile.replace_contents(pid.data, null, false, FileCreateFlags.NONE, null);
+
+ fd = Posix.open(device, Posix.O_RDWR /*| Posix.O_NONBLOCK*/);
+
+ if(fd < 0) {
+ fd = -1;
+ lockfile.delete();
+ error("Could not open device!\n");
+ }
+
+ } catch(Error e) {
+ error("Could not create lock file: %s!\n", e.message);
+ }
+
+
+ Posix.tcflush(fd, Posix.TCIOFLUSH);
+
+ Posix.tcgetattr(fd, out restoretio);
+
+ /* apply settings */
+ switch(rate) {
+ case 300:
+ baudrate = Posix.B300;
+ break;
+ case 600:
+ baudrate = Posix.B600;
+ break;
+ case 1200:
+ baudrate = Posix.B1200;
+ break;
+ case 2400:
+ baudrate = Posix.B2400;
+ break;
+ case 4800:
+ baudrate = Posix.B4800;
+ break;
+ case 9600:
+ baudrate = Posix.B9600;
+ break;
+ case 19200:
+ baudrate = Posix.B19200;
+ break;
+ case 38400:
+ baudrate = Posix.B38400;
+ break;
+ case 57600:
+ baudrate = Posix.B57600;
+ break;
+ case 115200:
+ baudrate = Posix.B115200;
+ break;
+ case 230400:
+ baudrate = Posix.B230400;
+ break;
+ default:
+ /* not supported */
+ rate = 9600;
+ break;
+ }
+
+ Posix.cfsetospeed(ref newtio, baudrate);
+ Posix.cfsetispeed(ref newtio, baudrate);
+
+ switch(bits) {
+ case 5:
+ newtio.c_cflag = (newtio.c_cflag & ~Posix.CSIZE) | Posix.CS5;
+ break;
+ case 6:
+ newtio.c_cflag = (newtio.c_cflag & ~Posix.CSIZE) | Posix.CS6;
+ break;
+ case 7:
+ newtio.c_cflag = (newtio.c_cflag & ~Posix.CSIZE) | Posix.CS7;
+ break;
+ case 8:
+ default:
+ newtio.c_cflag = (newtio.c_cflag & ~Posix.CSIZE) | Posix.CS8;
+ break;
+ }
+
+ newtio.c_cflag |= Posix.CLOCAL | Posix.CREAD;
+
+ newtio.c_cflag &= ~(Posix.PARENB | Posix.PARODD);
+
+ /* TODO: parity */
+
+ newtio.c_cflag &= ~Linux.Termios.CRTSCTS;
+
+ if(stopbits == 2)
+ newtio.c_cflag |= Posix.CSTOPB;
+ else
+ newtio.c_cflag &= ~Posix.CSTOPB;
+
+ newtio.c_iflag = Posix.IGNBRK;
+
+ newtio.c_lflag = 0;
+ newtio.c_oflag = 0;
+
+ newtio.c_cc[Posix.VTIME]=1;
+ newtio.c_cc[Posix.VMIN]=1;
+
+ newtio.c_lflag &= ~(Posix.ECHONL|Posix.NOFLSH);
+
+ int mcs=0;
+ Posix.ioctl(fd, Linux.Termios.TIOCMGET, out mcs);
+ mcs |= Linux.Termios.TIOCM_RTS;
+ Posix.ioctl(fd, Linux.Termios.TIOCMSET, out mcs);
+
+ Posix.tcsetattr(fd, Posix.TCSANOW, newtio);
+
+ this.byterate = rate/bits;
+
+ try {
+ io_read = new IOChannel.unix_new(fd);
+ io_read.set_line_term("\r\n", 2);
+ if(io_read.set_encoding(null) != IOStatus.NORMAL)
+ error("Failed to set encoding");
+ if(!(io_read.add_watch(IOCondition.IN | IOCondition.HUP, device_read) != 0)) {
+ error("Could not bind IOChannel");
+ }
+ } catch(IOChannelError e) {
+ error("IOChannel: %s", e.message);
+ }
+ }
+
+ ~Device() {
+ /* restore old tty config */
+ Posix.tcsetattr(fd, Posix.TCSANOW, restoretio);
+
+ /* close file */
+ Posix.close(fd);
+
+ /* remove lock */
+ lockfile.delete();
+ }
+
+ private bool device_read(IOChannel gio, IOCondition cond) {
+ IOStatus ret;
+ string msg;
+ size_t len, term_char;
+
+ if((cond & IOCondition.HUP) == IOCondition.HUP)
+ error("Lost device");
+
+ try {
+ ret = gio.read_line(out msg, out len, out term_char);
+ msg = msg[0:(long)term_char];
+
+ if(msg.has_prefix("USER ") || msg.has_prefix("STOCK") || msg.has_prefix("AMOUNT ")) {
+ if(!check_code39_checksum(msg))
+ received_barcode("SCANNER RETURNED INCORRECT DATA");
+ else {/* remove checksum */
+ msg = msg[0:-1];
+ received_barcode(msg);
+ }
+ }
+ else
+ received_barcode(msg);
+ }
+ catch(IOChannelError e) {
+ stderr.printf("IOChannel Error: %s", e.message);
+ return false;
+ }
+ catch(ConvertError e) {
+ stderr.printf("Convert Error: %s", e.message);
+ return false;
+ }
+ return true;
+ }
+
+ private ssize_t write(void *buf, size_t count) {
+ ssize_t size = Posix.write(fd, buf, count);
+ return size;
+ }
+
+ 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) {
+ uint size = byterate/10 * duration;
+ var msg = new uint8[size];
+ Posix.memset(msg, 0xFF, msg.length);
+ this.write(msg, msg.length);
+ }
+}