From 1ac3082d7cb8ef4b10651594a3e68b83f32d7d50 Mon Sep 17 00:00:00 2001
From: David Sullivan <david.sullivan1@motorolasolutions.com>
Date: Thu, 4 May 2023 14:51:38 -0500
Subject: [PATCH] adding project source code

---
 nfc_and_servo/.gitignore         |   6 +
 nfc_and_servo/README.md          |   3 +
 nfc_and_servo/include/README     |  39 ++++
 nfc_and_servo/include/door.h     |   9 +
 nfc_and_servo/include/nfc_read.h |  40 ++++
 nfc_and_servo/include/utils.h    |  14 ++
 nfc_and_servo/lib/README         |  46 +++++
 nfc_and_servo/platformio.ini     |  19 ++
 nfc_and_servo/src/door.cpp       |  21 +++
 nfc_and_servo/src/main.cpp       | 164 ++++++++++++++++
 nfc_and_servo/src/nfc_read.cpp   | 311 +++++++++++++++++++++++++++++++
 nfc_and_servo/src/utils.cpp      |  57 ++++++
 nfc_and_servo/test/README        |  11 ++
 13 files changed, 740 insertions(+)
 create mode 100644 nfc_and_servo/.gitignore
 create mode 100644 nfc_and_servo/README.md
 create mode 100644 nfc_and_servo/include/README
 create mode 100644 nfc_and_servo/include/door.h
 create mode 100644 nfc_and_servo/include/nfc_read.h
 create mode 100644 nfc_and_servo/include/utils.h
 create mode 100644 nfc_and_servo/lib/README
 create mode 100644 nfc_and_servo/platformio.ini
 create mode 100644 nfc_and_servo/src/door.cpp
 create mode 100644 nfc_and_servo/src/main.cpp
 create mode 100644 nfc_and_servo/src/nfc_read.cpp
 create mode 100644 nfc_and_servo/src/utils.cpp
 create mode 100644 nfc_and_servo/test/README

