Fingerprint to Arduino Due

Hi :smiley:

I need to use a library but it does not work in Arduino Due, as it uses SoftwareSerial and Arduino Due has more than 1 serial port to use. I tried to adapt the library but it did not work, I will make the library code available and if someone can help me find the error or help me fix the problem I thank you very much because I really need this library.

FPS_GT511C3_h

#ifndef FPS_GT511C3_h
#define FPS_GT511C3_h

#include "Arduino.h"
#include "SoftwareSerial.h"
#ifndef __GNUC__
#pragma region -= Command_Packet =-
#endif  //__GNUC__
/*
	Command_Packet represents the 12 byte command that we send to the finger print scanner
*/
class Command_Packet
{
	public:
		class Commands
		{
			public:
				enum Commands_Enum
				{
					NotSet				= 0x00,		// Default value for enum. Scanner will return error if sent this.
					Open				= 0x01,		// Open Initialization
					Close				= 0x02,		// Close Termination
					UsbInternalCheck	= 0x03,		// UsbInternalCheck Check if the connected USB device is valid
					ChangeEBaudRate		= 0x04,		// ChangeBaudrate Change UART baud rate
					SetIAPMode			= 0x05,		// SetIAPMode Enter IAP Mode In this mode, FW Upgrade is available
					CmosLed				= 0x12,		// CmosLed Control CMOS LED
					GetEnrollCount		= 0x20,		// Get enrolled fingerprint count
					CheckEnrolled		= 0x21,		// Check whether the specified ID is already enrolled
					EnrollStart			= 0x22,		// Start an enrollment
					Enroll1				= 0x23,		// Make 1st template for an enrollment
					Enroll2				= 0x24,		// Make 2nd template for an enrollment
					Enroll3				= 0x25,		// Make 3rd template for an enrollment, merge three templates into one template, save merged template to the database
					IsPressFinger		= 0x26,		// Check if a finger is placed on the sensor
					DeleteID			= 0x40,		// Delete the fingerprint with the specified ID
					DeleteAll			= 0x41,		// Delete all fingerprints from the database
					Verify1_1			= 0x50,		// Verification of the capture fingerprint image with the specified ID
					Identify1_N			= 0x51,		// Identification of the capture fingerprint image with the database
					VerifyTemplate1_1	= 0x52,		// Verification of a fingerprint template with the specified ID
					IdentifyTemplate1_N	= 0x53,		// Identification of a fingerprint template with the database
					CaptureFinger		= 0x60,		// Capture a fingerprint image(256x256) from the sensor
					MakeTemplate		= 0x61,		// Make template for transmission
					GetImage			= 0x62,		// Download the captured fingerprint image(256x256)
					GetRawImage			= 0x63,		// Capture & Download raw fingerprint image(320x240)
					GetTemplate			= 0x70,		// Download the template of the specified ID
					SetTemplate			= 0x71,		// Upload the template of the specified ID
					GetDatabaseStart	= 0x72,		// Start database download, obsolete
					GetDatabaseEnd		= 0x73,		// End database download, obsolete
					UpgradeFirmware		= 0x80,		// Not supported
					UpgradeISOCDImage	= 0x81,		// Not supported
					Ack					= 0x30,		// Acknowledge.
					Nack				= 0x31		// Non-acknowledge
			};
		};

		Commands::Commands_Enum Command;
		byte Parameter[4];								// Parameter 4 bytes, changes meaning depending on command							
		byte* GetPacketBytes();							// returns the bytes to be transmitted
		void ParameterFromInt(int i);

		Command_Packet();

	private: 
		static const byte COMMAND_START_CODE_1 = 0x55;	// Static byte to mark the beginning of a command packet	-	never changes
		static const byte COMMAND_START_CODE_2 = 0xAA;	// Static byte to mark the beginning of a command packet	-	never changes
		static const byte COMMAND_DEVICE_ID_1 = 0x01;	// Device ID Byte 1 (lesser byte)							-	theoretically never changes
		static const byte COMMAND_DEVICE_ID_2 = 0x00;	// Device ID Byte 2 (greater byte)							-	theoretically never changes
		byte command[2];								// Command 2 bytes

