Fingerprint and demo library for ARM-STM32 made from the Arduino library for R503

Dependents:   R503_fingerprint_HelloWorldV4

Fingerprint.cpp

Committer:
cdupaty
Date:
2021-05-26
Revision:
5:6fff11306a66
Parent:
3:394a5735eea0

File content as of revision 5:6fff11306a66:

/*!
 * @file Fingerprint.cpp
 * @mainpage Adafruit Fingerprint Sensor Library
 * @section intro_sec Introduction
 * This is a library for our optical Fingerprint sensor
 * Designed specifically to work with the Adafruit Fingerprint sensor
 * ---. http://www.adafruit.com/products/751
 * These displays use TTL Serial to communicate, 2 pins are required to
 * interface
 * Adafruit invests time and resources providing this open source code,
 * please support Adafruit and open-source hardware by purchasing
 * products from Adafruit!
 * @section author Author
 * Written by Limor Fried/Ladyada for Adafruit Industries.
 * @section license License
 * BSD license, all text above must be included in any redistribution
 *
 * STM32 adaptation by Christian Dupaty 03/2021
 *
 */

#include "Fingerprint.h"  
#include "mbed.h"


/*!
 * @brief Gets the command packet
 */
#define GET_CMD_PACKET(...)                                                    \
uint8_t data[] = {__VA_ARGS__};                                                \
 Fingerprint_Packet packet(FINGERPRINT_COMMANDPACKET, sizeof(data),data);      \
  writeStructuredPacket(packet);                                               \
  if (getStructuredPacket(&packet) != FINGERPRINT_OK)                          \
    return FINGERPRINT_PACKETRECIEVEERR;                                       \
  if (packet.type != FINGERPRINT_ACKPACKET)                                   \
    return FINGERPRINT_PACKETRECIEVEERR;

/*!
 * @brief Sends the command packet
 */
#define SEND_CMD_PACKET(...)                                                   \
  GET_CMD_PACKET(__VA_ARGS__);                                                 \
  return packet.data[0];

/***************************************************************************
 PUBLIC FUNCTIONS
 ***************************************************************************/


/**************************************************************************/
/*!
    @brief  Instantiates sensor with Software Serial
    @param  ss Pointer to SoftwareSerial object
    @param  password 32-bit integer password (default is 0)
*/
/**************************************************************************/
Fingerprint::Fingerprint(PinName serialTX, PinName serialRX, uint32_t password) :   R503Serial(serialTX, serialRX) 
{
  thePassword = password;
  theAddress = 0xFFFFFFFF;

  status_reg = 0x0; ///< The status register (set by getParameters)
  system_id = 0x0;  ///< The system identifier (set by getParameters)
  capacity = 64; ///< The fingerprint capacity (set by getParameters)
  security_level = 0; ///< The security level (set by getParameters)
  device_addr = 0xFFFFFFFF;      ///< The device address (set by getParameters)
  packet_len = 64;   ///< The max packet length (set by getParameters)
  baud_rate = 57600; ///< The UART baud rate (set by getParameters)
  // Init buffer de reception, les deux pointeurs egaux
  pe=buffUART;
  pl=buffUART;
  // active IT sur reception UART vers methode receiveUART
  R503Serial.attach(callback(this,&Fingerprint::receiveUART),RawSerial::RxIrq);
}

/**************************************************************************/
/*!
    @brief  Initializes serial interface and baud rate
    @param  baudrate Sensor's UART baud rate (usually 57600, 9600 or 115200)
*/
/**************************************************************************/
void Fingerprint::begin(uint32_t baudrate) {
     R503Serial.baud(baudrate);
}

/**************************************************************************/
/*!
    @brief  Verifies the sensors' access password (default password is
   0x0000000). A good way to also check if the sensors is active and responding
    @returns True if password is correct
*/
/**************************************************************************/
bool Fingerprint::verifyPassword(void) {
  return checkPassword() == FINGERPRINT_OK;
}

uint8_t Fingerprint::checkPassword(void) {
  GET_CMD_PACKET(FINGERPRINT_VERIFYPASSWORD, (uint8_t)(thePassword >> 24),(uint8_t)(thePassword >> 16), (uint8_t)(thePassword >> 8),(uint8_t)(thePassword & 0xFF));
  if (packet.data[0] == FINGERPRINT_OK)
    return FINGERPRINT_OK;
  else
    return FINGERPRINT_PACKETRECIEVEERR;
}

