esp32-fingerprint-safe/app/FingerPrint.cpp

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;
}