diff --git a/examples/UnitUnified/UnitFinger2/Automatic/main/Automatic.cpp b/examples/UnitUnified/UnitFinger2/Automatic/main/Automatic.cpp index 25994d3..e7695ef 100644 --- a/examples/UnitUnified/UnitFinger2/Automatic/main/Automatic.cpp +++ b/examples/UnitUnified/UnitFinger2/Automatic/main/Automatic.cpp @@ -38,7 +38,8 @@ void print_exists_users() } } -bool callback_enroll(const ConfirmCode confirm, const AutoEnrollStage stage, const uint8_t state) +bool callback_enroll(const uint16_t call_times, const uint16_t page_id, const ConfirmCode confirm, + const AutoEnrollStage stage, const uint8_t state) { lcd.startWrite(); switch (stage) { @@ -63,8 +64,8 @@ bool callback_enroll(const ConfirmCode confirm, const AutoEnrollStage stage, con break; } lcd.setCursor(0, 0); - lcd.printf("ENROLL:%02u [%02X] (%02X)", (uint8_t)stage, (uint8_t)confirm, state); - M5.Log.printf(" Enroll CB:%02u [%02X] (%02X)\n", (uint8_t)stage, (uint8_t)confirm, stage); + lcd.printf("ENROLL:%02u %02u [%02X] (%02X)", call_times, (uint8_t)stage, (uint8_t)confirm, state); + M5.Log.printf(" Enroll[%02u]:%02u [%02X] (%02X)\n", call_times, (uint8_t)stage, (uint8_t)confirm, stage); lcd.endWrite(); return true; // Abort if false @@ -111,12 +112,12 @@ void auto_enroll() } } -bool callback_identify(const ConfirmCode confirm, const AutoIdentifyStage stage) +bool callback_identify(const uint16_t call_times, const ConfirmCode confirm, const AutoIdentifyStage stage) { lcd.setCursor(0, 0); lcd.printf("IDENTIFY:%02u [%02X]", (uint8_t)stage, (uint8_t)confirm); lcd.endWrite(); - M5.Log.printf(" Identify CB:%02u [%02X]\n", (uint8_t)stage, (uint8_t)confirm); + M5.Log.printf(" Identify[%02u]:%02u [%02X]\n", call_times, (uint8_t)stage, (uint8_t)confirm); return true; // Abort if false } diff --git a/examples/UnitUnified/UnitFinger2/User/main/User.cpp b/examples/UnitUnified/UnitFinger2/User/main/User.cpp index 257728d..abd9034 100644 --- a/examples/UnitUnified/UnitFinger2/User/main/User.cpp +++ b/examples/UnitUnified/UnitFinger2/User/main/User.cpp @@ -27,12 +27,21 @@ m5::unit::UnitFinger2 unit; uint32_t cur_menu{}; uint16_t cur_user{0}; +bool callback_batch(const uint16_t call_times, const uint16_t actual_size, const uint16_t batch_size, + const uint16_t total_size, const uint16_t planned_size, const bool completed) +{ + M5.Log.printf(" [%03u]:%3u/%3u,%4u/%4u:%s\n", call_times, actual_size, batch_size, total_size, planned_size, + completed ? "COMPLETED" : "CONTINUE"); + + return true; // Abort if false +} + void make_random_user() { unit.wakeup(); // Template to buffer - if (!unit.writeTemplateAllBatches(template_data, template_data_size)) { + if (!unit.writeTemplateAllBatches(template_data, template_data_size, 128, callback_batch)) { M5_LOGE("Failed to writeTemplateAllBatches"); return; } @@ -183,7 +192,7 @@ void loop() std::vector temp{}; temp.resize(m5::unit::UnitFinger2::TEMPLATE_SIZE); uint16_t actual{}; - if (unit.readTemplateAllBatches(actual, temp.data(), temp.size())) { + if (unit.readTemplateAllBatches(actual, temp.data(), temp.size(), 256, callback_batch)) { m5::utility::log::dump(temp.data(), actual, false); } else { M5_LOGE("Failed to readTemplateAllBatches %u", cur_user); diff --git a/src/unit/unit_Finger2.cpp b/src/unit/unit_Finger2.cpp index e24d70f..45afe45 100644 --- a/src/unit/unit_Finger2.cpp +++ b/src/unit/unit_Finger2.cpp @@ -461,13 +461,14 @@ bool UnitFinger2::readTemplate(uint16_t& actual_size, uint8_t* buf, const uint16 } bool UnitFinger2::readTemplateAllBatches(uint16_t& actual_size, uint8_t* buf, const uint16_t buf_size, - const uint16_t batch_size) + const uint16_t batch_size, batch_callback_t callback) { if (!buf || !buf_size || !batch_size) { return false; } uint16_t offset{}; + uint16_t call_count{}; while (offset < buf_size) { uint16_t actual{}; if (!readTemplate(actual, buf + offset, batch_size, offset)) { @@ -475,6 +476,13 @@ bool UnitFinger2::readTemplateAllBatches(uint16_t& actual_size, uint8_t* buf, co } offset += actual; actual_size += actual; + + if (callback && !callback(call_count, actual, batch_size, actual_size, buf_size, actual < batch_size)) { + // Abort by callback + return true; + } + ++call_count; + if (actual < batch_size) { // No more data break; } @@ -503,13 +511,14 @@ bool UnitFinger2::writeTemplate(const uint16_t offset, const uint8_t* buf, const return transceive_command(pkt, CMD_DOWNLOAD_TEMPLATE, _address, params.data(), params.size()); } -bool UnitFinger2::writeTemplateAllBatches(const uint8_t* buf, const uint16_t buf_size, const uint16_t batch_size) +bool UnitFinger2::writeTemplateAllBatches(const uint8_t* buf, const uint16_t buf_size, const uint16_t batch_size, + batch_callback_t callback) { if (!buf || !buf_size || !batch_size) { return false; } - uint16_t offset{}; + uint16_t offset{}, call_count{}; uint16_t remain = buf_size; while (offset < buf_size) { uint16_t sz = std::min(remain, batch_size); @@ -518,6 +527,12 @@ bool UnitFinger2::writeTemplateAllBatches(const uint8_t* buf, const uint16_t buf } offset += sz; remain -= sz; + + if (callback && !callback(call_count, sz, batch_size, offset, buf_size, offset == buf_size)) { + // Abort by callback + return true; + } + ++call_count; } return offset == buf_size; } @@ -749,6 +764,7 @@ bool UnitFinger2::autoEnroll(ConfirmCode& confirm, const uint16_t page_id, const AutoEnrollStage stage{}; uint8_t state{}; + uint8_t process_times{}; confirm = ConfirmCode::PacketError; if (write_command(CMD_AUTO_ENROLL, _address, params, sizeof(params))) { // Depending on the flags specified, multiple responses may be returned @@ -766,14 +782,16 @@ bool UnitFinger2::autoEnroll(ConfirmCode& confirm, const uint16_t page_id, const stage = static_cast(pkt[10]); state = pkt[11]; - bool abort = - (stage < AutoEnrollStage::StoreTemplate && callback) ? !callback(confirm, stage, state) : false; + bool abort = (callback && stage < AutoEnrollStage::StoreTemplate) + ? !callback(process_times, page_id, confirm, stage, state) + : false; // M5_LIB_LOGD(">>>> Confirm:%02x Stage:%02u State:%02X abort:%u", confirm, stage, state, abort); if (abort || confirm != ConfirmCode::OK) { confirm = abort ? ConfirmCode::OperationBlocked : confirm; break; } + ++process_times; } while (stage < AutoEnrollStage::StoreTemplate); @@ -813,6 +831,7 @@ bool UnitFinger2::autoIdentify(bool& matched, uint16_t& matching_page_id, uint16 AutoIdentifyStage stage{}; auto confirm = ConfirmCode::PacketError; + uint8_t process_times{}; if (write_command(CMD_AUTO_IDENTIFY, _address, params, sizeof(params))) { // Depending on the flags specified, multiple responses may be returned do { @@ -827,13 +846,16 @@ bool UnitFinger2::autoIdentify(bool& matched, uint16_t& matching_page_id, uint16 // 0:Verify command 1:GetImage 5:Registered fingerprint comparison stage = static_cast(pkt[10]); - bool abort = (stage < AutoIdentifyStage::Result && callback) ? !callback(confirm, stage) : false; + bool abort = + (callback && stage < AutoIdentifyStage::Result) ? !callback(process_times, confirm, stage) : false; // M5_LIB_LOGD(">>>> Confirm:%02x Stage:%02u abort:%u", confirm, stage, abort); if (abort || confirm != ConfirmCode::OK) { confirm = abort ? ConfirmCode::OperationBlocked : confirm; break; } + + ++process_times; } while (stage < AutoIdentifyStage::Result); // Identify successful? diff --git a/src/unit/unit_Finger2.hpp b/src/unit/unit_Finger2.hpp index 62da744..7604374 100644 --- a/src/unit/unit_Finger2.hpp +++ b/src/unit/unit_Finger2.hpp @@ -217,34 +217,51 @@ enum class ConfirmCode : uint8_t { SmallImage, //!< 0x33:Image too small StaticObjectInImage, //!< 0x34:Static foreign object in the image (Orange) IllegalData, //!< 0x35:The data is illegal - NotUsed36, - StaticObjectInFeature, //!< 0x37:Static Foreign Object in Feature (Orange) - PacketTimeout = 0xF9, //!< 0xF9:Receive packet timeout - PacketBad, //!< 0xFA:Error Packet (e.g., data not fully received, other packet received) - PacketOverflow, //!< 0xFB:Packet overflow (e.g., when a packet exceeds the maximum length) - OperationBlocked, //!< 0xFC:This operation has been blocked - ParameterError, //!< 0xFD:Parameter error - NotActive, //!< 0xFE:The fingerprint module is not activated + PacketTimeout = 0xF9, //!< 0xF9:Receive packet timeout + PacketBad, //!< 0xFA:Error Packet (e.g., data not fully received, other packet received) + PacketOverflow, //!< 0xFB:Packet overflow (e.g., when a packet exceeds the maximum length) + OperationBlocked, //!< 0xFC:This operation has been blocked + ParameterError, //!< 0xFD:Parameter error + NotActive, //!< 0xFE:The fingerprint module is not activated PassiveActivation = 0xFF, //!< 0xFF:Passive activation }; /*! @brief Callback function for autoEnroll + @brief call_times Number of callback invocations (zero origin) + @param page_id page_id being attempted to register @param confirm ConfirmCode @param stage AutoEnrollStage - @param state state value of the stage - @retval true: Contiue process + @param state State value of the stage + @retval true: Continue process @retval false: Abort process */ -using auto_enroll_callback_t = bool (*)(const ConfirmCode confirm, const AutoEnrollStage stage, const uint8_t state); +using auto_enroll_callback_t = bool (*)(const uint16_t call_times, const uint16_t page_id, const ConfirmCode confirm, + const AutoEnrollStage stage, const uint8_t state); /*! @brief Callback function for autoIdentify + @brief call_times Number of callback invocations (zero origin) @param confirm ConfirmCode @param stage AutoIdentifyStage - @retval true: Contiue process + @retval true: Continue process @retval false: Abort process */ -using auto_identify_callback_t = bool (*)(const ConfirmCode confirm, const AutoIdentifyStage stage); +using auto_identify_callback_t = bool (*)(const uint16_t call_times, const ConfirmCode confirm, + const AutoIdentifyStage stage); + +/*! + @brief Callback for batch read/write + @brief call_times Number of callback invocations (zero origin) + @brief actual_size Size processed in a single batch operation + @brief batch_size Processing size per batch + @brief total_size Total processed size + @brief planned_size Planned size + @brief completed Is this the final step? + @retval true: Continue process + @retval false: Abort process (If completed == true, ignore) + */ +using batch_callback_t = bool (*)(const uint16_t call_times, const uint16_t actual_size, const uint16_t batch_size, + const uint16_t total_size, const uint16_t planned_size, const bool completed); } // namespace finger2 @@ -578,11 +595,13 @@ public: @brief Read the template @param [out] actual_size Actual size @param[out] buf Output buffer (at least 7262 bytes) + @param batch_size Processing size per batch + @param callback Callback invoked for each batch processing @return True if successful @pre The template exists in the buffer */ bool readTemplateAllBatches(uint16_t& actual_size, uint8_t* buf, const uint16_t buf_size, - const uint16_t batch_size = 128); + const uint16_t batch_size = 128, finger2::batch_callback_t callback = nullptr); /*! @brief Write the specific size template to the specific offset @param offset Offset address @@ -595,9 +614,12 @@ public: @brief Write the template @param buf Input buffer @param buf_size size of buf + @param batch_size Processing size per batch + @param callback Callback invoked for each batch processing @return True if successful */ - bool writeTemplateAllBatches(const uint8_t* buf, const uint16_t buf_size, const uint16_t batch_size = 128); + bool writeTemplateAllBatches(const uint8_t* buf, const uint16_t buf_size, const uint16_t batch_size = 128, + finger2::batch_callback_t callback = nullptr); /*! @brief Delete templates