diff --git a/nfc_and_servo/.gitignore b/nfc_and_servo/.gitignore
new file mode 100644
index 0000000..beaaf8a
--- /dev/null
+++ b/nfc_and_servo/.gitignore
@@ -0,0 +1,6 @@
+.pio
+.vscode/.browse.c_cpp.db*
+.vscode/c_cpp_properties.json
+.vscode/launch.json
+.vscode/ipch
+.vscode/extensions.json
diff --git a/nfc_and_servo/README.md b/nfc_and_servo/README.md
new file mode 100644
index 0000000..91cc3cd
--- /dev/null
+++ b/nfc_and_servo/README.md
@@ -0,0 +1,3 @@
+# Microcontroller Code to Run the Project
+- This is the source code for the project
+- the src/ directory contains all of the logic for reading, storing and verifying RFID cards, along with locking and unlocking the door by communicating with the servo motor
diff --git a/nfc_and_servo/include/README b/nfc_and_servo/include/README
new file mode 100644
index 0000000..194dcd4
--- /dev/null
+++ b/nfc_and_servo/include/README
@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
diff --git a/nfc_and_servo/include/door.h b/nfc_and_servo/include/door.h
new file mode 100644
index 0000000..c1b8060
--- /dev/null
+++ b/nfc_and_servo/include/door.h
@@ -0,0 +1,9 @@
+#include <Servo.h>
+#include <Arduino.h>
+
+#define DOOR_MAX_POS    180
+#define DOOR_MIN_POS    0
+#define DOOR_PIN        D3
+
+void unlockDoor(void);
+void lockDoor(void);
\ No newline at end of file
diff --git a/nfc_and_servo/include/nfc_read.h b/nfc_and_servo/include/nfc_read.h
new file mode 100644
index 0000000..a7026e0
--- /dev/null
+++ b/nfc_and_servo/include/nfc_read.h
@@ -0,0 +1,40 @@
+//include arduino libraries and util functions
+#include "utils.h"
+
+// include NFC libraries
+// #include "nfc_utils.h"
+#include "rfal_nfc.h"
+#include "rfal_rfst25r95.h"
+#include "ndef_class.h"
+
+// define pins used by system
+#define SPI_MOSI        D11
+#define SPI_MISO        D12
+#define SPI_SCK         D13
+#define CS_PIN          D10
+#define IRQ_IN_PIN      D8
+#define IRQ_OUT_PIN     D2
+#define INTERFACE_PIN   D9
+
+// define read states
+#define DEMO_ST_NOTINIT         0
+#define DEMO_ST_START_DISCOVERY 1
+#define DEMO_ST_DISCOVERY       2
+
+// define read feature
+#define NDEF_DEMO_READ  0U
+
+// maximum amount of features (only using read, set to 1)
+#define NDEF_DEMO_MAX_FEATURES  1U
+
+#define NDEF_LED_BLINK_DURATION     250U
+#define DEMO_ST_MANUFACTURER_ID     0x02U
+
+typedef struct {
+    char *tag_type;
+    char *nfcUID;
+} reader_response_t;
+
+reader_response_t readNFCUID(void);
+void initDevice(void);
+
diff --git a/nfc_and_servo/include/utils.h b/nfc_and_servo/include/utils.h
new file mode 100644
index 0000000..fa453c8
--- /dev/null
+++ b/nfc_and_servo/include/utils.h
@@ -0,0 +1,14 @@
+#pragma once
+#include <Arduino.h>
+#include <SPI.h>
+
+#define LED_A_PIN       D7
+#define LED_B_PIN       D6
+#define LED_F_PIN       D5
+#define LED_V_PIN       D4
+#define MAX_HEX_STR         4
+#define MAX_HEX_STR_LENGTH  128
+
+void ledsOn(void);
+void ledsOff(void);
+char *hex2str(unsigned char *data, size_t dataLen);
\ No newline at end of file
diff --git a/nfc_and_servo/lib/README b/nfc_and_servo/lib/README
new file mode 100644
index 0000000..6debab1
--- /dev/null
+++ b/nfc_and_servo/lib/README
@@ -0,0 +1,46 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link into executable file.
+
+The source code of each library should be placed in a an own separate directory
+("lib/your_library_name/[here are source files]").
+
+For example, see a structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+|  |
+|  |--Bar
+|  |  |--docs
+|  |  |--examples
+|  |  |--src
+|  |     |- Bar.c
+|  |     |- Bar.h
+|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+|  |
+|  |--Foo
+|  |  |- Foo.c
+|  |  |- Foo.h
+|  |
+|  |- README --> THIS FILE
+|
+|- platformio.ini
+|--src
+   |- main.c
+
+and a contents of `src/main.c`:
+```
+#include <Foo.h>
+#include <Bar.h>
+
+int main (void)
+{
+  ...
+}
+
+```
+
+PlatformIO Library Dependency Finder will find automatically dependent
+libraries scanning project source files.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html
diff --git a/nfc_and_servo/platformio.ini b/nfc_and_servo/platformio.ini
new file mode 100644
index 0000000..cc3c980
--- /dev/null
+++ b/nfc_and_servo/platformio.ini
@@ -0,0 +1,19 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nucleo_f401re]
+platform = ststm32
+board = nucleo_f401re
+framework = arduino
+monitor_speed = 115200
+lib_deps = 
+	stm32duino/STM32duino NFC-RFAL@^1.0.1
+	stm32duino/STM32duino ST25R95@^1.0.0
+	khoih-prog/FlashStorage_STM32@^1.2.0
diff --git a/nfc_and_servo/src/door.cpp b/nfc_and_servo/src/door.cpp
new file mode 100644
index 0000000..2dc5c6a
--- /dev/null
+++ b/nfc_and_servo/src/door.cpp
@@ -0,0 +1,21 @@
+#include "door.h"
+
+static Servo servo;
+
+void unlockDoor(void)
+{
+    servo.attach(DOOR_PIN);
+    for(int pos = DOOR_MAX_POS; pos >= DOOR_MIN_POS; pos--)
+    {
+        servo.write(pos);
+    }
+}
+
+void lockDoor(void)
+{
+    servo.attach(DOOR_PIN);
+    for(int pos = DOOR_MIN_POS; pos >= DOOR_MAX_POS; pos++)
+    {
+        servo.write(pos);
+    }
+}
\ No newline at end of file
diff --git a/nfc_and_servo/src/main.cpp b/nfc_and_servo/src/main.cpp
new file mode 100644
index 0000000..e5b51df
--- /dev/null
+++ b/nfc_and_servo/src/main.cpp
@@ -0,0 +1,164 @@
+#include "nfc_read.h"
+#include "door.h"
+#include <FlashStorage_STM32.h>
+
+#define PASSIVE_ISO_DEP_LEN 14
+#define MAX_NUM_KEYS 10
+#define NUM_KEYS_INDEX 200
+
+static bool verifyUID(const char *uid);
+
+static void addKeyToMemory(const char* uid);
+
+static void interruptCallback(void);
+
+/**
+ * numkeys becomes a global variable held in ram rather than something written to flash memory
+ * this simplifies the operation of adding keys as fewer writes to flash are required and indexing is simplified
+ * BENEFITS: fewer writes to flash memory(increased longevity), simplified memory indexing
+ * COSTS: more refresh cycles necessary for RAM, decrease the life of the ram, also increased 
+ * dependency on global variables reduces encapsulation somewhat
+*/
+static int numkeys = 0;
+
+void setup() {
+  // put your setup code here, to run once:
+  Serial.begin(115200); // setting baudrate
+  delay(1000);
+
+
+  pinMode(LED_A_PIN, OUTPUT);
+  pinMode(LED_B_PIN, OUTPUT);
+  pinMode(LED_F_PIN, OUTPUT);
+  pinMode(LED_V_PIN, OUTPUT);
+  pinMode(USER_BTN, INPUT);
+
+  attachInterrupt(digitalPinToInterrupt(USER_BTN), interruptCallback, RISING);
+
+  // /* check state of the push button when not pressed */
+  Serial.println("Welcome to X-NUCLEO-NFC03A1");
+  Serial.print(numkeys);
+  initDevice();
+  delay(1000);
+  reader_response_t readerResponse = readNFCUID();
+  delay(1000);
+  if (readerResponse.nfcUID && readerResponse.tag_type)
+  {
+    Serial.println("received uid");
+    delay(1000);
+    Serial.write(readerResponse.nfcUID);
+    Serial.write(readerResponse.tag_type);
+    delay(1000);
+    addKeyToMemory(readerResponse.nfcUID);
+  }
+  else
+  {
+    Serial.print("no UID received");
+  }
+
+  // Serial.print("Going to unlock the door");
+  // Serial.print("\r\n");
+  // delay(2000);
+  // unlockDoor();
+  // Serial.print("Unlocked the Door");
+  // Serial.print("\r\n");
+  // delay(3000);
+  // Serial.print("Locking Door");
+  // Serial.print("\r\n");
+  // lockDoor();
+  // Serial.print("Locked Door, ending execution");
+  // Serial.print("\r\n");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  reader_response_t readerResponse = readNFCUID();
+
+  if(readerResponse.nfcUID && readerResponse.tag_type)
+  {
+    if (verifyUID(readerResponse.nfcUID) == true)
+    {
+      Serial.print("valid uid");
+      Serial.print("\r\n");
+      Serial.print("running unlock door");
+      Serial.print("\r\n");
+      unlockDoor();
+      delay(1000);
+      Serial.print("unlocked door");
+      Serial.print("\r\n");
+      delay(6000);
+      Serial.print("locking door");
+      Serial.print("\r\n");
+      lockDoor();
+      delay(1000);
+      Serial.print("locked door");
+      Serial.print("\r\n");
+    }
+    else 
+    {
+      Serial.print("uid not found");
+      Serial.print("\r\n");
+    }
+  }
+  else 
+  {
+    Serial.print("no uid received");
+    Serial.print("\r\n");
+  }
+}
+
+static bool verifyUID(const char *uid)
+{
+
+  int increaseIndex = PASSIVE_ISO_DEP_LEN * sizeof(char);
+  for (int i = 0; i < 10 * increaseIndex; i+= increaseIndex)
+  {
+    char* eeprom_uid;
+    Serial.print("Reading from memory");
+    EEPROM.get(i, eeprom_uid);
+    delay(1000);
+    Serial.write(eeprom_uid);
+    if (strncmp(uid, eeprom_uid, strlen(uid)) == 0)
+    {
+      return true;
+    }
+    else
+    {
+      continue;
+    }
+  }
+  return false;
+}
+
+static void addKeyToMemory(const char* uid)
+{
+  delay(500);
+  Serial.print(numkeys);
+  if(numkeys < 10){
+    EEPROM.put(numkeys * PASSIVE_ISO_DEP_LEN * sizeof(char), uid);
+    delay(500);
+    numkeys++;
+    delay(500);
+    Serial.print("Successfully added keys");
+  }
+  else
+  {
+    Serial.print("Could not add key");
+  }
+}
+
+static void interruptCallback(void) 
+{
+  Serial.write("add a new key to memory\r\n");
+  reader_response_t readerResponse = readNFCUID();
+  if(readerResponse.nfcUID && readerResponse.tag_type)
+  {
+    Serial.write("writing key to memory\r\n");
+    addKeyToMemory(readerResponse.nfcUID);
+    Serial.write("key has been written to memory, returning to normal flow \r\n");
+  }
+  else 
+  {
+    Serial.write("new key could not be read\r\n");
+  }
+}
diff --git a/nfc_and_servo/src/nfc_read.cpp b/nfc_and_servo/src/nfc_read.cpp
new file mode 100644
index 0000000..30c16c5
--- /dev/null
+++ b/nfc_and_servo/src/nfc_read.cpp
@@ -0,0 +1,311 @@
+#include "nfc_read.h"
+
+static uint8_t state = DEMO_ST_NOTINIT;
+static uint8_t ndefDemoFeature = NDEF_DEMO_READ;
+static uint8_t ndefDemoPrevFeature = 0xFF;
+static uint8_t NFCID3[] = {0x01, 0xFE, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};
+static uint8_t GB[] = {0x46, 0x66, 0x6d, 0x01, 0x01, 0x11, 0x02, 0x02, 0x07, 0x80, 0x03, 0x02, 0x00, 0x03, 0x04, 0x01, 0x32, 0x07, 0x01, 0x03};
+static rfalNfcDiscoverParam discParam;
+static SPIClass dev_spi(SPI_MOSI, SPI_MISO, SPI_SCK);
+static RfalRfST25R95Class rfst25r95(&dev_spi, CS_PIN, IRQ_IN_PIN, IRQ_OUT_PIN, INTERFACE_PIN);
+static RfalNfcClass rfal_nfc(&rfst25r95);
+static NdefClass ndef(&rfal_nfc);
+static uint32_t timer;
+static uint32_t timerLed;
+static bool ledOn;
+static const uint8_t *ndefDemoFeatureDescription[] = {
+    (uint8_t *)"1. Tap a tag to read its content"};
+
+void initDevice(void)
+{
+    dev_spi.begin();
+
+    if (rfal_nfc.rfalNfcInitialize() == ERR_NONE)
+    {
+        discParam.compMode = RFAL_COMPLIANCE_MODE_NFC;
+        discParam.devLimit = 1U;
+        discParam.nfcfBR = RFAL_BR_212;
+        discParam.ap2pBR = RFAL_BR_424;
+
+        ST_MEMCPY(&discParam.nfcid3, NFCID3, sizeof(NFCID3));
+        ST_MEMCPY(&discParam.GB, GB, sizeof(GB));
+        discParam.GBLen = sizeof(GB);
+
+        discParam.notifyCb = NULL;
+        discParam.totalDuration = 100U;
+        discParam.wakeupEnabled = false;
+        discParam.wakeupConfigDefault = true;
+        discParam.techs2Find = (RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F | RFAL_NFC_POLL_TECH_V | RFAL_NFC_POLL_TECH_ST25TB);
+
+        state = DEMO_ST_START_DISCOVERY;
+    }
+}
+
+reader_response_t readNFCUID(void)
+{
+    while (true)
+    {
+        static rfalNfcDevice *nfcDevice;
+
+        rfalNfcaSensRes sensRes;
+        rfalNfcaSelRes selRes;
+
+        rfalNfcbSensbRes sensbRes;
+        uint8_t sensbResLen;
+
+        uint8_t devCnt = 0;
+        rfalFeliCaPollRes cardList[1];
+        uint8_t collisions = 0U;
+        rfalNfcfSensfRes *sensfRes;
+
+        rfalNfcvInventoryRes invRes;
+        uint8_t rcvdLen;
+        char *uidData = nullptr;
+
+        rfal_nfc.rfalNfcWorker();
+
+        if (ndefDemoFeature != ndefDemoPrevFeature)
+        {
+            ndefDemoPrevFeature = ndefDemoFeature;
+            Serial.print((char *)ndefDemoFeatureDescription[ndefDemoFeature]);
+            Serial.print("\r\n");
+        }
+        switch (state)
+        {
+        case DEMO_ST_START_DISCOVERY:
+            ledsOff();
+
+            rfal_nfc.rfalNfcDeactivate(false);
+            rfal_nfc.rfalNfcDiscover(&discParam);
+
+            state = DEMO_ST_DISCOVERY;
+            break;
+
+        case DEMO_ST_DISCOVERY:
+            if (rfalNfcIsDevActivated(rfal_nfc.rfalNfcGetState()))
+            {
+                rfal_nfc.rfalNfcGetActiveDevice(&nfcDevice);
+
+                ledsOff();
+
+                delay(50);
+                ndefDemoPrevFeature = 0xFF; /* Force Display of prompt */
+                reader_response_t readerResponse = {nullptr, nullptr};
+                switch (nfcDevice->type)
+                {
+                case RFAL_NFC_LISTEN_TYPE_NFCA:
+                    digitalWrite(LED_A_PIN, HIGH);
+                    switch (nfcDevice->dev.nfca.type)
+                    {
+                    case RFAL_NFCA_T1T:
+                    {
+                        Serial.print("ISO14443A/Topaz (NFC-A T1T) TAG found. UID: ");
+                        readerResponse.tag_type = "ISO1443A/Topaz (NFC-A T1T)";
+                        Serial.print(hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen));
+                        Serial.print("\r\n");
+                        rfal_nfc.rfalNfcaPollerSleep();
+                        break;
+                    }
+                    
+                    case RFAL_NFCA_T4T:
+                        Serial.print("NFCA PASSIVE ISO-DEP device found. UID: ");
+                        readerResponse.tag_type = "NFCA PASSIVE ISO-DEP";
+                        Serial.print(hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen));
+                        Serial.print("\r\n");
+                        // demoNdef(nfcDevice);
+                        rfal_nfc.rfalIsoDepDeselect();
+                        break;
+
+                    case RFAL_NFCA_T4T_NFCDEP:
+                    case RFAL_NFCA_NFCDEP:
+                    {
+                        Serial.print("NFCA Passive P2P device found. NFCID: ");
+                        char tagType[] = "NFCA Passive P2P";
+                        // readerResponse.tag_type = "NFCA Passive P2P";
+                        readerResponse.tag_type = tagType;
+                        Serial.print(hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen));
+                        Serial.print("\r\n");
+                        // demoP2P();
+                        break;
+                    }
+
+                    default:
+                        Serial.print("ISO14443A/NFC-A card found. UID: ");
+                        readerResponse.tag_type = "ISO1443A/NFC-A";
+                        Serial.print(hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen));
+                        Serial.print("\r\n");
+                        // demoNdef(nfcDevice);
+                        rfal_nfc.rfalNfcaPollerSleep();
+                        break;
+                    }
+                    Serial.print("Operation completed\r\nTag can be removed from the field\r\n");
+                    uidData = hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen);
+                    rfal_nfc.rfalNfcDeactivate(true);
+                    // return uidData;
+                    readerResponse.nfcUID = uidData;
+                    return readerResponse;
+                    rfal_nfc.rfalNfcaPollerInitialize();
+                    while (rfal_nfc.rfalNfcaPollerCheckPresence(RFAL_14443A_SHORTFRAME_CMD_WUPA, &sensRes) == ERR_NONE)
+                    {
+                        if (((nfcDevice->dev.nfca.type == RFAL_NFCA_T1T) &&
+                             (!rfalNfcaIsSensResT1T(&sensRes))) ||
+                            ((nfcDevice->dev.nfca.type != RFAL_NFCA_T1T) &&
+                             (rfal_nfc.rfalNfcaPollerSelect(nfcDevice->dev.nfca.nfcId1,
+                                                            nfcDevice->dev.nfca.nfcId1Len, &selRes) != ERR_NONE)))
+                        {
+                            break;
+                        }
+                        rfal_nfc.rfalNfcaPollerSleep();
+                        delay(130);
+                    }
+                    break;
+
+                case RFAL_NFC_LISTEN_TYPE_NFCB:
+
+                    Serial.print("ISO14443B/NFC-B card found. UID: ");
+                    readerResponse.tag_type = "ISO14443B/NFC-B";
+                    Serial.print(hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen));
+                    Serial.print("\r\n");
+                    // uidData = hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen);
+                    digitalWrite(LED_B_PIN, HIGH);
+                    // rfal_nfc.rfalNfcDeactivate(true);
+                    // return uidData;
+
+                    if (rfalNfcbIsIsoDepSupported(&nfcDevice->dev.nfcb))
+                    {
+                        // demoNdef(nfcDevice);
+                        rfal_nfc.rfalIsoDepDeselect();
+                    }
+                    else
+                    {
+                        rfal_nfc.rfalNfcbPollerSleep(nfcDevice->dev.nfcb.sensbRes.nfcid0);
+                    }
+                    /* Loop until tag is removed from the field */
+                    Serial.print("Operation completed\r\nTag can be removed from the field\r\n");
+                    uidData = hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen);
+                    rfal_nfc.rfalNfcDeactivate(true);
+                    // return uidData;
+                    readerResponse.nfcUID = uidData;
+                    return readerResponse;
+                    rfal_nfc.rfalNfcbPollerInitialize();
+                    while (rfal_nfc.rfalNfcbPollerCheckPresence(RFAL_NFCB_SENS_CMD_ALLB_REQ, RFAL_NFCB_SLOT_NUM_1, &sensbRes, &sensbResLen) == ERR_NONE)
+                    {
+                        if (ST_BYTECMP(sensbRes.nfcid0, nfcDevice->dev.nfcb.sensbRes.nfcid0, RFAL_NFCB_NFCID0_LEN) != 0)
+                        {
+                            break;
+                        }
+                        rfal_nfc.rfalNfcbPollerSleep(nfcDevice->dev.nfcb.sensbRes.nfcid0);
+                        delay(130);
+                    }
+                    break;
+
+                case RFAL_NFC_LISTEN_TYPE_NFCF:
+
+                    if (rfalNfcfIsNfcDepSupported(&nfcDevice->dev.nfcf))
+                    {
+                        Serial.print("NFCF Passive P2P device found. NFCID: ");
+                        readerResponse.tag_type = "NFCF Passive P2P device";
+                        Serial.print(hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen));
+                        Serial.print("\r\n");
+                        // demoP2P();
+                    }
+                    else
+                    {
+                        Serial.print("Felica/NFC-F card found. UID: ");
+                        Serial.print(hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen));
+                        Serial.print("\r\n");
+                        // demoNdef(nfcDevice);
+                    }
+
+                    digitalWrite(LED_F_PIN, HIGH);
+                    /* Loop until tag is removed from the field */
+                    Serial.print("Operation completed\r\nTag can be removed from the field\r\n");
+                    uidData = hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen);
+                    rfal_nfc.rfalNfcDeactivate(true);
+                    // return uidData;
+                    readerResponse.nfcUID = uidData;
+                    return readerResponse;
+                    devCnt = 1;
+                    rfal_nfc.rfalNfcfPollerInitialize(RFAL_BR_212);
+                    while (rfal_nfc.rfalNfcfPollerPoll(RFAL_FELICA_1_SLOT, RFAL_NFCF_SYSTEMCODE, RFAL_FELICA_POLL_RC_NO_REQUEST, cardList, &devCnt, &collisions) == ERR_NONE)
+                    {
+                        /* Skip the length field byte */
+                        sensfRes = (rfalNfcfSensfRes *)&((uint8_t *)cardList)[1];
+                        if (ST_BYTECMP(sensfRes->NFCID2, nfcDevice->dev.nfcf.sensfRes.NFCID2, RFAL_NFCF_NFCID2_LEN) != 0)
+                        {
+                            break;
+                        }
+                        delay(130);
+                    }
+                    break;
+
+                case RFAL_NFC_LISTEN_TYPE_NFCV:
+                {
+                    uint8_t devUID[RFAL_NFCV_UID_LEN];
+
+                    ST_MEMCPY(devUID, nfcDevice->nfcid, nfcDevice->nfcidLen); /* Copy the UID into local var */
+                    REVERSE_BYTES(devUID, RFAL_NFCV_UID_LEN);                 /* Reverse the UID for display purposes */
+                    Serial.print("ISO15693/NFC-V card found. UID: ");
+                    readerResponse.tag_type = "ISO15693/NFC-V";
+                    Serial.print(hex2str(devUID, RFAL_NFCV_UID_LEN));
+                    Serial.print("\r\n");
+                    uidData = hex2str(devUID, RFAL_NFCV_UID_LEN);
+
+                    digitalWrite(LED_V_PIN, HIGH);
+
+
+                    // demoNdef(nfcDevice);
+
+                    /* Loop until tag is removed from the field */
+                    Serial.print("Operation completed\r\nTag can be removed from the field\r\n");
+                    // uidData = nfcDevice->nfcid;
+                    rfal_nfc.rfalNfcDeactivate(true);
+                    readerResponse.nfcUID = uidData;
+                    // return uidData;
+                    return readerResponse;
+                    rfal_nfc.rfalNfcvPollerInitialize();
+                    while (rfal_nfc.rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, RFAL_NFCV_UID_LEN * 8U, nfcDevice->dev.nfcv.InvRes.UID, &invRes, (uint16_t *)&rcvdLen) == ERR_NONE)
+                    {
+                        delay(130);
+                    }
+                }
+                break;
+
+                case RFAL_NFC_LISTEN_TYPE_ST25TB:
+
+                    Serial.print("ST25TB card found. UID: ");
+                    readerResponse.tag_type = "ST25TB";
+                    Serial.print(hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen));
+                    Serial.print("\r\n");
+                    readerResponse.nfcUID = hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen);
+                    return readerResponse;
+                    digitalWrite(LED_B_PIN, HIGH);
+                    break;
+
+                case RFAL_NFC_LISTEN_TYPE_AP2P:
+
+                    Serial.print("NFC Active P2P device found. NFCID3: ");
+                    readerResponse.tag_type = "NFC Active P2P";
+                    Serial.print(hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen));
+                    Serial.print("\r\n");
+                    readerResponse.nfcUID = hex2str(nfcDevice->nfcid, nfcDevice->nfcidLen);
+                    return readerResponse;
+                    // demoP2P();
+                    break;
+
+                default:
+                    break;
+                }
+
+                rfal_nfc.rfalNfcDeactivate(true);
+                delay(500);
+                state = DEMO_ST_START_DISCOVERY;
+            }
+            break;
+
+        case DEMO_ST_NOTINIT:
+        default:
+            break;
+        }
+    }
+}
\ No newline at end of file
diff --git a/nfc_and_servo/src/utils.cpp b/nfc_and_servo/src/utils.cpp
new file mode 100644
index 0000000..ac59126
--- /dev/null
+++ b/nfc_and_servo/src/utils.cpp
@@ -0,0 +1,57 @@
+#include "utils.h"
+#include "nfc_utils.h"
+
+char hexStr[MAX_HEX_STR][MAX_HEX_STR_LENGTH];
+uint8_t hexStrIdx = 0;
+
+void ledsOn(void)
+{
+  digitalWrite(LED_A_PIN, HIGH);
+  digitalWrite(LED_B_PIN, HIGH);
+  digitalWrite(LED_F_PIN, HIGH);
+  digitalWrite(LED_V_PIN, HIGH);
+}
+
+void ledsOff(void)
+{
+  digitalWrite(LED_A_PIN, LOW);
+  digitalWrite(LED_B_PIN, LOW);
+  digitalWrite(LED_F_PIN, LOW);
+  digitalWrite(LED_V_PIN, LOW);    
+}
+
+char *hex2str(unsigned char *data, size_t dataLen)
+{
+  unsigned char *pin = data;
+  const char *hex = "0123456789ABCDEF";
+  char *pout = hexStr[hexStrIdx];
+  uint8_t i = 0;
+  uint8_t idx = hexStrIdx;
+  size_t len;
+
+  if (dataLen == 0) 
+  {
+    pout[0] = 0;
+  }
+  else
+  {
+    /* Trim data taht doesn't fit in buffer */
+    len = MIN(dataLen, (MAX_HEX_STR_LENGTH / 2));
+
+    for(; i < (len - 1); ++i)
+    {
+      *pout++ = hex[(*pin >> 4) & 0xF];
+      *pout++ = hex[(*pin++) & 0xF];
+      *pout = 0;
+    }
+    *pout++ = hex[(*pin >> 4) & 0xF];
+    *pout++ = hex[(*pin) & 0xF];
+    *pout = 0;
+  }
+
+  hexStrIdx++;
+  hexStrIdx %= MAX_HEX_STR;
+
+  return hexStr[idx];
+
+}
\ No newline at end of file
diff --git a/nfc_and_servo/test/README b/nfc_and_servo/test/README
new file mode 100644
index 0000000..9b1e87b
--- /dev/null
+++ b/nfc_and_servo/test/README
@@ -0,0 +1,11 @@
+
+This directory is intended for PlatformIO Test Runner and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PlatformIO Unit Testing:
+- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
-- 
GitLab