Hello everyone.
Is there is anyway to read hex data from file located in sd card and assign it to uint8_t array? the following example showing direct hex value to uint8_t variable and no issue with that.
The following is the way that I tried to read the hex data and assign it to uint8_t variable but it gives me different values when I print it in serial. Thanx in advance
void loadHexFromFile(){
File myFile;
myFile = SD.open("hex.txt");
uint8_t h_buf[768];
int h_len = myFile.readBytesUntil('\n', h_buf, sizeof(h_buf));
for (int i = 0; i < sizeof(h_buf); i++){
Serial.print(h_buf[i]);
}
myFile.close();
}
or, is it binary data such that the first byte is actually the value 2, the second byte is 0, etc.?
I suspect it is the first format. If true, you will need to read it in, parse it based on the comma and then interpret either 1 or 2 ascii chars as digits.
if you read the entire line in at once like you did, use strtok() to parse it into comma separated chunks and strtol() to parse those chunks into actual values.
I'm a little old-fashioned so I'd read one character at a time:
#include <SD.h>
uint8_t h_buf[768];
void loadHexFromFile()
{
File myFile;
myFile = SD.open("hex.txt");
int arrayIndex = 0;
int hexValue = 0;
while (myFile.available())
{
char c, p;
c = myFile.read();
// Looking for "0x" or "0X"
if (c != '0')
continue; // Skip anything that isn't a '0'
// Found a '0', now check for 'x' or 'X'
// Look at the next character but don't 'read' it
p = myFile.peek();
if (p != 'x' && p != 'X')
continue;
myFile.read(); // Read the 'x' from the buffer
// We have the "0x" prefix. Now accumulate hex digits
hexValue = 0;
// If we're at the end of the file, exit the loop
if (!myFile.available())
break;
// Look at the next character but don't 'read' it
p = myFile.peek();
// If it's not a hex digit, go back to looking for "0x"
if (!isxdigit(p))
continue;
c = myFile.read(); // Read the hex digit from the buffer
hexValue <<= 4;
if (c >= '0' && c <= '9')
{
hexValue += c - '0';
}
else if (c >= 'a' && c <= 'f')
{
hexValue += c - 'a' + 10;
}
else if (c >= 'A' && c <= 'F')
{
hexValue += c - 'A' + 10;
}
// If we're at the end of the file, exit the loop
if (!myFile.available())
{
h_buf[arrayIndex++] = hexValue; // One-digit number
break;
}
// Look at the next character but don't 'read' it
p = myFile.peek();
// If it's not a hex digit, save the one-digit number and
// go back to looking for the next '0x' prefix
if (!isxdigit(p))
{
h_buf[arrayIndex++] = hexValue; // One-digit number
continue;
}
c = myFile.read(); // Read the hex digit from the buffer
hexValue <<= 4; // Move the first digit left
// Add the new, second, digit
if (c >= '0' && c <= '9')
{
hexValue += c - '0';
}
else if (c >= 'a' && c <= 'f')
{
hexValue += c - 'a' + 10;
}
else if (c >= 'A' && c <= 'F')
{
hexValue += c - 'A' + 10;
}
h_buf[arrayIndex++] = hexValue; // Two-digit number
// Now we go back to looking for "0x".
}
// Reached end of file
myFile.close();
}
Of course, those aren't "Hex" values. They're binary values just like all other data inside the processor. They just happened to be presented in "Hex" format to make them more human-readable.
You could just have easily put in:
uint8_t h_buf[768] = {2,0, 29, 7, 139,132, ......
And the binary values within the processor would have been exactly the same.
If I had $1 for every time a newbie got wrapped around the axle over "Hex Numbers" and the difference between human-readable ASCII and actual binary values within the processor ........
@Juraj , @blh64 , @johnwasser , @gfvalvo thanks for your replies, actually I got that hex values from fingerprint sensor R503 Capacitive fingerprint using the following loops after the targeted template id is loaded successfully.
myFile = SD.open("hex.txt", FILE_WRITE);
for (int k = 0; k < (768/finger.packet_len); k++) {
for (int l = 0; l < finger.packet_len; l++) {
Serial.print("0x");
Serial.print(f_buf[(k * finger.packet_len) + l], HEX);
Serial.print(",");
myFile.print("0x");
myFile.print(f_buf[(k * finger.packet_len) + l], HEX);
myFile.print(",");
delay(10);
}
delay(10);
Serial.println("");
//myFile.println(""); // Just print in the same line.
}
myFile.close();
later when I open the hex.txt file and copy the hex and assign it to uint8_t variable to be send back to the same sensor everything is working fine.
The issue is that when I try to read it from the file using the way that I mentioned I got different values, and this may result in an alien fingerprint template not mine. , so am trying to backup single fingerprint template in a hex.txt and rewrite it to the same sensor back again if the fingerprint database is deleted.
But the function that write the template accepts only hex format, beside I don't know how to do so. the following is example of the function that write to the sensor and it accepts two args, 1st one is the template id, the 2nd is the uint8_t.
As I already stated, "HEX" is only a human-readable convenience. The data stored in the processor and manipulated by the code is binary. The following would read / write an array from / to a binary file:
That means I have to make the changes for reading template from sensor also. so I have to replace HEX by BIN while am reading for the sensor?
for (int k = 0; k < (768/finger.packet_len); k++) { //printing out the template data in seperate rows, where row-length = packet_length
for (int l = 0; l < finger.packet_len; l++) {
Serial.print(f_buf[(k * finger.packet_len) + l], BIN);
myFile.print(f_buf[(k * finger.packet_len) + l], BIN);
delay(10);
}
delay(10);
Serial.println("");
//myFile.println("");
}
Then I have to read the file using ReadFromFile() then send the h_buf to write_to_sensor function. I really appreciated. thanks alot
For reading the template and saving it in the file as hex, there is no issue. This is not the default libirary, rather is a custom library by AsifKhan I downloaded from guithub.
#include <SPI.h>
#include <SD.h>
#include <Adafruit_Fingerprint.h>
void(* resetFunc) (void) = 0;//declare reset function at address 0
#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(5, 4); //is d0(yellow) d1(green)
const int relayPin1 = 14; // TODO: Change according to your board 14 = d5 for node and wont go high on reset
#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);
uint8_t f_buf[768];
File myFile;
uint8_t id;
void setup(){
Serial.begin(115200);
finger.begin(57600);
delay(5000);
if (finger.verifyPassword()) {
Serial.println("Found fingerprint sensor!");
} else {
Serial.println("Did not find fingerprint sensor :(");
while (1);
}
Serial.print("Initializing SD card...");
if (!SD.begin(4)) {
Serial.println("initialization failed!");
return;
}
Serial.print(F("Status: 0x")); Serial.println(finger.status_reg, HEX);
Serial.print(F("Sys ID: 0x")); Serial.println(finger.system_id, HEX);
Serial.print(F("Capacity: ")); Serial.println(finger.capacity);
Serial.print(F("Security level: ")); Serial.println(finger.security_level);
Serial.print(F("Device address: ")); Serial.println(finger.device_addr, HEX);
Serial.print(F("Packet len: ")); Serial.println(finger.packet_len);
Serial.print(F("Baud rate: ")); Serial.println(finger.baud_rate);
finger.getTemplateCount();
Serial.print(F("stored template: ")); Serial.println(finger.templateCount);
if (SD.exists("fprint.fdb")){
SD.remove("fprint.fdb");
}
display_saved(1);
}
void display_saved(uint16_t id) {
myFile = SD.open("hex.txt", FILE_WRITE);
Serial.println("------------------------------------");
Serial.print("Attempting to load #"); Serial.println(id);
uint8_t p = finger.loadModel(id);
//uint8_t p = finger.loadModel(id);
while(p != FINGERPRINT_OK){
Serial.println("Trying to loead the model for id -> " + String(id));
Serial.print(".");
delay(1000);
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;
default:
Serial.print("Unknown error "); Serial.println(p);
return ;
}
// 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;
}
if (finger.get_template_buffer(768, f_buf) == FINGERPRINT_OK) {
Serial.println("Template data (comma sperated HEX):");
for (int k = 0; k < (768/finger.packet_len); k++) {
for (int l = 0; l < finger.packet_len; l++) {
Serial.print("0x");
Serial.print(f_buf[(k * finger.packet_len) + l], HEX);
Serial.print(",");
myFile.print("0x");
myFile.print(f_buf[(k * finger.packet_len) + l], HEX);
myFile.print(",");
delay(10);
}
delay(10);
Serial.println("");
//myFile.println("");
}
}else{
Serial.println("Failed to get the template into buffer..!!");
}
myFile.close();
}
void loop() {}
Here is the code that am using to read from the same file.
/***************************************************
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 <SPI.h>
#include <SD.h>
#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(5, 4);
#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);
void setup()
{
while (!Serial);
Serial.begin(115200);
Serial.println("Fingerprint template extractor");
// set the data rate for the sensor serial port
finger.begin(57600);
Serial.print("Initializing SD card...");
if (!SD.begin(4)) {
Serial.println("initialization failed!");
return;
}
if (finger.verifyPassword()) {
Serial.println("Found fingerprint sensor!");
} else {
Serial.println("Did not find fingerprint sensor :(");
while (1);
}
delay(2000);
loadHexFromFile();
}
void loadHexFromFile(){
// Here I want to read the hex file
// uint8_t h_buf[768] = {0x2,0x1,0x6A,0x12,0x8B,0xCD,0x3B,0x0,0x84,0xE5,0x10,0xE5,0x24,0xD8,0x6,0x9C,0xDC,0x85,0x1C.................\n};
// write_to_sensor(1, h_buf);
// but instead of passing the hex value to the h_buf manually, I want to read it from the hex.txt and pass the result as {hex} to h_buf.
File myFile;
myFile = SD.open("hex.txt");
uint8_t h_buf[768];
int h_len = myFile.readBytesUntil('\n', h_buf, sizeof(h_buf));
Serial.print(h_len); Serial.println('\n');
for (int i = 0; i < sizeof(h_buf); i++){
Serial.print(h_buf[i]);
}
myFile.close();
// If everything going well
// write_to_sensor(1, h_buf);
}
void write_to_sensor(int t_id, uint8_t fingerTemplate[]) {
int template_buf_size = 768;
Serial.println("Ready to write template to sensor...");
Serial.println("Enter the id to enroll against, i.e id (1 to 127)");
if (t_id == 0){
Serial.println("Not possible..!!");
}else{
Serial.print("Writing template against ID #"); Serial.println(t_id);
if (finger.write_template_to_sensor(template_buf_size, fingerTemplate)) {
Serial.println("now writing to sensor...");
} else {
Serial.println("writing to sensor failed");
return;
}
delay(10000);
Serial.print("ID "); Serial.println(t_id);
if (finger.storeModel(t_id) == FINGERPRINT_OK) {
Serial.print("Successfully stored against ID#"); Serial.println(t_id);
} else {
Serial.println("Storing error");
return ;
}
}
}
void loop()
{}
If it were my project, I'd do something like the code shown below. It compiles but I don't have the hardware to test it.
SAVING TO FILE:
Replace This:
if (finger.get_template_buffer(768, f_buf) == FINGERPRINT_OK) {
Serial.println("Template data (comma sperated HEX):");
for (int k = 0; k < (768/finger.packet_len); k++) {
for (int l = 0; l < finger.packet_len; l++) {
Serial.print("0x");
Serial.print(f_buf[(k * finger.packet_len) + l], HEX);
Serial.print(",");
myFile.print("0x");
myFile.print(f_buf[(k * finger.packet_len) + l], HEX);
myFile.print(",");
delay(10);
}
delay(10);
Serial.println("");
//myFile.println("");
}
}else{
Serial.println("Failed to get the template into buffer..!!");
}
myFile.close();
With This:
if (finger.get_template_buffer(768, f_buf) == FINGERPRINT_OK) {
size_t numPackets = 768 / finger.packet_len;
size_t numBytes = numPackets * finger.packet_len;
myFile.write(f_buf, numBytes);
Serial.print(numPackets);
Serial.print(" Packets (");
Serial.print(numBytes);
Serial.println(" Bytes) Written to File");
} else {
Serial.println("Failed to get the template into buffer..!!");
}
myFile.close();
READING FROM FILE:
Replace This:
void loadHexFromFile(){
// Here I want to read the hex file
// uint8_t h_buf[768] = {0x2,0x1,0x6A,0x12,0x8B,0xCD,0x3B,0x0,0x84,0xE5,0x10,0xE5,0x24,0xD8,0x6,0x9C,0xDC,0x85,0x1C.................\n};
// write_to_sensor(1, h_buf);
// but instead of passing the hex value to the h_buf manually, I want to read it from the hex.txt and pass the result as {hex} to h_buf.
File myFile;
myFile = SD.open("hex.txt");
uint8_t h_buf[768];
int h_len = myFile.readBytesUntil('\n', h_buf, sizeof(h_buf));
Serial.print(h_len); Serial.println('\n');
for (int i = 0; i < sizeof(h_buf); i++){
Serial.print(h_buf[i]);
}
myFile.close();
// If everything going well
// write_to_sensor(1, h_buf);
}
@gfvalvo I encountered one more issue, when I delete all the templates from the sensor, and try to write the templates from the SD, it wont store the templates back giving error storing. when I add only one template using the example provided by Adafruit, fingerprint template id 1 as the admin and upload the rest of the templates (2,3,4,5) i.e using your code it work, but the issue is that sometimes return ID incorrectly when I verify, and sometimes a particular finger not found. I don't know where is the error exactly. Thanks in advance.