tools fingerprint
authorkilian (dks-laptop) <ksaffran@dks.lu>
Sun, 10 Nov 2019 07:26:26 +0000 (08:26 +0100)
committerkilian (dks-laptop) <ksaffran@dks.lu>
Sun, 10 Nov 2019 07:26:26 +0000 (08:26 +0100)
CGI/api/fingerprint.cgi [new file with mode: 0644]
CGI/api/tools/fingerdelete.py [new file with mode: 0644]
CGI/api/tools/fingerenroll.py [new file with mode: 0644]
CGI/api/tools/fingerledoff.py [new file with mode: 0644]
CGI/api/tools/fingerledon.py [new file with mode: 0644]
CGI/api/tools/fingersearch.py [new file with mode: 0644]
CGI/api/tools/pyfingerprint2/__init__.py [new file with mode: 0644]
CGI/api/tools/pyfingerprint2/pyfingerprint.orig.py [new file with mode: 0644]
CGI/api/tools/pyfingerprint2/pyfingerprint.py [new file with mode: 0644]
syncdb.pl

diff --git a/CGI/api/fingerprint.cgi b/CGI/api/fingerprint.cgi
new file mode 100644 (file)
index 0000000..76c2d3f
--- /dev/null
@@ -0,0 +1,109 @@
+#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl
+use strict;
+use FindBin qw($Bin);
+# use lib ('CGI/api/lib/perl5');
+# use lib ('CGI/api/lib');
+use lib ($Bin.'/CGI/api/lib/perl5');
+use lib ($Bin.'/CGI/api/lib');
+use CGI;
+use CGI::Cookie;
+# use CGI::Carp qw/fatalsToBrowser/;
+use File::Basename;
+use JSON::PP;
+
+use dksconfig qw/$sitecfg/;
+use dksdb;
+my $cgi = new CGI();
+my $scriptpath = $cgi->url(-absolute => 1); 
+my $p = ();
+my @params = $cgi->param();
+foreach my $pe (@params){
+  $p->{$pe} = $cgi->param($pe);
+}
+my $html->{result} = ();
+# $p->{sid} = $cgi->cookie($sitecfg->{cookiename});
+# my $se = session->new();
+# my $sess = $se->getsession($p->{sid});
+if (exists($p->{fn}) ){
+  if (exists($p->{id_user})){
+    if (($p->{fn} eq "delete") || (($p->{fn} eq "renew"))){
+      my $sql = "select id,fingerpos from staff where id=".$p->{id_user}.";"; 
+      my $db = dksdb->new();
+      #$html->{result}->{sql} = $sql;
+      my @rdb = $db->query($sql);
+      if (scalar(@rdb) > 0){
+        my $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerdelete.py '.$rdb[0]->{fingerpos};
+        my $res = `$cmd`;
+        chomp($res);
+        if ($res eq ""){
+          my $sql = "update staff set fingerpos=null,fingerhash=null where id=".$p->{id_user}.";";
+          $html->{result}->{status} = "deleted";
+          if ($p->{fn} eq "renew"){
+            $p->{fn} = "new";  
+          }
+        }
+      }
+      
+    }
+    if ($p->{fn} eq "new"){
+      my $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerledon.py';
+      my $res = `$cmd`;
+      chomp($res);
+      if ($res eq ''){
+        $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerenroll.py';
+        my $res = `$cmd`;
+      }
+    
+    }elsif ($p->{fn} eq "check"){
+      my $cmd ='sudo /usr/bin/python '.dirname($0).'/tools/fingersearch.py'; 
+      my $res = `$cmd`;
+      chomp($res);
+      if ($res =~ /POS:.*HASH:/){
+        my ($pos,$hash) = $res =~  m/.*POS:(\d+);HASH:(.+)\s*$/;
+        #$html->{result}->{pos} = $pos;
+        #$html->{result}->{hash} = $hash;
+        if (length($pos) > 0 && length($hash) > 0){
+          my $sql = "select id,fingerpos,fingerhash from staff where id=".$p->{id_user}." and fingerpos=".$pos." and fingerhash='".$hash."';"; 
+          my $db = dksdb->new();
+          #$html->{result}->{sql} = $sql;
+          my @rdb = $db->query($sql);
+          if (scalar(@rdb) > 0 ){
+            $html->{result}->{status} ="OK";
+            #$html->{result}->{db} = \@rdb;
+            $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerledoff.py';
+            $res = `$cmd`;
+          }  
+        }
+        
+      } else {
+        $html->{result}->{status} = $res; 
+      }
+    }
+  }
+  elsif($p->{fn} eq "unload"){
+    my $cmd = 'ps ax | grep "tools/finger" | awk \'{ print \$ }\'';
+    my $res = `$cmd`;
+  }
+  elsif($p->{fn} eq "ledon"){
+    my $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerledon.py';
+    my $res = `$cmd`;
+    chomp($res);
+    if ($res eq ""){
+      $html->{result}->{status} = "ok";
+    } else {
+      $html->{result}->{status} = "error";
+    }
+  }
+  elsif($p->{fn} eq "ledoff"){
+    my $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerledoff.py';
+    my $res = `$cmd`;
+    chomp($res);
+    if ($res eq ""){
+      $html->{result}->{status} = "ok";
+    } else {
+      $html->{result}->{status} = "error";
+    }
+  }
+}
+print $cgi->header(-type=>"application/json", -charset => "utf-8");
+print JSON::PP::encode_json($html);
\ No newline at end of file
diff --git a/CGI/api/tools/fingerdelete.py b/CGI/api/tools/fingerdelete.py
new file mode 100644 (file)
index 0000000..ab3a325
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+PyFingerprint
+Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
+All rights reserved.
+
+"""
+import sys
+from pyfingerprint2.pyfingerprint import PyFingerprint
+if len(sys.argv) == 1:
+  print ('Error: No position!');
+  exit(1)
+
+## Deletes a finger from sensor
+##
+
+
+## Tries to initialize the sensor
+try:
+    f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000)
+
+    if ( f.verifyPassword() == False ):
+        raise ValueError('The given fingerprint sensor password is wrong!')
+
+except Exception as e:
+    print('The fingerprint sensor could not be initialized!')
+    print('Exception message: ' + str(e))
+    exit(1)
+
+## Gets some sensor information
+#print('Currently used templates: ' + str(f.getTemplateCount()) +'/'+ str(f.getStorageCapacity()))
+
+## Tries to delete the template of the finger
+try:
+    positionNumber = int(sys.argv[1])
+
+    if ( f.deleteTemplate(positionNumber) == True ):
+        True
+        #print('Template ' + str(positionNumber) +' deleted!')
+
+except Exception as e:
+    print('Operation failed!')
+    print('Exception message: ' + str(e))
+    exit(1)
diff --git a/CGI/api/tools/fingerenroll.py b/CGI/api/tools/fingerenroll.py
new file mode 100644 (file)
index 0000000..8319dc8
--- /dev/null
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+PyFingerprint
+Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
+All rights reserved.
+
+"""
+
+import time
+from pyfingerprint2.pyfingerprint import PyFingerprint
+
+
+## Enrolls new finger
+##
+
+## Tries to initialize the sensor
+try:
+    f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000)
+
+    if ( f.verifyPassword() == False ):
+        raise ValueError('The given fingerprint sensor password is wrong!')
+
+except Exception as e:
+    print('The fingerprint sensor could not be initialized!')
+    print('Exception message: ' + str(e))
+    exit(1)
+
+## Gets some sensor information
+print('Currently used templates: ' + str(f.getTemplateCount()) +'/'+ str(f.getStorageCapacity()))
+
+## Tries to enroll new finger
+try:
+    print('Waiting for finger...')
+
+    ## Wait that finger is read
+    while ( f.readImage() == False ):
+        pass
+
+    ## Converts read image to characteristics and stores it in charbuffer 1
+    f.convertImage(0x01)
+
+    ## Checks if finger is already enrolled
+    result = f.searchTemplate()
+    positionNumber = result[0]
+
+    if ( positionNumber >= 0 ):
+        print('Template already exists at position #' + str(positionNumber))
+        exit(0)
+
+    print('Remove finger...')
+    time.sleep(2)
+
+    print('Waiting for same finger again...')
+
+    ## Wait that finger is read again
+    while ( f.readImage() == False ):
+        pass
+
+    ## Converts read image to characteristics and stores it in charbuffer 2
+    f.convertImage(0x02)
+
+    ## Compares the charbuffers
+    if ( f.compareCharacteristics() == 0 ):
+        raise Exception('Fingers do not match')
+
+    ## Creates a template
+    f.createTemplate()
+
+    ## Saves template at new position number
+    positionNumber = f.storeTemplate()
+    print('Finger enrolled successfully!')
+    print('New template position #' + str(positionNumber))
+
+except Exception as e:
+    print('Operation failed!')
+    print('Exception message: ' + str(e))
+    exit(1)
diff --git a/CGI/api/tools/fingerledoff.py b/CGI/api/tools/fingerledoff.py
new file mode 100644 (file)
index 0000000..1eec425
--- /dev/null
@@ -0,0 +1,27 @@
+"""
+PyFingerprint
+Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
+All rights reserved.
+
+"""
+
+import time
+from pyfingerprint2.pyfingerprint import PyFingerprint
+
+
+## Enrolls new finger
+##
+
+## Tries to initialize the sensor
+try:
+    f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000)
+
+    if ( f.verifyPassword() == False ):
+        raise ValueError('The given fingerprint sensor password is wrong!')
+
+except Exception as e:
+    print('The fingerprint sensor could not be initialized!')
+    print('Exception message: ' + str(e))
+    exit(1)
+
+f.setLEDoff()
diff --git a/CGI/api/tools/fingerledon.py b/CGI/api/tools/fingerledon.py
new file mode 100644 (file)
index 0000000..8a08f7f
--- /dev/null
@@ -0,0 +1,27 @@
+"""
+PyFingerprint
+Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
+All rights reserved.
+
+"""
+
+import time
+from pyfingerprint2.pyfingerprint import PyFingerprint
+
+
+## Enrolls new finger
+##
+
+## Tries to initialize the sensor
+try:
+    f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000)
+
+    if ( f.verifyPassword() == False ):
+        raise ValueError('The given fingerprint sensor password is wrong!')
+
+except Exception as e:
+    print('The fingerprint sensor could not be initialized!')
+    print('Exception message: ' + str(e))
+    exit(1)
+
+f.setLEDon()
diff --git a/CGI/api/tools/fingersearch.py b/CGI/api/tools/fingersearch.py
new file mode 100644 (file)
index 0000000..be98fce
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+PyFingerprint
+Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
+All rights reserved.
+
+"""
+
+import hashlib
+from pyfingerprint2.pyfingerprint import PyFingerprint
+
+
+## Search for a finger
+##
+
+## Tries to initialize the sensor
+try:
+    f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000)
+
+    if ( f.verifyPassword() == False ):
+        raise ValueError('The given fingerprint sensor password is wrong!')
+
+except Exception as e:
+    print('The fingerprint sensor could not be initialized!')
+    print('Exception message: ' + str(e))
+    exit(1)
+
+## Gets some sensor information
+print('Currently used templates: ' + str(f.getTemplateCount()) +'/'+ str(f.getStorageCapacity()))
+
+## Tries to search the finger and calculate hash
+try:
+    print('Waiting for finger...')
+
+    ## Wait that finger is read
+    while ( f.readImage() == False ):
+        pass
+
+    ## Converts read image to characteristics and stores it in charbuffer 1
+    f.convertImage(0x01)
+
+    ## Searchs template
+    result = f.searchTemplate()
+
+    positionNumber = result[0]
+    accuracyScore = result[1]
+
+    if ( positionNumber == -1 ):
+        print('No match found!')
+        exit(0)
+    else:
+        print('Found template at position #' + str(positionNumber))
+        print('The accuracy score is: ' + str(accuracyScore))
+        ## Loads the found template to charbuffer 1
+        f.loadTemplate(positionNumber, 0x01)
+
+        ## Downloads the characteristics of template loaded in charbuffer 1
+        characterics = str(f.downloadCharacteristics(0x01)).encode('utf-8')
+
+        ## Hashes characteristics of template
+        #print('SHA-2 hash of template: ' + hashlib.sha256(characterics).hexdigest())
+        print('POS:' + str(positionNumber) + ';HASH:' + hashlib.sha256(characterics).hexdigest())
+
+except Exception as e:
+    print('Operation failed!')
+    print('Exception message: ' + str(e))
+    exit(1)
diff --git a/CGI/api/tools/pyfingerprint2/__init__.py b/CGI/api/tools/pyfingerprint2/__init__.py
new file mode 100644 (file)
index 0000000..4882220
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+PyFingerprint
+Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
+All rights reserved.
+
+"""
+
+__version__ = '1.5'
diff --git a/CGI/api/tools/pyfingerprint2/pyfingerprint.orig.py b/CGI/api/tools/pyfingerprint2/pyfingerprint.orig.py
new file mode 100644 (file)
index 0000000..af2f663
--- /dev/null
@@ -0,0 +1,1326 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+PyFingerprint
+Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
+All rights reserved.
+
+"""
+
+import os
+import serial
+from PIL import Image
+import struct
+
+
+## Baotou start byte
+FINGERPRINT_STARTCODE = 0xEF01
+
+## Packet identification
+##
+
+FINGERPRINT_COMMANDPACKET = 0x01
+
+FINGERPRINT_ACKPACKET = 0x07
+FINGERPRINT_DATAPACKET = 0x02
+FINGERPRINT_ENDDATAPACKET = 0x08
+
+## Instruction codes
+##
+
+FINGERPRINT_VERIFYPASSWORD = 0x13
+FINGERPRINT_SETPASSWORD = 0x12
+FINGERPRINT_SETADDRESS = 0x15
+FINGERPRINT_SETSYSTEMPARAMETER = 0x0E
+FINGERPRINT_GETSYSTEMPARAMETERS = 0x0F
+FINGERPRINT_TEMPLATEINDEX = 0x1F
+FINGERPRINT_TEMPLATECOUNT = 0x1D
+
+FINGERPRINT_READIMAGE = 0x01
+
+## Note: The documentation mean upload to host computer.
+FINGERPRINT_DOWNLOADIMAGE = 0x0A
+
+FINGERPRINT_CONVERTIMAGE = 0x02
+
+FINGERPRINT_CREATETEMPLATE = 0x05
+FINGERPRINT_STORETEMPLATE = 0x06
+FINGERPRINT_SEARCHTEMPLATE = 0x04
+FINGERPRINT_LOADTEMPLATE = 0x07
+FINGERPRINT_DELETETEMPLATE = 0x0C
+
+FINGERPRINT_CLEARDATABASE = 0x0D
+FINGERPRINT_GENERATERANDOMNUMBER = 0x14
+FINGERPRINT_COMPARECHARACTERISTICS = 0x03
+
+## Note: The documentation mean download from host computer.
+FINGERPRINT_UPLOADCHARACTERISTICS = 0x09
+
+## Note: The documentation mean upload to host computer.
+FINGERPRINT_DOWNLOADCHARACTERISTICS = 0x08
+
+## Packet reply confirmations
+##
+
+FINGERPRINT_OK = 0x00
+FINGERPRINT_ERROR_COMMUNICATION = 0x01
+
+FINGERPRINT_ERROR_WRONGPASSWORD = 0x13
+
+FINGERPRINT_ERROR_INVALIDREGISTER = 0x1A
+
+FINGERPRINT_ERROR_NOFINGER = 0x02
+FINGERPRINT_ERROR_READIMAGE = 0x03
+
+FINGERPRINT_ERROR_MESSYIMAGE = 0x06
+FINGERPRINT_ERROR_FEWFEATUREPOINTS = 0x07
+FINGERPRINT_ERROR_INVALIDIMAGE = 0x15
+
+FINGERPRINT_ERROR_CHARACTERISTICSMISMATCH = 0x0A
+
+FINGERPRINT_ERROR_INVALIDPOSITION = 0x0B
+FINGERPRINT_ERROR_FLASH = 0x18
+
+FINGERPRINT_ERROR_NOTEMPLATEFOUND = 0x09
+
+FINGERPRINT_ERROR_LOADTEMPLATE = 0x0C
+
+FINGERPRINT_ERROR_DELETETEMPLATE = 0x10
+
+FINGERPRINT_ERROR_CLEARDATABASE = 0x11
+
+FINGERPRINT_ERROR_NOTMATCHING = 0x08
+
+FINGERPRINT_ERROR_DOWNLOADIMAGE = 0x0F
+FINGERPRINT_ERROR_DOWNLOADCHARACTERISTICS = 0x0D
+
+## Unknown error codes
+##
+
+FINGERPRINT_ADDRCODE = 0x20
+FINGERPRINT_PASSVERIFY = 0x21
+
+FINGERPRINT_PACKETRESPONSEFAIL = 0x0E
+
+FINGERPRINT_ERROR_TIMEOUT = 0xFF
+FINGERPRINT_ERROR_BADPACKET = 0xFE
+
+
+class PyFingerprint(object):
+    """
+    A python written library for the ZhianTec ZFM-20 fingerprint sensor.
+
+    @attribute integer(4 bytes) __address
+    Address to connect to sensor.
+
+    @attribute integer(4 bytes) __password
+    Password to connect to sensor.
+
+    @attribute Serial __serial
+    UART serial connection via PySerial.
+    """
+    __address = None
+    __password = None
+    __serial = None
+
+    def __init__(self, port = '/dev/ttyUSB0', baudRate = 57600, address = 0xFFFFFFFF, password = 0x00000000):
+        """
+        Constructor
+
+        @param string port
+        @param integer baudRate
+        @param integer(4 bytes) address
+        @param integer(4 bytes) password
+        """
+
+        if ( os.path.exists(port) == False ):
+            raise ValueError('The fingerprint sensor port "' + port + '" was not found!')
+
+        if ( baudRate < 9600 or baudRate > 115200 or baudRate % 9600 != 0 ):
+            raise ValueError('The given baudrate is invalid!')
+
+        if ( address < 0x00000000 or address > 0xFFFFFFFF ):
+            raise ValueError('The given address is invalid!')
+
+        if ( password < 0x00000000 or password > 0xFFFFFFFF ):
+            raise ValueError('The given password is invalid!')
+
+        self.__address = address
+        self.__password = password
+
+        ## Initialize PySerial connection
+        self.__serial = serial.Serial(port = port, baudrate = baudRate, bytesize = serial.EIGHTBITS, timeout = 2)
+
+        if ( self.__serial.isOpen() == True ):
+            self.__serial.close()
+
+        self.__serial.open()
+
+    def __del__(self):
+        """
+        Destructor
+
+        """
+
+        ## Close connection if still established
+        if ( self.__serial is not None and self.__serial.isOpen() == True ):
+            self.__serial.close()
+
+    def __rightShift(self, n, x):
+        """
+        Shift a byte.
+
+        @param integer n
+        @param integer x
+        @return integer
+        """
+
+        return (n >> x & 0xFF)
+
+    def __leftShift(self, n, x):
+        """
+        Shift a byte.
+
+        @param integer n
+        @param integer x
+        @return integer
+        """
+
+        return (n << x)
+
+    def __bitAtPosition(self, n, p):
+        """
+        Get the bit of n at position p.
+
+        @param integer n
+        @param integer p
+        @return integer
+        """
+
+        ## A bitshift 2 ^ p
+        twoP = 1 << p
+
+        ## Binary AND composition (on both positions must be a 1)
+        ## This can only happen at position p
+        result = n & twoP
+        return int(result > 0)
+
+    def __byteToString(self, byte):
+        """
+        Converts a byte to string.
+
+        @param byte byte
+        @return string
+        """
+
+        return struct.pack('@B', byte)
+
+    def __stringToByte(self, string):
+        """
+        Convert one "string" byte (like '0xFF') to real integer byte (0xFF).
+
+        @param string string
+        @return byte
+        """
+
+        return struct.unpack('@B', string)[0]
+
+    def __writePacket(self, packetType, packetPayload):
+        """
+        Send a packet to fingerprint sensor.
+
+        @param integer(1 byte) packetType
+        @param tuple packetPayload
+
+        @return void
+        """
+
+        ## Write header (one byte at once)
+        self.__serial.write(self.__byteToString(self.__rightShift(FINGERPRINT_STARTCODE, 8)))
+        self.__serial.write(self.__byteToString(self.__rightShift(FINGERPRINT_STARTCODE, 0)))
+
+        self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 24)))
+        self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 16)))
+        self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 8)))
+        self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 0)))
+
+        self.__serial.write(self.__byteToString(packetType))
+
+        ## The packet length = package payload (n bytes) + checksum (2 bytes)
+        packetLength = len(packetPayload) + 2
+
+        self.__serial.write(self.__byteToString(self.__rightShift(packetLength, 8)))
+        self.__serial.write(self.__byteToString(self.__rightShift(packetLength, 0)))
+
+        ## The packet checksum = packet type (1 byte) + packet length (2 bytes) + payload (n bytes)
+        packetChecksum = packetType + self.__rightShift(packetLength, 8) + self.__rightShift(packetLength, 0)
+
+        ## Write payload
+        for i in range(0, len(packetPayload)):
+            self.__serial.write(self.__byteToString(packetPayload[i]))
+            packetChecksum += packetPayload[i]
+
+        ## Write checksum (2 bytes)
+        self.__serial.write(self.__byteToString(self.__rightShift(packetChecksum, 8)))
+        self.__serial.write(self.__byteToString(self.__rightShift(packetChecksum, 0)))
+
+    def __readPacket(self):
+        """
+        Receive a packet from fingerprint sensor.
+
+        Return a tuple that contain the following information:
+        0: integer(1 byte) The packet type.
+        1: integer(n bytes) The packet payload.
+
+        @return tuple
+        """
+
+        receivedPacketData = []
+        i = 0
+
+        while ( True ):
+
+            ## Read one byte
+            receivedFragment = self.__serial.read()
+
+            if ( len(receivedFragment) != 0 ):
+                receivedFragment = self.__stringToByte(receivedFragment)
+                ## print 'Received packet fragment = ' + hex(receivedFragment)
+
+            ## Insert byte if packet seems valid
+            receivedPacketData.insert(i, receivedFragment)
+            i += 1
+
+            ## Packet could be complete (the minimal packet size is 12 bytes)
+            if ( i >= 12 ):
+
+                ## Check the packet header
+                if ( receivedPacketData[0] != self.__rightShift(FINGERPRINT_STARTCODE, 8) or receivedPacketData[1] != self.__rightShift(FINGERPRINT_STARTCODE, 0) ):
+                    raise Exception('The received packet do not begin with a valid header!')
+
+                ## Calculate packet payload length (combine the 2 length bytes)
+                packetPayloadLength = self.__leftShift(receivedPacketData[7], 8)
+                packetPayloadLength = packetPayloadLength | self.__leftShift(receivedPacketData[8], 0)
+
+                ## Check if the packet is still fully received
+                ## Condition: index counter < packet payload length + packet frame
+                if ( i < packetPayloadLength + 9 ):
+                    continue
+
+                ## At this point the packet should be fully received
+
+                packetType = receivedPacketData[6]
+
+                ## Calculate checksum:
+                ## checksum = packet type (1 byte) + packet length (2 bytes) + packet payload (n bytes)
+                packetChecksum = packetType + receivedPacketData[7] + receivedPacketData[8]
+
+                packetPayload = []
+
+                ## Collect package payload (ignore the last 2 checksum bytes)
+                for j in range(9, 9 + packetPayloadLength - 2):
+                    packetPayload.append(receivedPacketData[j])
+                    packetChecksum += receivedPacketData[j]
+
+                ## Calculate full checksum of the 2 separate checksum bytes
+                receivedChecksum = self.__leftShift(receivedPacketData[i - 2], 8)
+                receivedChecksum = receivedChecksum | self.__leftShift(receivedPacketData[i - 1], 0)
+
+                if ( receivedChecksum != packetChecksum ):
+                    raise Exception('The received packet is corrupted (the checksum is wrong)!')
+
+                return (packetType, packetPayload)
+
+    def verifyPassword(self):
+        """
+        Verify password of the fingerprint sensor.
+
+        @return boolean
+        """
+
+        packetPayload = (
+            FINGERPRINT_VERIFYPASSWORD,
+            self.__rightShift(self.__password, 24),
+            self.__rightShift(self.__password, 16),
+            self.__rightShift(self.__password, 8),
+            self.__rightShift(self.__password, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Sensor password is correct
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ADDRCODE ):
+            raise Exception('The address is wrong')
+
+        ## DEBUG: Sensor password is wrong
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_WRONGPASSWORD ):
+            return False
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def setPassword(self, newPassword):
+        """
+        Set the password of the sensor.
+
+        @param integer(4 bytes) newPassword
+        @return boolean
+        """
+
+        ## Validate the password (maximum 4 bytes)
+        if ( newPassword < 0x00000000 or newPassword > 0xFFFFFFFF ):
+            raise ValueError('The given password is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_SETPASSWORD,
+            self.__rightShift(newPassword, 24),
+            self.__rightShift(newPassword, 16),
+            self.__rightShift(newPassword, 8),
+            self.__rightShift(newPassword, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Password set was successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            self.__password = newPassword
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def setAddress(self, newAddress):
+        """
+        Set the module address of the sensor.
+
+        @param integer(4 bytes) newAddress
+        @return boolean
+        """
+
+        ## Validate the address (maximum 4 bytes)
+        if ( newAddress < 0x00000000 or newAddress > 0xFFFFFFFF ):
+            raise ValueError('The given address is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_SETADDRESS,
+            self.__rightShift(newAddress, 24),
+            self.__rightShift(newAddress, 16),
+            self.__rightShift(newAddress, 8),
+            self.__rightShift(newAddress, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Address set was successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            self.__address = newAddress
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def setSystemParameter(self, parameterNumber, parameterValue):
+        """
+        Set a system parameter of the sensor.
+
+        @param integer(1 byte) parameterNumber
+        @param integer(1 byte) parameterValue
+        @return boolean
+        """
+
+        ## Validate the baudrate parameter
+        if ( parameterNumber == 4 ):
+
+            if ( parameterValue < 1 or parameterValue > 12 ):
+                raise ValueError('The given baudrate parameter is invalid!')
+
+        ## Validate the security level parameter
+        elif ( parameterNumber == 5 ):
+
+            if ( parameterValue < 1 or parameterValue > 5 ):
+                raise ValueError('The given security level parameter is invalid!')
+
+        ## Validate the package length parameter
+        elif ( parameterNumber == 6 ):
+
+            if ( parameterValue < 0 or parameterValue > 3 ):
+                raise ValueError('The given package length parameter is invalid!')
+
+        ## The parameter number is not valid
+        else:
+            raise ValueError('The given parameter number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_SETSYSTEMPARAMETER,
+            parameterNumber,
+            parameterValue,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Parameter set was successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDREGISTER ):
+            raise Exception('Invalid register number')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def getSystemParameters(self):
+        """
+        Get all available system information of the sensor.
+
+        Return a tuple that contain the following information:
+        0: integer(2 bytes) The status register.
+        1: integer(2 bytes) The system id.
+        2: integer(2 bytes) The storage capacity.
+        3: integer(2 bytes) The security level.
+        4: integer(4 bytes) The sensor address.
+        5: integer(2 bytes) The packet length.
+        6: integer(2 bytes) The baudrate.
+
+        @return tuple
+        """
+
+        packetPayload = (
+            FINGERPRINT_GETSYSTEMPARAMETERS,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Read successfully
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+
+            statusRegister     = self.__leftShift(receivedPacketPayload[1], 8) | self.__leftShift(receivedPacketPayload[2], 0)
+            systemID           = self.__leftShift(receivedPacketPayload[3], 8) | self.__leftShift(receivedPacketPayload[4], 0)
+            storageCapacity    = self.__leftShift(receivedPacketPayload[5], 8) | self.__leftShift(receivedPacketPayload[6], 0)
+            securityLevel      = self.__leftShift(receivedPacketPayload[7], 8) | self.__leftShift(receivedPacketPayload[8], 0)
+            deviceAddress      = ((receivedPacketPayload[9] << 8 | receivedPacketPayload[10]) << 8 | receivedPacketPayload[11]) << 8 | receivedPacketPayload[12] ## TODO
+            packetLength       = self.__leftShift(receivedPacketPayload[13], 8) | self.__leftShift(receivedPacketPayload[14], 0)
+            baudRate           = self.__leftShift(receivedPacketPayload[15], 8) | self.__leftShift(receivedPacketPayload[16], 0)
+
+            return (statusRegister, systemID, storageCapacity, securityLevel, deviceAddress, packetLength, baudRate)
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def getTemplateIndex(self, page):
+        """
+        Get a list of the template positions with usage indicator.
+
+        @param integer(1 byte) page
+        @return list
+        """
+
+        if ( page < 0 or page > 3 ):
+            raise ValueError('The given index page is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_TEMPLATEINDEX,
+            page,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Read index table successfully
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+
+            templateIndex = []
+
+            ## Contain the table page bytes (skip the first status byte)
+            pageElements = receivedPacketPayload[1:]
+
+            for pageElement in pageElements:
+                ## Test every bit (bit = template position is used indicator) of a table page element
+                for p in range(0, 7 + 1):
+                    positionIsUsed = (self.__bitAtPosition(pageElement, p) == 1)
+                    templateIndex.append(positionIsUsed)
+
+            return templateIndex
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def getTemplateCount(self):
+        """
+        Get the number of stored templates.
+
+        @return integer(2 bytes)
+        """
+
+        packetPayload = (
+            FINGERPRINT_TEMPLATECOUNT,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Read successfully
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            templateCount = self.__leftShift(receivedPacketPayload[1], 8)
+            templateCount = templateCount | self.__leftShift(receivedPacketPayload[2], 0)
+            return templateCount
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def readImage(self):
+        """
+        Read the image of a finger and stores it in ImageBuffer.
+
+        @return boolean
+        """
+
+        packetPayload = (
+            FINGERPRINT_READIMAGE,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Image read successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: No finger found
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_NOFINGER ):
+            return False
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_READIMAGE ):
+            raise Exception('Could not read image')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    ## TODO:
+    ## Implementation of uploadImage()
+
+    def downloadImage(self, imageDestination):
+        """
+        Download the image of a finger to host computer.
+
+        @param string imageDestination
+        @return void
+        """
+
+        destinationDirectory = os.path.dirname(imageDestination)
+
+        if ( os.access(destinationDirectory, os.W_OK) == False ):
+            raise ValueError('The given destination directory "' + destinationDirectory + '" is not writable!')
+
+        packetPayload = (
+            FINGERPRINT_DOWNLOADIMAGE,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+
+        ## Get first reply packet
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: The sensor will sent follow-up packets
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            pass
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_DOWNLOADIMAGE ):
+            raise Exception('Could not download image')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+        ## Initialize image library
+        resultImage = Image.new('L', (256, 288), 'white')
+        pixels = resultImage.load()
+
+        ## Y coordinate of current pixel
+        line = 0
+
+        ## Get follow-up data packets until the last data packet is received
+        while ( receivedPacketType != FINGERPRINT_ENDDATAPACKET ):
+
+            receivedPacket = self.__readPacket()
+
+            receivedPacketType = receivedPacket[0]
+            receivedPacketPayload = receivedPacket[1]
+
+            if ( receivedPacketType != FINGERPRINT_DATAPACKET and receivedPacketType != FINGERPRINT_ENDDATAPACKET ):
+                raise Exception('The received packet is no data packet!')
+
+            ## X coordinate of current pixel
+            x = 0
+
+            for i in range(0, len(receivedPacketPayload)):
+
+                ## Thanks to Danylo Esterman <soundcracker@gmail.com> for the "multiple with 17" improvement:
+
+                ## Draw left 4 Bits one byte of package
+                pixels[x, line] = (receivedPacketPayload[i] >> 4) * 17
+                x = x + 1
+
+                ## Draw right 4 Bits one byte of package
+                pixels[x, line] = (receivedPacketPayload[i] & 0b00001111) * 17
+                x = x + 1
+
+            line = line + 1
+
+        resultImage.save(imageDestination)
+
+    def convertImage(self, charBufferNumber = 0x01):
+        """
+        Convert the image in ImageBuffer to finger characteristics and store in CharBuffer1 or CharBuffer2.
+
+        @param integer(1 byte) charBufferNumber
+        @return boolean
+        """
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_CONVERTIMAGE,
+            charBufferNumber,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Image converted
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_MESSYIMAGE ):
+            raise Exception('The image is too messy')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_FEWFEATUREPOINTS ):
+            raise Exception('The image contains too few feature points')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDIMAGE ):
+            raise Exception('The image is invalid')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def createTemplate(self):
+        """
+        Combine the characteristics which are stored in CharBuffer1 and CharBuffer2 to a template.
+        The created template will be stored again in CharBuffer1 and CharBuffer2 as the same.
+
+        @return boolean
+        """
+
+        packetPayload = (
+            FINGERPRINT_CREATETEMPLATE,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Template created successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: The characteristics not matching
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_CHARACTERISTICSMISMATCH ):
+            return False
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def storeTemplate(self, positionNumber = -1, charBufferNumber = 0x01):
+        """
+        Save a template from the specified CharBuffer to the given position number.
+
+        @param integer(2 bytes) positionNumber
+        @param integer(1 byte) charBufferNumber
+        @return integer
+        """
+
+        ## Find a free index
+        if ( positionNumber == -1 ):
+            for page in range(0, 4):
+                ## Free index found?
+                if ( positionNumber >= 0 ):
+                    break
+
+                templateIndex = self.getTemplateIndex(page)
+
+                for i in range(0, len(templateIndex)):
+                    ## Index not used?
+                    if ( templateIndex[i] == False ):
+                        positionNumber = (len(templateIndex) * page) + i
+                        break
+
+        if ( positionNumber < 0x0000 or positionNumber >= self.getStorageCapacity() ):
+            raise ValueError('The given position number is invalid!')
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_STORETEMPLATE,
+            charBufferNumber,
+            self.__rightShift(positionNumber, 8),
+            self.__rightShift(positionNumber, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Template stored successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return positionNumber
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDPOSITION ):
+            raise Exception('Could not store template in that position')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_FLASH ):
+            raise Exception('Error writing to flash')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def searchTemplate(self):
+        """
+        Search the finger characteristics in CharBuffer in database.
+
+        Return a tuple that contain the following information:
+        0: integer(2 bytes) The position number of found template.
+        1: integer(2 bytes) The accuracy score of found template.
+
+        @return tuple
+        """
+
+        ## CharBuffer1 and CharBuffer2 are the same in this case
+        charBufferNumber = 0x01
+
+        ## Begin search at index 0
+        positionStart = 0x0000
+        templatesCount = self.getStorageCapacity()
+
+        packetPayload = (
+            FINGERPRINT_SEARCHTEMPLATE,
+            charBufferNumber,
+            self.__rightShift(positionStart, 8),
+            self.__rightShift(positionStart, 0),
+            self.__rightShift(templatesCount, 8),
+            self.__rightShift(templatesCount, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Found template
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+
+            positionNumber = self.__leftShift(receivedPacketPayload[1], 8)
+            positionNumber = positionNumber | self.__leftShift(receivedPacketPayload[2], 0)
+
+            accuracyScore = self.__leftShift(receivedPacketPayload[3], 8)
+            accuracyScore = accuracyScore | self.__leftShift(receivedPacketPayload[4], 0)
+
+            return (positionNumber, accuracyScore)
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: Did not found a matching template
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_NOTEMPLATEFOUND ):
+            return (-1, -1)
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def loadTemplate(self, positionNumber, charBufferNumber = 0x01):
+        """
+        Load an existing template specified by position number to specified CharBuffer.
+
+        @param integer(2 bytes) positionNumber
+        @param integer(1 byte) charBufferNumber
+        @return boolean
+        """
+
+        if ( positionNumber < 0x0000 or positionNumber >= self.getStorageCapacity() ):
+            raise ValueError('The given position number is invalid!')
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_LOADTEMPLATE,
+            charBufferNumber,
+            self.__rightShift(positionNumber, 8),
+            self.__rightShift(positionNumber, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Template loaded successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_LOADTEMPLATE ):
+            raise Exception('The template could not be read')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDPOSITION ):
+            raise Exception('Could not load template from that position')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def deleteTemplate(self, positionNumber, count = 1):
+        """
+        Delete templates from fingerprint database. Per default one.
+
+        @param integer(2 bytes) positionNumber
+        @param integer(2 bytes) count
+        @return boolean
+        """
+
+        capacity = self.getStorageCapacity()
+
+        if ( positionNumber < 0x0000 or positionNumber >= capacity ):
+            raise ValueError('The given position number is invalid!')
+
+        if ( count < 0x0000 or count > capacity - positionNumber ):
+            raise ValueError('The given count is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_DELETETEMPLATE,
+            self.__rightShift(positionNumber, 8),
+            self.__rightShift(positionNumber, 0),
+            self.__rightShift(count, 8),
+            self.__rightShift(count, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Template deleted successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDPOSITION ):
+            raise Exception('Invalid position')
+
+        ## DEBUG: Could not delete template
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_DELETETEMPLATE ):
+            return False
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def clearDatabase(self):
+        """
+        Clear the complete template database.
+
+        @return boolean
+        """
+
+        packetPayload = (
+            FINGERPRINT_CLEARDATABASE,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Database cleared successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: Could not clear database
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_CLEARDATABASE ):
+            return False
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def compareCharacteristics(self):
+        """
+        Compare the finger characteristics of CharBuffer1 with CharBuffer2 and return the accuracy score.
+
+        @return integer(2 bytes)
+        """
+
+        packetPayload = (
+            FINGERPRINT_COMPARECHARACTERISTICS,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Comparison successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            accuracyScore = self.__leftShift(receivedPacketPayload[1], 8)
+            accuracyScore = accuracyScore | self.__leftShift(receivedPacketPayload[2], 0)
+            return accuracyScore
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: The characteristics do not matching
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_NOTMATCHING ):
+            return 0
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def uploadCharacteristics(self, charBufferNumber = 0x01, characteristicsData = [0]):
+        """
+        Upload finger characteristics to CharBuffer1 or CharBuffer2.
+
+        @author: David Gilson <davgilson@live.fr>
+
+        @param integer(1 byte) charBufferNumber
+        @param integer(list) characteristicsData
+
+        @return boolean
+        Return true if everything is right.
+        """
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        if ( characteristicsData == [0] ):
+            raise ValueError('The characteristics data is required!')
+
+        maxPacketSize = self.getMaxPacketSize()
+
+        ## Upload command
+
+        packetPayload = (
+            FINGERPRINT_UPLOADCHARACTERISTICS,
+            charBufferNumber
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+
+        ## Get first reply packet
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: The sensor will sent follow-up packets
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            pass
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_PACKETRESPONSEFAIL ):
+            raise Exception('Could not upload characteristics')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+        ## Upload data packets
+        packetNbr = len(characteristicsData) / maxPacketSize
+
+        if ( packetNbr <= 1 ):
+            self.__writePacket(FINGERPRINT_ENDDATAPACKET, characteristicsData)
+        else:
+            i = 1
+            while ( i < packetNbr ):
+                lfrom = (i-1) * maxPacketSize
+                lto = lfrom + maxPacketSize
+                self.__writePacket(FINGERPRINT_DATAPACKET, characteristicsData[lfrom:lto])
+                i += 1
+
+            lfrom = (i-1) * maxPacketSize
+            lto = lfrom + maxPacketSize
+            self.__writePacket(FINGERPRINT_ENDDATAPACKET, characteristicsData[lfrom:lto])
+
+        ## Verify uploaded characteristics
+        characterics = self.downloadCharacteristics(charBufferNumber)
+        return (characterics == characteristicsData)
+
+    def getMaxPacketSize(self):
+        """
+        Get the maximum allowed size of packet by sensor.
+
+        @author: David Gilson <davgilson@live.fr>
+
+        @return int
+        Return the max size. Default 32 bytes.
+        """
+
+        packetMaxSizeType = self.getSystemParameters()[5]
+
+        if (packetMaxSizeType == 1):
+            return 64
+        elif (packetMaxSizeType == 2):
+            return 128
+        elif (packetMaxSizeType == 3):
+            return 256
+        else:
+            return 32
+
+    def getStorageCapacity(self):
+        """
+        Get the sensor storage capacity.
+
+        @return int
+        The storage capacity.
+        """
+
+        return self.getSystemParameters()[2]
+
+    def generateRandomNumber(self):
+        """
+        Generate a random 32-bit decimal number.
+
+        @author: Philipp Meisberger <team@pm-codeworks.de>
+
+        @return int
+        The generated random number
+        """
+        packetPayload = (
+            FINGERPRINT_GENERATERANDOMNUMBER,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            pass
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+        number = 0
+        number = number | self.__leftShift(receivedPacketPayload[1], 24)
+        number = number | self.__leftShift(receivedPacketPayload[2], 16)
+        number = number | self.__leftShift(receivedPacketPayload[3], 8)
+        number = number | self.__leftShift(receivedPacketPayload[4], 0)
+        return number
+
+    def downloadCharacteristics(self, charBufferNumber = 0x01):
+        """
+        Download the finger characteristics of CharBuffer1 or CharBuffer2.
+
+        @param integer(1 byte) charBufferNumber
+
+        @return list
+        Return a list that contains 512 integer(1 byte) elements of the characteristic.
+        """
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_DOWNLOADCHARACTERISTICS,
+            charBufferNumber,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+
+        ## Get first reply packet
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: The sensor will sent follow-up packets
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            pass
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_DOWNLOADCHARACTERISTICS ):
+            raise Exception('Could not download characteristics')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+        completePayload = []
+
+        ## Get follow-up data packets until the last data packet is received
+        while ( receivedPacketType != FINGERPRINT_ENDDATAPACKET ):
+
+            receivedPacket = self.__readPacket()
+
+            receivedPacketType = receivedPacket[0]
+            receivedPacketPayload = receivedPacket[1]
+
+            if ( receivedPacketType != FINGERPRINT_DATAPACKET and receivedPacketType != FINGERPRINT_ENDDATAPACKET ):
+                raise Exception('The received packet is no data packet!')
+
+            for i in range(0, len(receivedPacketPayload)):
+                completePayload.append(receivedPacketPayload[i])
+
+        return completePayload
diff --git a/CGI/api/tools/pyfingerprint2/pyfingerprint.py b/CGI/api/tools/pyfingerprint2/pyfingerprint.py
new file mode 100644 (file)
index 0000000..f5e8d19
--- /dev/null
@@ -0,0 +1,1358 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+PyFingerprint
+Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
+All rights reserved.
+
+"""
+
+import os
+import serial
+from PIL import Image
+import struct
+
+
+## Baotou start byte
+FINGERPRINT_STARTCODE = 0xEF01
+
+## Packet identification
+##
+
+FINGERPRINT_COMMANDPACKET = 0x01
+
+FINGERPRINT_ACKPACKET = 0x07
+FINGERPRINT_DATAPACKET = 0x02
+FINGERPRINT_ENDDATAPACKET = 0x08
+
+## Instruction codes
+##
+
+FINGERPRINT_VERIFYPASSWORD = 0x13
+FINGERPRINT_SETPASSWORD = 0x12
+FINGERPRINT_SETADDRESS = 0x15
+FINGERPRINT_SETSYSTEMPARAMETER = 0x0E
+FINGERPRINT_GETSYSTEMPARAMETERS = 0x0F
+FINGERPRINT_TEMPLATEINDEX = 0x1F
+FINGERPRINT_TEMPLATECOUNT = 0x1D
+
+FINGERPRINT_READIMAGE = 0x01
+
+## Note: The documentation mean upload to host computer.
+FINGERPRINT_DOWNLOADIMAGE = 0x0A
+
+FINGERPRINT_CONVERTIMAGE = 0x02
+
+FINGERPRINT_CREATETEMPLATE = 0x05
+FINGERPRINT_STORETEMPLATE = 0x06
+FINGERPRINT_SEARCHTEMPLATE = 0x04
+FINGERPRINT_LOADTEMPLATE = 0x07
+FINGERPRINT_DELETETEMPLATE = 0x0C
+
+FINGERPRINT_CLEARDATABASE = 0x0D
+FINGERPRINT_GENERATERANDOMNUMBER = 0x14
+FINGERPRINT_COMPARECHARACTERISTICS = 0x03
+
+## Note: The documentation mean download from host computer.
+FINGERPRINT_UPLOADCHARACTERISTICS = 0x09
+
+## Note: The documentation mean upload to host computer.
+FINGERPRINT_DOWNLOADCHARACTERISTICS = 0x08
+## LED 
+FINGERPRINT_LEDON = 0x50
+FINGERPRINT_LEDOFF = 0x51
+## Packet reply confirmations
+##
+
+FINGERPRINT_OK = 0x00
+FINGERPRINT_ERROR_COMMUNICATION = 0x01
+
+FINGERPRINT_ERROR_WRONGPASSWORD = 0x13
+
+FINGERPRINT_ERROR_INVALIDREGISTER = 0x1A
+
+FINGERPRINT_ERROR_NOFINGER = 0x02
+FINGERPRINT_ERROR_READIMAGE = 0x03
+
+FINGERPRINT_ERROR_MESSYIMAGE = 0x06
+FINGERPRINT_ERROR_FEWFEATUREPOINTS = 0x07
+FINGERPRINT_ERROR_INVALIDIMAGE = 0x15
+
+FINGERPRINT_ERROR_CHARACTERISTICSMISMATCH = 0x0A
+
+FINGERPRINT_ERROR_INVALIDPOSITION = 0x0B
+FINGERPRINT_ERROR_FLASH = 0x18
+
+FINGERPRINT_ERROR_NOTEMPLATEFOUND = 0x09
+
+FINGERPRINT_ERROR_LOADTEMPLATE = 0x0C
+
+FINGERPRINT_ERROR_DELETETEMPLATE = 0x10
+
+FINGERPRINT_ERROR_CLEARDATABASE = 0x11
+
+FINGERPRINT_ERROR_NOTMATCHING = 0x08
+
+FINGERPRINT_ERROR_DOWNLOADIMAGE = 0x0F
+FINGERPRINT_ERROR_DOWNLOADCHARACTERISTICS = 0x0D
+
+## Unknown error codes
+##
+
+FINGERPRINT_ADDRCODE = 0x20
+FINGERPRINT_PASSVERIFY = 0x21
+
+FINGERPRINT_PACKETRESPONSEFAIL = 0x0E
+
+FINGERPRINT_ERROR_TIMEOUT = 0xFF
+FINGERPRINT_ERROR_BADPACKET = 0xFE
+
+
+class PyFingerprint(object):
+    """
+    A python written library for the ZhianTec ZFM-20 fingerprint sensor.
+
+    @attribute integer(4 bytes) __address
+    Address to connect to sensor.
+
+    @attribute integer(4 bytes) __password
+    Password to connect to sensor.
+
+    @attribute Serial __serial
+    UART serial connection via PySerial.
+    """
+    __address = None
+    __password = None
+    __serial = None
+
+    def __init__(self, port = '/dev/ttyUSB0', baudRate = 57600, address = 0xFFFFFFFF, password = 0x00000000):
+        """
+        Constructor
+
+        @param string port
+        @param integer baudRate
+        @param integer(4 bytes) address
+        @param integer(4 bytes) password
+        """
+
+        if ( os.path.exists(port) == False ):
+            raise ValueError('The fingerprint sensor port "' + port + '" was not found!')
+
+        if ( baudRate < 9600 or baudRate > 115200 or baudRate % 9600 != 0 ):
+            raise ValueError('The given baudrate is invalid!')
+
+        if ( address < 0x00000000 or address > 0xFFFFFFFF ):
+            raise ValueError('The given address is invalid!')
+
+        if ( password < 0x00000000 or password > 0xFFFFFFFF ):
+            raise ValueError('The given password is invalid!')
+
+        self.__address = address
+        self.__password = password
+
+        ## Initialize PySerial connection
+        self.__serial = serial.Serial(port = port, baudrate = baudRate, bytesize = serial.EIGHTBITS, timeout = 2)
+
+        if ( self.__serial.isOpen() == True ):
+            self.__serial.close()
+
+        self.__serial.open()
+
+    def __del__(self):
+        """
+        Destructor
+
+        """
+
+        ## Close connection if still established
+        if ( self.__serial is not None and self.__serial.isOpen() == True ):
+            self.__serial.close()
+
+    def __rightShift(self, n, x):
+        """
+        Shift a byte.
+
+        @param integer n
+        @param integer x
+        @return integer
+        """
+
+        return (n >> x & 0xFF)
+
+    def __leftShift(self, n, x):
+        """
+        Shift a byte.
+
+        @param integer n
+        @param integer x
+        @return integer
+        """
+
+        return (n << x)
+
+    def __bitAtPosition(self, n, p):
+        """
+        Get the bit of n at position p.
+
+        @param integer n
+        @param integer p
+        @return integer
+        """
+
+        ## A bitshift 2 ^ p
+        twoP = 1 << p
+
+        ## Binary AND composition (on both positions must be a 1)
+        ## This can only happen at position p
+        result = n & twoP
+        return int(result > 0)
+
+    def __byteToString(self, byte):
+        """
+        Converts a byte to string.
+
+        @param byte byte
+        @return string
+        """
+
+        return struct.pack('@B', byte)
+
+    def __stringToByte(self, string):
+        """
+        Convert one "string" byte (like '0xFF') to real integer byte (0xFF).
+
+        @param string string
+        @return byte
+        """
+
+        return struct.unpack('@B', string)[0]
+
+    def __writePacket(self, packetType, packetPayload):
+        """
+        Send a packet to fingerprint sensor.
+
+        @param integer(1 byte) packetType
+        @param tuple packetPayload
+
+        @return void
+        """
+
+        ## Write header (one byte at once)
+        self.__serial.write(self.__byteToString(self.__rightShift(FINGERPRINT_STARTCODE, 8)))
+        self.__serial.write(self.__byteToString(self.__rightShift(FINGERPRINT_STARTCODE, 0)))
+
+        self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 24)))
+        self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 16)))
+        self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 8)))
+        self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 0)))
+
+        self.__serial.write(self.__byteToString(packetType))
+
+        ## The packet length = package payload (n bytes) + checksum (2 bytes)
+        packetLength = len(packetPayload) + 2
+
+        self.__serial.write(self.__byteToString(self.__rightShift(packetLength, 8)))
+        self.__serial.write(self.__byteToString(self.__rightShift(packetLength, 0)))
+
+        ## The packet checksum = packet type (1 byte) + packet length (2 bytes) + payload (n bytes)
+        packetChecksum = packetType + self.__rightShift(packetLength, 8) + self.__rightShift(packetLength, 0)
+
+        ## Write payload
+        for i in range(0, len(packetPayload)):
+            self.__serial.write(self.__byteToString(packetPayload[i]))
+            packetChecksum += packetPayload[i]
+
+        ## Write checksum (2 bytes)
+        self.__serial.write(self.__byteToString(self.__rightShift(packetChecksum, 8)))
+        self.__serial.write(self.__byteToString(self.__rightShift(packetChecksum, 0)))
+
+    def __readPacket(self):
+        """
+        Receive a packet from fingerprint sensor.
+
+        Return a tuple that contain the following information:
+        0: integer(1 byte) The packet type.
+        1: integer(n bytes) The packet payload.
+
+        @return tuple
+        """
+
+        receivedPacketData = []
+        i = 0
+
+        while ( True ):
+
+            ## Read one byte
+            receivedFragment = self.__serial.read()
+
+            if ( len(receivedFragment) != 0 ):
+                receivedFragment = self.__stringToByte(receivedFragment)
+                ## print 'Received packet fragment = ' + hex(receivedFragment)
+
+            ## Insert byte if packet seems valid
+            receivedPacketData.insert(i, receivedFragment)
+            i += 1
+
+            ## Packet could be complete (the minimal packet size is 12 bytes)
+            if ( i >= 12 ):
+
+                ## Check the packet header
+                if ( receivedPacketData[0] != self.__rightShift(FINGERPRINT_STARTCODE, 8) or receivedPacketData[1] != self.__rightShift(FINGERPRINT_STARTCODE, 0) ):
+                    raise Exception('The received packet do not begin with a valid header!')
+
+                ## Calculate packet payload length (combine the 2 length bytes)
+                packetPayloadLength = self.__leftShift(receivedPacketData[7], 8)
+                packetPayloadLength = packetPayloadLength | self.__leftShift(receivedPacketData[8], 0)
+
+                ## Check if the packet is still fully received
+                ## Condition: index counter < packet payload length + packet frame
+                if ( i < packetPayloadLength + 9 ):
+                    continue
+
+                ## At this point the packet should be fully received
+
+                packetType = receivedPacketData[6]
+
+                ## Calculate checksum:
+                ## checksum = packet type (1 byte) + packet length (2 bytes) + packet payload (n bytes)
+                packetChecksum = packetType + receivedPacketData[7] + receivedPacketData[8]
+
+                packetPayload = []
+
+                ## Collect package payload (ignore the last 2 checksum bytes)
+                for j in range(9, 9 + packetPayloadLength - 2):
+                    packetPayload.append(receivedPacketData[j])
+                    packetChecksum += receivedPacketData[j]
+
+                ## Calculate full checksum of the 2 separate checksum bytes
+                receivedChecksum = self.__leftShift(receivedPacketData[i - 2], 8)
+                receivedChecksum = receivedChecksum | self.__leftShift(receivedPacketData[i - 1], 0)
+
+                if ( receivedChecksum != packetChecksum ):
+                    raise Exception('The received packet is corrupted (the checksum is wrong)!')
+
+                return (packetType, packetPayload)
+
+    def verifyPassword(self):
+        """
+        Verify password of the fingerprint sensor.
+
+        @return boolean
+        """
+
+        packetPayload = (
+            FINGERPRINT_VERIFYPASSWORD,
+            self.__rightShift(self.__password, 24),
+            self.__rightShift(self.__password, 16),
+            self.__rightShift(self.__password, 8),
+            self.__rightShift(self.__password, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Sensor password is correct
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ADDRCODE ):
+            raise Exception('The address is wrong')
+
+        ## DEBUG: Sensor password is wrong
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_WRONGPASSWORD ):
+            return False
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def setPassword(self, newPassword):
+        """
+        Set the password of the sensor.
+
+        @param integer(4 bytes) newPassword
+        @return boolean
+        """
+
+        ## Validate the password (maximum 4 bytes)
+        if ( newPassword < 0x00000000 or newPassword > 0xFFFFFFFF ):
+            raise ValueError('The given password is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_SETPASSWORD,
+            self.__rightShift(newPassword, 24),
+            self.__rightShift(newPassword, 16),
+            self.__rightShift(newPassword, 8),
+            self.__rightShift(newPassword, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Password set was successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            self.__password = newPassword
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def setAddress(self, newAddress):
+        """
+        Set the module address of the sensor.
+
+        @param integer(4 bytes) newAddress
+        @return boolean
+        """
+
+        ## Validate the address (maximum 4 bytes)
+        if ( newAddress < 0x00000000 or newAddress > 0xFFFFFFFF ):
+            raise ValueError('The given address is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_SETADDRESS,
+            self.__rightShift(newAddress, 24),
+            self.__rightShift(newAddress, 16),
+            self.__rightShift(newAddress, 8),
+            self.__rightShift(newAddress, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Address set was successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            self.__address = newAddress
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def setSystemParameter(self, parameterNumber, parameterValue):
+        """
+        Set a system parameter of the sensor.
+
+        @param integer(1 byte) parameterNumber
+        @param integer(1 byte) parameterValue
+        @return boolean
+        """
+
+        ## Validate the baudrate parameter
+        if ( parameterNumber == 4 ):
+
+            if ( parameterValue < 1 or parameterValue > 12 ):
+                raise ValueError('The given baudrate parameter is invalid!')
+
+        ## Validate the security level parameter
+        elif ( parameterNumber == 5 ):
+
+            if ( parameterValue < 1 or parameterValue > 5 ):
+                raise ValueError('The given security level parameter is invalid!')
+
+        ## Validate the package length parameter
+        elif ( parameterNumber == 6 ):
+
+            if ( parameterValue < 0 or parameterValue > 3 ):
+                raise ValueError('The given package length parameter is invalid!')
+
+        ## The parameter number is not valid
+        else:
+            raise ValueError('The given parameter number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_SETSYSTEMPARAMETER,
+            parameterNumber,
+            parameterValue,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Parameter set was successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDREGISTER ):
+            raise Exception('Invalid register number')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+    
+      
+    def getSystemParameters(self):
+        """
+        Get all available system information of the sensor.
+
+        Return a tuple that contain the following information:
+        0: integer(2 bytes) The status register.
+        1: integer(2 bytes) The system id.
+        2: integer(2 bytes) The storage capacity.
+        3: integer(2 bytes) The security level.
+        4: integer(4 bytes) The sensor address.
+        5: integer(2 bytes) The packet length.
+        6: integer(2 bytes) The baudrate.
+
+        @return tuple
+        """
+
+        packetPayload = (
+            FINGERPRINT_GETSYSTEMPARAMETERS,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Read successfully
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+
+            statusRegister     = self.__leftShift(receivedPacketPayload[1], 8) | self.__leftShift(receivedPacketPayload[2], 0)
+            systemID           = self.__leftShift(receivedPacketPayload[3], 8) | self.__leftShift(receivedPacketPayload[4], 0)
+            storageCapacity    = self.__leftShift(receivedPacketPayload[5], 8) | self.__leftShift(receivedPacketPayload[6], 0)
+            securityLevel      = self.__leftShift(receivedPacketPayload[7], 8) | self.__leftShift(receivedPacketPayload[8], 0)
+            deviceAddress      = ((receivedPacketPayload[9] << 8 | receivedPacketPayload[10]) << 8 | receivedPacketPayload[11]) << 8 | receivedPacketPayload[12] ## TODO
+            packetLength       = self.__leftShift(receivedPacketPayload[13], 8) | self.__leftShift(receivedPacketPayload[14], 0)
+            baudRate           = self.__leftShift(receivedPacketPayload[15], 8) | self.__leftShift(receivedPacketPayload[16], 0)
+
+            return (statusRegister, systemID, storageCapacity, securityLevel, deviceAddress, packetLength, baudRate)
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def getTemplateIndex(self, page):
+        """
+        Get a list of the template positions with usage indicator.
+
+        @param integer(1 byte) page
+        @return list
+        """
+
+        if ( page < 0 or page > 3 ):
+            raise ValueError('The given index page is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_TEMPLATEINDEX,
+            page,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Read index table successfully
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+
+            templateIndex = []
+
+            ## Contain the table page bytes (skip the first status byte)
+            pageElements = receivedPacketPayload[1:]
+
+            for pageElement in pageElements:
+                ## Test every bit (bit = template position is used indicator) of a table page element
+                for p in range(0, 7 + 1):
+                    positionIsUsed = (self.__bitAtPosition(pageElement, p) == 1)
+                    templateIndex.append(positionIsUsed)
+
+            return templateIndex
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def getTemplateCount(self):
+        """
+        Get the number of stored templates.
+
+        @return integer(2 bytes)
+        """
+
+        packetPayload = (
+            FINGERPRINT_TEMPLATECOUNT,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Read successfully
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            templateCount = self.__leftShift(receivedPacketPayload[1], 8)
+            templateCount = templateCount | self.__leftShift(receivedPacketPayload[2], 0)
+            return templateCount
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def readImage(self):
+        """
+        Read the image of a finger and stores it in ImageBuffer.
+
+        @return boolean
+        """
+
+        packetPayload = (
+            FINGERPRINT_READIMAGE,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Image read successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: No finger found
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_NOFINGER ):
+            return False
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_READIMAGE ):
+            raise Exception('Could not read image')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    ## TODO:
+    ## Implementation of uploadImage()
+    def setLEDoff(self):
+        packetPayload = (
+            FINGERPRINT_LEDOFF,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+
+        ## Get first reply packet
+        receivedPacket = self.__readPacket()
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+    def setLEDon(self):
+        packetPayload = (
+            FINGERPRINT_LEDON,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+
+        ## Get first reply packet
+        receivedPacket = self.__readPacket()
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+    def downloadImage(self, imageDestination):
+        """
+        Download the image of a finger to host computer.
+
+        @param string imageDestination
+        @return void
+        """
+
+        destinationDirectory = os.path.dirname(imageDestination)
+
+        if ( os.access(destinationDirectory, os.W_OK) == False ):
+            raise ValueError('The given destination directory "' + destinationDirectory + '" is not writable!')
+
+        packetPayload = (
+            FINGERPRINT_DOWNLOADIMAGE,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+
+        ## Get first reply packet
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: The sensor will sent follow-up packets
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            pass
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_DOWNLOADIMAGE ):
+            raise Exception('Could not download image')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+        ## Initialize image library
+        resultImage = Image.new('L', (256, 288), 'white')
+        pixels = resultImage.load()
+
+        ## Y coordinate of current pixel
+        line = 0
+
+        ## Get follow-up data packets until the last data packet is received
+        while ( receivedPacketType != FINGERPRINT_ENDDATAPACKET ):
+
+            receivedPacket = self.__readPacket()
+
+            receivedPacketType = receivedPacket[0]
+            receivedPacketPayload = receivedPacket[1]
+
+            if ( receivedPacketType != FINGERPRINT_DATAPACKET and receivedPacketType != FINGERPRINT_ENDDATAPACKET ):
+                raise Exception('The received packet is no data packet!')
+
+            ## X coordinate of current pixel
+            x = 0
+
+            for i in range(0, len(receivedPacketPayload)):
+
+                ## Thanks to Danylo Esterman <soundcracker@gmail.com> for the "multiple with 17" improvement:
+
+                ## Draw left 4 Bits one byte of package
+                pixels[x, line] = (receivedPacketPayload[i] >> 4) * 17
+                x = x + 1
+
+                ## Draw right 4 Bits one byte of package
+                pixels[x, line] = (receivedPacketPayload[i] & 0b00001111) * 17
+                x = x + 1
+
+            line = line + 1
+
+        resultImage.save(imageDestination)
+
+    def convertImage(self, charBufferNumber = 0x01):
+        """
+        Convert the image in ImageBuffer to finger characteristics and store in CharBuffer1 or CharBuffer2.
+
+        @param integer(1 byte) charBufferNumber
+        @return boolean
+        """
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_CONVERTIMAGE,
+            charBufferNumber,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Image converted
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_MESSYIMAGE ):
+            raise Exception('The image is too messy')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_FEWFEATUREPOINTS ):
+            raise Exception('The image contains too few feature points')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDIMAGE ):
+            raise Exception('The image is invalid')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def createTemplate(self):
+        """
+        Combine the characteristics which are stored in CharBuffer1 and CharBuffer2 to a template.
+        The created template will be stored again in CharBuffer1 and CharBuffer2 as the same.
+
+        @return boolean
+        """
+
+        packetPayload = (
+            FINGERPRINT_CREATETEMPLATE,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Template created successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: The characteristics not matching
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_CHARACTERISTICSMISMATCH ):
+            return False
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def storeTemplate(self, positionNumber = -1, charBufferNumber = 0x01):
+        """
+        Save a template from the specified CharBuffer to the given position number.
+
+        @param integer(2 bytes) positionNumber
+        @param integer(1 byte) charBufferNumber
+        @return integer
+        """
+
+        ## Find a free index
+        if ( positionNumber == -1 ):
+            for page in range(0, 4):
+                ## Free index found?
+                if ( positionNumber >= 0 ):
+                    break
+
+                templateIndex = self.getTemplateIndex(page)
+
+                for i in range(0, len(templateIndex)):
+                    ## Index not used?
+                    if ( templateIndex[i] == False ):
+                        positionNumber = (len(templateIndex) * page) + i
+                        break
+
+        if ( positionNumber < 0x0000 or positionNumber >= self.getStorageCapacity() ):
+            raise ValueError('The given position number is invalid!')
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_STORETEMPLATE,
+            charBufferNumber,
+            self.__rightShift(positionNumber, 8),
+            self.__rightShift(positionNumber, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Template stored successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return positionNumber
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDPOSITION ):
+            raise Exception('Could not store template in that position')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_FLASH ):
+            raise Exception('Error writing to flash')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def searchTemplate(self):
+        """
+        Search the finger characteristics in CharBuffer in database.
+
+        Return a tuple that contain the following information:
+        0: integer(2 bytes) The position number of found template.
+        1: integer(2 bytes) The accuracy score of found template.
+
+        @return tuple
+        """
+
+        ## CharBuffer1 and CharBuffer2 are the same in this case
+        charBufferNumber = 0x01
+
+        ## Begin search at index 0
+        positionStart = 0x0000
+        templatesCount = self.getStorageCapacity()
+
+        packetPayload = (
+            FINGERPRINT_SEARCHTEMPLATE,
+            charBufferNumber,
+            self.__rightShift(positionStart, 8),
+            self.__rightShift(positionStart, 0),
+            self.__rightShift(templatesCount, 8),
+            self.__rightShift(templatesCount, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Found template
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+
+            positionNumber = self.__leftShift(receivedPacketPayload[1], 8)
+            positionNumber = positionNumber | self.__leftShift(receivedPacketPayload[2], 0)
+
+            accuracyScore = self.__leftShift(receivedPacketPayload[3], 8)
+            accuracyScore = accuracyScore | self.__leftShift(receivedPacketPayload[4], 0)
+
+            return (positionNumber, accuracyScore)
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: Did not found a matching template
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_NOTEMPLATEFOUND ):
+            return (-1, -1)
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def loadTemplate(self, positionNumber, charBufferNumber = 0x01):
+        """
+        Load an existing template specified by position number to specified CharBuffer.
+
+        @param integer(2 bytes) positionNumber
+        @param integer(1 byte) charBufferNumber
+        @return boolean
+        """
+
+        if ( positionNumber < 0x0000 or positionNumber >= self.getStorageCapacity() ):
+            raise ValueError('The given position number is invalid!')
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_LOADTEMPLATE,
+            charBufferNumber,
+            self.__rightShift(positionNumber, 8),
+            self.__rightShift(positionNumber, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Template loaded successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_LOADTEMPLATE ):
+            raise Exception('The template could not be read')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDPOSITION ):
+            raise Exception('Could not load template from that position')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def deleteTemplate(self, positionNumber, count = 1):
+        """
+        Delete templates from fingerprint database. Per default one.
+
+        @param integer(2 bytes) positionNumber
+        @param integer(2 bytes) count
+        @return boolean
+        """
+
+        capacity = self.getStorageCapacity()
+
+        if ( positionNumber < 0x0000 or positionNumber >= capacity ):
+            raise ValueError('The given position number is invalid!')
+
+        if ( count < 0x0000 or count > capacity - positionNumber ):
+            raise ValueError('The given count is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_DELETETEMPLATE,
+            self.__rightShift(positionNumber, 8),
+            self.__rightShift(positionNumber, 0),
+            self.__rightShift(count, 8),
+            self.__rightShift(count, 0),
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Template deleted successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDPOSITION ):
+            raise Exception('Invalid position')
+
+        ## DEBUG: Could not delete template
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_DELETETEMPLATE ):
+            return False
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def clearDatabase(self):
+        """
+        Clear the complete template database.
+
+        @return boolean
+        """
+
+        packetPayload = (
+            FINGERPRINT_CLEARDATABASE,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Database cleared successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            return True
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: Could not clear database
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_CLEARDATABASE ):
+            return False
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def compareCharacteristics(self):
+        """
+        Compare the finger characteristics of CharBuffer1 with CharBuffer2 and return the accuracy score.
+
+        @return integer(2 bytes)
+        """
+
+        packetPayload = (
+            FINGERPRINT_COMPARECHARACTERISTICS,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: Comparison successful
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            accuracyScore = self.__leftShift(receivedPacketPayload[1], 8)
+            accuracyScore = accuracyScore | self.__leftShift(receivedPacketPayload[2], 0)
+            return accuracyScore
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        ## DEBUG: The characteristics do not matching
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_NOTMATCHING ):
+            return 0
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+    def uploadCharacteristics(self, charBufferNumber = 0x01, characteristicsData = [0]):
+        """
+        Upload finger characteristics to CharBuffer1 or CharBuffer2.
+
+        @author: David Gilson <davgilson@live.fr>
+
+        @param integer(1 byte) charBufferNumber
+        @param integer(list) characteristicsData
+
+        @return boolean
+        Return true if everything is right.
+        """
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        if ( characteristicsData == [0] ):
+            raise ValueError('The characteristics data is required!')
+
+        maxPacketSize = self.getMaxPacketSize()
+
+        ## Upload command
+
+        packetPayload = (
+            FINGERPRINT_UPLOADCHARACTERISTICS,
+            charBufferNumber
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+
+        ## Get first reply packet
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: The sensor will sent follow-up packets
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            pass
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_PACKETRESPONSEFAIL ):
+            raise Exception('Could not upload characteristics')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+        ## Upload data packets
+        packetNbr = len(characteristicsData) / maxPacketSize
+
+        if ( packetNbr <= 1 ):
+            self.__writePacket(FINGERPRINT_ENDDATAPACKET, characteristicsData)
+        else:
+            i = 1
+            while ( i < packetNbr ):
+                lfrom = (i-1) * maxPacketSize
+                lto = lfrom + maxPacketSize
+                self.__writePacket(FINGERPRINT_DATAPACKET, characteristicsData[lfrom:lto])
+                i += 1
+
+            lfrom = (i-1) * maxPacketSize
+            lto = lfrom + maxPacketSize
+            self.__writePacket(FINGERPRINT_ENDDATAPACKET, characteristicsData[lfrom:lto])
+
+        ## Verify uploaded characteristics
+        characterics = self.downloadCharacteristics(charBufferNumber)
+        return (characterics == characteristicsData)
+
+    def getMaxPacketSize(self):
+        """
+        Get the maximum allowed size of packet by sensor.
+
+        @author: David Gilson <davgilson@live.fr>
+
+        @return int
+        Return the max size. Default 32 bytes.
+        """
+
+        packetMaxSizeType = self.getSystemParameters()[5]
+
+        if (packetMaxSizeType == 1):
+            return 64
+        elif (packetMaxSizeType == 2):
+            return 128
+        elif (packetMaxSizeType == 3):
+            return 256
+        else:
+            return 32
+
+    def getStorageCapacity(self):
+        """
+        Get the sensor storage capacity.
+
+        @return int
+        The storage capacity.
+        """
+
+        return self.getSystemParameters()[2]
+
+    def generateRandomNumber(self):
+        """
+        Generate a random 32-bit decimal number.
+
+        @author: Philipp Meisberger <team@pm-codeworks.de>
+
+        @return int
+        The generated random number
+        """
+        packetPayload = (
+            FINGERPRINT_GENERATERANDOMNUMBER,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            pass
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+        number = 0
+        number = number | self.__leftShift(receivedPacketPayload[1], 24)
+        number = number | self.__leftShift(receivedPacketPayload[2], 16)
+        number = number | self.__leftShift(receivedPacketPayload[3], 8)
+        number = number | self.__leftShift(receivedPacketPayload[4], 0)
+        return number
+
+    def downloadCharacteristics(self, charBufferNumber = 0x01):
+        """
+        Download the finger characteristics of CharBuffer1 or CharBuffer2.
+
+        @param integer(1 byte) charBufferNumber
+
+        @return list
+        Return a list that contains 512 integer(1 byte) elements of the characteristic.
+        """
+
+        if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ):
+            raise ValueError('The given charbuffer number is invalid!')
+
+        packetPayload = (
+            FINGERPRINT_DOWNLOADCHARACTERISTICS,
+            charBufferNumber,
+        )
+
+        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)
+
+        ## Get first reply packet
+        receivedPacket = self.__readPacket()
+
+        receivedPacketType = receivedPacket[0]
+        receivedPacketPayload = receivedPacket[1]
+
+        if ( receivedPacketType != FINGERPRINT_ACKPACKET ):
+            raise Exception('The received packet is no ack packet!')
+
+        ## DEBUG: The sensor will sent follow-up packets
+        if ( receivedPacketPayload[0] == FINGERPRINT_OK ):
+            pass
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ):
+            raise Exception('Communication error')
+
+        elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_DOWNLOADCHARACTERISTICS ):
+            raise Exception('Could not download characteristics')
+
+        else:
+            raise Exception('Unknown error '+ hex(receivedPacketPayload[0]))
+
+        completePayload = []
+
+        ## Get follow-up data packets until the last data packet is received
+        while ( receivedPacketType != FINGERPRINT_ENDDATAPACKET ):
+
+            receivedPacket = self.__readPacket()
+
+            receivedPacketType = receivedPacket[0]
+            receivedPacketPayload = receivedPacket[1]
+
+            if ( receivedPacketType != FINGERPRINT_DATAPACKET and receivedPacketType != FINGERPRINT_ENDDATAPACKET ):
+                raise Exception('The received packet is no data packet!')
+
+            for i in range(0, len(receivedPacketPayload)):
+                completePayload.append(receivedPacketPayload[i])
+
+        return completePayload
index 798016b..1e78afe 100644 (file)
--- a/syncdb.pl
+++ b/syncdb.pl
-#!/usr/bin/perl\r
-\r
-use strict;\r
-use Data::Dumper;\r
-use JSON::PP;\r
-use DBI;\r
-use DBD::SQLite;\r
-use Encode;\r
-my $strcfg = "";\r
-open(CFG,$ENV{HOME}.'/data/hourtrax.json');\r
-while (my $l = <CFG>){\r
-       chomp($l);\r
-       $strcfg .= $l;\r
-}\r
-close(CFG);\r
-my $cmd = "mount | grep ".$ENV{HOME}."/sync"; \r
-my $ismnt = `$cmd`;\r
-chomp($ismnt);\r
-#print "Test 1: mounted:".$ismnt."\n";\r
-if ($ismnt ne ""){\r
-       my $cmd = "sudo umount ".$ENV{HOME}."/sync";\r
-       system($cmd);\r
-} \r
-my $data = JSON::PP::decode_json($strcfg);\r
-my $conn = "sudo mount -t cifs -o username=".$data->{sync}->{user}.",password=".$data->{sync}->{pwd}." //".$data->{sync}->{host}.'/'.$data->{sync}->{path}." ".$ENV{HOME}.'/sync';\r
-#print $conn."\n";\r
-my $ret = `$conn`;\r
-#print $ret."\n";\r
-\r
-if ($ret =~ /unable to/){\r
-       print "$ret\n";\r
-       exit(1);\r
-} else {\r
-       my $localdb = $ENV{HOME}.'/data/hourtrax.sqlite';\r
-       my $remotedb = $ENV{HOME}.'/sync/'.$data->{sync}->{dbname}.".sqlite";\r
-       if (-e $remotedb){\r
-               my $rd = &dbquery('id',$data->{sync}->{sql},$remotedb) ;\r
-       foreach my $r (keys(%{$rd})){\r
-               my $sql1= "select id,prename,surname from staff where id='".$r."'";\r
-               my $rl = &dbquery('id',$sql1,$localdb);\r
-               if (keys(%{$rl}) > 0){\r
-                       if (($rd->{$r}->{prename} ne $rl->{$r}->{prename}) || \r
-                               ($rd->{$r}->{surname} ne $rl->{$r}->{surname})){\r
-                                       &dbexec("UPDATE staff set prename='".$rd->{$r}->{prename}."',surname='".$rd->{$r}->{surname}."' where id='".$r."'",$localdb);\r
-                       }\r
-                       my $sql2= "select id,idstaff,weekhours,startdate from contract where idstaff='".$r."' and startdate='".$rd->{$r}->{startdate}."'";\r
-                       my $rl2 = &dbquery('idstaff',$sql2,$localdb);\r
-                   if (keys(%{$rl2}) > 0){\r
-                       if (($rl2->{$rd->{$r}->{id}}->{weekhours} ne  $rl->{$r}->{weekhours}) && ($rl->{$r}->{weekhours} ne '')){\r
-                                &dbexec("UPDATE contract SET weekhours='".$rl->{$r}->{weekhours}."' WHERE id='".$rl2->{$rd->{$r}->{id}}->{id}."'",,$localdb);\r
-                       }\r
-                   }else {\r
-                       &dbexec("INSERT INTO contract (idstaff,weekhours,startdate) VALUES ('".$rd->{$r}->{id}."','".$rd->{$r}->{weekhours}."',date('".$rd->{$r}->{startdate}."');",$localdb);\r
-                   }\r
-               }else {\r
-                       &dbexec("INSERT INTO staff (id,prename,surname) VALUES ('".$rd->{$r}->{id}."','".$rd->{$r}->{prename}."','".$rd->{$r}->{surname}."')",$data->{sync}->{sql},$localdb);\r
-                       &dbexec("INSERT INTO contract (idstaff,weekhours,startdate) VALUES ('".$rd->{$r}->{id}."','".$rd->{$r}->{weekhours}."',date('".$rd->{$r}->{startdate}."');",$localdb);\r
-               }\r
-       }                               \r
-       }\r
-       \r
-}\r
-$cmd = "sudo umount ".$ENV{HOME}."/sync";\r
-system($cmd);\r
-print "Normal END!\n";\r
-\r
-\r
-sub dbquery(){\r
-    my $key = shift;\r
-    my $stat = shift;\r
-    my $file = shift;\r
-    my $retdata =();\r
-    my $dbh = DBI->connect('DBI:SQLite:dbname='.$file,"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1})  or exit(2);\r
-    #$stat = encode("utf8", $stat);\r
-\r
-   #open FILE,">>/tmp/sql.log";\r
-   print "Query with key: $stat\n";\r
-   #  close FILE;\r
-    my $sth = $dbh->prepare($stat);\r
-   $sth->execute() or exit(2);\r
-   while(my $data = $sth->fetchrow_hashref())\r
-   {\r
-     if (exists $data->{$key}){\r
-        foreach my $k (keys %{$data}){\r
-            $retdata->{$data->{$key}}{$k} = decode( "utf8", $data->{$k});\r
-        }\r
-     }\r
-   }\r
-   if (keys(%{$retdata}) == 0){\r
-    $retdata =();\r
-   }\r
-   $sth->finish();\r
-   $dbh->disconnect();\r
-   return $retdata;\r
-}\r
-\r
-sub dbexec(){\r
-    my $stat = shift;\r
-    my $file =shift;\r
-#    my $dbh = DBI->connect('DBI:SQLite:dbname='.$$file,"","",{PrintError=>1,AutoCommit=>1})  or exit(2);\r
-    print "Exec: $stat\n";\r
-#    my $sth = $dbh->prepare($stat);\r
-#   my $rv =$dbh->do($stat) or exit(2);\r
-#   $dbh->disconnect();\r
-   return 1;\r
-#   return $rv;\r
-}\r
-\r
+#!/home/dks/perl5/perlbrew/perls/perl-5.28.1/bin/perl
+use strict;
+use FindBin qw($Bin);
+# use lib ('CGI/api/lib/perl5');
+# use lib ('CGI/api/lib');
+use lib ($Bin.'/CGI/api/lib/perl5');
+use lib ($Bin.'/CGI/api/lib');
+# use CGI::Carp qw/fatalsToBrowser/;
+use File::Basename;
+use JSON::PP;
+use Getopt::Long;
+use dksconfig qw/$sitecfg/;
+use dksdb;
+use Encode;
+my $sql = "";
+my @allsql = ();
+my $file = "";
+GetOptions("sql|s=s" => \$sql,"file|f=s" => \$file);
+if ($sql ne ""){
+  @allsql = split(";",$sql);
+}
+elsif ($file ne "" && -e $file){
+  my $strfile = "";
+  open(SQF,$file);
+  while (my $l = <SQF>){
+    $strfile .= $l;
+  }
+  close(SQF);
+  @allsql = split(";",$strfile);
+}
+my $db = dksdb->new();
+my $qall = ();
+my $cnt = 0;
+foreach my $sq (@allsql){
+  my $qres = ();
+  if ($sq eq ""){next;}
+  if (lc($sql) =~ /^\s*select/){
+    $qall->{$cnt} = $db->query($sq.";");
+  } else {
+    $qall->{$cnt} = $db->exec($sq.";");
+  }
+  $cnt++;
+}
+my $json = JSON::PP->new->utf8;
+$json->pretty(1);
+print $json->encode($qall);
+
+