/* v2.0 - 17/07/24
*/
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_PN532.h>
#include <LittleFS.h>
#include "Adafruit_Keypad.h"
#define PN532_SCK (11)
#define PN532_MOSI (10)
#define PN532_SS (12)
#define PN532_MISO (9)
#define PN532_IRQ (8)
#define PN532_RESET (7)
#define TIME_INTERVAL 1000 //Time interval between readings
#define SD_DATAFILE_NAME "/Data002.txt"
#define ID_NUMBER "0001"
File dataFile; // File object for SD card
//Private variables
int successCount = 0; // Counter for successful records
uint8_t i = 0;
unsigned long currentTime = 0;
unsigned long elapsedTime = 0;
unsigned long startTime = 0; // Variable to store the start time
unsigned long totalTime = 0; // Variable to store the total time elapsed
uint8_t idNumberString[] = ID_NUMBER;
const byte ROWS = 4; // rows
const byte COLS = 3; // columns
char keys[ROWS][COLS] = {
{ '1', '2', '3' },
{ '4', '5', '6' },
{ '7', '8', '9' },
{ '*', '0', '#' }
};
//connect to the row and column pinouts of the keypad
uint8_t rowPins[ROWS] = { 38, 21, 37, 36 };
uint8_t colPins[COLS] = { 35, 20, 19 }; // Change 20 to 34 and 19 to 33 for the new actual board
// Declare global variables for timing
unsigned long previousMillis = 0; // Stores the last time the keypad was checked
const long interval = 50; // Interval at which to check the keypad (milliseconds)
//private funcion prototypes
void UpdateTime(void);
void PrintTime(unsigned long milliseconds);
void SaveDataMT1(uint8_t responseLength, uint8_t* response);
void SaveDataMT2(int count, unsigned long time, uint8_t responseLength, uint8_t* response);
void SaveDataVT1(uint8_t responseLength, uint8_t* response);
void SaveDataVT2(int count, unsigned long time, uint8_t responseLength, uint8_t* response);
void readData(); // for debug only can be removed
//initialize an instance of class Keypad and NFC
Adafruit_Keypad customKeypad = Adafruit_Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);
TaskHandle_t keypadTaskHandle = NULL;
TaskHandle_t nfcTaskHandle = NULL;
void setup(void) {
Serial.begin(115200);
Serial.println("Loading...");
customKeypad.begin();
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (!versiondata) {
Serial.println("Didn't find NFC board");
while (1)
; // Halt
}
Serial.print("Found NFC board, version: ");
Serial.println((versiondata >> 24) & 0xFF, HEX);
Serial.print("Firmware ver. ");
Serial.print((versiondata >> 16) & 0xFF, DEC);
Serial.print('.');
Serial.println((versiondata >> 8) & 0xFF, DEC);
nfc.SAMConfig(); // Configure board to read RFID tags
// Create tasks
xTaskCreatePinnedToCore(
keypadTask,
"Keypad Task",
4096,
NULL,
1,
&keypadTaskHandle,
1);
xTaskCreatePinnedToCore(
nfcTask,
"NFC Task",
4096,
NULL,
2,
&nfcTaskHandle,
1);
// Create or open a file named "data.txt" for writing
// Initialize LittleFS
if (!LittleFS.begin()) {
Serial.println("An error has occurred while mounting storage");
// Format LittleFS
Serial.println("Formatting LittleFS...");
LittleFS.format();
Serial.println("LittleFS formatted");
return;
}
// Open or create the file
dataFile = LittleFS.open(SD_DATAFILE_NAME, "w");
// Check if the file opened successfully
if (!dataFile) {
Serial.println("Error: Unable to open file.");
while (1)
;
}
int i = 0;
dataFile.print("ID NUMBER - ");
while (idNumberString[i] != '\0') {
dataFile.print(idNumberString[i] - '0');
++i;
}
dataFile.println();
// Close the file
dataFile.close();
// Start the timer
startTime = millis();
}
void loop() {
// Main loop is not used in this setup; tasks handle everything
}
// Keypad task function
void keypadTask(void* pvParameters) {
while (true) {
customKeypad.tick();
while (customKeypad.available()) {
keypadEvent e = customKeypad.read();
char keyChar = (char)e.bit.KEY;
// Check key press event
if (e.bit.EVENT == KEY_JUST_PRESSED) {
Serial.println(keyChar);
// For data checking only
if (keyChar == '*') {
// Handle the '*' key press here
Serial.println("The '*' key was pressed! Reading the file...");
readData();
}
} else if (e.bit.EVENT == KEY_JUST_RELEASED) {
// Calculate elapsed time since start
UpdateTime();
Serial.print("Time elapsed since start: ");
PrintTime(elapsedTime);
Serial.print("Total time elapsed: ");
PrintTime(totalTime);
}
}
vTaskDelay(10 / portTICK_PERIOD_MS); // Yield to other tasks
}
}
// NFC task function
void nfcTask(void* pvParameters) {
while (true) {
// Serial.println("Waiting for a card");
if (nfc.inListPassiveTarget()) {
// Create or open a file named "data.txt" for writing
dataFile = LittleFS.open(SD_DATAFILE_NAME, "w");
// Check if the file opened successfully
if (!dataFile) {
Serial.println("Error: Unable to open file.");
while (1)
;
}
uint8_t response[170];
uint8_t responseLength = sizeof(response);
uint8_t apdu[] = { 0x00, 0xA4, 0x04, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x04, 0x10, 0x10, 0x00 };
uint8_t apduLength = sizeof(apdu);
memset(response, 0, sizeof(response));
if (nfc.inDataExchange(apdu, apduLength, response, &responseLength)) {
if (responseLength > 3) {
Serial.print("MT1: ");
Serial.println(responseLength);
nfc.PrintHexChar(response, responseLength);
SaveDataMT1(responseLength, response);
// If response length is more than 3 bytes, send the second APDU command
uint8_t responseLength = sizeof(response);
uint8_t secondApdu[] = { 0x00, 0xB2, 0x01, 0x0C, 0x00 };
uint8_t secondApduLength = sizeof(secondApdu);
memset(response, 0, sizeof(response));
if (nfc.inDataExchange(secondApdu, secondApduLength, response, &responseLength)) {
Serial.print("MT2: ");
Serial.println(responseLength);
nfc.PrintHexChar(response, responseLength);
successCount++; // Increment success count
Serial.print("Success count: ");
Serial.println(successCount);
// Calculate elapsed time since start
UpdateTime();
Serial.print("Time elapsed since start: ");
PrintTime(elapsedTime);
Serial.print("Total time elapsed: ");
PrintTime(totalTime);
// Write response data to the file
SaveDataMT2(successCount, totalTime, responseLength, response);
delay(TIME_INTERVAL);
} else {
Serial.println("Second APDU failed!");
}
}
else {
// If response length is less than or equal to 3 bytes, send the third APDU command
uint8_t responseLength = sizeof(response);
uint8_t thirdApdu[] = { 0x00, 0xA4, 0x04, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x00 };
uint8_t thirdApduLength = sizeof(thirdApdu);
memset(response, 0, sizeof(response));
if (nfc.inDataExchange(thirdApdu, thirdApduLength, response, &responseLength)) {
Serial.print("VT1: ");
Serial.println(responseLength);
nfc.PrintHexChar(response, responseLength);
SaveDataVT1(responseLength, response);
// Check if the response length is more than 30 bytes
if (responseLength > 30) {
// If so, send the fourth APDU command
uint8_t responseLength = sizeof(response);
uint8_t fourthApdu[] = { 0x00, 0xB2, 0x01, 0x0C, 0x00 };
uint8_t fourthApduLength = sizeof(fourthApdu);
memset(response, 0, sizeof(response));
if (nfc.inDataExchange(fourthApdu, fourthApduLength, response, &responseLength)) {
Serial.print("VT2: ");
Serial.println(responseLength);
nfc.PrintHexChar(response, responseLength);
successCount++; // Increment success count
Serial.print("Success count: ");
Serial.println(successCount);
// Calculate elapsed time since start
UpdateTime();
Serial.print("Time elapsed since start: ");
PrintTime(elapsedTime);
Serial.print("Total time elapsed: ");
PrintTime(totalTime);
// Write response data to the file
SaveDataVT2(successCount, totalTime, responseLength, response);
delay(TIME_INTERVAL);
} else {
Serial.println("Fourth APDU failed!");
}
}
}
}
}
// Close the file
dataFile.close();
}
//delay(TIME_INTERVAL);
}
}
void UpdateTime(void) {
currentTime = millis();
elapsedTime = currentTime - startTime;
// Update total time
totalTime += elapsedTime;
// Reset start time
startTime = currentTime;
return;
}
void PrintTime(unsigned long milliseconds) {
// Calculate hours, minutes, and seconds
unsigned long seconds = milliseconds / 1000;
unsigned long hours = seconds / 3600;
unsigned long minutes = (seconds % 3600) / 60;
seconds = seconds % 60;
// Print time in the desired format
char timeStr[9]; // Format: 00:00:00\0
sprintf(timeStr, "%02lu:%02lu:%02lu", hours, minutes, seconds);
Serial.println(timeStr);
}
void SaveTime(unsigned long milliseconds) {
int i = 0;
// Calculate hours, minutes, and seconds
unsigned long seconds = milliseconds / 1000;
unsigned long hours = seconds / 3600;
unsigned long minutes = (seconds % 3600) / 60;
seconds = seconds % 60;
// Print time in the desired format
char timeStr[9]; // Format: 00:00:00\0
sprintf(timeStr, "%02lu:%02lu:%02lu", hours, minutes, seconds);
while (i < 8) {
dataFile.print(timeStr[i]);
i++;
}
dataFile.println();
return;
}
void SaveTimeResponse(unsigned long time, uint8_t responseLength, uint8_t* response) {
SaveResponse(responseLength, response);
dataFile.print('T');
dataFile.print('I');
dataFile.print('M');
dataFile.print('E');
dataFile.print(':');
dataFile.print(' ');
SaveTime(time);
return;
}
void SaveResponse(uint8_t responseLength, uint8_t* response) {
int i = 0;
while (i < responseLength) {
dataFile.print(' ');
dataFile.print(response[i], HEX);
i++;
}
dataFile.println();
return;
}
void SaveCount(int count) {
dataFile.print('C');
dataFile.print('O');
dataFile.print('U');
dataFile.print('N');
dataFile.print('T');
dataFile.print(':');
dataFile.print(' ');
dataFile.print(count, DEC);
dataFile.println();
return;
}
void SaveDataMT1(uint8_t responseLength, uint8_t* response) {
dataFile.print("MT1: ");
SaveResponse(responseLength, response);
Serial.println("Data written to file successfully.");
return;
}
void SaveDataMT2(int count, unsigned long time, uint8_t responseLength, uint8_t* response) {
dataFile.print("MT2: ");
SaveTimeResponse(time, responseLength, response);
SaveCount(count);
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.println();
Serial.println("Data written to file successfully.");
return;
}
void SaveDataVT1(uint8_t responseLength, uint8_t* response) {
dataFile.print("VT1: ");
SaveResponse(responseLength, response);
Serial.println("Data written to file successfully.");
return;
}
void SaveDataVT2(int count, unsigned long time, uint8_t responseLength, uint8_t* response) {
dataFile.print('V');
dataFile.print('T');
dataFile.print('2');
dataFile.print(':');
dataFile.print(' ');
SaveTimeResponse(time, responseLength, response);
SaveCount(count);
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.print('-');
dataFile.println();
Serial.println("Data written to file successfully.");
return;
}
// For Debug purposes only will be removed
void readData()
{
// Create or open a file named "data.txt" for writing
dataFile = LittleFS.open(SD_DATAFILE_NAME, "r");
// Check if the file opened successfully
if (!dataFile) {
Serial.println("Error: Unable to open file.");
while (1)
;
}
// Read the file contents line by line
Serial.println("************************************ START ************************************");
while (dataFile.available()) {
String line = dataFile.readStringUntil('\n');
Serial.println(line); // Print each line to the Serial Monitor
}
Serial.println("************************************* END *************************************");
// Close the file
dataFile.close();
}