/**************************************************************************/
/*!
    @brief  Get the sensors parameters, fills in the member variables
    status_reg, system_id, capacity, security_level, device_addr, packet_len
    and baud_rate
    @returns True if password is correct
*/
/**************************************************************************/
uint8_t Fingerprint::getParameters(void) {
  GET_CMD_PACKET(FINGERPRINT_READSYSPARAM);

  status_reg = ((uint16_t)packet.data[1] << 8) | packet.data[2];
  system_id = ((uint16_t)packet.data[3] << 8) | packet.data[4];
  capacity = ((uint16_t)packet.data[5] << 8) | packet.data[6];
  security_level = ((uint16_t)packet.data[7] << 8) | packet.data[8];
  device_addr = ((uint32_t)packet.data[9] << 24) |
                ((uint32_t)packet.data[10] << 16) |
                ((uint32_t)packet.data[11] << 8) | (uint32_t)packet.data[12];
  packet_len = ((uint16_t)packet.data[13] << 8) | packet.data[14];
  if (packet_len == 0) {
    packet_len = 32;
  } else if (packet_len == 1) {
    packet_len = 64;
  } else if (packet_len == 2) {
    packet_len = 128;
  } else if (packet_len == 3) {
    packet_len = 256;
  }
  baud_rate = (((uint16_t)packet.data[15] << 8) | packet.data[16]) * 9600;

  return packet.data[0];
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to take an image of the finger pressed on surface
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_NOFINGER</code> if no finger detected
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
    @returns <code>FINGERPRINT_IMAGEFAIL</code> on imaging error
*/
/**************************************************************************/
uint8_t Fingerprint::getImage(void) {
  SEND_CMD_PACKET(FINGERPRINT_GETIMAGE);
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to convert image to feature template
    @param slot Location to place feature template (put one in 1 and another in
   2 for verification to create model)
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_IMAGEMESS</code> if image is too messy
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
    @returns <code>FINGERPRINT_FEATUREFAIL</code> on failure to identify
   fingerprint features
    @returns <code>FINGERPRINT_INVALIDIMAGE</code> on failure to identify
   fingerprint features
*/
uint8_t Fingerprint::image2Tz(uint8_t slot) {
  SEND_CMD_PACKET(FINGERPRINT_IMAGE2TZ, slot);
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to take two print feature template and create a
   model
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
    @returns <code>FINGERPRINT_ENROLLMISMATCH</code> on mismatch of fingerprints
*/
uint8_t Fingerprint::createModel(void) {
  SEND_CMD_PACKET(FINGERPRINT_REGMODEL);
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to store the calculated model for later matching
    @param   location The model location #
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_BADLOCATION</code> if the location is invalid
    @returns <code>FINGERPRINT_FLASHERR</code> if the model couldn't be written
   to flash memory
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
uint8_t Fingerprint::storeModel(uint16_t location) {
  SEND_CMD_PACKET(FINGERPRINT_STORE, 0x01, (uint8_t)(location >> 8),
                  (uint8_t)(location & 0xFF));
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to load a fingerprint model from flash into buffer 1
    @param   location The model location #
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_BADLOCATION</code> if the location is invalid
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
uint8_t Fingerprint::loadModel(uint16_t location) {
  SEND_CMD_PACKET(FINGERPRINT_LOAD, 0x01, (uint8_t)(location >> 8),
                  (uint8_t)(location & 0xFF));
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to transfer 256-byte fingerprint template from the
   buffer to the UART
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
uint8_t Fingerprint::getModel(void) {
  SEND_CMD_PACKET(FINGERPRINT_UPLOAD, 0x01);
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to delete a model in memory
    @param   location The model location #
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_BADLOCATION</code> if the location is invalid
    @returns <code>FINGERPRINT_FLASHERR</code> if the model couldn't be written
   to flash memory
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
uint8_t Fingerprint::deleteModel(uint16_t location) {
  SEND_CMD_PACKET(FINGERPRINT_DELETE, (uint8_t)(location >> 8),
                  (uint8_t)(location & 0xFF), 0x00, 0x01);
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to delete ALL models in memory
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_BADLOCATION</code> if the location is invalid
    @returns <code>FINGERPRINT_FLASHERR</code> if the model couldn't be written
   to flash memory
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
uint8_t Fingerprint::emptyDatabase(void) {
  SEND_CMD_PACKET(FINGERPRINT_EMPTY);
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to search the current slot 1 fingerprint features to
   match saved templates. The matching location is stored in <b>fingerID</b> and
   the matching confidence in <b>confidence</b>
    @returns <code>FINGERPRINT_OK</code> on fingerprint match success
    @returns <code>FINGERPRINT_NOTFOUND</code> no match made
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
/**************************************************************************/
uint8_t Fingerprint::fingerFastSearch(void) {
  // high speed search of slot #1 starting at page 0x0000 and page #0x00A3
  GET_CMD_PACKET(FINGERPRINT_HISPEEDSEARCH, 0x01, 0x00, 0x00, 0x00, 0xA3);
  fingerID = 0xFFFF;
  confidence = 0xFFFF;

  fingerID = packet.data[1];
  fingerID <<= 8;
  fingerID |= packet.data[2];

  confidence = packet.data[3];
  confidence <<= 8;
  confidence |= packet.data[4];

  return packet.data[0];
}

/**************************************************************************/
/*!
    @brief   Control the built in LED
    @param on True if you want LED on, False to turn LED off
    @returns <code>FINGERPRINT_OK</code> on success
*/
/**************************************************************************/
uint8_t Fingerprint::LEDcontrol(bool on) {
  if (on) {
    SEND_CMD_PACKET(FINGERPRINT_LEDON);
  } else {
    SEND_CMD_PACKET(FINGERPRINT_LEDOFF);
  }
}

/**************************************************************************/
/*!
    @brief   Control the built in Aura LED (if exists). Check datasheet/manual
    for different colors and control codes available
    @param control The control code (e.g. breathing, full on)
    @param speed How fast to go through the breathing/blinking cycles
    @param coloridx What color to light the indicator
    @param count How many repeats of blinks/breathing cycles
    @returns <code>FINGERPRINT_OK</code> on fingerprint match success
    @returns <code>FINGERPRINT_NOTFOUND</code> no match made
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
/**************************************************************************/
uint8_t Fingerprint::LEDcontrol(uint8_t control, uint8_t speed,
                                         uint8_t coloridx, uint8_t count) {
  SEND_CMD_PACKET(FINGERPRINT_AURALEDCONFIG, control, speed, coloridx, count);
}

/**************************************************************************/
/*!
    @brief   Ask the sensor to search the current slot fingerprint features to
   match saved templates. The matching location is stored in <b>fingerID</b> and
   the matching confidence in <b>confidence</b>
   @param slot The slot to use for the print search, defaults to 1
    @returns <code>FINGERPRINT_OK</code> on fingerprint match success
    @returns <code>FINGERPRINT_NOTFOUND</code> no match made
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
/**************************************************************************/
uint8_t Fingerprint::fingerSearch(uint8_t slot) {
  // search of slot starting thru the capacity
  GET_CMD_PACKET(FINGERPRINT_SEARCH, slot, 0x00, 0x00, capacity >> 8,
                 capacity & 0xFF);

  fingerID = 0xFFFF;
  confidence = 0xFFFF;

  fingerID = packet.data[1];
  fingerID <<= 8;
  fingerID |= packet.data[2];

  confidence = packet.data[3];
  confidence <<= 8;
  confidence |= packet.data[4];

  return packet.data[0];
}

/**************************************************************************/
/*!
    @brief   Ask the sensor for the number of templates stored in memory. The
   number is stored in <b>templateCount</b> on success.
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
/**************************************************************************/
uint8_t Fingerprint::getTemplateCount(void) {
  GET_CMD_PACKET(FINGERPRINT_TEMPLATECOUNT);

  templateCount = packet.data[1];
  templateCount <<= 8;
  templateCount |= packet.data[2];

  return packet.data[0];
}

/**************************************************************************/
/*!
    @brief   Set the password on the sensor (future communication will require
   password verification so don't forget it!!!)
    @param   password 32-bit password code
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_PACKETRECIEVEERR</code> on communication error
*/
/**************************************************************************/
uint8_t Fingerprint::setPassword(uint32_t password) {
  SEND_CMD_PACKET(FINGERPRINT_SETPASSWORD, (password >> 24), (password >> 16),
                  (password >> 8), password);
}

/**************************************************************************/
/*!
    @brief   Helper function to process a packet and send it over UART to the
   sensor
    @param   packet A structure containing the bytes to transmit
*/
/**************************************************************************/

void Fingerprint::writeStructuredPacket(const Fingerprint_Packet &packet) 
{
  R503Serial.putc((uint8_t)(packet.start_code >> 8));
  R503Serial.putc((uint8_t)(packet.start_code & 0xFF));
  R503Serial.putc(packet.address[0]);
  R503Serial.putc(packet.address[1]);
  R503Serial.putc(packet.address[2]);
  R503Serial.putc(packet.address[3]);
  R503Serial.putc(packet.type);

  uint16_t wire_length = packet.length + 2;
  R503Serial.putc((uint8_t)(wire_length >> 8));
  R503Serial.putc((uint8_t)(wire_length & 0xFF));

  #ifdef FINGERPRINT_DEBUG
  printf("-> Send packet \n-> ");
  printf("0x%02X%02X ",(uint8_t)(packet.start_code >> 8),(uint8_t)(packet.start_code & 0xFF));
  printf(", 0x%02X ",packet.address[0]);
  printf(", 0x%02X ",packet.address[1]);
  printf(", 0x%02X ",packet.address[2]);
  printf(", 0x%02X ",packet.address[3]);
  printf(", 0x%02X ",packet.type);
  printf(", 0x%02X ",(uint8_t)(wire_length >> 8));
  printf(", 0x%02X \n-> Data  ",(uint8_t)(wire_length & 0xFF));
  #endif

  uint16_t sum = ((wire_length) >> 8) + ((wire_length)&0xFF) + packet.type;
  for (uint8_t i = 0; i < packet.length; i++) 
  {
    R503Serial.putc(packet.data[i]);
    sum += packet.data[i];
  #ifdef FINGERPRINT_DEBUG
    printf(", 0x%02X ",packet.data[i]);
  #endif
  }
//  #ifdef FINGERPRINT_DEBUG
//  printf("\n-\n");
//  #endif

  R503Serial.putc((uint8_t)(sum >> 8));
  R503Serial.putc((uint8_t)(sum & 0xFF));

#ifdef FINGERPRINT_DEBUG
  printf("-> chksum = 0x%02X%02X \n",(uint8_t)(sum >> 8),(uint8_t)(sum & 0xFF));
#endif

  return;
}

/**************************************************************************/
/*!
    @brief   Helper function to receive data over UART from the sensor and
   process it into a packet
    @param   packet A structure containing the bytes received
    @param   timeout how many milliseconds we're willing to wait
    @returns <code>FINGERPRINT_OK</code> on success
    @returns <code>FINGERPRINT_TIMEOUT</code> or
   <code>FINGERPRINT_BADPACKET</code> on failure
*/
/**************************************************************************/
uint8_t Fingerprint::getStructuredPacket(Fingerprint_Packet *packet, uint16_t timeout) 
{
  uint8_t byte;
  uint16_t idx = 0, timer = 0;

#ifdef FINGERPRINT_DEBUG
  printf("\n<----------------------packet reception\n<- ");
#endif

  while (true) 
  {
    while (pl==pe)   // rien n'est arrivé 
    {
      wait_ms(1);
      timer++;
      if (timer >= timeout) 
      {
        #ifdef FINGERPRINT_DEBUG
        printf("Timed out\n");
        #endif
        return FINGERPRINT_TIMEOUT;
      }
    }
    byte = readUARTbuff();

    #ifdef FINGERPRINT_DEBUG
    printf("0x%02X, ",byte);
    #endif
    switch (idx) 
    {
        case 0:
          if (byte != (FINGERPRINT_STARTCODE >> 8))
            continue;
          packet->start_code = (uint16_t)byte << 8;
          break;
        case 1:
          packet->start_code |= byte;
          if (packet->start_code != FINGERPRINT_STARTCODE)
            return FINGERPRINT_BADPACKET;
          break;
        case 2: // 4 bytes for adress
        case 3:  
        case 4:
        case 5:
          packet->address[idx - 2] = byte;
          break;
        case 6:
          packet->type = byte;
          break;
        case 7:
          packet->length = (uint16_t)byte << 8;
          break;
        case 8:
          packet->length |= byte;
          #ifdef FINGERPRINT_DEBUG
           printf("\n<- Data ");
          #endif
          break;
        default:
          packet->data[idx - 9] = byte;
          if ((idx - 8) == packet->length) 
          {
                #ifdef FINGERPRINT_DEBUG
                printf("\n<--------------------packet reception OK \n\n");
                #endif
                return FINGERPRINT_OK;
          }
          break;
    }
    idx++;
  }
  // Shouldn't get here so...
  // return FINGERPRINT_BADPACKET;
}

/*
Added by Christian Dupaty, STM32 adaptation
*/

/***************************************************************************
 PRIVATE FUNCTIONS
 ***************************************************************************/

void Fingerprint::receiveUART(void) {
    uint8_t c;
    while(!R503Serial.readable());
    c=R503Serial.getc();
    *pe=c;
    pe++;
    if (pe>buffUART+sizeof(buffUART)) pe=buffUART;
}

uint8_t Fingerprint::readUARTbuff(void) {
   uint8_t c;
   c=*pl;
   pl++;
   if (pl>buffUART+sizeof(buffUART)) pl=buffUART;
   return c;
}