From decd3073ef1b30a3091f4ec31f3c057bd234a09e Mon Sep 17 00:00:00 2001 From: Andrey Perminov Date: Tue, 22 Jun 2021 13:02:08 -0700 Subject: [PATCH] Added experimental library for Arduino The library has not been tested yet on a real Arduino board. Any improvements would be greatly appreciated. --- Arduino_lib/BMLite/README.adoc | 19 + .../examples/bmlite_demo/bmlite_demo.ino | 330 ++++++++++++++++ Arduino_lib/BMLite/keywords.txt | 15 + Arduino_lib/BMLite/library.properties | 9 + Arduino_lib/BMLite/src/BMLite.h | 24 ++ Arduino_lib/BMLite/src/bmlite_hal.h | 131 +++++++ Arduino_lib/BMLite/src/bmlite_if.cpp | 324 ++++++++++++++++ Arduino_lib/BMLite/src/bmlite_if.h | 365 ++++++++++++++++++ Arduino_lib/BMLite/src/bmlite_if_callbacks.h | 108 ++++++ Arduino_lib/BMLite/src/fpc_bep_types.h | 93 +++++ Arduino_lib/BMLite/src/fpc_crc.cpp | 88 +++++ Arduino_lib/BMLite/src/fpc_crc.h | 37 ++ Arduino_lib/BMLite/src/fpc_hcp_common.h | 223 +++++++++++ Arduino_lib/BMLite/src/hcp_tiny.cpp | 305 +++++++++++++++ Arduino_lib/BMLite/src/hcp_tiny.h | 146 +++++++ Arduino_lib/BMLite/src/platform.cpp | 100 +++++ Arduino_lib/BMLite/src/platform.h | 106 +++++ 17 files changed, 2423 insertions(+) create mode 100644 Arduino_lib/BMLite/README.adoc create mode 100644 Arduino_lib/BMLite/examples/bmlite_demo/bmlite_demo.ino create mode 100644 Arduino_lib/BMLite/keywords.txt create mode 100644 Arduino_lib/BMLite/library.properties create mode 100644 Arduino_lib/BMLite/src/BMLite.h create mode 100644 Arduino_lib/BMLite/src/bmlite_hal.h create mode 100644 Arduino_lib/BMLite/src/bmlite_if.cpp create mode 100644 Arduino_lib/BMLite/src/bmlite_if.h create mode 100644 Arduino_lib/BMLite/src/bmlite_if_callbacks.h create mode 100644 Arduino_lib/BMLite/src/fpc_bep_types.h create mode 100644 Arduino_lib/BMLite/src/fpc_crc.cpp create mode 100644 Arduino_lib/BMLite/src/fpc_crc.h create mode 100644 Arduino_lib/BMLite/src/fpc_hcp_common.h create mode 100644 Arduino_lib/BMLite/src/hcp_tiny.cpp create mode 100644 Arduino_lib/BMLite/src/hcp_tiny.h create mode 100644 Arduino_lib/BMLite/src/platform.cpp create mode 100644 Arduino_lib/BMLite/src/platform.h diff --git a/Arduino_lib/BMLite/README.adoc b/Arduino_lib/BMLite/README.adoc new file mode 100644 index 0000000..ee3914c --- /dev/null +++ b/Arduino_lib/BMLite/README.adoc @@ -0,0 +1,19 @@ += BM-Lite Library for Arduino = + +This library allows an Arduino board to access FPC BM-LIte module. + +== License == + +Copyright (c) 2020 Andrey Perminov + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/Arduino_lib/BMLite/examples/bmlite_demo/bmlite_demo.ino b/Arduino_lib/BMLite/examples/bmlite_demo/bmlite_demo.ino new file mode 100644 index 0000000..3348a89 --- /dev/null +++ b/Arduino_lib/BMLite/examples/bmlite_demo/bmlite_demo.ino @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2020 Andrey Perminov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#define BMLITE_PIN_RESET 2 +#define BMLITE_PIN_STATUS 4 + +#define LED1 14 +#define LED2 15 +#define LED3 16 +#define LED4 17 + +#define BMLITE_BUTTON 3 + +#define BMLITE_CS_PIN 8 +//#define BMLITE_MISO_PIN ARDUINO_12_PIN +//#define BMLITE_MOSI_PIN ARDUINO_11_PIN +//#define BMLITE_CLK_PIN ARDUINO_13_PIN + + +int leds[4] = {LED1, LED2, LED3, LED4}; + + +#define DATA_BUFFER_SIZE (512) +static uint8_t hcp_txrx_buffer[MTU]; +static uint8_t hcp_data_buffer[DATA_BUFFER_SIZE]; + +static HCP_comm_t hcp_chain; + +void setup() { + + char *version; + + hcp_chain.write = platform_bmlite_spi_send; + hcp_chain.read = platform_bmlite_spi_receive; + hcp_chain.phy_rx_timeout = 2000; + hcp_chain.pkt_buffer = hcp_data_buffer; + hcp_chain.pkt_size_max = sizeof(hcp_data_buffer); + hcp_chain.pkt_size = 0; + hcp_chain.txrx_buffer = hcp_txrx_buffer; + + + // put your setup code here, to run once: + pinMode(BMLITE_PIN_RESET, OUTPUT); + pinMode(BMLITE_PIN_STATUS, INPUT); + + for(int i=0; i<4; i++) { + pinMode(leds[i], OUTPUT); + } + set_leds(0); + + pinMode(BMLITE_BUTTON, INPUT); + + SPI.begin(); + pinMode(BMLITE_CS_PIN, OUTPUT); + + platform_init(NULL); + + // This block is for debug purpose only and can be safely removed + { + version = (char *)malloc(50); + memset(version, 0, 50); + fpc_bep_result_t res = bep_version(&hcp_chain, version, 99); + free(version); + } + +} + +uint16_t template_id; +uint32_t current_id = 0; +bool match; + + +void loop() { + // put your main code here, to run repeatedly: + int res; + + uint32_t btn_time = hal_get_button_press_time(); + hal_set_leds(BMLITE_LED_STATUS_READY,0); + if (btn_time < 200) { + // nothing hapened + } else if (btn_time < 5000) { + // Enroll + res = bep_enroll_finger(&hcp_chain); + res = bep_template_save(&hcp_chain, current_id++); + } else { + // Erase All templates + hal_set_leds(BMLITE_LED_STATUS_DELETE_TEMPLATES, true); + res = bep_template_remove_all(&hcp_chain); + current_id = 0; + } + res = bep_identify_finger(&hcp_chain, 0, &template_id, &match); + if (res == FPC_BEP_RESULT_TIMEOUT) { + platform_bmlite_reset(); + } else if (res != FPC_BEP_RESULT_OK) { + return; + } + hal_set_leds(BMLITE_LED_STATUS_MATCH, match); + res = sensor_wait_finger_not_present(&hcp_chain, 0); +} + +void bmlite_on_error(bmlite_error_t error, int32_t value) +{ + if(value != FPC_BEP_RESULT_TIMEOUT) { + hal_set_leds(BMLITE_LED_STATUS_ERROR, false); + } else { + // Timeout - not really an error here + hal_set_leds(BMLITE_LED_STATUS_ERROR, true); + } +} + +// void bmlite_on_start_capture(); +// void bmlite_on_finish_capture(); + +void bmlite_on_start_enroll() +{ + hal_set_leds(BMLITE_LED_STATUS_ENROLL, true); +} + +void bmlite_on_finish_enroll() +{ + hal_set_leds(BMLITE_LED_STATUS_ENROLL, false); +} + +void bmlite_on_start_enrollcapture() +{ + hal_set_leds(BMLITE_LED_STATUS_WAITTOUCH, true); +} + +void bmlite_on_finish_enrollcapture() +{ + hal_set_leds(BMLITE_LED_STATUS_READY, false); +} + +void bmlite_on_identify_start() +{ + hal_set_leds(BMLITE_LED_STATUS_READY, true); +} + +// void bmlite_on_identify_finish(); + + +/* + * Arduino HAL Implementation + */ + +fpc_bep_result_t hal_board_init(void *params) +{ + (void)params; + + return FPC_BEP_RESULT_OK; +} + +void hal_bmlite_reset(bool state) +{ + if(!state) { + digitalWrite(BMLITE_PIN_RESET, HIGH); + } else { + digitalWrite(BMLITE_PIN_RESET, LOW); + } +} + +bool hal_bmlite_get_status(void) +{ + return digitalRead(BMLITE_PIN_STATUS); +} + + +/** LED ON time in ms */ +#define LED_SOLID_ON_TIME_MS 700 + +/** LED blink time in ms */ +#define LED_BLINK_TIME_MS 200 + +static void set_leds(uint8_t color) +{ + uint32_t i; + + for(i=0; i<4; i++) { + digitalWrite(leds[i], color & 1); + color = color >> 1; + } +} + +void hal_set_leds(platform_led_status_t status, uint16_t mode) +{ + switch(status) { + case BMLITE_LED_STATUS_READY: + set_leds(0); + break; + case BMLITE_LED_STATUS_MATCH: + if (mode) { + set_leds(1); + } else { + set_leds(2); + } + hal_timebase_busy_wait(500); + break; + case BMLITE_LED_STATUS_WAITTOUCH: + if (mode) { + set_leds(3); + } + break; + case BMLITE_LED_STATUS_ENROLL: + if (mode) { + // Start enroll + set_leds(1); + hal_timebase_busy_wait(500); + set_leds(2); + hal_timebase_busy_wait(500); + } else { + // Finish enroll + set_leds(1); + hal_timebase_busy_wait(100); + set_leds(0); + hal_timebase_busy_wait(100); + set_leds(2); + hal_timebase_busy_wait(100); + } + break; + case BMLITE_LED_STATUS_DELETE_TEMPLATES: + set_leds(4); + hal_timebase_busy_wait(100); + set_leds(0); + hal_timebase_busy_wait(100); + set_leds(4); + hal_timebase_busy_wait(100); + break; + case BMLITE_LED_STATUS_ERROR: + if (mode) { + set_leds(3); + hal_timebase_busy_wait(70); + } else { + set_leds(3); + hal_timebase_busy_wait(500); + set_leds(0); + hal_timebase_busy_wait(500); + set_leds(3); + hal_timebase_busy_wait(500); + } + break; + } +} + + +fpc_bep_result_t hal_bmlite_spi_write_read(uint8_t *buff, size_t size) +{ + + digitalWrite(BMLITE_CS_PIN, LOW); + SPI.transfer(buff,size); + digitalWrite(BMLITE_CS_PIN, HIGH); + + return FPC_BEP_RESULT_OK; +} + + +volatile uint32_t button_pressed_time = 0; + +static uint32_t btn_press_start; +static uint32_t btn_pressed = 0; + +void hal_timebase_init(void) +{ +} + +void hal_timebase_busy_wait(uint32_t delay) +{ + uint32_t start; + uint32_t delay_internal = 0; + + /* Ensure minimum delay or skip if delay is zero*/ + if (delay) { + delay_internal = delay + 1; + start = micros(); + while ((micros() - start) < delay_internal) { + } + } +} + +hal_tick_t hal_timebase_get_tick(void) +{ + return micros(); +} + +static void check_buttons() +{ + if (digitalRead(BMLITE_BUTTON)) { + if (btn_pressed == 0) { + btn_press_start = micros(); + btn_pressed = 1; + } + } else { // Btn released + if (btn_pressed) { + if (micros() > btn_press_start) { + button_pressed_time = micros() - btn_press_start; + } else { + button_pressed_time = micros() + ~btn_press_start + 1; + } + btn_pressed = 0; + } + } +} + +uint32_t hal_get_button_press_time() +{ + uint32_t time = button_pressed_time; + button_pressed_time = 0; + return time; +} + +uint32_t hal_check_button_pressed() +{ + uint32_t time = button_pressed_time; + return time; +} diff --git a/Arduino_lib/BMLite/keywords.txt b/Arduino_lib/BMLite/keywords.txt new file mode 100644 index 0000000..088931e --- /dev/null +++ b/Arduino_lib/BMLite/keywords.txt @@ -0,0 +1,15 @@ +####################################### +# Syntax Coloring Map BMLite +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/Arduino_lib/BMLite/library.properties b/Arduino_lib/BMLite/library.properties new file mode 100644 index 0000000..2c451b9 --- /dev/null +++ b/Arduino_lib/BMLite/library.properties @@ -0,0 +1,9 @@ +name=BMLite +version=0.1 +author=Andrey Perminov +maintainer= +sentence=Allows Arduino/Genuino boards access to FPC BM-Lite module. +paragraph= +category= +url= +architectures=avr,megaavr,sam,samd,nrf52,stm32f4,mbed diff --git a/Arduino_lib/BMLite/src/BMLite.h b/Arduino_lib/BMLite/src/BMLite.h new file mode 100644 index 0000000..8a6e4e0 --- /dev/null +++ b/Arduino_lib/BMLite/src/BMLite.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 Andrey Perminov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define BMLITE_USE_CALLBACK + +#include "bmlite_if.h" +#include "hcp_tiny.h" +#include "platform.h" +#include "bmlite_hal.h" \ No newline at end of file diff --git a/Arduino_lib/BMLite/src/bmlite_hal.h b/Arduino_lib/BMLite/src/bmlite_hal.h new file mode 100644 index 0000000..a9a1c27 --- /dev/null +++ b/Arduino_lib/BMLite/src/bmlite_hal.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2020 Andrey Perminov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file bmlite_hal.h + * @brief BM-Lite HAL functions. + * + * All functions must be implemented in order to support BM-Lite on a Board + */ + +#ifndef BMLITE_H +#define BMLITE_H + +#include +#include +#include + +#include "fpc_bep_types.h" + +#ifdef __arm__ +typedef uint32_t hal_tick_t; +#else +typedef uint64_t hal_tick_t; +#endif + +/** + * @brief LED status. + * + * Different LED status. + */ +typedef enum { + BMLITE_LED_STATUS_READY = 0, + BMLITE_LED_STATUS_MATCH, + BMLITE_LED_STATUS_WAITTOUCH, + BMLITE_LED_STATUS_ENROLL, + BMLITE_LED_STATUS_DELETE_TEMPLATES, + BMLITE_LED_STATUS_ERROR, +} platform_led_status_t; + + +/* + * @brief Board initialization + * @param[in] params - pointer to additional parameters + */ + +fpc_bep_result_t hal_board_init(void *params); + +/* + * @brief Control BM-Lite Reset pin + * @param[in] True - Activate RESET + * False - Deactivate RESET + */ +void hal_bmlite_reset(bool state); + +/* + * @brief SPI write-read + * @param[in] Write buffer + * @param[in] Read buffer + * @param[in] Size + * @param[in] Leave CS asserted + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t hal_bmlite_spi_write_read(uint8_t *buff, size_t size); + +/* + * @brief Check if BM-Lite IRQ pin is set + * @return ::bool + */ +bool hal_bmlite_get_status(void); + +/** + * @brief Initializes timebase. Starts system tick counter. + */ +void hal_timebase_init(void); + +/** + * @brief Reads the system tick counter. + * + * @return Tick count since hal_timebase_init() call. [ms] + */ +hal_tick_t hal_timebase_get_tick(void); + +/** + * @brief Busy wait. + * + * @param[in] ms Time to wait [ms]. + * 0 => return immediately + * 1 => wait at least 1ms etc. + */ +void hal_timebase_busy_wait(uint32_t ms); + +/** + * Optional functions for Buttons & Leds control + */ + +/** + * @brief Get button press time (msec) + * + * @return ::uint32_t + */ +uint32_t hal_get_button_press_time(void); + +/** + * @brief Check if button was pressed and released. + * + * @return Button press time in milli seconds. + */ +uint32_t hal_check_button_pressed(void); + +/** + * @brief Set LED(s) status + * @param[in] Status + * @param[in] Status modifier + */ +void hal_set_leds(platform_led_status_t status, uint16_t mode); + + +#endif /* BMLITE_H */ diff --git a/Arduino_lib/BMLite/src/bmlite_if.cpp b/Arduino_lib/BMLite/src/bmlite_if.cpp new file mode 100644 index 0000000..438a70a --- /dev/null +++ b/Arduino_lib/BMLite/src/bmlite_if.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2020 Andrey Perminov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hcp_tiny.h" +#include "bmlite_if.h" +#include "bmlite_hal.h" +#include + +#include "bmlite_if_callbacks.h" + +#define MAX_CAPTURE_ATTEMPTS 15 +#define MAX_SINGLE_CAPTURE_ATTEMPTS 3 +#define CAPTURE_TIMEOUT 3000 + +#define exit_if_err(c) { bep_result = c; if(bep_result || chain->bep_result) goto exit; } + +#define assert(c) { fpc_bep_result_t res = c; if(res) return res; } + +#ifdef BMLITE_USE_CALLBACK +/** + * @brief Mock callback functions + */ +__attribute__((weak)) void bmlite_on_error(bmlite_error_t error, int32_t value) { (void)error; (void)value; } + +__attribute__((weak)) void bmlite_on_start_capture() {} +__attribute__((weak)) void bmlite_on_finish_capture() {} + +__attribute__((weak)) void bmlite_on_start_enroll() {} +__attribute__((weak)) void bmlite_on_finish_enroll() {} + +__attribute__((weak)) void bmlite_on_start_enrollcapture() {} +__attribute__((weak)) void bmlite_on_finish_enrollcapture() {} + +__attribute__((weak)) void bmlite_on_identify_start() {} +__attribute__((weak)) void bmlite_on_identify_finish() {} +#endif + +fpc_bep_result_t bep_enroll_finger(HCP_comm_t *chain) +{ + uint32_t samples_remaining = 0; + fpc_bep_result_t bep_result = FPC_BEP_RESULT_OK; + bool enroll_done = false; + + bmlite_on_start_enroll(); + /* Enroll start */ + exit_if_err(bmlite_send_cmd(chain, CMD_ENROLL, ARG_START)); + + for (uint8_t i = 0; i < MAX_CAPTURE_ATTEMPTS; ++i) { + + bmlite_on_start_enrollcapture(); + bep_result = bep_capture(chain, CAPTURE_TIMEOUT); + bmlite_on_finish_enrollcapture(); + + if (bep_result != FPC_BEP_RESULT_OK) { + continue; + } + + /* Enroll add */ + bep_result = bmlite_send_cmd(chain, CMD_ENROLL, ARG_ADD); + if (bep_result != FPC_BEP_RESULT_OK) { + continue; + } + + bmlite_get_arg(chain, ARG_COUNT); + samples_remaining = *(uint32_t *)chain->arg.data; +// DEBUG("Enroll samples remaining: %d\n", samples_remaining); + + /* Break enrolling if we can't collect enough correct images for enroll*/ + if (samples_remaining == 0U) { + enroll_done = true; + break; + } + + sensor_wait_finger_not_present(chain, 0); + } + + bep_result = bmlite_send_cmd(chain, CMD_ENROLL, ARG_FINISH); + +exit: + bmlite_on_finish_enroll(); + return (!enroll_done) ? FPC_BEP_RESULT_GENERAL_ERROR : bep_result; +} + +fpc_bep_result_t bep_identify_finger(HCP_comm_t *chain, uint32_t timeout, uint16_t *template_id, bool *match) +{ + fpc_bep_result_t bep_result; + *match = false; + + bmlite_on_identify_start(); + + exit_if_err(bep_capture(chain, timeout)); + exit_if_err(bep_image_extract(chain)); + exit_if_err(bep_identify(chain)); + exit_if_err(bmlite_get_arg(chain, ARG_MATCH)); + *match = *(bool *)chain->arg.data; + if(*match) { + bmlite_get_arg(chain, ARG_ID); + *template_id = *(uint16_t *)chain->arg.data; + // Delay for possible updating template on BM-Lite + hal_timebase_busy_wait(50); + } +exit: + bmlite_on_identify_finish(); + return bep_result; +} + +fpc_bep_result_t sensor_wait_finger_present(HCP_comm_t *chain, uint16_t timeout) +{ + fpc_bep_result_t bep_result; + uint32_t prev_timeout = chain->phy_rx_timeout; + + bmlite_on_start_capture(); + chain->phy_rx_timeout = timeout; + bep_result = bmlite_send_cmd_arg(chain, CMD_WAIT, ARG_FINGER_DOWN, ARG_TIMEOUT, &timeout, sizeof(timeout)); + chain->phy_rx_timeout = prev_timeout; + bmlite_on_finish_capture(); + + return bep_result; +} + +fpc_bep_result_t sensor_wait_finger_not_present(HCP_comm_t *chain, uint16_t timeout) +{ + fpc_bep_result_t bep_result; + uint32_t prev_timeout = chain->phy_rx_timeout; + + chain->phy_rx_timeout = timeout; + bep_result = bmlite_send_cmd_arg(chain, CMD_WAIT, ARG_FINGER_UP, ARG_TIMEOUT, &timeout, sizeof(timeout)); + chain->phy_rx_timeout = prev_timeout; + + return bep_result; +} + +fpc_bep_result_t bep_capture(HCP_comm_t *chain, uint16_t timeout) +{ + fpc_bep_result_t bep_result; + uint32_t prev_timeout = chain->phy_rx_timeout; + + bmlite_on_start_capture(); + chain->phy_rx_timeout = timeout; + for(int i=0; i< MAX_SINGLE_CAPTURE_ATTEMPTS; i++) { + bep_result = bmlite_send_cmd_arg(chain, CMD_CAPTURE, ARG_NONE, ARG_TIMEOUT, &timeout, sizeof(timeout)); + if( !(bep_result || chain->bep_result)) + break; + } + chain->phy_rx_timeout = prev_timeout; + bmlite_on_finish_capture(); + + return bep_result; +} + +fpc_bep_result_t bep_image_get_size(HCP_comm_t *chain, uint32_t *size) +{ + assert(bmlite_send_cmd(chain, CMD_IMAGE, ARG_SIZE)); + assert(bmlite_get_arg(chain, ARG_SIZE)); + + *size = *(uint32_t*)chain->arg.data; + + return FPC_BEP_RESULT_OK; +} + +fpc_bep_result_t image_create(HCP_comm_t *chain) +{ + return bmlite_send_cmd(chain, CMD_IMAGE, ARG_CREATE); +} + +fpc_bep_result_t image_delete(HCP_comm_t *chain) +{ + return bmlite_send_cmd(chain, CMD_IMAGE, ARG_DELETE); +} + +fpc_bep_result_t bep_image_get(HCP_comm_t *chain, uint8_t *data, uint32_t size) +{ + assert(bmlite_send_cmd(chain, CMD_IMAGE, ARG_UPLOAD)); + return bmlite_copy_arg(chain, ARG_DATA, data, size); +} + +fpc_bep_result_t bep_image_put(HCP_comm_t *chain, uint8_t *data, uint32_t size) +{ + return bmlite_send_cmd_arg(chain, CMD_IMAGE, ARG_DOWNLOAD, ARG_DATA, data, size); +} + +fpc_bep_result_t bep_image_extract(HCP_comm_t *chain) +{ + return bmlite_send_cmd(chain, CMD_IMAGE, ARG_EXTRACT); +} + +fpc_bep_result_t bep_identify(HCP_comm_t *chain) +{ + return bmlite_send_cmd(chain, CMD_IDENTIFY, ARG_NONE); +} + +fpc_bep_result_t bep_template_save(HCP_comm_t *chain, uint16_t template_id) +{ + return bmlite_send_cmd_arg(chain, CMD_TEMPLATE, ARG_SAVE, ARG_ID, &template_id, sizeof(template_id)); +} + +fpc_bep_result_t bep_template_remove_ram(HCP_comm_t *chain) +{ + return bmlite_send_cmd(chain, CMD_TEMPLATE, ARG_DELETE); +} + +fpc_bep_result_t bep_template_get(HCP_comm_t *chain, uint8_t *data, uint32_t size) +{ + assert(bmlite_send_cmd(chain, CMD_TEMPLATE, ARG_UPLOAD)); + return bmlite_copy_arg(chain, ARG_DATA, data, size); +} + +fpc_bep_result_t bep_template_put(HCP_comm_t *chain, uint8_t *data, uint16_t length) +{ + return bmlite_send_cmd_arg(chain, CMD_TEMPLATE, ARG_DOWNLOAD, + ARG_DATA, data, length); +} + +fpc_bep_result_t bep_template_remove(HCP_comm_t *chain, uint16_t template_id) +{ + return bmlite_send_cmd_arg(chain, CMD_STORAGE_TEMPLATE, ARG_DELETE, + ARG_ID, &template_id, sizeof(template_id)); +} + +fpc_bep_result_t bep_template_remove_all(HCP_comm_t *chain) +{ + return bmlite_send_cmd_arg(chain, CMD_STORAGE_TEMPLATE, ARG_DELETE, + ARG_ALL, 0, 0); +} + +fpc_bep_result_t bep_template_load_storage(HCP_comm_t *chain, uint16_t template_id) +{ + return bmlite_send_cmd_arg(chain, CMD_STORAGE_TEMPLATE, ARG_UPLOAD, + ARG_ID, &template_id, sizeof(template_id)); +} + +fpc_bep_result_t bep_template_get_count(HCP_comm_t *chain, uint16_t *count) +{ + assert(bmlite_send_cmd(chain, CMD_STORAGE_TEMPLATE, ARG_COUNT)); + assert(bmlite_get_arg(chain, ARG_COUNT)); + *count = *(uint16_t*)chain->arg.data; + return FPC_BEP_RESULT_OK; +} + +fpc_bep_result_t bep_template_get_ids(HCP_comm_t *chain) +{ + assert(bmlite_send_cmd(chain, CMD_STORAGE_TEMPLATE, ARG_ID)); + return bmlite_get_arg(chain, ARG_DATA); +} + +fpc_bep_result_t bep_sw_reset(HCP_comm_t *chain) +{ + return bmlite_send_cmd(chain, CMD_RESET, ARG_NONE); +} + +fpc_bep_result_t bep_sensor_calibrate(HCP_comm_t *chain) +{ + return bmlite_send_cmd(chain, CMD_STORAGE_CALIBRATION, ARG_NONE); +} + +fpc_bep_result_t bep_sensor_calibrate_remove(HCP_comm_t *chain) +{ + return bmlite_send_cmd(chain, CMD_STORAGE_CALIBRATION, ARG_DELETE); +} + +fpc_bep_result_t bep_version(HCP_comm_t *chain, char *version, int len) +{ + assert(bmlite_send_cmd_arg(chain, CMD_INFO, ARG_GET, ARG_VERSION, 0, 0)); + return bmlite_copy_arg(chain, ARG_VERSION, version, len); +} + +fpc_bep_result_t bep_unique_id_get(HCP_comm_t *chain, uint8_t *unique_id) +{ + assert(bmlite_send_cmd_arg(chain, CMD_INFO, ARG_GET, ARG_UNIQUE_ID, 0, 0)); + return bmlite_copy_arg(chain, ARG_UNIQUE_ID, unique_id, 12); +} + +fpc_bep_result_t bep_uart_speed_set(HCP_comm_t *chain, uint32_t speed) +{ + assert(bmlite_init_cmd(chain, CMD_COMMUNICATION, ARG_SPEED)); + assert(bmlite_add_arg(chain, ARG_SET, 0, 0)); + assert(bmlite_add_arg(chain, ARG_DATA, (uint8_t*)&speed, sizeof(speed))); + return bmlite_tranceive(chain); + +} + +fpc_bep_result_t bep_uart_speed_get(HCP_comm_t *chain, uint32_t *speed) +{ + assert(bmlite_init_cmd(chain, CMD_COMMUNICATION, ARG_SPEED)); + assert(bmlite_add_arg(chain, ARG_GET, 0, 0)); + assert(bmlite_tranceive(chain)); + return bmlite_copy_arg(chain, ARG_DATA, speed, sizeof(speed)); + +} + +fpc_bep_result_t bep_sensor_reset(HCP_comm_t *chain) +{ + // Delay for possible updating template on BM-Lite + hal_timebase_busy_wait(50); + + return bmlite_send_cmd(chain, CMD_SENSOR, ARG_RESET); +} + +fpc_bep_result_t bmlite_send_cmd(HCP_comm_t *chain, uint16_t cmd, uint16_t arg_type) +{ + assert(bmlite_init_cmd(chain, cmd, arg_type)); + return bmlite_tranceive(chain); +} + +fpc_bep_result_t bmlite_send_cmd_arg(HCP_comm_t *chain, uint16_t cmd, uint16_t arg1_type, uint16_t arg2_type, void *arg2_data, uint16_t arg2_length) +{ + assert(bmlite_init_cmd(chain, cmd, arg1_type)); + assert(bmlite_add_arg(chain, arg2_type, arg2_data, arg2_length)); + + return bmlite_tranceive(chain); +} diff --git a/Arduino_lib/BMLite/src/bmlite_if.h b/Arduino_lib/BMLite/src/bmlite_if.h new file mode 100644 index 0000000..a2977fd --- /dev/null +++ b/Arduino_lib/BMLite/src/bmlite_if.h @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2020 Andrey Perminov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BMLITE_IF_H +#define BMLITE_IF_H + +#include "hcp_tiny.h" +#include "bmlite_if_callbacks.h" + +/** + * @brief Enroll finger. Created template must be saved to FLASH storage + * + * @param[in] chain - HCP com chain + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_enroll_finger(HCP_comm_t *chain); + +/** + * @brief Capture and identify finger against existing templates in Flash storage + * + * @param[in] chain - HCP com chain + * @param[in] timeout - timeout (msec). Maximum timeout 65535 msec + * set to 0 for waiting indefinitely + * + * @param[out] template_id - pointer for matched template ID + * @param[out] match - pointer to match result + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_identify_finger(HCP_comm_t *chain, uint32_t timeout, + uint16_t *template_id, bool *match); + +/** + * @brief Wait for finger present on sensor" + * + * @param[in] chain - HCP com chain + * @param[in] timeout - timeout (msec). Maximum timeout 65535 msec + * set to 0 for waiting indefinitely + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t sensor_wait_finger_present(HCP_comm_t *chain, uint16_t timeout); + +/** + * @brief Wait for finger not present on sensor" + * + * @param[in] chain - HCP com chain + * @param[in] timeout - timeout (msec). Maximum timeout 65535 msec + * set to 0 for waiting indefinitely + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t sensor_wait_finger_not_present(HCP_comm_t *chain, uint16_t timeout); + +/** + * @brief Wait for finger present on sensor and capture image" + * + * @param[in] chain - HCP com chain + * @param[in] timeout - timeout (msec). Maximum timeout 65535 msec + * set to 0 for waiting indefinitely + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_capture(HCP_comm_t *chain, uint16_t timeout); + +/** + * @brief Get size of captured image + * + * @param[in] chain - HCP com chain + * + * @param[out] size + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_image_get_size(HCP_comm_t *chain, uint32_t *size); + +/** + * @brief Allocates image buffer on FPC BM-LIte + * + * @param[in] chain - HCP com chain + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t image_create(HCP_comm_t *chain); + +/** + * @brief Deletes image buffer on FPC BM-LIte + * + * @param[in] chain - HCP com chain + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t image_delete(HCP_comm_t *chain); + +/** + * @brief Pull captured image from FPC BM-Lite + * + * @param[in] chain - HCP com chain + * + * @param[in] data - pointer to image buffer + * @param[in] size - size of the image buffer + * if buffer size is not enough the image + * will be truncated + * chain->arg.size will contain real size of the image + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_image_get(HCP_comm_t *chain, uint8_t *data, uint32_t size); + +/** + * @brief Push image to FPC BM-Lite + * + * @param[in] chain - HCP com chain + * + * @param[in] data - pointer to image buffer + * @param[in] size - size of the image buffer + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_image_put(HCP_comm_t *chain, uint8_t *data, uint32_t size); + +/** + * @brief Extract image features to prepare image for enrolling or matching + * + * @param[in] chain - HCP com chain + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_image_extract(HCP_comm_t *chain); + +/** + * @brief Identify prepared image against existing templates in Flash storage + * + * @param[in] chain - HCP com chain + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_identify(HCP_comm_t *chain); + +/** + * @brief Save template after enroll is finished to FLASH storage + * + * @param[in] chain - HCP com chain + * @param[out] template_id - template ID + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_template_save(HCP_comm_t *chain, uint16_t template_id); + +/** + * @brief Remove template from RAM + * + * @param[in] chain - HCP com chain + * @param[in] template_id - template ID + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_template_remove_ram(HCP_comm_t *chain); + +/** + * @brief Pull template stored in RAM from FPC BM-Lite + * + * @param[in] chain - HCP com chain + * + * @param[in] data - pointer to template buffer + * @param[in] size - size of the template buffer + * if buffer size is not enough the template + * will be truncated + * chain->arg.size will contain real size of the template + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_template_get(HCP_comm_t *chain, uint8_t *data, uint32_t size); + +/** + * @brief Push template to FPC BM-Lite and stored it to RAM + * + * @param[in] chain - HCP com chain + * + * @param[in] data - pointer to template buffer + * @param[in] size - size of the template buffer + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_template_put(HCP_comm_t *chain, uint8_t *data, uint16_t length); + +/** + * @brief Remove template from FLASH storage + * + * @param[in] chain - HCP com chain + * @param[in] template_id - template ID + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_template_remove(HCP_comm_t *chain, uint16_t template_id); + +/** + * @brief Remove all templates from FLASH storage + * + * @param[in] chain - HCP com chain + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_template_remove_all(HCP_comm_t *chain); + +/** + * @brief Copy template from FLASH storage to RAM + * + * @param[in] chain - HCP com chain + * @param[in] template_id - template ID + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_template_load_storage(HCP_comm_t *chain, uint16_t template_id); + +/** + * @brief Remove template from FLASH storage + * + * @param[in] chain - HCP com chain + * @param[out] template_id - template ID + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_template_get_count(HCP_comm_t *chain, uint16_t *count); + +/** + * @brief Get array of template ID stored on FPC BM-LIte + * + * @param[in] chain - HCP com chain + * @return ::fpc_bep_result_t + * chain->arg.data - pointer to array of uint16_t of IDs + * chain->arg.size - length of the array (in bytes). For calculating + * number of templates divide the arg.size by 2 + */ +fpc_bep_result_t bep_template_get_ids(HCP_comm_t *chain); + +/** + * @brief Software reset of FCP BM-Lite + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_sw_reset(HCP_comm_t *chain); + +/** + * @brief Calibrate FPC BM-LIte sensor and store calibration data to FLASH storage + * + * @param[in] chain - HCP com chain + * + * @return ::fpc_bep_result_t + * + * FPC BM-Lite must be restarted to activate new calibration data + */ +fpc_bep_result_t bep_sensor_calibrate(HCP_comm_t *chain); + +/** + * @brief Remove FPC BM-LIte sensor calibration data from FLASH storage + * + * @param[in] chain - HCP com chain + * + * @return ::fpc_bep_result_t + * + * FPC BM-Lite must be restarted to activate + */ +fpc_bep_result_t bep_sensor_calibrate_remove(HCP_comm_t *chain); + +/** + * @brief Get version of FPC BM-LIte firmware + * + * @param[in] chain - HCP com chain + * @param[in] version - pointer to data buffer + * @param[in] size - size of the data buffer + * if buffer size is not enough the data + * will be truncated + * chain->arg.size will contain real size of the data + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_version(HCP_comm_t *chain, char *version, int len); + +/** + * @brief Get version of FPC BM-LIte firmware + * + * @param[in] chain - HCP com chain + * @param[in] unique_id - pointer to data buffer + * chain->arg.size will contain real size of the data + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_unique_id_get(HCP_comm_t *chain, uint8_t *unique_id); + +/** + * @brief Set requested UART communication speed + * + * @param[in] chain - HCP com chain + * @param[in] speed - UART speed + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_uart_speed_set(HCP_comm_t *chain, uint32_t speed); + +/** + * @brief Get current UART communication speed + * + * @param[in] chain - HCP com chain + * @param[out] speed - UART speed + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_uart_speed_get(HCP_comm_t *chain, uint32_t *speed); + +/** + * @brief Reset FPC BM-Lite fingerprint sensor + * + * @param[in] chain - HCP com chain + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bep_sensor_reset(HCP_comm_t *chain); + +/** + * @brief Build and send command to FPC BM-Lite and receive answer + * + * @param[in] chain - HCP com chain + * @param[in] cmd - BM-Lite command + * @param[in] arg_type - Argument without parameters + * set to ARG_NONE if the command has no argument + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bmlite_send_cmd(HCP_comm_t *chain, uint16_t cmd, uint16_t arg_type); + +/** + * @brief Build and send command with additiona argument with parameters + * + * @param[in] chain - HCP com chain + * @param[in] cmd - BM-Lite command + * @param[in] arg1_type - argument 1 without parameters + * set to ARG_NONE if the command has no argument without paramener + * @param[in] arg2_type - argument 2 + * @param[in] arg2_data - data pointer for argument 2 + * set to 0 if argument 2 has no parameter + * @param[in] arg2_length - length of data for argument 2 + * set to 0 if argument 2 has no parameter + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bmlite_send_cmd_arg(HCP_comm_t *chain, uint16_t cmd, uint16_t arg1_type, uint16_t arg2_type, void *arg2_data, uint16_t arg2_length); + + + +#endif \ No newline at end of file diff --git a/Arduino_lib/BMLite/src/bmlite_if_callbacks.h b/Arduino_lib/BMLite/src/bmlite_if_callbacks.h new file mode 100644 index 0000000..6f816f7 --- /dev/null +++ b/Arduino_lib/BMLite/src/bmlite_if_callbacks.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020 Andrey Perminov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BMLITE_IF_CALLBACKS_H +#define BMLITE_IF_CALLBACKS_H +#include + +#ifndef BMLITE_USE_CALLBACK + #define bmlite_on_error(error, value) + #define bmlite_on_start_capture() + #define bmlite_on_finish_capture() + #define bmlite_on_finish_enroll() + #define bmlite_on_start_enroll() + #define bmlite_on_start_enrollcapture() + #define bmlite_on_finish_enrollcapture() + #define bmlite_on_identify_start() + #define bmlite_on_identify_finish() + +#else + +typedef enum { + BMLITE_ERROR_OK = 0, + BMLITE_ERROR_CAPTURE, + BMLITE_ERROR_CAPTURE_START, + BMLITE_ERROR_ENROLL_START, + BMLITE_ERROR_ENROLL_ADD, + BMLITE_ERROR_ENROLL_FINISH, + BMLITE_ERROR_WRONG_ANSWER, + BMLITE_ERROR_FINGER_WAIT, + BMLITE_ERROR_IDENTYFY, + BMLITE_ERROR_TEMPLATE_SAVE, + BMLITE_ERROR_TEMPLATE_DELETE, + BMLITE_ERROR_TEMPLATE_COUNT, + BMLITE_ERROR_TEMPLATE_GETIDS, + BMLITE_ERROR_IMAGE_EXTRACT, + BMLITE_ERROR_IMAGE_GETSIZE, + BMLITE_ERROR_IMAGE_GET, + BMLITE_ERROR_GETVERSION, + BMLITE_ERROR_SW_RESET, + BMLITE_ERROR_CALIBRATE, + BMLITE_ERROR_CALIBRATE_DELETE, + BMLITE_ERROR_SEND_CMD, + BMLITE_ERROR_GET_ARG, +} bmlite_error_t; + +/** + * @brief Error Callback function + * + * @param[in] Callback Error Code + * @param[in] BEP result code + */ +void bmlite_on_error(bmlite_error_t error, int32_t value); + +/** + * @brief Starting Capture Callback function + */ +void bmlite_on_start_capture(); + +/** + * @brief Finishing Capture Callback function + */ +void bmlite_on_finish_capture(); + +/** + * @brief Starting Enroll Callback function + */ +void bmlite_on_start_enroll(); + +/** + * @brief Finishing Enroll Callback function + */ +void bmlite_on_finish_enroll(); + +/** + * @brief Starting Capture for Enroll Callback function + */ +void bmlite_on_start_enrollcapture(); + +/** + * @brief Finishing Capture for Enroll Callback function + */ +void bmlite_on_finish_enrollcapture(); + +/** + * @brief Starting Identify Callback function + */ +void bmlite_on_identify_start(); + +/** + * @brief Finishing Identify Callback function + */ +void bmlite_on_identify_finish(); +#endif // BMLITE_USE_CALLBACK + +#endif \ No newline at end of file diff --git a/Arduino_lib/BMLite/src/fpc_bep_types.h b/Arduino_lib/BMLite/src/fpc_bep_types.h new file mode 100644 index 0000000..31f310d --- /dev/null +++ b/Arduino_lib/BMLite/src/fpc_bep_types.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020 Fingerprint Cards AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FPC_BEP_TYPES_H +#define FPC_BEP_TYPES_H + +#include +#include +#include +/** + * @file fpc_bep_types.h + * @brief Biometric Embedded Platform types. + * + * This is the common types used by Biometric Embedded Platform (BEP) library. + * + * @note This is a work-in-progress specification. Implementers are informed + * that this API may change without providing any backward compatibility. + * However it is FPC's ambition that the API shall remain compatible between + * releases. + */ + +/** @brief Common result returned by BEP functions. */ +typedef enum { + /** No errors occurred. */ + FPC_BEP_RESULT_OK = 0, + /** General error. */ + FPC_BEP_RESULT_GENERAL_ERROR = -1, + /** Internal error. */ + FPC_BEP_RESULT_INTERNAL_ERROR = -2, + /** Invalid argument. */ + FPC_BEP_RESULT_INVALID_ARGUMENT = -3, + /** The functionality is not implemented. */ + FPC_BEP_RESULT_NOT_IMPLEMENTED = -4, + /** The operation was cancelled. */ + FPC_BEP_RESULT_CANCELLED = -5, + /** Out of memory. */ + FPC_BEP_RESULT_NO_MEMORY = -6, + /** Resources are not available. */ + FPC_BEP_RESULT_NO_RESOURCE = -7, + /** An I/O error occurred. */ + FPC_BEP_RESULT_IO_ERROR = -8, + /** Sensor is broken. */ + FPC_BEP_RESULT_BROKEN_SENSOR = -9, + /** The operation cannot be performed in the current state. */ + FPC_BEP_RESULT_WRONG_STATE = -10, + /** The operation timed out. */ + FPC_BEP_RESULT_TIMEOUT = -11, + /** The ID is not unique. */ + FPC_BEP_RESULT_ID_NOT_UNIQUE = -12, + /** The ID is not found. */ + FPC_BEP_RESULT_ID_NOT_FOUND = -13, + /** The format is invalid. */ + FPC_BEP_RESULT_INVALID_FORMAT = -14, + /** An image capture error occurred. */ + FPC_BEP_RESULT_IMAGE_CAPTURE_ERROR = -15, + /** Sensor hardware id or sensor configuration mismatch. */ + FPC_BEP_RESULT_SENSOR_MISMATCH = -16, + /** Invalid parameter. */ + FPC_BEP_RESULT_INVALID_PARAMETER = -17, + /** Missing Template. */ + FPC_BEP_RESULT_MISSING_TEMPLATE = -18, + /** Invalid Calibration.*/ + FPC_BEP_RESULT_INVALID_CALIBRATION = -19, + /** Calibration/template storage not formatted.*/ + FPC_BEP_RESULT_STORAGE_NOT_FORMATTED = -20, + /** Sensor hasn't been initialized. */ + FPC_BEP_RESULT_SENSOR_NOT_INITIALIZED = -21, + /** Enroll fail after too many bad images. */ + FPC_BEP_RESULT_TOO_MANY_BAD_IMAGES = -22, + /** Cryptographic operation failed. */ + FPC_BEP_RESULT_CRYPTO_ERROR = -23, + /** The functionality is not supported. */ + FPC_BEP_RESULT_NOT_SUPPORTED = -24, + /** Finger not stable during image capture. */ + FPC_BEP_FINGER_NOT_STABLE = -25, + /** The functionality could not be used before it's initialized. */ + FPC_BEP_RESULT_NOT_INITIALIZED = -26, +} fpc_bep_result_t; + +#endif /* FPC_BEP_TYPES_H */ diff --git a/Arduino_lib/BMLite/src/fpc_crc.cpp b/Arduino_lib/BMLite/src/fpc_crc.cpp new file mode 100644 index 0000000..8536adc --- /dev/null +++ b/Arduino_lib/BMLite/src/fpc_crc.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Fingerprint Cards AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file fpc_crc.c + * @brief CRC32 calculation. + */ + +#include + +#include "fpc_crc.h" + +/** + * The constants here are for the CRC-32 generator polynomial, as defined in + * the Microsoft Systems Journal, March 1995, pp. 107-108. + */ +static const uint32_t crc32_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +uint32_t fpc_crc(uint32_t crc, const void *buf, uint32_t size) +{ + const uint8_t *p; + + p = (const uint8_t *)buf; + crc = crc ^ ~0U; + + while (size--) { + crc = crc32_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + } + return crc ^ ~0U; +} + diff --git a/Arduino_lib/BMLite/src/fpc_crc.h b/Arduino_lib/BMLite/src/fpc_crc.h new file mode 100644 index 0000000..9c01afa --- /dev/null +++ b/Arduino_lib/BMLite/src/fpc_crc.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Fingerprint Cards AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FPC_CRC_H +#define FPC_CRC_H + +/** + * @file fpc_crc.h + * @brief Functionality for calculating CRC-32. + */ + +#include + +/** + * @brief Calculates CRC-32 value for the data in the buffer. + * + * @param crc Accumulated CRC-32 value, must be 0 on first call. + * @param buf Buffer with data to calculate CRC-32 for. + * @param size Size of buffer in number of bytes. + * @return CRC-32 value for the data in buffer. + */ +uint32_t fpc_crc(uint32_t crc, const void *buf, uint32_t size); + +#endif /* FPC_CRC_H */ diff --git a/Arduino_lib/BMLite/src/fpc_hcp_common.h b/Arduino_lib/BMLite/src/fpc_hcp_common.h new file mode 100644 index 0000000..76cbf63 --- /dev/null +++ b/Arduino_lib/BMLite/src/fpc_hcp_common.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2020 Fingerprint Cards AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file fpc_hcp_common.h + * @brief Host Communication Protocol common type definitions. + */ + +#ifndef FPC_HCP_COMMON_H +#define FPC_HCP_COMMON_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Returns the smallest of two values. */ +#define HCP_MIN(x, y) (((x) < (y)) ? (x) : (y)) + +/** Program specific commands base number */ +#define CMD_APP_BASE_VAL 0xE000 + +/** Program specific arguments base number */ +#define ARG_APP_BASE_VAL 0x7000 + +/** HCP Command definitions */ +enum fpc_hcp_cmd { + CMD_NONE = 0x0000, + + /* Biometry */ + CMD_CAPTURE = 0x0001, + CMD_ENROLL = 0x0002, + CMD_IDENTIFY = 0x0003, + CMD_MATCH = 0x0004, + CMD_IMAGE = 0x0005, + CMD_TEMPLATE = 0x0006, + CMD_WAIT = 0x0007, + CMD_SETTINGS = 0x0008, + + /* Sensor */ + CMD_NAVIGATE = 0x1001, + CMD_SENSOR = 0x1002, + CMD_DEADPIXELS = 0x1003, + + /* Security */ + CMD_CONNECT = 0x2001, + CMD_RECONNECT = 0x2002, + + /* Firmware */ + CMD_RESET = 0x3002, + CMD_CANCEL = 0x3003, + CMD_INFO = 0x3004, + + /* Storage */ + CMD_STORAGE_TEMPLATE = 0x4002, + CMD_STORAGE_CALIBRATION = 0x4003, + CMD_STORAGE_LOG = 0x4004, + CMD_STORAGE_SETTINGS = 0x4005, + + /* Hardware */ + CMD_TEST = 0x5001, + CMD_MCU = 0x5002, + CMD_GPIO = 0x5003, + + /* Communication */ + CMD_COMMUNICATION = 0x6001, + + /* Application specific commands */ + CMD_APP_BASE = CMD_APP_BASE_VAL, + + /* Debug */ + CMD_DIAG = 0xF003, + + CMD_FFFF = 0xFFFF, +}; +/** HCP Command type */ +typedef uint16_t fpc_hcp_cmd_t; + +/** HCP Argument definitions */ +enum fpc_hcp_arg { + ARG_NONE = 0x0000, + + /* Biometry */ + ARG_FINGER_DOWN = 0x0001, + ARG_FINGER_UP = 0x0002, + ARG_START = 0x0003, + ARG_ADD = 0x0004, + ARG_FINISH = 0x0005, + ARG_ID = 0x0006, + ARG_ALL = 0x0007, + ARG_EXTRACT = 0x0008, + ARG_MATCH_IMAGE = 0x0009, + ARG_MATCH = 0x000A, + + /* Data */ + ARG_ACQUIRE = 0x1001, + ARG_RELEASE = 0x1002, + ARG_SET = 0x1003, + ARG_GET = 0x1004, + ARG_UPLOAD = 0x1005, + ARG_DOWNLOAD = 0x1006, + ARG_CREATE = 0x1007, + ARG_SAVE = 0x1008, + ARG_DELETE = 0x1009, + ARG_DATA = 0x100A, + ARG_UPDATE = 0x100B, + ARG_SEQ_NR = 0x100C, + ARG_SEQ_LEN = 0x100D, + + /* Results */ + ARG_RESULT = 0x2001, + ARG_COUNT = 0x2002, + ARG_SIZE = 0x2003, + ARG_LEVEL = 0x2004, + ARG_FORMAT = 0x2005, + ARG_FLAG = 0x2006, + ARG_PROPERTIES = 0x2007, + ARG_SPEED = 0x2008, + ARG_PROD_TEST = 0x2009, + + /* Sensor */ + ARG_SENSOR_TYPE = 0x3001, + ARG_WIDTH = 0x3002, + ARG_HEIGHT = 0x3003, + ARG_RESET = 0x3004, + ARG_DPI = 0x3005, + ARG_MAX_SPI_CLOCK = 0x3006, + ARG_NUM_SUB_AREAS_WIDTH = 0x3007, + ARG_NUM_SUB_AREAS_HEIGHT = 0x3008, + ARG_IRQ_STATUS = 0x3009, + ARG_RESET_HARD = 0x300A, + + /* MCU */ + ARG_IDLE = 0x4001, + ARG_SLEEP = 0x4002, + ARG_DEEP_SLEEP = 0x4003, + ARG_POWER_MODE = 0x4004, + ARG_BUSY_WAIT = 0x4005, + + /* Misc */ + ARG_TIMEOUT = 0x5001, + ARG_DONE = 0x5002, + + /* Info */ + ARG_BOOT = 0x6001, + ARG_STATUS = 0x6002, + ARG_VERSION = 0x6003, + ARG_UNIQUE_ID = 0x6004, + + /* Application specific arguments */ + ARG_APP_BASE = ARG_APP_BASE_VAL, + + /* VSM */ + ARG_NONCE = 0x8001, + ARG_MAC = 0x8002, + ARG_RANDOM = 0x8003, + ARG_CLAIM = 0x8004, + ARG_PUBLIC_KEY = 0x8005, + ARG_CIPHERTEXT = 0x8006, + + /* Communication */ + ARG_MTU = 0x9001, + + /* Debug */ + ARG_STACK = 0xE001, + ARG_FILL = 0xE002, + ARG_HEAP = 0xE003, + + /* Log */ + ARG_MODE = 0xF001, + ARG_DEBUG = 0xF002, + + ARG_FFFF = 0xFFFF, +}; +/** HCP Argument type */ +typedef uint16_t fpc_hcp_arg_t; + +/** + * @brief Command Argument + */ +typedef struct fpc_hcp_arg_data { + /** Argument */ + fpc_hcp_arg_t arg; + /** Size of data */ + uint16_t size; + /** Free data inside HCP */ + bool free_data; + /** Pointer to data */ + uint8_t *data; +} fpc_hcp_arg_data_t; + +/** + * @brief Application Command Packet + */ +typedef struct fpc_hcp_packet { + /** Command ID */ + fpc_hcp_cmd_t id; + /** Number of arguments */ + uint16_t num_args; + /** Pointer to argument data */ + fpc_hcp_arg_data_t *arguments; +} fpc_hcp_packet_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* FPC_HCP_COMMON_H */ diff --git a/Arduino_lib/BMLite/src/hcp_tiny.cpp b/Arduino_lib/BMLite/src/hcp_tiny.cpp new file mode 100644 index 0000000..9431bfb --- /dev/null +++ b/Arduino_lib/BMLite/src/hcp_tiny.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2020 Andrey Perminov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "fpc_crc.h" +#include "hcp_tiny.h" +#include "bmlite_if_callbacks.h" + +#ifdef DEBUG +#include +#include +#define LOG_DEBUG(...) printf(__VA_ARGS__) +#else +#define LOG_DEBUG(...) +#endif + +static uint32_t fpc_com_ack = FPC_BEP_ACK; + +static fpc_bep_result_t _rx_link(HCP_comm_t *hcp_comm); +static fpc_bep_result_t _tx_link(HCP_comm_t *hcp_comm); + +typedef struct { + uint16_t cmd; + uint16_t args_nr; + uint8_t args[]; +} _HCP_cmd_t; + +typedef struct { + uint16_t arg; + uint16_t size; + uint8_t pld[]; +} _CMD_arg_t; + +typedef struct { + uint16_t lnk_chn; + uint16_t lnk_size; + uint16_t t_size; + uint16_t t_seq_nr; + uint16_t t_seq_len; + _HCP_cmd_t t_pld; +} _HPC_pkt_t; + +fpc_bep_result_t bmlite_init_cmd(HCP_comm_t *hcp_comm, uint16_t cmd, uint16_t arg_key) +{ + fpc_bep_result_t bep_result; + + _HCP_cmd_t *out = (_HCP_cmd_t *)hcp_comm->pkt_buffer; + out->cmd = cmd; + out->args_nr = 0; + hcp_comm->pkt_size = 4; + + if(arg_key != ARG_NONE) { + bep_result = bmlite_add_arg(hcp_comm, arg_key, NULL, 0); + if(bep_result) { + bmlite_on_error(BMLITE_ERROR_SEND_CMD, bep_result); + return bep_result; + } + } + + return FPC_BEP_RESULT_OK; +} + +fpc_bep_result_t bmlite_add_arg(HCP_comm_t *hcp_comm, uint16_t arg_type, void *arg_data, uint16_t arg_size) +{ + if(hcp_comm->pkt_size + 4 + arg_size > hcp_comm->pkt_size_max) { + bmlite_on_error(BMLITE_ERROR_SEND_CMD, FPC_BEP_RESULT_NO_MEMORY); + return FPC_BEP_RESULT_NO_MEMORY; + } + + ((_HCP_cmd_t *)hcp_comm->pkt_buffer)->args_nr++; + _CMD_arg_t *args = (_CMD_arg_t *)(&hcp_comm->pkt_buffer[hcp_comm->pkt_size]); + args->arg = arg_type; + args->size = arg_size; + if(arg_size) { + memcpy(&args->pld, arg_data, arg_size); + } + hcp_comm->pkt_size += 4 + arg_size; + return FPC_BEP_RESULT_OK; +} + +fpc_bep_result_t bmlite_get_arg(HCP_comm_t *hcp_comm, uint16_t arg_type) +{ + uint16_t i = 0; + uint8_t *buffer = hcp_comm->pkt_buffer; + uint16_t args_nr = ((_HCP_cmd_t *)(buffer))->args_nr; + uint8_t *pdata = (uint8_t *)&((_HCP_cmd_t *)(buffer))->args; + while (i < args_nr && (uint32_t)(pdata - buffer) <= hcp_comm->pkt_size) { + _CMD_arg_t *parg = (_CMD_arg_t *)pdata; + if(parg->arg == arg_type) { + hcp_comm->arg.size = parg->size; + hcp_comm->arg.data = parg->pld; + return FPC_BEP_RESULT_OK; + } else { + i++; + pdata += 4 + parg->size; + } + } + + // Ignore missing ARG_RESULT because some command return result other way + // if (arg_type != ARG_RESULT) { + bmlite_on_error(BMLITE_ERROR_GET_ARG, FPC_BEP_RESULT_INVALID_ARGUMENT); + // } + return FPC_BEP_RESULT_INVALID_ARGUMENT; +} + +fpc_bep_result_t bmlite_copy_arg(HCP_comm_t *hcp_comm, uint16_t arg_key, void *arg_data, uint16_t arg_data_size) +{ + fpc_bep_result_t bep_result; + bep_result = bmlite_get_arg(hcp_comm, arg_key); + if(bep_result == FPC_BEP_RESULT_OK) { + if(arg_data == NULL) { + bmlite_on_error(BMLITE_ERROR_GET_ARG, FPC_BEP_RESULT_NO_MEMORY); + return FPC_BEP_RESULT_NO_MEMORY; + } + memcpy(arg_data, hcp_comm->arg.data, HCP_MIN(arg_data_size, hcp_comm->arg.size)); + } else { + bmlite_on_error(BMLITE_ERROR_GET_ARG, FPC_BEP_RESULT_INVALID_ARGUMENT); + return FPC_BEP_RESULT_INVALID_ARGUMENT; + } + + return bep_result; +} + +fpc_bep_result_t bmlite_tranceive(HCP_comm_t *hcp_comm) +{ + fpc_bep_result_t bep_result; + + bep_result = bmlite_send(hcp_comm); + if (bep_result == FPC_BEP_RESULT_OK) { + bep_result = bmlite_receive(hcp_comm); + + if (bmlite_get_arg(hcp_comm, ARG_RESULT) == FPC_BEP_RESULT_OK) { + hcp_comm->bep_result = (fpc_bep_result_t)*(int8_t*)hcp_comm->arg.data; + } else { + hcp_comm->bep_result = FPC_BEP_RESULT_OK; + } + } + + return bep_result; +} + +fpc_bep_result_t bmlite_receive(HCP_comm_t *hcp_comm) +{ + fpc_bep_result_t bep_result = FPC_BEP_RESULT_OK; + fpc_bep_result_t com_result = FPC_BEP_RESULT_OK; + uint16_t seq_nr = 0; + uint16_t seq_len = 1; + uint8_t *p = hcp_comm->pkt_buffer; + _HPC_pkt_t *pkt = (_HPC_pkt_t *)hcp_comm->txrx_buffer; + uint16_t buf_len = 0; + + while(seq_nr < seq_len) { + bep_result = _rx_link(hcp_comm); + + if (!bep_result) { + seq_nr = pkt->t_seq_nr; + seq_len = pkt->t_seq_len; + if(pkt->t_size != pkt->lnk_size - 6) { + com_result = FPC_BEP_RESULT_IO_ERROR; + continue; + } + if(buf_len + pkt->t_size < hcp_comm->pkt_size_max) { + memcpy(p, &pkt->t_pld, pkt->t_size); + p += pkt->t_size; + buf_len += pkt->t_size; + } else { + com_result = FPC_BEP_RESULT_NO_MEMORY; + } +#ifdef DEBUG + if (seq_len > 1) + LOG_DEBUG("Received data chunk %d of %d\n", seq_nr, seq_len); +#endif + } else { + bmlite_on_error(BMLITE_ERROR_SEND_CMD, bep_result); + return bep_result; + } + } + + hcp_comm->pkt_size = buf_len; + if(com_result != FPC_BEP_RESULT_OK) { + bmlite_on_error(BMLITE_ERROR_SEND_CMD, com_result); + } + return com_result; +} + +static fpc_bep_result_t _rx_link(HCP_comm_t *hcp_comm) +{ + // Get size, msg and CRC + fpc_bep_result_t result = hcp_comm->read(4, hcp_comm->txrx_buffer, hcp_comm->phy_rx_timeout, NULL); + _HPC_pkt_t *pkt = (_HPC_pkt_t *)hcp_comm->txrx_buffer; + uint16_t size; + + if (result) { + LOG_DEBUG("Timed out waiting for response.\n"); + return result; + } + + size = pkt->lnk_size; + + // Check if size plus header and crc is larger than max package size. + if (MTU < size + 8) { + // LOG_DEBUG("S: Invalid size %d, larger than MTU %d.\n", size, MTU); + bmlite_on_error(BMLITE_ERROR_SEND_CMD, FPC_BEP_RESULT_IO_ERROR); + return FPC_BEP_RESULT_IO_ERROR; + } + + hcp_comm->read(size + 4, hcp_comm->txrx_buffer + 4, 100, NULL); + + uint32_t crc = *(uint32_t *)(hcp_comm->txrx_buffer + 4 + size); + uint32_t crc_calc = fpc_crc(0, hcp_comm->txrx_buffer+4, size); + + if (crc_calc != crc) { + LOG_DEBUG("CRC mismatch. Calculated %04X, received %04X\n", + (unsigned int)crc_calc, (unsigned int)crc); + bmlite_on_error(BMLITE_ERROR_SEND_CMD, FPC_BEP_RESULT_IO_ERROR); + return FPC_BEP_RESULT_IO_ERROR; + } + + // Send Ack + hcp_comm->write(4, (uint8_t *)&fpc_com_ack, 0, NULL); + + return FPC_BEP_RESULT_OK; +} + +fpc_bep_result_t bmlite_send(HCP_comm_t *hcp_comm) +{ + uint16_t seq_nr = 1; + fpc_bep_result_t bep_result = FPC_BEP_RESULT_OK; + uint16_t data_left = hcp_comm->pkt_size; + uint8_t *p = hcp_comm->pkt_buffer; + + _HPC_pkt_t *phy_frm = (_HPC_pkt_t *)hcp_comm->txrx_buffer; + + // Application MTU size is PHY MTU - (Transport and Link overhead) + uint16_t app_mtu = MTU - 6 - 8; + + // Calculate sequence length + uint16_t seq_len = (data_left / app_mtu) + 1; + + phy_frm->lnk_chn = 0; + phy_frm->t_seq_len = seq_len; + + for (seq_nr = 1; seq_nr <= seq_len && !bep_result; seq_nr++) { + phy_frm->t_seq_nr = seq_nr; + if (data_left < app_mtu) { + phy_frm->t_size = data_left; + } else { + phy_frm->t_size = app_mtu; + } + memcpy(&phy_frm->t_pld, p, phy_frm->t_size); + phy_frm->lnk_size = phy_frm->t_size + 6; + p += phy_frm->t_size; + data_left -= phy_frm->t_size; + + bep_result = _tx_link(hcp_comm); + } + + if(bep_result) { + bmlite_on_error(BMLITE_ERROR_SEND_CMD, bep_result); + } + return bep_result; +} + +static fpc_bep_result_t _tx_link(HCP_comm_t *hcp_comm) +{ + fpc_bep_result_t bep_result; + + _HPC_pkt_t *pkt = (_HPC_pkt_t *)hcp_comm->txrx_buffer; + + uint32_t crc_calc = fpc_crc(0, &pkt->t_size, pkt->lnk_size); + *(uint32_t *)(hcp_comm->txrx_buffer + pkt->lnk_size + 4) = crc_calc; + uint16_t size = pkt->lnk_size + 8; + + bep_result = hcp_comm->write(size, hcp_comm->txrx_buffer, 0, NULL); + + // Wait for ACK + uint32_t ack; + bep_result = hcp_comm->read(4, (uint8_t *)&ack, 500, NULL); + if (bep_result == FPC_BEP_RESULT_TIMEOUT) { + LOG_DEBUG("ASK read timeout\n"); + bmlite_on_error(BMLITE_ERROR_SEND_CMD, FPC_BEP_RESULT_TIMEOUT); + return FPC_BEP_RESULT_IO_ERROR; + } + + if(ack != fpc_com_ack) { + return FPC_BEP_RESULT_IO_ERROR; + } + + return FPC_BEP_RESULT_OK; +} + diff --git a/Arduino_lib/BMLite/src/hcp_tiny.h b/Arduino_lib/BMLite/src/hcp_tiny.h new file mode 100644 index 0000000..d87226a --- /dev/null +++ b/Arduino_lib/BMLite/src/hcp_tiny.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2020 Andrey Perminov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HCP_H +#define HCP_H + +#include "fpc_bep_types.h" +#include "fpc_hcp_common.h" + +/** MTU for HCP physical layer */ +#define MTU 256 + +/** Communication acknowledge definition */ +#define FPC_BEP_ACK 0x7f01ff7f + +typedef struct { + uint32_t size; + uint8_t *data; +} HCP_arg_t; + +typedef struct { + /** Send data to BM-Lite */ + fpc_bep_result_t (*write) (uint16_t, const uint8_t *, uint32_t, void *); + /** Receive data from BM-Lite */ + fpc_bep_result_t (*read)(uint16_t, uint8_t *, uint32_t, void *); + /** Receive timeout (msec). Applys ONLY to receiving packet from BM-Lite on physical layer */ + uint32_t phy_rx_timeout; + /** Data buffer for application layer */ + uint8_t *pkt_buffer; + /** Size of data buffer */ + uint32_t pkt_size_max; + /** Current size of incoming or outcoming command packet */ + uint32_t pkt_size; + /** Buffer of MTU size for transport layer */ + uint8_t *txrx_buffer; + /** Values of last argument pulled by bmlite_get_arg + Values are valid only right after bmlite_get_arg() call */ + HCP_arg_t arg; + /** Result of execution command on BM-Lite */ + fpc_bep_result_t bep_result; +} HCP_comm_t; + +/** + * @brief Send prepared command packet to FPC BM-LIte + * + * @param[in] hcp_comm - pointer to HCP_comm struct + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bmlite_send(HCP_comm_t *hcp_comm); + +/** + * @brief Receive answer from FPC BM-LIte + * + * @param[in] hcp_comm - pointer to HCP_comm struct + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bmlite_receive(HCP_comm_t *hcp_comm); + +/** + * @brief Send prepared command packet to FPC BM-LIte and receive answer + * + * @param[in] hcp_comm - pointer to HCP_comm struct + * + * Returns result of executing command in BM-LIte in hcp_comm->bep_result + * if communication with BM-Lite was successful. + * Please not that some BM-Lite command does not return result in ARG_RESULT. + * They return data with some other argument instead. + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bmlite_tranceive(HCP_comm_t *hcp_comm); + +/** + * @brief Initialize new command for BM-Lite + * + * @param[in] hcp_comm - pointer to HCP_comm struct + * @param[in] cmd - command to send + * @param[in] arg - Argument for the command without parameterd + * Use ARG_NONE and add arguments by bmlite_add_arg() if + * you need to add argument with parameter + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bmlite_init_cmd(HCP_comm_t *hcp_comm, uint16_t cmd, uint16_t arg); + +/** + * @brief Add argument to command. + * Must be used only after command buffer is initialized by bmlite_init_cmd() + * + * @param[in] hcp_comm - pointer to HCP_comm struct + * @param[in] arg_type - argument key + * @param[in] arg_data - argument data + * @param[in] arg_size - argument data length + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bmlite_add_arg(HCP_comm_t *hcp_comm, uint16_t arg_type, void *arg_data, uint16_t arg_size); + +/** + * @brief Search for argument in received answer. + * + * @param[in] hcp_comm - pointer to HCP_comm struct + * @param[in] arg_type - argument key + * + * If found, place pointer to argument data in receiving buffer to hcp_comm->arg.data + * and size of the argument in hcp_comm->arg.size + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bmlite_get_arg(HCP_comm_t *hcp_comm, uint16_t arg_type); + +/** + * @brief Search for argument in received answer and copy argument's data + * to arg_data + * + * @param[in] hcp_comm - pointer to HCP_comm struct + * @param[in] arg_type - argument key + * @param[out] arg_data - pointer for memory to copy argument value + * @param[out] arg_data_size - size of data area for copying argument value + * + * If found, argument's data will be copyed to arg_data + * If received argument's size greater that arg_data_size, the copyed data will be + * truncated to arg_data_size. + * Still hcp_comm->arg.data will be pointed to argument's data in receiving buffer + * and real size of the argument will be hcp_comm->arg.size + * + * @return ::fpc_bep_result_t + */ +fpc_bep_result_t bmlite_copy_arg(HCP_comm_t *hcp_comm, uint16_t arg_key, void *arg_data, uint16_t arg_data_size); + +#endif \ No newline at end of file diff --git a/Arduino_lib/BMLite/src/platform.cpp b/Arduino_lib/BMLite/src/platform.cpp new file mode 100644 index 0000000..f520e49 --- /dev/null +++ b/Arduino_lib/BMLite/src/platform.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020 Fingerprint Cards AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Modified by Andrey Perminov + * for BM-Lite applications + */ + + +/** + * @file platform.c + * @brief Platform specific functions + */ +#ifdef DEBUG_COMM +#include +#define LOG_DEBUG(...) printf(__VA_ARGS__) +#else +#define LOG_DEBUG(...) +#endif + +#include "fpc_bep_types.h" +#include "platform.h" +#include "bmlite_hal.h" + +fpc_bep_result_t platform_init(void *params) +{ + fpc_bep_result_t result; + result = hal_board_init(params); + if(result == FPC_BEP_RESULT_OK) { + hal_timebase_init(); + platform_bmlite_reset(); + } + return result; +} + +void platform_bmlite_reset(void) +{ + hal_bmlite_reset(true); + hal_timebase_busy_wait(100); + hal_bmlite_reset(false); + hal_timebase_busy_wait(100); +} + +fpc_bep_result_t platform_bmlite_spi_send(uint16_t size, const uint8_t *data, uint32_t timeout, + void *session) +{ +#ifdef DEBUG_COMM + LOG_DEBUG("-> "); + for (int i=0; i= timeout) { + return FPC_BEP_RESULT_TIMEOUT; + } + + fpc_bep_result_t res = hal_bmlite_spi_write_read(data, size); + +#ifdef DEBUG_COMM + LOG_DEBUG("<- "); + for (int i=0; i + * for FPC BM-Lite applications + */ + + +#ifndef PLATFORM_H +#define PLATFORM_H + +/** + * @file platform.h + * @brief Platform specific function interface + */ + +#include +#include +#include + +#include "fpc_bep_types.h" + +/** + * @brief Initializes board + * + * @param[in] params - pointer to additional parameters. + */ +fpc_bep_result_t platform_init(void *params); + +/** + * @brief Does BM-Lite HW Reset + * + */ +void platform_bmlite_reset(void); + +/** + * @brief Sends data over SPI port in blocking mode. + * + * @param[in] size Number of bytes to send. + * @param[in] data Data buffer to send. + * @param[in] timeout Timeout in ms. Use 0 for infinity. + * + * @return ::fpc_com_result_t + */ +fpc_bep_result_t platform_bmlite_spi_send(uint16_t size, const uint8_t *data, uint32_t timeout, + void *session); + +/** + * @brief Sends data over UART port in blocking mode. + * + * @param[in] size Number of bytes to send. + * @param[in] data Data buffer to send. + * @param[in] timeout Timeout in ms. Use 0 for infinity. + * + * @return ::fpc_com_result_t + */ +fpc_bep_result_t platform_bmlite_uart_send(uint16_t size, const uint8_t *data, uint32_t timeout, + void *session); + +/** + * @brief Receives data from SPI port in blocking mode. + * + * @param[in] size Number of bytes to receive. + * @param[in, out] data Data buffer to fill. + * @param[in] timeout Timeout in ms. Use 0 for infinity. + * + * @return ::fpc_com_result_t + */ +fpc_bep_result_t platform_bmlite_spi_receive(uint16_t size, uint8_t *data, uint32_t timeout, + void *session); + +/** + * @brief Receives data from UART port in blocking mode. + * + * @param[in] size Number of bytes to receive. + * @param[in, out] data Data buffer to fill. + * @param[in] timeout Timeout in ms. Use 0 for infinity. + * + * @return ::fpc_com_result_t + */ +fpc_bep_result_t platform_bmlite_uart_receive(uint16_t size, uint8_t *data, uint32_t timeout, + void *session); + +/** + * @brief Stops execution if a debug interface is attached. + */ +void platform_halt_if_debug(void); + +/** + * @brief Performs a software reset. + */ +void platform_sw_reset(void) __attribute__((__noreturn__)); + +#endif /* PLATFORM_H */