asdasdasd

Dependencies:   mbed

Fork of FINAL_PROJECT_4180 by Gedeon Nyengele

FPScanner.cpp

Committer:
xemnas214
Date:
2016-11-23
Revision:
14:ca57ad53761b
Parent:
2:1b1c0502bb08

File content as of revision 14:ca57ad53761b:

/* 
    FPScanner.h v1.0 - Library for controlling the GT-511C3 Finger Print Scanner (FPS)
    Created by Josh Hawley, July 23rd 2013
    Licensed for non-commercial use, must include this license message
    basically, Feel free to hack away at it, but just give me credit for my work =)
    TLDR; Wil Wheaton's Law
*/

#include "FPScanner.h"


// returns the 12 bytes of the generated command packet
// remember to call delete on the returned array
byte* Command_Packet::GetPacketBytes()
{
    byte* packetbytes= new byte[12];
    
    // update command before calculating checksum (important!)
    word cmd = Command;
    command[0] = GetLowByte(cmd);
    command[1] = GetHighByte(cmd);

    word checksum = _CalculateChecksum();

    packetbytes[0] = COMMAND_START_CODE_1;
    packetbytes[1] = COMMAND_START_CODE_2;
    packetbytes[2] = COMMAND_DEVICE_ID_1;
    packetbytes[3] = COMMAND_DEVICE_ID_2;
    packetbytes[4] = Parameter[0];
    packetbytes[5] = Parameter[1];
    packetbytes[6] = Parameter[2];
    packetbytes[7] = Parameter[3];
    packetbytes[8] = command[0];
    packetbytes[9] = command[1];
    packetbytes[10] = GetLowByte(checksum);
    packetbytes[11] = GetHighByte(checksum);

    return packetbytes;
}

// Converts the int to bytes and puts them into the paramter array
void Command_Packet::ParameterFromInt(int i)
{
    Parameter[0] = (i & 0x000000ff);
    Parameter[1] = (i & 0x0000ff00) >> 8;
    Parameter[2] = (i & 0x00ff0000) >> 16;
    Parameter[3] = (i & 0xff000000) >> 24;
}

// Returns the high byte from a word
byte Command_Packet::GetHighByte(word w)
{
    return (byte)(w>>8)&0x00FF;
}

// Returns the low byte from a word
byte Command_Packet::GetLowByte(word w)
{
    return (byte)w&0x00FF;
}

word Command_Packet::_CalculateChecksum()
{
    word w = 0;
    w += COMMAND_START_CODE_1;
    w += COMMAND_START_CODE_2;
    w += COMMAND_DEVICE_ID_1;
    w += COMMAND_DEVICE_ID_2;
    w += Parameter[0];
    w += Parameter[1];
    w += Parameter[2];
    w += Parameter[3];
    w += command[0];
    w += command[1];

    return w;
}

Command_Packet::Command_Packet()
{
};

// creates and parses a response packet from the finger print scanner
Response_Packet::Response_Packet(byte* buffer)
{
    // CheckParsing(buffer[0], COMMAND_START_CODE_1, COMMAND_START_CODE_1);
    // CheckParsing(buffer[1], COMMAND_START_CODE_2, COMMAND_START_CODE_2);
    // CheckParsing(buffer[2], COMMAND_DEVICE_ID_1, COMMAND_DEVICE_ID_1);
    // CheckParsing(buffer[3], COMMAND_DEVICE_ID_2, COMMAND_DEVICE_ID_2);
    // CheckParsing(buffer[8], 0x30, 0x31);
    if (buffer[8] == 0x30) ACK = true; else ACK = false;
    // CheckParsing(buffer[9], 0x00, 0x00);

    word checksum = CalculateChecksum(buffer, 10);
    byte checksum_low = GetLowByte(checksum);
    byte checksum_high = GetHighByte(checksum);
    // CheckParsing(buffer[10], checksum_low, checksum_low);
    // CheckParsing(buffer[11], checksum_high, checksum_high);
    
    Error = ErrorCodes::ParseFromBytes(buffer[5], buffer[4]);

    ParameterBytes[0] = buffer[4];
    ParameterBytes[1] = buffer[5];
    ParameterBytes[2] = buffer[6];
    ParameterBytes[3] = buffer[7];
    ResponseBytes[0]=buffer[8];
    ResponseBytes[1]=buffer[9];
    for (int i=0; i < 12; i++)
    {
        RawBytes[i]=buffer[i];
    }
}

// parses bytes into one of the possible errors from the finger print scanner
Response_Packet::ErrorCodes::Errors_Enum Response_Packet::ErrorCodes::ParseFromBytes(byte high, byte low)
{
    Errors_Enum e = INVALID;
    if (high == 0x00)
    {
    }
    if (high == 0x01)
    {
        switch(low)
        {
            case 0x00: e = NO_ERROR; break;
            case 0x01: e = NACK_TIMEOUT; break;
            case 0x02: e = NACK_INVALID_BAUDRATE; break;        
            case 0x03: e = NACK_INVALID_POS; break;         
            case 0x04: e = NACK_IS_NOT_USED; break;     
            case 0x05: e = NACK_IS_ALREADY_USED; break;
            case 0x06: e = NACK_COMM_ERR; break;
            case 0x07: e = NACK_VERIFY_FAILED; break;
            case 0x08: e = NACK_IDENTIFY_FAILED; break;
            case 0x09: e = NACK_DB_IS_FULL; break;
            case 0x0A: e = NACK_DB_IS_EMPTY; break;
            case 0x0B: e = NACK_TURN_ERR; break;
            case 0x0C: e = NACK_BAD_FINGER; break;
            case 0x0D: e = NACK_ENROLL_FAILED; break;
            case 0x0E: e = NACK_IS_NOT_SUPPORTED; break;
            case 0x0F: e = NACK_DEV_ERR; break;
            case 0x10: e = NACK_CAPTURE_CANCELED; break;
            case 0x11: e = NACK_INVALID_PARAM; break;
            case 0x12: e = NACK_FINGER_IS_NOT_PRESSED; break;
        }
    }
    return e;
}

// Gets an int from the parameter bytes
int Response_Packet::IntFromParameter()
{
    int retval = 0;
    retval = (retval << 8) + ParameterBytes[3];
    retval = (retval << 8) + ParameterBytes[2];
    retval = (retval << 8) + ParameterBytes[1];
    retval = (retval << 8) + ParameterBytes[0];
    return retval;
}

// calculates the checksum from the bytes in the packet
word Response_Packet::CalculateChecksum(byte* buffer, int length)
{
    word checksum = 0;
    for (int i=0; i<length; i++)
    {
        checksum +=buffer[i];
    }
    return checksum;
}

// Returns the high byte from a word
byte Response_Packet::GetHighByte(word w)
{
    return (byte)(w>>8)&0x00FF;
}

// Returns the low byte from a word
byte Response_Packet::GetLowByte(word w)
{
    return (byte)w&0x00FF;
}

// checks to see if the byte is the proper value, and logs it to the serial channel if not
bool Response_Packet::CheckParsing(byte b, byte propervalue, byte alternatevalue)
{
    bool retval = (b == propervalue) || (b == alternatevalue);
    return retval;
    
}


// Creates a new object to interface with the fingerprint scanner
FPScanner::FPScanner(PinName tx, PinName rx)
    : _serial(tx,rx)
{
    pin_TX = tx;
    pin_RX = rx;    
    _serial.baud(9600);
};


//Initialises the device and gets ready for commands
void FPScanner::Open()
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::Open;
    cp->Parameter[0] = 0x00;
    cp->Parameter[1] = 0x00;
    cp->Parameter[2] = 0x00;
    cp->Parameter[3] = 0x00;
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();
    delete cp;
    delete rp;
    delete [] packetbytes;
}

// According to the DataSheet, this does nothing... 
// Implemented it for completeness.
void FPScanner::Close()
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::Close;
    cp->Parameter[0] = 0x00;
    cp->Parameter[1] = 0x00;
    cp->Parameter[2] = 0x00;
    cp->Parameter[3] = 0x00;
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();
    delete cp;
    delete rp;
    delete [] packetbytes;
};

// Turns on or off the LED backlight
// Parameter: true turns on the backlight, false turns it off
// Returns: True if successful, false if not
bool FPScanner::SetLED(bool on)
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::CmosLed;
    if (on)
    {
        cp->Parameter[0] = 0x01;
    }
    else
    {
        cp->Parameter[0] = 0x00;
    }
    cp->Parameter[1] = 0x00;
    cp->Parameter[2] = 0x00;
    cp->Parameter[3] = 0x00;
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();
    bool retval = true;
    if (rp->ACK == false) retval = false;
    delete rp;
    delete [] packetbytes;
    delete cp;
    return retval;
};

