Adafruit fingerprint code explanation

Hi, I am trying to understand what this piece of code does. I am not sure about that. The main code goes into the fingerprint sensor and reads the data and dumps the hexadecimal signature for the fingerprint. I am trying to undertstand the code which does that peice. Here is the snippet

  uint8_t fingerTemplate[512]; // the real template
  memset(fingerTemplate, 0xff, 512);


  // filtering only the data packets
  int uindx = 9, index = 0;
  while (index < 534) {
    while (index < uindx) ++index;
    uindx += 256;
    while (index < uindx) {
      fingerTemplate[index++] = bytesReceived[index];
    }
    uindx += 2;
    while (index < uindx) ++index;
    uindx = index + 9;
  }
  for (int i = 0; i < 512; ++i) {
    //Serial.print("0x");
    printHex(fingerTemplate[i], 2);
    //Serial.print(", ");
  }
  Serial.println("\ndone.");
}

//print the fingerprint template
void printHex(int num, int precision) {
  char tmp[16];
  char format[128];

  sprintf(format, "%%.%dX", precision);

  sprintf(tmp, format, num);
  Serial.print(tmp);

Here is the complete code:

#include <Adafruit_Fingerprint.h>

#if (defined(__AVR__) || defined(ESP8266)) && !defined(__AVR_ATmega2560__)
// For UNO and others without hardware serial, we must use software serial...
// pin #2 is IN from sensor (GREEN wire)
// pin #3 is OUT from arduino  (WHITE wire)
// Set up the serial port to use softwareserial..
SoftwareSerial mySerial(2, 3);

#else
// On Leonardo/M0/etc, others with hardware serial, use hardware serial!
// #0 is green wire, #1 is white
#define mySerial Serial1

#endif


Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);

int getFingerprintIDez();

void setup()
{
  while(!Serial);
  Serial.begin(9600);
  Serial.println("Fingerprint template extractor");

  // set the data rate for the sensor serial port
  finger.begin(57600);

  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
  } else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1);
  }

  // Try to get the templates for fingers 1 through 10
  for (int finger = 1; finger < 10; finger++) {
    downloadFingerprintTemplate(finger);
  }
}

uint8_t downloadFingerprintTemplate(uint16_t id)
{
  Serial.println("------------------------------------");
  Serial.print("Attempting to load #"); Serial.println(id);
  uint8_t p = finger.loadModel(id);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" loaded");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

  // OK success!

  Serial.print("Attempting to get #"); Serial.println(id);
  p = finger.getModel();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" transferring:");
      break;
   default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

  // one data packet is 267 bytes. in one data packet, 11 bytes are 'usesless' :D
  uint8_t bytesReceived[534]; // 2 data packets
  memset(bytesReceived, 0xff, 534);

  uint32_t starttime = millis();
  int i = 0;
  while (i < 534 && (millis() - starttime) < 20000) {
      if (mySerial.available()) {
          bytesReceived[i++] = mySerial.read();
      }
  }
  Serial.print(i); Serial.println(" bytes read.");
  Serial.println("Decoding packet...");

  uint8_t fingerTemplate[512]; // the real template
  memset(fingerTemplate, 0xff, 512);

  // filtering only the data packets
  int uindx = 9, index = 0;
  while (index < 534) {
      while (index < uindx) ++index;
      uindx += 256;
      while (index < uindx) {
          fingerTemplate[index++] = bytesReceived[index];
      }
      uindx += 2;
      while (index < uindx) ++index;
      uindx = index + 9;
  }
  for (int i = 0; i < 512; ++i) {
      //Serial.print("0x");
      printHex(fingerTemplate[i], 2);
      //Serial.print(", ");
  }
  Serial.println("\ndone.");

  /*
  uint8_t templateBuffer[256];
  memset(templateBuffer, 0xff, 256);  //zero out template buffer
  int index=0;
  uint32_t starttime = millis();
  while ((index < 256) && ((millis() - starttime) < 1000))
  {
    if (mySerial.available())
    {
      templateBuffer[index] = mySerial.read();
      index++;
    }
  }

  Serial.print(index); Serial.println(" bytes read");

  //dump entire templateBuffer.  This prints out 16 lines of 16 bytes
  for (int count= 0; count < 16; count++)
  {
    for (int i = 0; i < 16; i++)
    {
      Serial.print("0x");
      Serial.print(templateBuffer[count*16+i], HEX);
      Serial.print(", ");
    }
    Serial.println();
  }*/
}



