268 lines
7.5 KiB
C++
268 lines
7.5 KiB
C++
#include <SmingCore.h>
|
|
#include "FingerPrint.h"
|
|
|
|
static struct CFingerErrorsExplain
|
|
{
|
|
uint8_t error;
|
|
const char *str;
|
|
} gs_FingerErrors[] = {
|
|
{ERROR_OK, "ERROR_OK: command execution complete"},
|
|
{ERROR_COMMUNICATION, "ERROR_COMMUNICATION: error when receiving data package"},
|
|
{ERROR_NOFINGER, "ERROR_NOFINGER: no finger on the sensor"},
|
|
{ERROR_READIMAGE, "ERROR_READIMAGE: fail to enroll the finger"},
|
|
{ERROR_MESSYIMAGE, "ERROR_MESSYIMAGE: fail to generate character file due to the over-disorderly fingerprint image"},
|
|
{ERROR_FEWFEATUREPOINTS, "ERROR_FEWFEATUREPOINTS: fail to generate character file due to lackness of character point or over-smallness of fingerprint image"},
|
|
{ERROR_NOTMATCHING, "ERROR_NOTMATCHING: finger doesn't match"},
|
|
{ERROR_NOTEMPLATEFOUND, "ERROR_NOTEMPLATEFOUND: fail to find the matching finger"},
|
|
{ERROR_CHARACTERISTICSMISMATCH, "ERROR_CHARACTERISTICSMISMATCH: fail to combine the character files"},
|
|
{ERROR_INVALIDPOSITION, "ERROR_INVALIDPOSITION: addressing PageID is beyond the finger library"},
|
|
{ERROR_LOADTEMPLATE, "ERROR_LOADTEMPLATE: error when reading template from library or the template is invalid"},
|
|
{ERROR_UPLOADTEMPLATE, "ERROR_UPLOADTEMPLATE: error when uploading template"},
|
|
{ERROR_PACKETRESPONSEFAIL, "ERROR_PACKETRESPONSEFAIL: Module can't receive the following data packages"},
|
|
{ERROR_UPLOADIMAGE, "ERROR_UPLOADIMAGE: error when uploading image"},
|
|
{ERROR_DELETETEMPLATE, "ERROR_DELETETEMPLATE: fail to delete the template"},
|
|
{ERROR_CLEARDATABASE, "ERROR_CLEARDATABASE: fail to clear finger library"},
|
|
{ERROR_WRONGPASSWORD, "ERROR_WRONGPASSWORD: wrong password"},
|
|
{ERROR_INVALIDIMAGE, "ERROR_INVALIDIMAGE: fail to generate the image for the lackness of valid primary image"},
|
|
{ERROR_FLASH, "ERROR_FLASH: error when writing flash"},
|
|
{ERROR_NODEF, "ERROR_NODEF: No definition error"},
|
|
{ERROR_INVALIDREGISTER, "ERROR_INVALIDREGISTER: invalid register number"},
|
|
{ERROR_INCORRECTREGISTERCONF, "ERROR_INCORRECTREGISTERCONF: incorrect configuration of register"},
|
|
{ERROR_INVALIDNOTEPADPAGE, "ERROR_INVALIDNOTEPADPAGE: wrong notepad page number"},
|
|
{ERROR_COMMUNICATIONPORT, "ERROR_COMMUNICATIONPORT: fail to operate the communication port"}
|
|
};
|
|
|
|
const char *CFingerPrint::ExplainFingerError(uint8_t error)
|
|
{
|
|
CFingerErrorsExplain *pFound = NULL;
|
|
for(int i = 0; i < sizeof(gs_FingerErrors) / sizeof(*gs_FingerErrors); i++)
|
|
{
|
|
if(error == gs_FingerErrors[i].error)
|
|
{
|
|
pFound = &gs_FingerErrors[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(pFound)
|
|
return pFound->str;
|
|
|
|
return "Unknown error.";
|
|
}
|
|
|
|
CFingerPrint::CFingerPrint()
|
|
{
|
|
m_RecvState = RECV_DROP;
|
|
}
|
|
|
|
void CFingerPrint::Init(HardwareSerial &serial, uint32_t address, uint32_t password)
|
|
{
|
|
if(m_pSerial)
|
|
return;
|
|
|
|
m_pSerial = &serial;
|
|
m_Address = address;
|
|
m_Password = password;
|
|
|
|
m_pSerial->onDataReceived(StreamDataReceivedDelegate(&CFingerPrint::OnData, this));
|
|
}
|
|
|
|
void CFingerPrint::OnData(Stream &stream, char arrivedChar, unsigned short availableCharsCount)
|
|
{
|
|
if(m_RecvState == RECV_DONE)
|
|
return;
|
|
|
|
if(m_RecvState == RECV_DROP)
|
|
{
|
|
while(stream.available())
|
|
stream.read();
|
|
|
|
return;
|
|
}
|
|
|
|
// RECV_WAITING
|
|
while(stream.available())
|
|
{
|
|
uint8_t cur = stream.read();
|
|
|
|
if(m_RecvIndex == 0 && cur != 0xEF || m_RecvIndex == 1 && cur != 0x01)
|
|
{
|
|
debugf("skip garbage header at %d: %X", m_RecvIndex, cur);
|
|
m_RecvIndex = 0;
|
|
continue;
|
|
}
|
|
|
|
m_aRecvBuffer[m_RecvIndex++] = cur;
|
|
|
|
// Packet could be complete (the minimal packet size is 12 bytes)
|
|
if(m_RecvIndex >= 12)
|
|
{
|
|
// Check the packet header (redundant)
|
|
uint16_t header = m_aRecvBuffer[0] << 8 | m_aRecvBuffer[1];
|
|
if(header != 0xEF01)
|
|
{
|
|
debugf("wrong header: %X", header);
|
|
m_RecvIndex = 0;
|
|
continue;
|
|
}
|
|
|
|
// Calculate packet payload length
|
|
uint16_t length = m_aRecvBuffer[7] << 8 | m_aRecvBuffer[8];
|
|
|
|
// Check if the packet is still fully received
|
|
// Condition: index counter < packet payload length + packet frame
|
|
if(m_RecvIndex < length + 9)
|
|
continue;
|
|
|
|
// At this point the packet should be fully received
|
|
uint8_t ident = m_aRecvBuffer[6];
|
|
|
|
// Calculate checksum:
|
|
// Checksum = packet type (1 byte) + packet length RAW!! (2 bytes) + packet payload (n bytes)
|
|
uint16_t calcChecksum = ident;
|
|
const uint16_t tmp = 7 + length;
|
|
for(uint16_t i = 7; i < tmp; i++)
|
|
calcChecksum += m_aRecvBuffer[i];
|
|
|
|
// Checksum in received data package
|
|
uint16_t recvChecksum = m_aRecvBuffer[m_RecvIndex - 2] << 8 | m_aRecvBuffer[m_RecvIndex - 1];
|
|
|
|
if(calcChecksum != recvChecksum)
|
|
{
|
|
debugf("checksum!!: %X != %X", calcChecksum, recvChecksum);
|
|
m_RecvIndex = 0;
|
|
continue;
|
|
}
|
|
|
|
m_RecvIndex = 0;
|
|
m_RecvState = RECV_DONE;
|
|
|
|
(this->*m_fnRecvCallback)((FingerPrintIdent)ident, &m_aRecvBuffer[9], length - 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
int CFingerPrint::Recv(FingerPrintIdent *pIdent, uint8_t *pData, uint16_t maxLength, const int maxTime)
|
|
{
|
|
m_RecvState = RECV_DONE;
|
|
m_RecvIndex = 0;
|
|
|
|
debugf("Start manual recv:");
|
|
int Ret = -9999;
|
|
|
|
int timeout = maxTime;
|
|
while(true)
|
|
{
|
|
while(!m_pSerial->available())
|
|
{
|
|
if(--timeout == 0)
|
|
return Ret;
|
|
delay(1);
|
|
}
|
|
|
|
uint8_t cur = m_pSerial->read();
|
|
m_aRecvBuffer[m_RecvIndex++] = cur;
|
|
|
|
// Packet could be complete (the minimal packet size is 12 bytes)
|
|
if(m_RecvIndex >= 12)
|
|
{
|
|
// Check the packet header
|
|
uint16_t header = m_aRecvBuffer[0] << 8 | m_aRecvBuffer[1];
|
|
if(header != 0xEF01)
|
|
{
|
|
debugf("wrong header: %X", header);
|
|
m_RecvIndex = 0;
|
|
return Ret;
|
|
}
|
|
|
|
// Calculate packet payload length
|
|
uint16_t length = m_aRecvBuffer[7] << 8 | m_aRecvBuffer[8];
|
|
|
|
// Check if the packet is still fully received
|
|
// Condition: index counter < packet payload length + packet frame
|
|
if(m_RecvIndex < length + 9)
|
|
continue;
|
|
|
|
// At this point the packet should be fully received
|
|
uint8_t ident = m_aRecvBuffer[6];
|
|
|
|
// Calculate checksum:
|
|
// Checksum = packet type (1 byte) + packet length RAW! (2 bytes) + packet payload (n bytes)
|
|
uint16_t calcChecksum = ident + length;
|
|
uint16_t tmp = 9 + length - 2;
|
|
for(uint16_t i = 9; i < tmp; i++)
|
|
calcChecksum += m_aRecvBuffer[i];
|
|
|
|
// Checksum in received data package
|
|
uint16_t recvChecksum = m_aRecvBuffer[m_RecvIndex - 2] << 8 | m_aRecvBuffer[m_RecvIndex - 1];
|
|
|
|
if(calcChecksum != recvChecksum)
|
|
{
|
|
debugf("checksum!!: %X != %X", calcChecksum, recvChecksum);
|
|
m_RecvIndex = 0;
|
|
return Ret;
|
|
}
|
|
|
|
length -= 2;
|
|
Ret = 0;
|
|
|
|
if(pIdent)
|
|
*(uint8_t *)pIdent = ident;
|
|
|
|
if(pData)
|
|
{
|
|
memcpy(pData, &m_aRecvBuffer[9], min(length, maxLength));
|
|
Ret = (int)maxLength - length; // >= 0 = OK
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
debugf("End recv. (%dms)", maxTime - timeout);
|
|
m_RecvIndex = 0;
|
|
|
|
return Ret;
|
|
}
|
|
|
|
int CFingerPrint::Write(FingerPrintIdent ident, uint8_t *pData, uint16_t length)
|
|
{
|
|
m_RecvState = RECV_WAITING;
|
|
|
|
// Header
|
|
const uint16_t Header = 0xEF01;
|
|
m_pSerial->write(Header >> 8 & 0xFF);
|
|
m_pSerial->write(Header >> 0 & 0xFF);
|
|
|
|
// Address
|
|
m_pSerial->write(m_Address >> 24 & 0xFF);
|
|
m_pSerial->write(m_Address >> 16 & 0xFF);
|
|
m_pSerial->write(m_Address >> 8 & 0xFF);
|
|
m_pSerial->write(m_Address >> 0 & 0xFF);
|
|
|
|
// Package identifier
|
|
m_pSerial->write(ident);
|
|
|
|
// Package length
|
|
length += 2; // Checksum
|
|
m_pSerial->write(length >> 8 & 0xFF);
|
|
m_pSerial->write(length >> 0 & 0xFF);
|
|
|
|
// Checksum
|
|
uint16_t Checksum = ident + length;
|
|
|
|
// Data
|
|
length -= 2;
|
|
for(uint16_t i = 0; i < length; i++)
|
|
{
|
|
m_pSerial->write(pData[i]);
|
|
Checksum += pData[i];
|
|
}
|
|
|
|
// Checksum
|
|
m_pSerial->write(Checksum >> 8 & 0xFF);
|
|
m_pSerial->write(Checksum >> 0 & 0xFF);
|
|
|
|
return length;
|
|
}
|