		word _CalculateChecksum();						// Checksum is calculated using byte addition
		byte GetHighByte(word w);						
		byte GetLowByte(word w);
};
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
#pragma region -= Response_Packet =-
#endif  //__GNUC__
/*
	Response_Packet represents the returned data from the finger print scanner 
*/
class Response_Packet
{
	public:
		class ErrorCodes
		{
			public:
				enum Errors_Enum
				{
					NO_ERROR					= 0x0000,	// Default value. no error
					NACK_TIMEOUT				= 0x1001,	// Obsolete, capture timeout
					NACK_INVALID_BAUDRATE		= 0x1002,	// Obsolete, Invalid serial baud rate
					NACK_INVALID_POS			= 0x1003,	// The specified ID is not between 0~199
					NACK_IS_NOT_USED			= 0x1004,	// The specified ID is not used
					NACK_IS_ALREADY_USED		= 0x1005,	// The specified ID is already used
					NACK_COMM_ERR				= 0x1006,	// Communication Error
					NACK_VERIFY_FAILED			= 0x1007,	// 1:1 Verification Failure
					NACK_IDENTIFY_FAILED		= 0x1008,	// 1:N Identification Failure
					NACK_DB_IS_FULL				= 0x1009,	// The database is full
					NACK_DB_IS_EMPTY			= 0x100A,	// The database is empty
					NACK_TURN_ERR				= 0x100B,	// Obsolete, Invalid order of the enrollment (The order was not as: EnrollStart -> Enroll1 -> Enroll2 -> Enroll3)
					NACK_BAD_FINGER				= 0x100C,	// Too bad fingerprint
					NACK_ENROLL_FAILED			= 0x100D,	// Enrollment Failure
					NACK_IS_NOT_SUPPORTED		= 0x100E,	// The specified command is not supported
					NACK_DEV_ERR				= 0x100F,	// Device Error, especially if Crypto-Chip is trouble
					NACK_CAPTURE_CANCELED		= 0x1010,	// Obsolete, The capturing is canceled
					NACK_INVALID_PARAM			= 0x1011,	// Invalid parameter
					NACK_FINGER_IS_NOT_PRESSED	= 0x1012,	// Finger is not pressed
					INVALID						= 0XFFFF	// Used when parsing fails
				};

				static Errors_Enum ParseFromBytes(byte high, byte low);
		};
		Response_Packet(byte* buffer, bool UseSerialDebug);
		ErrorCodes::Errors_Enum Error;
		byte RawBytes[12];
		byte ParameterBytes[4];
		byte ResponseBytes[2];
		bool ACK;
		static const byte COMMAND_START_CODE_1 = 0x55;	// Static byte to mark the beginning of a command packet	-	never changes
		static const byte COMMAND_START_CODE_2 = 0xAA;	// Static byte to mark the beginning of a command packet	-	never changes
		static const byte COMMAND_DEVICE_ID_1 = 0x01;	// Device ID Byte 1 (lesser byte)							-	theoretically never changes
		static const byte COMMAND_DEVICE_ID_2 = 0x00;	// Device ID Byte 2 (greater byte)							-	theoretically never changes
		int IntFromParameter();

	private: 
		bool CheckParsing(byte b, byte propervalue, byte alternatevalue, const char* varname, bool UseSerialDebug);
		word CalculateChecksum(byte* buffer, int length);
		byte GetHighByte(word w);						
		byte GetLowByte(word w);
};
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
#pragma region -= Data_Packet =- 
#endif  //__GNUC__
// Data Mule packet for receiving large data(in 128 byte pieces) from the FPS
// This class can only transmit one packet at a time
//class Data_Packet
//{
//public:
//	static int CheckSum;
//	int PacketID;
//	int ValidByteLength;
//	byte Data[128];
//	void StartNewPacket();
//	bool IsLastPacket;
//private:
//	static int NextPacketID;
//};
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__


/*
	Object for controlling the GT-511C3 Finger Print Scanner (FPS)
*/
class FPS_GT511C3
{
 
 public:
	// Enables verbose debug output using hardware Serial 
	bool UseSerialDebug;

#ifndef __GNUC__
	#pragma region -= Constructor/Destructor =-
#endif  //__GNUC__
	// Creates a new object to interface with the fingerprint scanner
	FPS_GT511C3(uint8_t rx, uint8_t tx);
	
	// destructor
	~FPS_GT511C3();
#ifndef __GNUC__
	#pragma endregion
#endif  //__GNUC__


#ifndef __GNUC__
	#pragma region -= Device Commands =-
#endif  //__GNUC__
	//Initialises the device and gets ready for commands
	void Open();

