Hello everyone,
I need some help, I'm trying to read a .BMP image from an SD card reader but apparently ,its not compatible. I dont know what more i can do to solve this problem:
#include <SD.h>
#include <SPI.h>
#include "fpm.h"
#include <SoftwareSerial.h>
#define SSpin 10
SoftwareSerial mySerial(2, 3);
FPM finger(&mySerial);
File myFile;
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (!entry) {// No more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs + 1);
} else {
// Files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
void setup() {
Serial.begin(57600);
Serial.println("Initializing SD card...");
if (!SD.begin(SSpin)) {
Serial.println("Initialization failed!");
return;
}
Serial.println("SD Initialization done.");
if (!SD.exists("two.bmp")) {
Serial.println("File not found.");
return;
}
Serial.println("File exists.");
// Abre el archivo de imagen en la tarjeta SD
myFile = SD.open("one.png", FILE_READ);
if (!myFile) {
Serial.println("Error opening file.");
return;
}
Serial.println("File opened successfully.");
size_t fileSize = myFile.size();
uint8_t buffer[fileSize];
myFile.read(buffer, fileSize);
myFile.close();
// Inicializa el sensor de huellas dactilares
if (!finger.begin(FPM_DEFAULT_PASSWORD, FPM_DEFAULT_ADDRESS, FPM_SYS_PARAMS_LEN)) {
Serial.println("Did not find fingerprint sensor :(");
return;
}
Serial.println("Fingerprint sensor found!");
// Procesa la imagen con el sensor de huellas dactilares
FPMStatus status = finger.uploadImage(buffer, fileSize);
delete[] buffer; // Libera la memoria del buffer
if (status != FPMStatus::OK) {
Serial.println("Failed to upload image.");
return;
}
Serial.println("Image uploaded successfully.");
// Genera el archivo de caracteres a partir de la imagen
status = finger.image2Tz(1);
if (status != FPMStatus::OK) {
Serial.println("Failed to generate character file.");
return;
}
Serial.println("Character file generated successfully.");
// Genera una plantilla
status = finger.generateTemplate();
if (status != FPMStatus::OK) {
Serial.println("Failed to generate template.");
return;
}
Serial.println("Template generated successfully.");
// Guarda la plantilla en el buffer del sensor
status = finger.storeTemplate(1, 1);
if (status != FPMStatus::OK) {
Serial.println("Failed to store template.");
return;
}
Serial.println("Template stored successfully.");
// Descarga la plantilla para comparación
status = finger.downloadTemplate(1);
if (status != FPMStatus::OK) {
Serial.println("Failed to download template.");
return;
}
Serial.println("Template downloaded successfully.");
// Compara las huellas dactilares
uint16_t score;
status = finger.matchTemplatePair(&score);
if (status != FPMStatus::OK) {
Serial.println("Fingerprints do not match.");
return;
}
Serial.print("Fingerprints match with a score of ");
Serial.println(score);
}
void loop() {
}
The main purpose is to read the BMP image from the sd sensor, download this image to the buffer sensor (save in the image buffer from the optical sensor r307), generate a template and match "my image" (the picture that i read from the sd card) and match with the fingerprint that i have in my sensor r307.
The schematic for my circuit is:
I moved your topic to an appropriate forum category @agonzale.
In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.
How big is the file? What is fileSize?
I have a web server that opens and serves many types of files. I use a 65 byte array (tBuf) to hold the output of the SD, then send to the client. myFile is the file handle.
My image with extension .BMP has 126KB and the dimension is 256x288 (i resize the image as my optical sensor r307 need in his image buffer an image in format bmp with 256x288) the problem is the library SD.h, i did some probes and with and bmp image said: error reading the image.
With this 3 lines that you post, what is the purpose?
Additionally, when I need to read other image with PNG format said:
SD init done.
File exists.
File opened successfully.
[+]readPacket timeout.
[+]begin: password verification failed
Did not find fingerprint sensor
But i use the connection that i told in the forum and when i tried Adafruit my sensor conexion works well, so i dont know,
any idea?
You need either to pre-allocate a buffer (put it as global to make things easier) with a suitable size to be able to contain the largest file you need to load, or use malloc() to dynamically do it (but such method is pretty hard to be managed at this level so I don't suggest you to do so).
Said that, the schematics shows a UNO (so I suppose you're working with it): how can you think you can fit/allocate 126kB into that poor Arduino UNO RAM? Use a smaller buffer (1k or less) and make a loop where you read the file in chunks (e.g. read one buffer data size, write the buffer to destination, and repeat cycle until the end of file).
Does your Arduino have 128K memory available? uint8_t buffer[fileSize];
// This loops until the file EOF is reached
while(myFile.available()) {
// clienCount is the number of bytes received. 64 until the last read.
clientCount = myFile.read(tBuf,64);
// this writes the clientCount bytes to the client
client.write((byte*)tBuf,clientCount);
}
Instead of sending it to the client like in my case, send it to your device 64 bytes at a time.
If it is a serial port, change "client.write" to "Serial.write".
Wow, thanks for the advice, now I can read my BMP image and appears:
Initializing SD card...
SD Initialization done.
File opened successfully.
First few bytes of BMP file: 42 20 0 49 0 6E 0 66 0 6F
The problem is that is in a loop and appears all time the same message.
My uploaded code is:
#include <SD.h>
#include <SPI.h>
#include "fpm.h"
#include <SoftwareSerial.h>
#define SSpin 10
SoftwareSerial mySerial(2, 3);
FPM finger(&mySerial);
File dataFile;
void setupSDcard() {
Serial.println("Initializing SD card...");
if (!SD.begin(SSpin)) {
Serial.println("Initialization failed!");
while (1);
}
Serial.println("SD Initialization done.");
}
void SendFile(String Filename) {
char temp[20];
Filename.toCharArray(temp, 20);
dataFile = SD.open(temp);
if (dataFile) {
Serial.println("File opened successfully.");
ReadTheFile();
dataFile.close();
} else {
Serial.print("Error opening file: ");
Serial.println(temp);
delay(1000);
setupSDcard();
return;
}
}
void ReadTheFile() {
const size_t bufferSize = 64;
uint8_t buffer[bufferSize];
if (dataFile.available()) {
dataFile.read(buffer, 10);
Serial.print("First few bytes of BMP file: ");
for (int i = 0; i < 10; i++) {
Serial.print(buffer[i], HEX);
Serial.print(" ");
}
Serial.println();
}
// Inicializa el sensor de huellas dactilares
if (!finger.begin()) {
Serial.println("Did not find fingerprint sensor :(");
return;
}
Serial.println("Fingerprint sensor found!");
// Procesa la imagen con el sensor de huellas dactilares en fragmentos
while (dataFile.available()) {
size_t bytesRead = dataFile.read(buffer, bufferSize);
FPMStatus status = finger.uploadImage(buffer, bytesRead);
if (status != FPMStatus::OK) {
Serial.println("Failed to upload image fragment.");
return;
}
}
Serial.println("Image uploaded successfully.");
// Genera el archivo de caracteres a partir de la imagen
FPMStatus status = finger.image2Tz(1);
if (status != FPMStatus::OK) {
Serial.println("Failed to generate character file.");
return;
}
Serial.println("Character file generated successfully.");
// Genera una plantilla
status = finger.generateTemplate();
if (status != FPMStatus::OK) {
Serial.println("Failed to generate template.");
return;
}
Serial.println("Template generated successfully.");
// Guarda la plantilla en el buffer del sensor
status = finger.storeTemplate(1, 1);
if (status != FPMStatus::OK) {
Serial.println("Failed to store template.");
return;
}
Serial.println("Template stored successfully.");
// Descarga la plantilla para comparación
status = finger.downloadTemplate(1);
if (status != FPMStatus::OK) {
Serial.println("Failed to download template.");
return;
}
Serial.println("Template downloaded successfully.");
// Compara las huellas dactilares
uint16_t score;
status = finger.matchTemplatePair(&score);
if (status != FPMStatus::OK) {
Serial.println("Fingerprints do not match.");
return;
}
Serial.print("Fingerprints match with a score of ");
Serial.println(score);
}
void setup() {
Serial.begin(57600);
setupSDcard();
SendFile("prueba.bmp");
}
void loop() {
}
I use a function that its implemented in a library, taking into account the dataset from my r307 optical sensor, I have the functions:
bool FPM::begin(uint32_t pwd, uint32_t addr, FPMSystemParams * params)
{
delay(2000); /* 500 ms at least according to datasheet */
#if (FPM_LOG_LEVEL != FPM_LOG_LEVEL_SILENT)
printf_begin();
#endif
address = addr;
password = pwd;
if (!verifyPassword(password)) {
FPM_LOGLN_ERROR("begin: password verification failed");
return false;
}
/* check if the user has supplied fixed parameters manually,
* this is needed for some sensors like the R308, which don't support SET_PARAM */
if (params != NULL) {
useFixedParams = true;
memcpy(&sysParams, params, sizeof(FPMSystemParams));
FPM_LOGLN_VERBOSE("begin: using fixed params");
}
else if (readParams() != FPMStatus::OK) {
FPM_LOGLN_ERROR("begin: read params failed");
return false;
}
return true;
}
FPMStatus FPM::uploadImage(uint8_t* buffer, size_t bufferSize) {
buffer[0] = FPM_IMGUPLOAD;
memcpy(&buffer[1], buffer, bufferSize);
return writeCommandGetResponse(bufferSize + 1);
}
FPMStatus FPM::image2Tz(uint8_t slot)
{
buffer[0] = FPM_IMAGE2TZ;
buffer[1] = slot;
return writeCommandGetResponse(2);
}
FPMStatus FPM::generateTemplate(void)
{
buffer[0] = FPM_REGMODEL;
return writeCommandGetResponse(1);
}
FPMStatus FPM::storeTemplate(uint16_t id, uint8_t slot)
{
buffer[0] = FPM_STORE;
buffer[1] = slot;
buffer[2] = id >> 8; buffer[3] = id & 0xFF;
return writeCommandGetResponse(4);
}
FPMStatus FPM::downloadImage(void)
{
buffer[0] = FPM_IMGUPLOAD;
return writeCommandGetResponse(1);
}
FPMStatus FPM::matchTemplatePair(uint16_t * score)
{
buffer[0] = FPM_PAIRMATCH;
writePacket(FPM_COMMANDPACKET, buffer, 1);
FPMStatus confirmCode;
uint16_t readLen = 0;
FPMStatus status = readAckGetResponse(&confirmCode, &readLen);
if (FPM::isErrorCode(status)) return status;
if (confirmCode != FPMStatus::OK) return confirmCode;
if (readLen != 2) return FPMStatus::READ_ERROR;
*score = buffer[1];
*score <<= 8;
*score |= buffer[2];
return confirmCode;
}
and I need to first read the BMP image from the SD, then download the image to the sensor image buffer, generate a template and then compare my uploaded image with the image that is stored in my sensor buffer.
const size_t bufferSize = 64;
uint8_t buffer[bufferSize];
if (dataFile.available()) {
dataFile.read(buffer, 10);
Serial.print("First few bytes of BMP file: ");
for (int i = 0; i < 10; i++) {
Serial.print(buffer[i], HEX);
Serial.print(" ");
}
Serial.println();
}
You here define a 64 bytes buffer but read just the first 10, then do nothing more. What are you expecting this does other than always showing the very first 10 bytes?
you added a "while()" loop, but the first 10 bytes are gone so even if it could do the job, the resulting bitmap is incomplete.
I don't know your finger reader so I can't say if you can "stream" the data in blocks, but you need to review your code (I'd start with just a testing code before trying to go on with this project...) or search around for some other examples of uploading bitmaps to finger reader.
A couple things.
When you read from the SD, it increments the file pointer.
You are reading 10 bytes initially. That increments the file pointer.
When you do the "while", it will start sending at position 10. Reset the pointer to start at the beginning. datafile.seek(0);
Also note in the example, it uses snprintf() in a do.while loop. This is getting the image. I don't see a function that allows BMP files to be imported, just copied from the sensor.
do {
status = finger.getImage();
switch (status)
{
case FPMStatus::OK:
Serial.println("Image taken.");
break;
case FPMStatus::NOFINGER:
Serial.println(".");
break;
default:
/* allow retries even when an error happens */
snprintf(printfBuf, PRINTF_BUF_SZ, "getImage(): error 0x%X", static_cast<uint16_t>(status));
Serial.println(printfBuf);
break;
}
yield();
}
while (status != FPMStatus::OK);
Nah, I have another problem, and it's that (as you can see in the uploaded image) I don't have enough space in my image buffer to save the image since it has 70KB.
So maybe it would be easier to download the image stored in my optical sensor and try to compare it with my original image using a Python method or something? I'm not sure...
Thanks for your latest advice; dividing the image to read it worked for me.
But now, I've discovered that it will be impossible to do it this way, as my optical sensor doesn't have enough memory to save the image.
I'll try to download the template from my sensor and later compare the image stored on my PC with the one from the sensor. I don't have any more ideas...