#include #include #include "utils.h" #include "main.h" #include "FingerPrint.h" #include "FingerLogic.h" CFingerLogic::CFingerLogic(CMain *pMain) { m_pFingerPrint = NULL; m_State = STATE_INITIAL; m_Finger = false; m_Power = false; m_pMain = pMain; memset(&m_FingerParams, 0, sizeof(m_FingerParams)); memset(m_aFingerSlots, 0, sizeof(m_aFingerSlots)); m_FingerSlotsAdded = 0; m_ErrorCounter = 0; m_InitTimer.initializeMs(100, TimerDelegate(&CFingerLogic::InitFinger, this)); m_PowerOffTimer.initializeMs(1000, TimerDelegate(&CFingerLogic::PowerOff, this)); } void CFingerLogic::Init(CFingerPrint *pFingerPrint) { m_pFingerPrint = pFingerPrint; InitFinger(); } void CFingerLogic::SetState(FingerLogicState state) { m_State = state; if(m_State == STATE_ERROR) m_ErrorCounter++; if(m_State == STATE_READY || m_State == STATE_ERROR) { m_PowerOffTimer.startOnce(); } else { m_PowerOffTimer.stop(); PowerOn(); } } void CFingerLogic::PowerOff() { if(!m_Power) return; debugf("PowerOff()"); m_Power = false; m_ErrorCounter = 0; Main().FingerPower(false); } void CFingerLogic::PowerOn() { if(m_Power) return; debugf("PowerOn()"); m_Power = true; Main().FingerPower(true); system_soft_wdt_feed(); delayMilliseconds(100); system_soft_wdt_feed(); } void CFingerLogic::OnFinger(bool finger) { debugf("OnFinger: %s", finger ? "DOWN" : "UP"); m_Finger = finger; if(finger) { if(m_State == STATE_READY) VerifyFinger(); else if(m_State == STATE_ENROLL_WAITFINGER1 || m_State == STATE_ENROLL_WAITFINGER2) EnrollFinger_OnFinger(); } } bool CFingerLogic::FingerSlot(uint16_t index) { if(index > m_FingerSlotsAdded) return false; return m_aFingerSlots[index / 8] & (1 << (index % 8)); } bool CFingerLogic::FingerSlot(uint16_t index, bool value) { if(index > m_FingerSlotsAdded) return false; if(value) m_aFingerSlots[index / 8] |= (1 << (index % 8)); else m_aFingerSlots[index / 8] &= ~(1 << (index % 8)); return true; } int CFingerLogic::FirstFreeFingerSlot() { for(int i = 0; i < m_FingerSlotsAdded / 8; i++) { if(m_aFingerSlots[i] != 0xFF) { uint8_t val = m_aFingerSlots[i]; for(int j = 0; j < 8; j++) { if(!(val & (1 << j))) return (i * 8) + j; } } } return -1; } void CFingerLogic::InitFinger() { if(m_State > STATE_INIT_VERIFYPASSWORD) return; if(m_ErrorCounter > 100) return; SetState(STATE_INIT_VERIFYPASSWORD); FingerPrint().AsyncVerifyPassword((VerifyPasswordCallback)InitFinger_OnVerifyPassword, this); m_InitTimer.start(); m_ErrorCounter++; } void CFingerLogic::InitFinger_OnVerifyPassword(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { pThis->m_ErrorCounter--; pThis->m_InitTimer.stop(); debugf("InitFinger_OnVerifyPassword: (%d) %s", error, errorStr); if(error == ERROR_OK) { pThis->SetState(STATE_INIT_READSYSTEMPARAMETERS); pThis->FingerPrint().AsyncReadSystemParameters((ReadSystemParametersCallback)InitFinger_OnReadSystemParameters, pThis); } else pThis->SetState(STATE_ERROR); } void CFingerLogic::InitFinger_OnReadSystemParameters(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, CFingerSystemParameters *param) { debugf("InitFinger_OnReadSystemParameters: (%d) %s", error, errorStr); if(error == ERROR_OK) { memcpy(&pThis->m_FingerParams, param, sizeof(CFingerSystemParameters)); debugf("statusRegister: %d", param->statusRegister); debugf("systemID: %d", param->systemID); debugf("storageCapacity: %d", param->storageCapacity); debugf("securityLevel: %d", param->securityLevel); debugf("deviceAddress: %X", param->deviceAddress); debugf("packetLength: %d", param->packetLength); debugf("baudRate: %d", param->baudRate); if(param->securityLevel != pThis->Main().Settings().m_SecurityLevel) { pThis->SetState(STATE_INIT_SETSYSTEM_SECURITYLEVEL); pThis->FingerPrint().AsyncSetSystemParameter((SetSystemParameterCallback)InitFinger_OnSetSystemSecurityLevel, pThis, FINGERPRINT_SECURITY_REG_ADDR, pThis->Main().Settings().m_SecurityLevel); } else { pThis->SetState(STATE_INIT_READTEMPLATEMAP); pThis->FingerPrint().AsyncReadTemplateMap((ReadTemplateMapCallback)InitFinger_OnReadTemplateMap, pThis, 0); } } else { pThis->SetState(STATE_ERROR); pThis->m_InitTimer.start(); } } void CFingerLogic::InitFinger_OnSetSystemSecurityLevel(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("InitFinger_OnSetSystemSecurityLevel: (%d) %s", error, errorStr); if(error == ERROR_OK) { pThis->SetState(STATE_INIT_READTEMPLATEMAP); pThis->FingerPrint().AsyncReadTemplateMap((ReadTemplateMapCallback)InitFinger_OnReadTemplateMap, pThis, 0); } else { pThis->SetState(STATE_ERROR); pThis->m_InitTimer.start(); } } void CFingerLogic::InitFinger_OnReadTemplateMap(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, uint8_t *pData, uint16_t dataLen) { debugf("InitFinger_OnReadTemplateMap: (%d) %s (%p, %d)", error, errorStr, pData, dataLen); if(error == ERROR_OK) { memcpy(&pThis->m_aFingerSlots[pThis->m_FingerSlotsAdded/8], pData, dataLen); pThis->m_FingerSlotsAdded += dataLen * 8; if(pThis->m_FingerSlotsAdded < pThis->m_FingerParams.storageCapacity) { uint8_t page = pThis->m_FingerSlotsAdded / 8 / dataLen; pThis->FingerPrint().AsyncReadTemplateMap((ReadTemplateMapCallback)InitFinger_OnReadTemplateMap, pThis, page); } else { pThis->InitFinger_VerifyTemplates(); } } } void CFingerLogic::InitFinger_VerifyTemplates() { SetState(STATE_INIT_VERIFYTEMPLATES); HashMap &fingerMap = Main().Settings().m_FingerPrints; uint16_t fingerCount = fingerMap.count(); // Check consistency (1) for(uint16_t i = 0; i < fingerCount; i++) { uint16_t id = fingerMap.keyAt(i); if(!FingerSlot(id)) { SetState(STATE_ERROR); FingerPrint().EmptyDatabase(); fingerMap.clear(); Main().Settings().Save(); debugf("InitFinger_VerifyTemplates: INCONSITENCY(1) AT SLOT %d !!!", id); return; } } // Check consistency (2) for(uint16_t id = 0; id < m_FingerSlotsAdded; id++) { if(FingerSlot(id) && !fingerMap.contains(id)) { SetState(STATE_ERROR); FingerPrint().EmptyDatabase(); fingerMap.clear(); Main().Settings().Save(); debugf("InitFinger_VerifyTemplates: INCONSITENCY(2) AT SLOT %d !!!", id); return; } } if(!fingerCount) { SetState(STATE_READY); return; } m_iBuffer = 0; uint16_t position = fingerMap.keyAt(m_iBuffer); FingerPrint().AsyncLoadTemplate((LoadTemplateCallback)InitFinger_OnLoadTemplate, this, position, 0x01); } void CFingerLogic::InitFinger_OnLoadTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("InitFinger_OnLoadTemplate: (%d) %s", error, errorStr); if(error == ERROR_OK) { pThis->FingerPrint().AsyncDownloadCharacteristics((DownloadCharacteristicsCallback)InitFinger_OnDownloadCharacteristics, pThis, 0x01); } else { pThis->SetState(STATE_ERROR); pThis->m_InitTimer.start(); } } void CFingerLogic::InitFinger_OnDownloadCharacteristics(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, int8_t *pChar, uint16_t charLen) { debugf("InitFinger_OnDownloadCharacteristics: (%d) %s (%p, %d)", error, errorStr, pChar, charLen); if(error == ERROR_OK) { Crypto::Sha256 ctx; ctx.update(pChar, charLen); uint8_t *digest = ctx.getHash().data(); const CSettings::CFingerPrint &finger = pThis->Main().Settings().m_FingerPrints.valueAt(pThis->m_iBuffer); char aHexDigest1[SHA256_SIZE*2+1]; char aHexDigest2[SHA256_SIZE*2+1]; bytes2hex(digest, sizeof(digest), aHexDigest1, sizeof(aHexDigest1)); bytes2hex(finger.m_aDigest, sizeof(finger.m_aDigest), aHexDigest2, sizeof(aHexDigest2)); debugf("Index: %d -> Num: %d \"%s\" (%s ?= %s)", pThis->m_iBuffer, finger.m_FingerNum, finger.m_aLabel, aHexDigest1, aHexDigest2); if(memcmp(digest, finger.m_aDigest, SHA256_SIZE) != 0) { pThis->SetState(STATE_ERROR); debugf("InitFinger_VerifyTemplates: DIVERGENT DIGEST AT SLOT %d !!!", pThis->m_iBuffer); return; } pThis->m_iBuffer++; if(pThis->m_iBuffer >= pThis->Main().Settings().m_FingerPrints.count()) { debugf("InitFinger_VerifyTemplates: DONE! Verified %d templates.", pThis->m_iBuffer); pThis->SetState(STATE_READY); return; } uint16_t position = pThis->Main().Settings().m_FingerPrints.keyAt(pThis->m_iBuffer); pThis->FingerPrint().AsyncLoadTemplate((LoadTemplateCallback)InitFinger_OnLoadTemplate, pThis, position, 0x01); } else { pThis->SetState(STATE_ERROR); pThis->m_InitTimer.start(); } } void CFingerLogic::VerifyFinger() { if(m_State != STATE_READY) return; SetState(STATE_VERIFY_READIMAGE); FingerPrint().AsyncReadImage((ReadImageCallback)VerifyFinger_OnReadImage, this); } void CFingerLogic::VerifyFinger_OnReadImage(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("VerifyFinger_OnReadImage: (%d) %s", error, errorStr); if(error == ERROR_OK) { pThis->SetState(STATE_VERIFY_CONVERTIMAGE); pThis->FingerPrint().AsyncConvertImage((ConvertImageCallback)VerifyFinger_OnConvertImage, pThis, 0x01); } else { pThis->SetState(STATE_READY); if(pThis->m_Finger) pThis->VerifyFinger(); } } void CFingerLogic::VerifyFinger_OnConvertImage(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("VerifyFinger_OnConvertImage: (%d) %s", error, errorStr); if(error == ERROR_OK) { pThis->SetState(STATE_VERIFY_SEARCHTEMPLATE); pThis->FingerPrint().AsyncSearchTemplate((SearchTemplateCallback)VerifyFinger_OnSearchTemplate, pThis, 0x01, 0, pThis->m_FingerParams.storageCapacity); } else { pThis->SetState(STATE_READY); if(pThis->m_Finger) pThis->VerifyFinger(); } } void CFingerLogic::VerifyFinger_OnSearchTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, int16_t position, int16_t score) { debugf("VerifyFinger_OnSearchTemplate: (%d) %s (%d, %d)", error, errorStr, position, score); if(error == ERROR_OK) { pThis->m_iBuffer = position; pThis->SetState(STATE_VERIFY_LOADTEMPLATE); pThis->FingerPrint().AsyncLoadTemplate((LoadTemplateCallback)VerifyFinger_OnLoadTemplate, pThis, position, 0x01); } else pThis->SetState(STATE_READY); } void CFingerLogic::VerifyFinger_OnLoadTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("VerifyFinger_OnLoadTemplate: (%d) %s", error, errorStr); if(error == ERROR_OK) { pThis->SetState(STATE_VERIFY_DOWNLOADCHARACTERISTICS); pThis->FingerPrint().AsyncDownloadCharacteristics((DownloadCharacteristicsCallback)VerifyFinger_OnDownloadCharacteristics, pThis, 0x01); } else pThis->SetState(STATE_READY); } void CFingerLogic::VerifyFinger_OnDownloadCharacteristics(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, int8_t *pChar, uint16_t charLen) { debugf("VerifyFinger_OnDownloadCharacteristics: (%d) %s (%p, %d)", error, errorStr, pChar, charLen); if(error == ERROR_OK) { Crypto::Sha256 ctx; ctx.update(pChar, charLen); uint8_t *digest = ctx.getHash().data(); char aHexDigest[SHA256_SIZE*2+1]; bytes2hex(digest, sizeof(digest), aHexDigest, sizeof(aHexDigest)); debugf("Finger hexdigest: %s", aHexDigest); pThis->Main().OnFingerVerified(pThis->m_iBuffer, digest); } pThis->SetState(STATE_READY); } bool CFingerLogic::EnrollFinger(bool cancel) { if(cancel) { if(m_State < STATE_ENROLL_WAITFINGER1 || m_State > STATE_ENROLL_DOWNLOADCHARACTERISTICS) return false; SetState(STATE_READY); return true; } if(m_State != STATE_READY) return false; SetState(STATE_ENROLL_WAITFINGER1); if(m_Finger) EnrollFinger_OnFinger(); return true; } void CFingerLogic::EnrollFinger_OnFinger() { if(m_State == STATE_ENROLL_WAITFINGER1) { SetState(STATE_ENROLL_READIMAGE1); FingerPrint().AsyncReadImage((ReadImageCallback)EnrollFinger_OnReadImage1, this); } else if(m_State == STATE_ENROLL_WAITFINGER2) { SetState(STATE_ENROLL_READIMAGE2); FingerPrint().AsyncReadImage((ReadImageCallback)EnrollFinger_OnReadImage2, this); } } void CFingerLogic::EnrollFinger_OnReadImage1(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("EnrollFinger_OnReadImage1: (%d) %s", error, errorStr); if(pThis->m_State != STATE_ENROLL_READIMAGE1) return; if(error == ERROR_OK) { pThis->SetState(STATE_ENROLL_CONVERTIMAGE1); pThis->FingerPrint().AsyncConvertImage((ConvertImageCallback)EnrollFinger_OnConvertImage1, pThis, 0x01); } else { pThis->SetState(STATE_ENROLL_WAITFINGER1); char aBuf[512]; m_snprintf(aBuf, sizeof(aBuf), "Error while scanning finger: %s
Lift your finger and try again.", errorStr); pThis->Main().EnrollMessage(aBuf); } } void CFingerLogic::EnrollFinger_OnConvertImage1(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("EnrollFinger_OnConvertImage1: (%d) %s", error, errorStr); if(pThis->m_State != STATE_ENROLL_CONVERTIMAGE1) return; if(error == ERROR_OK) { pThis->SetState(STATE_ENROLL_SEARCHTEMPLATE); pThis->FingerPrint().AsyncSearchTemplate((SearchTemplateCallback)EnrollFinger_OnSearchTemplate, pThis, 0x01, 0, pThis->m_FingerParams.storageCapacity); } else { pThis->SetState(STATE_ENROLL_WAITFINGER1); char aBuf[512]; m_snprintf(aBuf, sizeof(aBuf), "Error while analyzing finger: %s
Lift your finger and try again.", errorStr); pThis->Main().EnrollMessage(aBuf); } } void CFingerLogic::EnrollFinger_OnSearchTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, int16_t position, int16_t score) { debugf("EnrollFinger_OnSearchTemplate: (%d) %s (%d, %d)", error, errorStr, position, score); if(pThis->m_State != STATE_ENROLL_SEARCHTEMPLATE) return; if(error == ERROR_OK) { pThis->SetState(STATE_READY); pThis->Main().EnrollMessage("Aborting: This finger is already enrolled!", true); } else { pThis->SetState(STATE_ENROLL_WAITFINGER2); pThis->Main().EnrollMessage("Finger scanned. Lift finger and place it on the sensor again to enroll."); } } void CFingerLogic::EnrollFinger_OnReadImage2(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("EnrollFinger_OnReadImage2: (%d) %s", error, errorStr); if(pThis->m_State != STATE_ENROLL_READIMAGE2) return; if(error == ERROR_OK) { pThis->SetState(STATE_ENROLL_CONVERTIMAGE2); pThis->FingerPrint().AsyncConvertImage((ConvertImageCallback)EnrollFinger_OnConvertImage2, pThis, 0x02); } else { pThis->SetState(STATE_ENROLL_WAITFINGER2); char aBuf[512]; m_snprintf(aBuf, sizeof(aBuf), "Error while scanning finger: %s
Lift your finger and try again.", errorStr); pThis->Main().EnrollMessage(aBuf); } } void CFingerLogic::EnrollFinger_OnConvertImage2(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("EnrollFinger_OnConvertImage2: (%d) %s", error, errorStr); if(pThis->m_State != STATE_ENROLL_CONVERTIMAGE2) return; if(error == ERROR_OK) { pThis->SetState(STATE_ENROLL_COMPARE); pThis->FingerPrint().AsyncCompareCharacteristics((CompareCharacteristicsCallback)EnrollFinger_OnCompareCharacteristics, pThis); } else { pThis->SetState(STATE_ENROLL_WAITFINGER2); char aBuf[512]; m_snprintf(aBuf, sizeof(aBuf), "Error while analyzing finger: %s
Lift your finger and try again.", errorStr); pThis->Main().EnrollMessage(aBuf); } } void CFingerLogic::EnrollFinger_OnCompareCharacteristics(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, int16_t score) { debugf("EnrollFinger_OnCompareCharacteristics: (%d) %s (%d)", error, errorStr, score); if(pThis->m_State != STATE_ENROLL_COMPARE) return; if(error == ERROR_OK) { pThis->SetState(STATE_ENROLL_CREATETEMPLATE); pThis->FingerPrint().AsyncCreateTemplate((CreateTemplateCallback)EnrollFinger_OnCreateTemplate, pThis); } else { pThis->SetState(STATE_ENROLL_WAITFINGER1); char aBuf[512]; m_snprintf(aBuf, sizeof(aBuf), "Error while comparing fingers: %s
Lift your finger and try again.", errorStr); pThis->Main().EnrollMessage(aBuf); } } void CFingerLogic::EnrollFinger_OnCreateTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("EnrollFinger_OnCreateTemplate: (%d) %s", error, errorStr); if(pThis->m_State != STATE_ENROLL_CREATETEMPLATE) return; if(error == ERROR_OK) { pThis->SetState(STATE_ENROLL_STORETEMPLATE); pThis->m_iBuffer = pThis->FirstFreeFingerSlot(); pThis->FingerPrint().AsyncStoreTemplate((StoreTemplateCallback)EnrollFinger_OnStoreTemplate, pThis, pThis->m_iBuffer, 0x01); } else pThis->SetState(STATE_READY); } void CFingerLogic::EnrollFinger_OnStoreTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, uint16_t positionNumber) { debugf("EnrollFinger_OnStoreTemplate: (%d) %s (%d)", error, errorStr, positionNumber); if(pThis->m_State != STATE_ENROLL_STORETEMPLATE) return; if(error == ERROR_OK) { pThis->FingerSlot(positionNumber, true); pThis->SetState(STATE_ENROLL_LOADTEMPLATE); pThis->FingerPrint().AsyncLoadTemplate((LoadTemplateCallback)EnrollFinger_OnLoadTemplate, pThis, positionNumber, 0x01); } else pThis->SetState(STATE_READY); } void CFingerLogic::EnrollFinger_OnLoadTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("EnrollFinger_OnLoadTemplate: (%d) %s", error, errorStr); if(pThis->m_State != STATE_ENROLL_LOADTEMPLATE) return; if(error == ERROR_OK) { pThis->SetState(STATE_ENROLL_DOWNLOADCHARACTERISTICS); pThis->FingerPrint().AsyncDownloadCharacteristics((DownloadCharacteristicsCallback)EnrollFinger_OnDownloadCharacteristics, pThis, 0x01); } else pThis->SetState(STATE_READY); } void CFingerLogic::EnrollFinger_OnDownloadCharacteristics(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, int8_t *pChar, uint16_t charLen) { debugf("EnrollFinger_OnDownloadCharacteristics: (%d) %s (%p, %d)", error, errorStr, pChar, charLen); if(pThis->m_State != STATE_ENROLL_DOWNLOADCHARACTERISTICS) return; if(error == ERROR_OK) { Crypto::Sha256 ctx; ctx.update(pChar, charLen); uint8_t *digest = ctx.getHash().data(); pThis->Main().OnFingerEnrolled(pThis->m_iBuffer, digest); } pThis->SetState(STATE_READY); } void CFingerLogic::SetSecurityLevel(int securityLevel) { SetState(STATE_SETSYSTEM_SECURITYLEVEL); FingerPrint().AsyncSetSystemParameter((SetSystemParameterCallback)SetSecurityLevel_OnSetSystemSecurityLevel, this, FINGERPRINT_SECURITY_REG_ADDR, securityLevel); } void CFingerLogic::SetSecurityLevel_OnSetSystemSecurityLevel(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { debugf("SetSecurityLevel_OnSetSystemSecurityLevel: (%d) %s", error, errorStr); pThis->SetState(STATE_READY); }