	// Does not actually do anything (according to the datasheet)
	// I implemented open, so had to do closed too... lol
	void Close();

	// Turns on or off the LED backlight
	// LED must be on to see fingerprints
	// Parameter: true turns on the backlight, false turns it off
	// Returns: True if successful, false if not
	bool SetLED(bool on);
	
	// Changes the baud rate of the connection
	// Parameter: 9600 - 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 ChangeBaudRate(unsigned long baud);

	// Gets the number of enrolled fingerprints
	// Return: The total number of enrolled fingerprints
	int GetEnrollCount();

	// checks to see if the ID number is in use or not
	// Parameter: 0-2999, if using GT-521F52
        //            0-199, if using GT-521F32/GT-511C3
	// Return: True if the ID number is enrolled, false if not
	bool CheckEnrolled(int id);

	// Starts the Enrollment Process
	// Parameter: 0-2999, if using GT-521F52
        //            0-199, if using GT-521F32/GT-511C3
	// Return:
	//	0 - ACK
	//	1 - Database is full
	//	2 - Invalid Position
	//	3 - Position(ID) is already used
	int EnrollStart(int id);

	// Gets the first scan of an enrollment
	// Return: 
	//	0 - ACK
	//	1 - Enroll Failed
	//	2 - Bad finger
	//	3 - ID in use
	int Enroll1();

	// Gets the Second scan of an enrollment
	// Return: 
	//	0 - ACK
	//	1 - Enroll Failed
	//	2 - Bad finger
	//	3 - ID in use
	int Enroll2();

	// Gets the Third scan of an enrollment
	// Finishes Enrollment
	// Return: 
	//	0 - ACK
	//	1 - Enroll Failed
	//	2 - Bad finger
	//	3 - ID in use
	int Enroll3();

	// Checks to see if a finger is pressed on the FPS
	// Return: true if finger pressed, false if not
	bool IsPressFinger();

	// Deletes the specified ID (enrollment) from the database
	// Returns: true if successful, false if position invalid
	bool DeleteID(int ID);

	// Deletes all IDs (enrollments) from the database
	// Returns: true if successful, false if db is empty
	bool DeleteAll();

	// Checks the currently pressed finger against a specific ID
	// Parameter: 0-2999, if using GT-521F52 (id number to be checked)
        //            0-199, if using GT-521F32/GT-511C3 (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 Verify1_1(int id);

	// Checks the currently pressed finger against all enrolled fingerprints
	// Returns:
	//	Verified against the specified ID (found, and here is the ID number)
        //           0-2999, if using GT-521F52
        //           0-199, if using GT-521F32/GT-511C3
        //      Failed to find the fingerprint in the database
        // 	     3000, if using GT-521F52
        //           200, if using GT-521F32/GT-511C3
	int Identify1_N();

	// Captures the currently pressed finger into onboard ram
	// 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 CaptureFinger(bool highquality);
#ifndef __GNUC__
	#pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
	#pragma region -= Not implemented commands =-
#endif  //__GNUC__
	// Gets an image that is 258x202 (52116 bytes) and returns it in 407 Data_Packets
	// Use StartDataDownload, and then GetNextDataPacket until done
	// Returns: True (device confirming download starting)
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//bool GetImage();

	// Gets an image that is qvga 160x120 (19200 bytes) and returns it in 150 Data_Packets
	// Use StartDataDownload, and then GetNextDataPacket until done
	// Returns: True (device confirming download starting)
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//bool GetRawImage();

	// Gets a template from the fps (498 bytes) in 4 Data_Packets
	// Use StartDataDownload, and then GetNextDataPacket until done
	// Parameter: 0-199 ID number
	// Returns: 
	//	0 - ACK Download starting
	//	1 - Invalid position
	//	2 - ID not used (no template to download
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//int GetTemplate(int id);

	// Uploads a template to the fps 
	// Parameter: the template (498 bytes)
	// Parameter: the ID number to upload
	// Parameter: Check for duplicate fingerprints already on fps
	// Returns: 
	//	0-199 - ID duplicated
	//	200 - Uploaded ok (no duplicate if enabled)
	//	201 - Invalid position
	//	202 - Communications error
	//	203 - Device error
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//int SetTemplate(byte* tmplt, int id, bool duplicateCheck);