void printHex(int num, int precision) {
    char tmp[16];
    char format[128];

    sprintf(format, "%%.%dX", precision);

    sprintf(tmp, format, num);
    Serial.print(tmp);
}

void loop()
{}


The while loop moves 512 bytes from bytesReceived and skips over some values that presumably are the ones filtered out. But leaves gaps in the fingerTemplate array?

256 bytes like

    1	move bytesReceived[	  9	] to fingerTemplate[	 10	]
...
  256	move bytesReceived[	264	] to fingerTemplate[	265	]
  
and 256 more like 

  257	move bytesReceived[	276	] to fingerTemplate[	277	]
...
  512	move bytesReceived[	531	] to fingerTemplate[	532	]

As far as I can tell.

Some real genius coding there, too:

    while (index < uindx) ++index;

LOL!

The for loop print out 512 values of the fingerTemplate array starting at 0.

This looks to be an overly complicated way to accomplish some task, but that is what it does.

a7

1 Like
 uint8_t fingerTemplate[512]; // the real template`

Uh oh, this is going to be a problem when the white starts moving things into slots that aren’t there?

And I have just noticed your snippet doesn’t come from your complete code, which I hadn’t looked at as no reason to, so

what are you doing? who wrote that code? the snippet? where did that come from?

a7

a7

This code is an example code from Adafruit for its fingerprint sensor, to scan the fingerprint and give its signature on the serial monitor.
I am trying to capture the signatures and store it in a database.

Well mind your array indexing. :expressionless:

I will look at the ada code if I can find it. As far as I can see it is kinda odd and will write into memory it shouldn’t.

Best: come to some understanding of what you want to do and write your the code…

I mean srsly

   while (index < uindx) ++index;

makes me wanna just stop reading.

a7

lol. Kinda had the same feeling. I was trying to understand what the person has written, so that I can write my own code. .

Here is the link for the code

THX, I found it. Or something enough like it. It does indeed write off the end of the array.

I copied and pasted the snippet into a "real" C program context using an online interpreter. Changed but I feel certain not damaged to illustrate, viz:

# include <stdio.h>

//   uint8_t fingerTemplate[512]; // the real template

int main()
{
    printf("Hello World\n");
    
    int uindx = 9, index = 0;
    while (index < 534) {
        while (index < uindx) ++index;
        uindx += 256;
        while (index < uindx) {
 //                 fingerTemplate[index++] = bytesReceived[index];
 
            printf("writing into fingerTemplate at index %d.\n", index);
            index++;
      }
      uindx += 2;
      while (index < uindx) ++index;
      uindx = index + 9;
  }

    return 0;
}

The last line of output reads

writing into fingerTemplate at index 531.

Oops, as is said. :expressionless:

Sometimes errors like that do not cause immediate problems. So are not seen, but can manifest at any point and be tots unrelated to the problem(s) they cause.

a7

1 Like

It seems like a very convoluted way of getting a subset of bytes from one array to another. And buggy, as you proved.

1 Like

According to the docs that ship with the Adafruit Fingerprint Library, the return data is a normal "packet" consisting of 9 header bytes, the data and 2 checksum bytes.

Something like this should at least help you debug it