// Changes the baud rate of the connection
// Parameter: 9600, 19200, 38400, 57600, 115200
// Returns: True if success, false if invalid baud
// NOTE: Untested (don't have a logic level changer and a voltage divider is too slow)
bool FPScanner::ChangeBaudRate(int baud)
{
    if ((baud == 9600) || (baud == 19200) || (baud == 38400) || (baud == 57600) || (baud == 115200))
    {

        Command_Packet* cp = new Command_Packet();
        cp->Command = Command_Packet::Commands::Open;
        cp->ParameterFromInt(baud);
        byte* packetbytes = cp->GetPacketBytes();
        SendCommand(packetbytes, 12);
        Response_Packet* rp = GetResponse();
        bool retval = rp->ACK;
        if (retval) 
        {
            _serial.baud(baud);
        }
        delete cp;
        delete rp;
        delete [] packetbytes;
        return retval;
    }
    return false;
}

// Gets the number of enrolled fingerprints
// Return: The total number of enrolled fingerprints
int FPScanner::GetEnrollCount()
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::GetEnrollCount;
    cp->Parameter[0] = 0x00;
    cp->Parameter[1] = 0x00;
    cp->Parameter[2] = 0x00;
    cp->Parameter[3] = 0x00;
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();

    int retval = rp->IntFromParameter();
    delete cp;
    delete rp;
    delete [] packetbytes;
    return retval;
}

// checks to see if the ID number is in use or not
// Parameter: 0-199
// Return: True if the ID number is enrolled, false if not
bool FPScanner::CheckEnrolled(int id)
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::CheckEnrolled;
    cp->ParameterFromInt(id);
    byte* packetbytes = cp->GetPacketBytes();   
    SendCommand(packetbytes, 12);   
    Response_Packet* rp = GetResponse();
    bool retval = false;
    retval = rp->ACK;
    delete cp;
    delete rp;
    delete [] packetbytes;
    return retval;
}

// Starts the Enrollment Process
// Parameter: 0-199
// Return:
//  0 - ACK
//  1 - Database is full
//  2 - Invalid Position
//  3 - Position(ID) is already used
int FPScanner::EnrollStart(int id)
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::EnrollStart;
    cp->ParameterFromInt(id);
    byte* packetbytes = cp->GetPacketBytes();
    delete cp;
    SendCommand(packetbytes, 12);
    delete [] packetbytes;
    Response_Packet* rp = GetResponse();
    int retval = 0;
    if (rp->ACK == false)
    {
        if (rp->Error == Response_Packet::ErrorCodes::NACK_DB_IS_FULL) retval = 1;
        if (rp->Error == Response_Packet::ErrorCodes::NACK_INVALID_POS) retval = 2;
        if (rp->Error == Response_Packet::ErrorCodes::NACK_IS_ALREADY_USED) retval = 3;
    }
    delete rp;
    return retval;
}

// Gets the first scan of an enrollment
// Return: 
//  0 - ACK
//  1 - Enroll Failed
//  2 - Bad finger
//  3 - ID in use
int FPScanner::Enroll1()
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::Enroll1;
    byte* packetbytes = cp->GetPacketBytes();
    delete cp;
    SendCommand(packetbytes, 12);
    delete [] packetbytes;
    Response_Packet* rp = GetResponse();
    int retval = rp->IntFromParameter();
    if (retval < 200) retval = 3; else retval = 0;
    if (rp->ACK == false)
    {
        if (rp->Error == Response_Packet::ErrorCodes::NACK_ENROLL_FAILED) retval = 1;
        if (rp->Error == Response_Packet::ErrorCodes::NACK_BAD_FINGER) retval = 2;
    }
    delete rp;
    if (rp->ACK) return 0; else return retval;
}

// Gets the Second scan of an enrollment
// Return: 
//  0 - ACK
//  1 - Enroll Failed
//  2 - Bad finger
//  3 - ID in use
int FPScanner::Enroll2()
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::Enroll2;
    byte* packetbytes = cp->GetPacketBytes();
    delete cp;
    SendCommand(packetbytes, 12);
    delete [] packetbytes;
    Response_Packet* rp = GetResponse();
    int retval = rp->IntFromParameter();
    if (retval < 200) retval = 3; else retval = 0;
    if (rp->ACK == false)
    {
        if (rp->Error == Response_Packet::ErrorCodes::NACK_ENROLL_FAILED) retval = 1;
        if (rp->Error == Response_Packet::ErrorCodes::NACK_BAD_FINGER) retval = 2;
    }
    delete rp;
    if (rp->ACK) return 0; else return retval;
}

// Gets the Third scan of an enrollment
// Finishes Enrollment
// Return: 
//  0 - ACK
//  1 - Enroll Failed
//  2 - Bad finger
//  3 - ID in use
int FPScanner::Enroll3()
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::Enroll3;
    byte* packetbytes = cp->GetPacketBytes();
    delete cp;
    SendCommand(packetbytes, 12);
    delete [] packetbytes;
    Response_Packet* rp = GetResponse();
    int retval = rp->IntFromParameter();
    if (retval < 200) retval = 3; else retval = 0;
    if (rp->ACK == false)
    {
        if (rp->Error == Response_Packet::ErrorCodes::NACK_ENROLL_FAILED) retval = 1;
        if (rp->Error == Response_Packet::ErrorCodes::NACK_BAD_FINGER) retval = 2;
    }
    delete rp;
    if (rp->ACK) return 0; else return retval;
}

// Checks to see if a finger is pressed on the FPS
// Return: true if finger pressed, false if not
bool FPScanner::IsPressFinger()
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::IsPressFinger;
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();
    bool retval = false;
    int pval = rp->ParameterBytes[0];
    pval += rp->ParameterBytes[1];
    pval += rp->ParameterBytes[2];
    pval += rp->ParameterBytes[3];
    if (pval == 0) retval = true;
    delete rp;
    delete [] packetbytes;
    delete cp;
    return retval;
}

// Deletes the specified ID (enrollment) from the database
// Parameter: 0-199 (id number to be deleted)
// Returns: true if successful, false if position invalid
bool FPScanner::DeleteID(int id)
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::DeleteID;
    cp->ParameterFromInt(id);
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();
    bool retval = rp->ACK;
    delete rp;
    delete [] packetbytes;
    delete cp;
    return retval;
}

// Deletes all IDs (enrollments) from the database
// Returns: true if successful, false if db is empty
bool FPScanner::DeleteAll()
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::DeleteAll;
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();
    bool retval = rp->ACK;
    delete rp;
    delete [] packetbytes;
    delete cp;
    return retval;
}

// Checks the currently pressed finger against a specific ID
// Parameter: 0-199 (id number to be checked)
// Returns:
//  0 - Verified OK (the correct finger)
//  1 - Invalid Position
//  2 - ID is not in use
//  3 - Verified FALSE (not the correct finger)
int FPScanner::Verify1_1(int id)
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::Verify1_1;
    cp->ParameterFromInt(id);
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();
    int retval = 0;
    if (rp->ACK == false)
    {
        if (rp->Error == Response_Packet::ErrorCodes::NACK_INVALID_POS) retval = 1;
        if (rp->Error == Response_Packet::ErrorCodes::NACK_IS_NOT_USED) retval = 2;
        if (rp->Error == Response_Packet::ErrorCodes::NACK_VERIFY_FAILED) retval = 3;
    }
    delete rp;
    delete [] packetbytes;
    delete cp;
    return retval;
}

// Checks the currently pressed finger against all enrolled fingerprints
// Returns:
//  0-199: Verified against the specified ID (found, and here is the ID number)
//  200: Failed to find the fingerprint in the database
int FPScanner::Identify1_N()
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::Identify1_N;
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();
    int retval = rp->IntFromParameter();
    if (retval > 200) retval = 200;
    delete rp;
    delete [] packetbytes;
    delete cp;
    return retval;
}

// Captures the currently pressed finger into onboard ram use this prior to other commands
// Parameter: true for high quality image(slower), false for low quality image (faster)
// Generally, use high quality for enrollment, and low quality for verification/identification
// Returns: True if ok, false if no finger pressed
bool FPScanner::CaptureFinger(bool highquality)
{
    Command_Packet* cp = new Command_Packet();
    cp->Command = Command_Packet::Commands::CaptureFinger;
    if (highquality)
    {
        cp->ParameterFromInt(1);
    }
    else
    {
        cp->ParameterFromInt(0);
    }
    byte* packetbytes = cp->GetPacketBytes();
    SendCommand(packetbytes, 12);
    Response_Packet* rp = GetResponse();
    bool retval = rp->ACK;
    delete rp;
    delete [] packetbytes;
    delete cp;
    return retval;

}


// Sends the command to the software serial channel
void FPScanner::SendCommand(byte cmd[], int length)
{
    for (int i = 0; i < length; i++) {
        _serial.putc(cmd[i]);
    }
};

// Gets the response to the command from the software serial channel (and waits for it)
Response_Packet* FPScanner::GetResponse()
{
    byte firstbyte = 0;
    bool done = false;
    while (done == false)
    {
        firstbyte = (byte)_serial.getc();
        if (firstbyte == Response_Packet::COMMAND_START_CODE_1)
        {
            done = true;
        }
    }
    byte* resp = new byte[12];
    resp[0] = firstbyte;
    for (int i=1; i < 12; i++)
    {
        resp[i]= (byte) _serial.getc();
    }
    Response_Packet* rp = new Response_Packet(resp);
    delete [] resp;
    return rp;
};