	// Commands that are not implemented (and why)
	// VerifyTemplate1_1 - Couldn't find a good reason to implement this on an arduino
	// IdentifyTemplate1_N - Couldn't find a good reason to implement this on an arduino
	// MakeTemplate - Couldn't find a good reason to implement this on an arduino
	// UsbInternalCheck - not implemented - Not valid config for arduino
	// GetDatabaseStart - historical command, no longer supported
	// GetDatabaseEnd - historical command, no longer supported
	// UpgradeFirmware - Data Sheet says not supported
	// UpgradeISOCDImage - Data Sheet says not supported
	// SetIAPMode - for upgrading firmware (which is not supported)
	// Ack and Nack	are listed as a commands for some unknown reason... not implemented
#ifndef __GNUC__
  #pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
	#pragma endregion
#endif  //__GNUC__

	void serialPrintHex(byte data);
	void SendToSerial(byte data[], int length);

	// resets the Data_Packet class, and gets ready to download
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//void StartDataDownload();

	// Returns the next data packet 
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//Data_Packet GetNextDataPacket();

private:
	 void SendCommand(byte cmd[], int length);
	 Response_Packet* GetResponse();
	 uint8_t pin_RX,pin_TX;
	 SoftwareSerial _serial;
};


#endif

FPS_GT511C3.cpp

#include "FPS_GT511C3.h"

#ifndef __GNUC__
#pragma region -= Command_Packet Definitions =-
#endif  //__GNUC__

// 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()
{
};
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
#pragma region -= Response_Packet Definitions =-
#endif  //__GNUC__
// creates and parses a response packet from the finger print scanner
Response_Packet::Response_Packet(byte* buffer, bool UseSerialDebug)
{
	CheckParsing(buffer[0], COMMAND_START_CODE_1, COMMAND_START_CODE_1, "COMMAND_START_CODE_1", UseSerialDebug);
	CheckParsing(buffer[1], COMMAND_START_CODE_2, COMMAND_START_CODE_2, "COMMAND_START_CODE_2", UseSerialDebug);
	CheckParsing(buffer[2], COMMAND_DEVICE_ID_1, COMMAND_DEVICE_ID_1, "COMMAND_DEVICE_ID_1", UseSerialDebug);
	CheckParsing(buffer[3], COMMAND_DEVICE_ID_2, COMMAND_DEVICE_ID_2, "COMMAND_DEVICE_ID_2", UseSerialDebug);
	CheckParsing(buffer[8], 0x30, 0x31, "AckNak_LOW", UseSerialDebug);
	if (buffer[8] == 0x30) ACK = true; else ACK = false;
	CheckParsing(buffer[9], 0x00, 0x00, "AckNak_HIGH", UseSerialDebug);

	word checksum = CalculateChecksum(buffer, 10);
	byte checksum_low = GetLowByte(checksum);
	byte checksum_high = GetHighByte(checksum);
	CheckParsing(buffer[10], checksum_low, checksum_low, "Checksum_LOW", UseSerialDebug);
	CheckParsing(buffer[11], checksum_high, checksum_high, "Checksum_HIGH", UseSerialDebug);

	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)
	{
	}
	// grw 01/03/15 - replaced if clause with else clause for any non-zero high byte
	// if (high == 0x01)
	// {
	else {
		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, const char* varname, bool UseSerialDebug)
{
	bool retval = (b != propervalue) && (b != alternatevalue);
	if ((UseSerialDebug) && (retval))
	{
		Serial.print("Response_Packet parsing error ");
		Serial.print(varname);
		Serial.print(" ");
		Serial.print(propervalue, HEX);
		Serial.print(" || ");
		Serial.print(alternatevalue, HEX);
		Serial.print(" != ");
		Serial.println(b, HEX);
	}
  return retval;
}
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
#pragma region -= Data_Packet =-
#endif  //__GNUC__
//void Data_Packet::StartNewPacket()
//{
//	Data_Packet::NextPacketID = 0;
//	Data_Packet::CheckSum = 0;
//}
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
#pragma region -= FPS_GT511C3 Definitions =-
#endif  //__GNUC__