/***************************************************
  This is an example sketch for our optical Fingerprint sensor

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/


#include <Adafruit_Fingerprint.h>

#if (defined(__AVR__) || defined(ESP8266)) && !defined(__AVR_ATmega2560__)
// For UNO and others without hardware serial, we must use software serial...
// pin #2 is IN from sensor (GREEN wire)
// pin #3 is OUT from arduino  (WHITE wire)
// Set up the serial port to use softwareserial..
SoftwareSerial mySerial(2, 3);

#else
// On Leonardo/M0/etc, others with hardware serial, use hardware serial!
// #0 is green wire, #1 is white
#define mySerial Serial1

#endif


Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);

int getFingerprintIDez();

void setup()
{
  while (!Serial);
  Serial.begin(9600);
  Serial.println("Fingerprint template extractor");

  // set the data rate for the sensor serial port
  finger.begin(57600);

  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
  } else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1);
  }

  // Try to get the templates for fingers 1 through 10
  for (int finger = 1; finger < 10; finger++) {
    downloadFingerprintTemplate(finger);
  }
}

uint8_t downloadFingerprintTemplate(uint16_t id)
{
  Serial.println("------------------------------------");
  Serial.print("Attempting to load #"); Serial.println(id);
  uint8_t p = finger.loadModel(id);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" loaded");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

  // OK success!

  Serial.print("Attempting to get #"); Serial.println(id);
  p = finger.getModel();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" transferring:");
      break;
    default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

  /*
     The data comes back as a standard packet
     2 bytes: 0xef01
     4 bytes: address
     1 byte: 0x02 (packet ID)
     2 bytes: N (data length)
     N bytes: actual data
     2 bytes:  checksum
  */


  const int buff_size = 267;
  const int header_size = 9;

  uint8_t templateBuffer[buff_size];
  memset(templateBuffer, 0xff, buff_size);  //zero out template buffer
  int index = 0;

  // attempt to read in header
  uint32_t starttime = millis();
  while ((index < header_size) && ((millis() - starttime) < 1000))
  {
    if (mySerial.available())
    {
      templateBuffer[index] = mySerial.read();
      index++;
    }
  }

  Serial.print(index); Serial.println(" bytes read");

  if ( index != header_size ) {
    Serial.println("bad header");
    return 1;
  }

  uint16_t start = templateBuffer[0] << 8 + templateBuffer[1];
  uint32_t addr = templateBuffer[2] << 24 + templateBuffer[3] << 16 + templateBuffer[4] << 8 + templateBuffer[5];
  uint8_t p_id = templateBuffer[6];
  uint16_t count = templateBuffer[7] << 8 + templateBuffer[8];

  Serial.print( "start: 0x"); Serial.println(start, HEX);
  Serial.print( "addr: 0x"); Serial.println(addr, HEX);
  Serial.print( "p_id: 0x"); Serial.println(p_id, HEX);
  Serial.print( "count: 0x"); Serial.println(count, HEX);

  if ( start != 0xef01 ) { Serial.println("Bad start"); return 1; };
  if ( p_id != 0x02 ) { Serial.println("Bad packet ID"); return 1; };
  if ( count > 256) { Serial.println("Count too high"); return 1; };

  count += 2;   // read 2 byte checksum at end of data
  
  // attempt to read in data
  starttime = millis();
  while (count && ((millis() - starttime) < 10000))
  {
    if (mySerial.available())
    {
      templateBuffer[index] = mySerial.read();
      index++;
      count--;
    }
  }

  if ( count ) { Serial.println("timeout reading data"); return 1; }
  
  //dump entire templateBuffer.  This prints out 16 lines of 16 bytes
  for (int count = 0; count < 16; count++)
  {
    for (int i = 0; i < 16; i++)
    {
      Serial.print("0x");
      Serial.print(templateBuffer[count * 16 + i+ header_size], HEX);
      Serial.print(", ");
    }
    Serial.println();
  }
}



void printHex(int num, int precision) {
  char tmp[16];
  char format[128];

  sprintf(format, "%%.%dX", precision);

  sprintf(tmp, format, num);
  Serial.print(tmp);
}

void loop()
{}

1 Like

a little more pondering... If the intent of the code was to pull out the data from 2 packets, then it reduces to this

  // filtering only the data packets
  int uindx = 9, index = 0;
  memcpy(fingerTemplate + index, bytesReceived + uindx, 256);   // first 256 bytes
  uindx += 256;       // skip data
  uindx += 2;         // skip checksum
  uindx = index + 9;  // skip next header
  index += 256;       // advance pointer
  memcpy(fingerTemplate + index, bytesReceived + uindx, 256);   // second 256 bytes

That don’t look right. Maybe mean

   uindx += 9;   // skip next header...

Also is the data known to be 256 bytes? To skip the data in the input buffer count should be added, not 256.

The printout does print 256 values, which is still odd because there are two data packets received. Or there were in the other code earlier.

a7

Good catch! That should be

 // filtering only the data packets
  int uindx = 9, index = 0;
  memcpy(fingerTemplate + index, bytesReceived + uindx, 256);   // first 256 bytes
  uindx += 256;       // skip data
  uindx += 2;         // skip checksum
  uindx += 9;        // skip next header
  index += 256;       // advance pointer
  memcpy(fingerTemplate + index, bytesReceived + uindx, 256);   // second 256 bytes
1 Like