#ifndef __GNUC__
#pragma region -= Constructor/Destructor =-
#endif  //__GNUC__
// Creates a new object to interface with the fingerprint scanner
FPS_GT511C3::FPS_GT511C3(uint8_t rx, uint8_t tx)
	: _serial(rx,tx)
{
	pin_RX = rx;
	pin_TX = tx;
	_serial.begin(9600);
	this->UseSerialDebug = false;
};

// destructor
FPS_GT511C3::~FPS_GT511C3()
{
	_serial.~SoftwareSerial();
}
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
#pragma region -= Device Commands =-
#endif  //__GNUC__
//Initialises the device and gets ready for commands
void FPS_GT511C3::Open()
{
	if (UseSerialDebug) Serial.println("FPS - 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();
	delete cp;
	SendCommand(packetbytes, 12);
	Response_Packet* rp = GetResponse();
	delete rp;
	delete packetbytes;
}

// According to the DataSheet, this does nothing...
// Implemented it for completeness.
void FPS_GT511C3::Close()
{
	if (UseSerialDebug) Serial.println("FPS - 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();
	delete cp;
	SendCommand(packetbytes, 12);
	Response_Packet* rp = GetResponse();
	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 FPS_GT511C3::SetLED(bool on)
{
	Command_Packet* cp = new Command_Packet();
	cp->Command = Command_Packet::Commands::CmosLed;
	if (on)
	{
		if (UseSerialDebug) Serial.println("FPS - LED on");
		cp->Parameter[0] = 0x01;
	}
	else
	{
		if (UseSerialDebug) Serial.println("FPS - LED off");
		cp->Parameter[0] = 0x00;
	}
	cp->Parameter[1] = 0x00;
	cp->Parameter[2] = 0x00;
	cp->Parameter[3] = 0x00;
	byte* packetbytes = cp->GetPacketBytes();
	delete cp;
	SendCommand(packetbytes, 12);
	Response_Packet* rp = GetResponse();
	bool retval = true;
	if (rp->ACK == false) retval = false;
	delete rp;
	delete packetbytes;
	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 FPS_GT511C3::ChangeBaudRate(unsigned long baud)
{
	if ((baud == 9600) || (baud == 19200) || (baud == 38400) || (baud == 57600) || (baud == 115200))
	{

		if (UseSerialDebug) Serial.println("FPS - ChangeBaudRate");
		Command_Packet* cp = new Command_Packet();
		cp->Command = Command_Packet::Commands::Open;
		cp->ParameterFromInt(baud);
		byte* packetbytes = cp->GetPacketBytes();
		delete cp;
		SendCommand(packetbytes, 12);
		Response_Packet* rp = GetResponse();
		bool retval = rp->ACK;
		if (retval)
		{
			_serial.end();
			_serial.begin(baud);
		}
		delete rp;
		delete packetbytes;
		return retval;
	}
	return false;
}

// Gets the number of enrolled fingerprints
// Return: The total number of enrolled fingerprints
int FPS_GT511C3::GetEnrollCount()
{
	if (UseSerialDebug) Serial.println("FPS - GetEnrolledCount");
	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();
	delete cp;
	SendCommand(packetbytes, 12);
	Response_Packet* rp = GetResponse();

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

// checks to see if the ID number is in use or not
// Parameter: 0-2999, if using GT-521F52
//            0-199, if using GT-521F32/GT-511C3
// Return: True if the ID number is enrolled, false if not
bool FPS_GT511C3::CheckEnrolled(int id)
{
	if (UseSerialDebug) Serial.println("FPS - CheckEnrolled");
	Command_Packet* cp = new Command_Packet();
	cp->Command = Command_Packet::Commands::CheckEnrolled;
	cp->ParameterFromInt(id);
	byte* packetbytes = cp->GetPacketBytes();
	delete cp;
	SendCommand(packetbytes, 12);
	delete packetbytes;
	Response_Packet* rp = GetResponse();
	bool retval = false;
	retval = rp->ACK;
	delete rp;
	return retval;
}

// Starts the Enrollment Process
// Parameter: 0-2999, if using GT-521F52
//            0-199, if using GT-521F32/GT-511C3
// Return:
//	0 - ACK
//	1 - Database is full
//	2 - Invalid Position
//	3 - Position(ID) is already used
int FPS_GT511C3::EnrollStart(int id)
{
	if (UseSerialDebug) Serial.println("FPS - EnrollStart");
	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 FPS_GT511C3::Enroll1()
{
	if (UseSerialDebug) Serial.println("FPS - 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();
//Change to  "retval < 3000", if using GT-521F52
//Leave "reval < 200", if using GT-521F32/GT-511C3
	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 FPS_GT511C3::Enroll2()
{
	if (UseSerialDebug) Serial.println("FPS - 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();
//Change to "retval < 3000", if using GT-521F52
//Leave "reval < 200", if using GT-521F32/GT-511C3
	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 FPS_GT511C3::Enroll3()
{
	if (UseSerialDebug) Serial.println("FPS - 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();
//Change to "retval < 3000", if using GT-521F52
//Leave "reval < 200", if using GT-521F32/GT-511C3
        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 FPS_GT511C3::IsPressFinger()
{
	if (UseSerialDebug) Serial.println("FPS - IsPressFinger");
	Command_Packet* cp = new Command_Packet();
	cp->Command = Command_Packet::Commands::IsPressFinger;
	byte* packetbytes = cp->GetPacketBytes();
	delete cp;
	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;
	return retval;
}

// Deletes the specified ID (enrollment) from the database
// Parameter: 0-2999, if using GT-521F52 (id number to be deleted)
//            0-199, if using GT-521F32/GT-511C3(id number to be deleted)
// Returns: true if successful, false if position invalid
bool FPS_GT511C3::DeleteID(int id)
{
	if (UseSerialDebug) Serial.println("FPS - DeleteID");
	Command_Packet* cp = new Command_Packet();
	cp->Command = Command_Packet::Commands::DeleteID;
	cp->ParameterFromInt(id);
	byte* packetbytes = cp->GetPacketBytes();
	delete cp;
	SendCommand(packetbytes, 12);
	Response_Packet* rp = GetResponse();
	bool retval = rp->ACK;
	delete rp;
	delete packetbytes;
	return retval;
}

// Deletes all IDs (enrollments) from the database
// Returns: true if successful, false if db is empty
bool FPS_GT511C3::DeleteAll()
{
	if (UseSerialDebug) Serial.println("FPS - 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-2999, if using GT-521F52 (id number to be checked)
//            0-199, if using GT-521F32/GT-511C3 (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 FPS_GT511C3::Verify1_1(int id)
{
	if (UseSerialDebug) Serial.println("FPS - Verify1_1");
	Command_Packet* cp = new Command_Packet();
	cp->Command = Command_Packet::Commands::Verify1_1;
	cp->ParameterFromInt(id);
	byte* packetbytes = cp->GetPacketBytes();
	delete cp;
	SendCommand(packetbytes, 12);
	Response_Packet* rp = GetResponse();
	int retval = 0;
	if (rp->ACK == false)
	{
		retval = 3; // grw 01/03/15 - set default value of not verified before assignment
		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;
	return retval;
}

// Checks the currently pressed finger against all enrolled fingerprints
// Returns:
//	Verified against the specified ID (found, and here is the ID number)
//           0-2999, if using GT-521F52
//           0-199, if using GT-521F32/GT-511C3
//      Failed to find the fingerprint in the database
// 	     3000, if using GT-521F52
//           200, if using GT-521F32/GT-511C3
int FPS_GT511C3::Identify1_N()
{
	if (UseSerialDebug) Serial.println("FPS - Identify1_N");
	Command_Packet* cp = new Command_Packet();
	cp->Command = Command_Packet::Commands::Identify1_N;
	byte* packetbytes = cp->GetPacketBytes();
	delete cp;
	SendCommand(packetbytes, 12);
	Response_Packet* rp = GetResponse();
	int retval = rp->IntFromParameter();
//Change to "retval > 3000" and "retval = 3000", if using GT-521F52
//Leave "reval > 200" and "retval = 200", if using GT-521F32/GT-511C3
	if (retval > 200) retval = 200;
	delete rp;
	delete packetbytes;
	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 FPS_GT511C3::CaptureFinger(bool highquality)
{
	if (UseSerialDebug) Serial.println("FPS - CaptureFinger");
	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();
	delete cp;
	SendCommand(packetbytes, 12);
	Response_Packet* rp = GetResponse();
	bool retval = rp->ACK;
	delete rp;
	delete packetbytes;
	return retval;

}
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
#pragma region -= Not imlemented commands =-
#endif  //__GNUC__
// Gets an image that is 258x202 (52116 bytes) and returns it in 407 Data_Packets
// Use StartDataDownload, and then GetNextDataPacket until done
// Returns: True (device confirming download starting)
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
//bool FPS_GT511C3::GetImage()
//{
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//return false;
//}

// Gets an image that is qvga 160x120 (19200 bytes) and returns it in 150 Data_Packets
// Use StartDataDownload, and then GetNextDataPacket until done
// Returns: True (device confirming download starting)
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
//bool FPS_GT511C3::GetRawImage()
//{
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//return false;
//}

// Gets a template from the fps (498 bytes) in 4 Data_Packets
// Use StartDataDownload, and then GetNextDataPacket until done
// Parameter: 0-199 ID number
// Returns:
//	0 - ACK Download starting
//	1 - Invalid position
//	2 - ID not used (no template to download
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
//int FPS_GT511C3::GetTemplate(int id)
//{
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//return false;
//}

// Uploads a template to the fps
// Parameter: the template (498 bytes)
// Parameter: the ID number to upload
// Parameter: Check for duplicate fingerprints already on fps
// Returns:
//	0-199 - ID duplicated
//	200 - Uploaded ok (no duplicate if enabled)
//	201 - Invalid position
//	202 - Communications error
//	203 - Device error
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
//int FPS_GT511C3::SetTemplate(byte* tmplt, int id, bool duplicateCheck)
//{
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
	//return -1;
//}

// resets the Data_Packet class, and gets ready to download
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
//void FPS_GT511C3::StartDataDownload()
//{
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
//}

// Returns the next data packet
	// Not implemented due to memory restrictions on the arduino
	// may revisit this if I find a need for it
//Data_Packet GetNextDataPacket()
//{
//	return 0;
//}

// Commands that are not implemented (and why)
// VerifyTemplate1_1 - Couldn't find a good reason to implement this on an arduino
// IdentifyTemplate1_N - Couldn't find a good reason to implement this on an arduino
// MakeTemplate - Couldn't find a good reason to implement this on an arduino
// UsbInternalCheck - not implemented - Not valid config for arduino
// GetDatabaseStart - historical command, no longer supported
// GetDatabaseEnd - historical command, no longer supported
// UpgradeFirmware - Data sheet says not supported
// UpgradeISOCDImage - Data sheet says not supported
// SetIAPMode - for upgrading firmware (which data sheet says is not supported)
// Ack and Nack	are listed as commands for some unknown reason... not implemented
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__


#ifndef __GNUC__
#pragma region -= Private Methods =-
#endif  //__GNUC__
// Sends the command to the software serial channel
void FPS_GT511C3::SendCommand(byte cmd[], int length)
{
	_serial.write(cmd, length);
	if (UseSerialDebug)
	{
		Serial.print("FPS - SEND: ");
		SendToSerial(cmd, length);
		Serial.println();
	}
};

// Gets the response to the command from the software serial channel (and waits for it)
Response_Packet* FPS_GT511C3::GetResponse()
{
	byte firstbyte = 0;
	bool done = false;
	_serial.listen();
	while (done == false)
	{
		firstbyte = (byte)_serial.read();
		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++)
	{
		while (_serial.available() == false) delay(10);
		resp[i]= (byte) _serial.read();
	}
	Response_Packet* rp = new Response_Packet(resp, UseSerialDebug);
	delete resp;
	if (UseSerialDebug)
	{
		Serial.print("FPS - RECV: ");
		SendToSerial(rp->RawBytes, 12);
		Serial.println();
		Serial.println();
	}
	return rp;
};

// sends the bye aray to the serial debugger in our hex format EX: "00 AF FF 10 00 13"
void FPS_GT511C3::SendToSerial(byte data[], int length)
{
  boolean first=true;
  Serial.print("\"");
  for(int i=0; i<length; i++)
  {
	if (first) first=false; else Serial.print(" ");
	serialPrintHex(data[i]);
  }
  Serial.print("\"");
}

// sends a byte to the serial debugger in the hex format we want EX "0F"
void FPS_GT511C3::serialPrintHex(byte data)
{
  char tmp[16];
  sprintf(tmp, "%.2X",data);
  Serial.print(tmp);
}
#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__

#ifndef __GNUC__
#pragma endregion
#endif  //__GNUC__

:smiley: Thank you all; :smiley: