Like so many other projects, this one started with someone saying to me “wouldn’t it be great if...”

 

So, I thought the best place to start part 2 of my NOVSIS Proof of Concept (POC) project is with a video demo and then I will unpack the various elements that make up the project.

 

If you have no idea what I'm talking about in this blog, maybe read part 1 first.

 

 

5.0 The NOVSIS Demo

 

 

 

6.0 Unpacking the Visitor Sign-In Interface

 

Let me now unpack what was shown in the video.

 

I will start with the electronic Visitor Book Interface, as shown in the system architecture diagram, which I referred to in the video as the Visitor “box”.

 

As mentioned in blog 1, the visitor’s box is made up of 3 development modules, namely the PN7150 controller, the PSoC 4 M0 / BLE module and the ESP8266 WiFi module.

 

I also noted in blog 1 that there was no real added value to push the three development modules inside a box and had planned to leave as is, but then it was actually tidier to have them in a box and it would allow me to evaluate the visuals using just a RGB LED as the user interface and a blue LED for connectivity status, hence it is now inside a semi-sealed plastic enclosure.

 

So, here is what I ended up with:

 

 

{gallery:autoplay=false} Visitor Book Interface

 

The Visitor's "box" is powered via USB (5V) through the PSoC 4 BLE Pioneer Baseboard.

 

I hacked the PN7150 Arduino shield to add in a UART interface for the ESP8266. It was rather fortunate that the 2nd PSoC 4 UART block pins were located just where I needed them. The PSoC 4 and the ESP8266 reset pins were connected to ensure a sequenced reboot.

 

There are two lots of firmware for the project.

 

The main firmware for the PSoC 4 BLE module was developed using PSoC Creator 4.2 and the other firmware for the ESP8266 WiFi module was developed using the Arduino IDE.

 

Let’s look at the firmware in a little more detail. Code for this project can be found on my github page.

 

 

PSoC 4 Firmware

 

The PSoC 4 firmware is built off combination of existing examples, which were modified to suit my application. There is one full duplex UART block, 2 SBC blocks (one used for UART and the other for I2C) and 1 BLE block.

 

As mentioned in blog 1, the firmware for the PN7150 controller is a port of NXP’s demo firmware. This uses the I2C SBC block operating at a clock speed of 100kHz.

 

There are 2 serial (UART) connections. One is for the serial monitor to view debugging information and the other is to handle serial communication with the ESP8266.

 

Here is the top-level design view:

 

{gallery:autoplay=false} PSoC Top Level Design

 

The firmware for the BLE module is configured as a peripheral server and makes use of a single custom GATT service with a single service characteristic to handle the data transfer between the central client device, i.e. the phone, and the module. The BLE functionality is only triggered when it detects a P2P event and has transferred a simple NDEF text message, which contains the BLE name and part of the 128-bit service UUID. The reason for doing it this way, rather than the NDEF format that allows for the transfer of BLE device information, is that I was using MIT App Inventor to develop the phone app and the NFC block available only does a NDEF text read. I always have the option to modify the App Inventor code for the NFC block as it is open source when I find the time, but I'm happy with the keep it simple approach as it works for me.

 

        /* Is P2P discovery ? */
        if (RfInterface.Interface == INTF_NFCDEP)
        {
            // Create new condition to ensure that this only happens when we do not want to write the the MIFARE card
            if (VcardMode != 2) {
                /* Turn On the Amber Read OK LED */
                LED_Green_Write(LED_ON);
                LED_Red_Write(LED_ON);
                LED_Blue_Write(LED_OFF);
                if ((RfInterface.ModeTech & MODE_LISTEN) == MODE_LISTEN) DBG_PRINTF(" - P2P TARGET MODE: Activated from remote Initiator\r\n");
                else DBG_PRINTF(" - P2P INITIATOR MODE: Remote Target activated\r\n");


                /* Process with SNEP for NDEF exchange */
                NxpNci_ProcessP2pMode(RfInterface);


                DBG_PRINTF("PEER LOST\r\n");
                /* Turn Off the LEDs */
                LED_Green_Write(LED_OFF);
                LED_Red_Write(LED_OFF);
                
                if (activateBLE) {
                    DBG_PRINTF(" >> Entering BLE mode...\r\n");
                    
                    // WE NOW ENTER BLE MODE UNTIL DISCONNECTED
                    // =========================================
                    /* Infinite loop until activateBLE is false again*/
                    while(1)
                    {
                        /* Process pending BLE events */
                        CyBle_ProcessEvents();
                        
                        if (!activateBLE) break;
                        
                    }
                }
            }
        }

 

The BLE Event Handler (Process Events) then does the rest:

 


#include <ble.h>


/***************************************
*        Global BLE Variables
***************************************/


extern uint8_t VcardMode;                  // We set this to say we have sent off a Vcard


/* Array to store a Vcard Data Field */
uint8 VcardFieldData[VDAT_CHAR_DATA_LEN] = {'\0'};
uint8 VcardRespData[3] = {'\0'};


CYBLE_CONN_HANDLE_T  connectionHandle;


/* Status flag for the Stack Busy state. This flag is used to notify the application 
* whether there is stack buffer free to push more data or not */
uint8 StackBusyStatus = 0;


uint16 Vcardcntr = 0;


_Bool VcardRecd = false;


/* Local variable to store the current CCCD value */
uint8 VDatCCCDvalue[CCCD_DATA_LEN];


/* Handle value to update the CCCD */
CYBLE_GATT_HANDLE_VALUE_PAIR_T VDatNotificationCCCDhandle;




/*******************************************************************************
* Function Name: BLEStackEventHandler
********************************************************************************
*
* Summary:
*  This is an event callback function to receive events from the CYBLE Component.
*
* Parameters:
*  uint8 event:       Event from the CYBLE component.
*  void* eventParams: A structure instance for corresponding event type. The
*                     list of events structure is described in the component
*                     datasheet.
*
* Return:
*  None
*
*******************************************************************************/


void BLEStackEventHandler(uint32 event, void *eventParam)
{
    CYBLE_API_RESULT_T apiResult;
    CYBLE_GAP_BD_ADDR_T localBLEAddr;
    
/* Local variable to store the data received as part of the Write request events */
CYBLE_GATTS_WRITE_REQ_PARAM_T *wrReqParam;


    uint8 i8;
    uint16 i16;


    extern _Bool activateBLE;
    
    switch(event)
    {
    /**********************************************************
    *                       General Events
    ***********************************************************/
    case CYBLE_EVT_STACK_ON: /* This event is received when the component is Started */
        DBG_PRINTF("[%lx] Bluetooth On. Device address is: ", event);
        for(i8 = CYBLE_GAP_BD_ADDR_SIZE; i8 > 0u; i8--)
        {
            DBG_PRINTF("%2.2X", localBLEAddr.bdAddr[i8-1]);
        }
        DBG_PRINTF("\r\n");


        /* Enter discoverable mode so that the remote Client could find the device. */
        apiResult = CyBle_GappStartAdvertisement(CYBLE_ADVERTISING_FAST);


        if(apiResult != CYBLE_ERROR_OK)
        {
            DBG_PRINTF("StartAdvertisement API Error: %d \r\n", apiResult);
        }
        
        break;


    case CYBLE_EVT_TIMEOUT:
        /* Possible timeout event parameter values:
        * CYBLE_GAP_ADV_MODE_TO -> GAP limited discoverable mode timeout;
        * CYBLE_GAP_AUTH_TO -> GAP pairing process timeout.
        */
        if(CYBLE_GAP_ADV_MODE_TO == *(uint8 *) eventParam)
        {
            DBG_PRINTF("Advertisement timeout occurred. Advertisement will be disabled.\r\n");
        }
        else
        {
            DBG_PRINTF("Timeout occurred.\r\n");
        }
        break;


    case CYBLE_EVT_HARDWARE_ERROR:    /* This event indicates that some internal HW error has occurred. */
        DBG_PRINTF("Hardware Error \r\n");
        break;


    case CYBLE_EVT_HCI_STATUS:
        DBG_PRINTF("HCI Error. Error code is %x.\r\n", *(uint8 *) eventParam);
        break;


    /**********************************************************
    *                       GAP Events
    ***********************************************************/
    case CYBLE_EVT_GAPP_ADVERTISEMENT_START_STOP:
        if(CyBle_GetState() == CYBLE_STATE_DISCONNECTED)
        {
            DBG_PRINTF("[%lx]  >>> BLE Disconnected \r\n", event);
            LED_Blue_Write(LED_OFF);
            activateBLE = false;
            DBG_PRINTF(" -- Returning to NFC mode...\r\n");
        }    
        break;


    case CYBLE_EVT_GAP_DEVICE_CONNECTED:
        DBG_PRINTF("[%lx] CYBLE_EVT_GAP_DEVICE_CONNECTED: %d \r\n", event, connectionHandle.bdHandle);
        LED_Blue_Write(LED_ON);
        // Clear the data from VcardFieldData
        memset(VcardFieldData, '\0', VDAT_CHAR_DATA_LEN);
        Vcardcntr = 0;
        VcardRecd = false;
        break;


    case CYBLE_EVT_GAP_DEVICE_DISCONNECTED:
        DBG_PRINTF("[%lx] CYBLE_EVT_GAP_DEVICE_DISCONNECTED\r\n", event);
        LED_Blue_Write(LED_OFF);
        activateBLE = false;
        DBG_PRINTF(" -- Returning to NFC mode...\r\n");
        break;


    /**********************************************************
    *                       GATT Events
    ***********************************************************/
    case CYBLE_EVT_GATT_CONNECT_IND:
        /* GATT connection was established */
        connectionHandle = *(CYBLE_CONN_HANDLE_T *) eventParam;
        DBG_PRINTF("[%lx] CYBLE_EVT_GATT_CONNECT_IND: %x\r\n", event, connectionHandle.attId);
        break;


    case CYBLE_EVT_GATT_DISCONNECT_IND:
        /* GATT connection was disabled */
        DBG_PRINTF("[%lx] CYBLE_EVT_GATT_DISCONNECT_IND:\r\n", event);
        connectionHandle.attId = 0u;


        break;


    case CYBLE_EVT_GATTS_XCNHG_MTU_REQ:
        break;


    case CYBLE_EVT_GATTS_INDICATION_ENABLED:
        break;


    case CYBLE_EVT_GATTC_READ_BY_TYPE_RSP:
        {
            CYBLE_GATTC_GRP_ATTR_DATA_LIST_T *locAttrData;
            
            locAttrData = &(*(CYBLE_GATTC_READ_BY_GRP_RSP_PARAM_T *)eventParam).attrData;
            
            DBG_PRINTF("[%lx] EVT_GATT_READ_BY_TYPE_RSP len=%x, value: ", event, locAttrData->attrLen);
            for(i8 = 0u; i8 < locAttrData->attrLen; i8++)
            { 
                DBG_PRINTF("%2.2x ",*(uint8 *)(locAttrData->attrValue + i8));
            }
            DBG_PRINTF("\r\n");
        }
        break;


        case CYBLE_EVT_GATTS_READ_CHAR_VAL_ACCESS_REQ:
        /* Triggered on server side when client sends read request and when
        * characteristic has CYBLE_GATT_DB_ATTR_CHAR_VAL_RD_EVENT property set.
        * This event could be ignored by application unless it need to response
        * by error response which needs to be set in gattErrorCode field of
        * event parameter. */
        DBG_PRINTF("[%lx] CYBLE_EVT_GATTS_READ_CHAR_VAL_ACCESS_REQ: handle: %x \r\n", event, 
            ((CYBLE_GATTS_CHAR_VAL_READ_REQ_T *)eventParam)->attrHandle);
        break;


    case CYBLE_EVT_GATTS_WRITE_REQ:
/* This event is received when Central device sends a Write command on an Attribute */
        wrReqParam = (CYBLE_GATTS_WRITE_REQ_PARAM_T *) eventParam;
        /*
        DBG_PRINTF("Data Received: len %d | act len %d | %s", 
            wrReqParam->handleValPair.value.len,
            wrReqParam->handleValPair.value.actualLen,
            wrReqParam->handleValPair.value.val );
        */
        DBG_PRINTF("[%lx] CYBLE_EVT_GATTS_WRITE_REQ - %x\r\n", event, wrReqParam->handleValPair.attrHandle);
if(CYBLE_THROUGHPUT_SERVICE_V_DATA_CHARACTERISTIC_CLIENT_CHARACTERISTIC_CONFIGURATION_DESC_HANDLE == wrReqParam->handleValPair.attrHandle)
{
/* Extract the Write value sent by the Client/App for the CCCD */
            if(wrReqParam->handleValPair.value.val[CYBLE_THROUGHPUT_SERVICE_V_DATA_CHARACTERISTIC_CLIENT_CHARACTERISTIC_CONFIGURATION_DESC_INDEX] == true) {
                DBG_PRINTF(">> CYBLE_THROUGHPUT_SERVICE_V_DATA_CHARACTERISTIC_CLIENT_CHARACTERISTIC_CONFIGURATION_DESC_INDEX - true\r\n");
                //rgbledNotifications = TRUE;
            }
            else if(wrReqParam->handleValPair.value.val[CYBLE_THROUGHPUT_SERVICE_V_DATA_CHARACTERISTIC_CLIENT_CHARACTERISTIC_CONFIGURATION_DESC_INDEX] == false) {
                DBG_PRINTF(">> CYBLE_THROUGHPUT_SERVICE_V_DATA_CHARACTERISTIC_CLIENT_CHARACTERISTIC_CONFIGURATION_DESC_INDEX - true\r\n");
                //rgbledNotifications = FALSE;
            }
            
    /* Update CCCD handle with notification status data*/
    VDatNotificationCCCDhandle.attrHandle = CYBLE_THROUGHPUT_SERVICE_V_DATA_CHARACTERISTIC_CLIENT_CHARACTERISTIC_CONFIGURATION_DESC_HANDLE;
    VDatNotificationCCCDhandle.value.val = VDatCCCDvalue;
    VDatNotificationCCCDhandle.value.len = CCCD_DATA_LEN;
            
    /* Report data to BLE component for sending data when read by Central device */
    CyBle_GattsWriteAttributeValue(&VDatNotificationCCCDhandle, 0, &connectionHandle, CYBLE_GATT_DB_PEER_INITIATED);

/* Update the Vcard Notification attribute with new color coordinates */
            if (VcardRecd) {
                uint8 RespVal[] = {0x07};
    SendVcardAckOverVcardNotification(RespVal, 1);
            }
            else {
                uint8 RespVal[] = {0x01};
    SendVcardAckOverVcardNotification(RespVal, 1);
            }
            
        }
/* Check if the returned handle is matching and extract the Vcard data*/
        if(CYBLE_THROUGHPUT_SERVICE_V_DATA_CHARACTERISTIC_CHAR_HANDLE == wrReqParam->handleValPair.attrHandle)
        {
/* Extract the Write value sent by the Client/App for V Data characteristic */
            if ((Vcardcntr + wrReqParam->handleValPair.value.len) < VDAT_CHAR_DATA_LEN) {
                for (i8 = 0; i8 < wrReqParam->handleValPair.value.len; i8++) {
                    if (wrReqParam->handleValPair.value.val[i8] > 31 && wrReqParam->handleValPair.value.val[i8] < 127) {
                        VcardFieldData[Vcardcntr] = wrReqParam->handleValPair.value.val[i8];
                        Vcardcntr++;
                    }
                }
            }
            
            // This should be the last data segment -- let's check it's ok
            DBG_PRINTF("Vcard Data Length: %u\r\n", Vcardcntr);
            VcardRecd = true;
            for (i16 = 1; i16 < Vcardcntr; i16++) {
                if ((VcardFieldData[i16-1] == '^') && (VcardFieldData[i16] == '^')) {
                    DBG_PRINTF("\r");
                    VcardFieldData[i16-1] = '\r';
                }
                else if ((VcardFieldData[i16-1] == '^') && (VcardFieldData[i16] != '^')) {
                    DBG_PRINTF("\n");
                    VcardFieldData[i16-1] = '\n';
                }
                else {
                    DBG_PRINTF("%c", VcardFieldData[i16-1]);
                }
            }
            if (VcardFieldData[Vcardcntr-1] == '^') {
                DBG_PRINTF("\n");
                VcardFieldData[i16-1] = '\n';
            }
            else {
                DBG_PRINTF("%c", VcardFieldData[Vcardcntr-1]);
            }
            DBG_PRINTF("\r\n");
            // Now send via UART WIFI
            UART_WIFI_UartPutChar('v');
            UART_WIFI_UartPutCRLF(0x07);            // Hardcode the vCard byte that is used
            UART_WIFI_UartPutString((const char*)VcardFieldData);
            UART_WIFI_UartPutCRLF(0xC7);
            
            VcardMode = 1;                  // We set this to say we have sent off a Vcard
            
            // Now send a response back to BLE app
            uint8 RespVal[] = {0x07};
    SendVcardAckOverVcardNotification(RespVal, 1);
        
        }

/* Send the response to the write request received. */
CyBle_GattsWriteRsp(connectionHandle);
        break;
            
    case CYBLE_EVT_GATTC_WRITE_RSP:
        DBG_PRINTF("[%lx] CYBLE_EVT_GATTC_WRITE_RSP\r\n", event);
        break;


    case CYBLE_EVT_GATTS_WRITE_CMD_REQ:
        DBG_PRINTF("[%lx] CYBLE_EVT_GATTS_WRITE_CMD_REQ\r\n", event);
/* This event is received when Central device sends a Write command on an Attribute */
        wrReqParam = (CYBLE_GATTS_WRITE_REQ_PARAM_T *) eventParam;
        /*
        DBG_PRINTF("Data Received: len %d | act len %d | %s", 
            wrReqParam->handleValPair.value.len,
            wrReqParam->handleValPair.value.actualLen,
            wrReqParam->handleValPair.value.val );
        */
        
        if ((Vcardcntr + wrReqParam->handleValPair.value.len) < VDAT_CHAR_DATA_LEN) {
            for (i8 = 0; i8 < wrReqParam->handleValPair.value.len; i8++) {
                if (wrReqParam->handleValPair.value.val[i8] > 31 && wrReqParam->handleValPair.value.val[i8] < 127) {
                    VcardFieldData[Vcardcntr] = wrReqParam->handleValPair.value.val[i8];
                    Vcardcntr++;
                }
            }
        }
        
        break;


    case CYBLE_EVT_GATTS_PREP_WRITE_REQ:
        DBG_PRINTF("[%lx] CYBLE_EVT_GATTS_PREP_WRITE_REQ\r\n", event);
        break;


    case CYBLE_EVT_GATTS_EXEC_WRITE_REQ:
        DBG_PRINTF("[%lx] CYBLE_EVT_GATTS_EXEC_WRITE_REQ\r\n", event);
        break;


    case CYBLE_EVT_GATTS_HANDLE_VALUE_CNF:
        DBG_PRINTF("[%lx] CYBLE_EVT_GATTS_HANDLE_VALUE_CNF\r\n", event); 
        //dataSendConfirmed = 1;
        break;
       
            
    /**********************************************************
    *                       Other Events
    ***********************************************************/
    case CYBLE_EVT_PENDING_FLASH_WRITE:
        /* Inform application that flash write is pending. Stack internal data 
        * structures are modified and require to be stored in Flash using 
        * CyBle_StoreBondingData() */
        DBG_PRINTF("CYBLE_EVT_PENDING_FLASH_WRITE\r\n");
        break;


case CYBLE_EVT_STACK_BUSY_STATUS:
/* This event is generated when the internal stack buffer is full and no more
* data can be accepted or the stack has buffer available and can accept data.
* This event is used by application to prevent pushing lot of data to stack. */

/* Extract the present stack status */
        StackBusyStatus = * (uint8*)eventParam;
        DBG_PRINTF("CYBLE_EVT_STACK_BUSY_STATUS: %x\r\n", StackBusyStatus);
        
        break;


    default:
        DBG_PRINTF("OTHER event: %lx \r\n", event);
        break;
    }
}


/*******************************************************************************
* Function Name: SendVcardAckOverVcardNotification
********************************************************************************
* Summary:
*        Send a Vcard ack data to as BLE Notifications. This function updates
* the notification handle with some data and triggers the BLE component to send 
* notification
*
* Parameters:
*  uint8 *VcardData: pointer to an array containing a response
*  uint8 len: length of the array
*
* Return:
*  void
*
*******************************************************************************/
void SendVcardAckOverVcardNotification(uint8 *VcardData, uint8 len)
{
/* 'rgbLednotificationHandle' stores RGB LED notification data parameters */
CYBLE_GATTS_HANDLE_VALUE_NTF_T vCardnotificationHandle;

/* If stack is not busy, then send the notification */
if(StackBusyStatus == CYBLE_STACK_STATE_FREE)
{
/* Update notification handle with CapSense slider data*/
vCardnotificationHandle.attrHandle = CYBLE_THROUGHPUT_SERVICE_V_DATA_CHARACTERISTIC_CHAR_HANDLE;
vCardnotificationHandle.value.val = VcardData;
vCardnotificationHandle.value.len = len;

/* Send the updated handle as part of attribute for notifications */
CyBle_GattsNotification(connectionHandle,&vCardnotificationHandle);
}
}

 

 

 

ESP8266 Firmware

 

The ESP8266 based firmware is reliant on the following Arduino open-source libraries:

 

  • ESP8266 Hash library – this creates a unique hash for the vcard received, which is sent onto the cloud together with a subset of the vcard data
  • NTPClient + wifiUDP libraries – these are used to request the actual time from the online NTP server and create a date stamp for the data received
  • FirebaseESP8266 library – this is used to connect and send data to and extract data from the Firebase cloud database service. Google Firebase was chosen because of this library and the fact that no server side code was needed at all to make things work. This library can be found via the Arduino Library Manager search engine.
  • ESP8266WiFi library – this is used to handle wifi connectivity

 

As mentioned above the Arduino code is available on my github page. It should be fairly self explanatory. Much of the code relates to string parsing to extract information and is heavily reliant on the Firebase library to send and receive information via the cloud. At the moment it is using just the polling rather than the streaming option to receive updates. I plan to modify this at some stage.

 

 

7.0 Unpacking the Visitor Sign-In Process

 

In the video I demonstrated two visitor sign-in processes. The first used a NFC tag to transfer the business card (or vcard) details across and the second method used a phone app. Here is how the two processes worked.

 

Option 1: Using a NFC Tag to store your Business Card or contact details on

 

As we all should know by now, a common electronic format for storing business card or contact details is in a contacts list, which you will find on all phones and email systems.

 

The contacts list data structure or data format has been around for eons and I can still recall those days using Microsoft Outlook to share contact details with other colleagues, and vice versa. Then when email arrived there would be this vcard attachment. So this is nothing new.

 

With smart phones, such as those using Android OS, there is also a range of options available to allow you to share your contact details... as shown below. But where is NFC, you may ask? Well, it’s there under disguise... but we won’t be using that method (directly) anyway.

 

 

It’s called Android Beam. Here is a quick summary of what it's about.

 

Android Beam was introduced in 2011 with Android version 4.0 (Ice Cream Sandwich). 

 

According to https://developer.android.com/about/versions/android-4.0-highlights.html, Android Beam uses NFC to pair your devices over Bluetooth, then transfers files over the Bluetooth connection. It can also transfer very small pieces of data (contacts, links, etc) directly over NFC. For larger payloads, developers can even use Android Beam to initiate a connection and transfer the data over Bluetooth, without the need for user-visible pairing.

 

However, by 2017, ComputerWorld included Android Beam in a list of "once-trumpeted features that quietly faded away", observing that "despite the admirable marketing effort, Beam never quite worked particularly well, and numerous other systems for sharing stuff proved to be simpler and more reliable. https://en.wikipedia.org/wiki/Android_Beam

 

And in May 2019, it was announced that Android Beam will be discontinued in Android Q and is not present in the second Android Q beta for the Google Pixel 3.

 

More on Android Beam later.

 

So, what information do we need for an office visitor’s book and can we obtain that information from the data stored in a contacts list. Let’s review.

 

So, typically, the information required would be:

 

  • Date
  • Name
  • Company
  • Car Registration (if driven there)
  • Who you’re visiting (or these days for GDPR purposes a meeting reference identifier)
  • Time of arrival
  • Badge Number (for office use)

 

Now, let’s look at what is possible via the phone’s contact list.

 

 

So, hopefully you spotted in the screenshot gallery that the data fields missing from the array of standard options are car registration and a meeting reference, or who you are visiting.

 

Nevertheless, with a bit of creative thinking we can add these in by tweaking what’s available.

 

For example we can use “Events” to provide a meeting date and create a “custom event” where we use the meeting reference as the custom event name. Or we can use “Notes” as another option to store car reg details as well as meeting reference.

 

Unfortunately, this method would not really cut it in the real world. Firstly, there is the problem of getting this methodology adopted and used by all. Then for each meeting you would have to remember to manually change the meeting reference to reflect the new meeting etc. Then there is the problem of transferring this information across.

 

Well, as this is an NFC based project let’s use an NFC-based solution.

 

This is where NXP’s free App, NFC Writer comes in handy. I already mentioned this app in blog 1, where I showed how to use the app to provision WiFi. The same process can be used here.

 

 

Then when we are ready to transfer this information we click SAVE & WRITE and we can use our phone to write these details onto an NFC Tag Card, such as this one.

 

And that is it. We have a contactless card that can be used to transfer business card information to our electronic visitor book.

 

But, when I looked at this, I realised with the PN7150 controller the card could be removed from the process and we could use the phone directly using P2P mode. And to make this an even smoother user experience, I felt that a custom app would be needed. I even had the idea that you could use this app and the phone’s camera to take a “selfie” for the electronic visitor’s book for higher security type organisations where a visual ID would also be required for visitor verification.

 

Let’s now unpack the second option.

 

 

Option 2: Using NFC and Bluetooth LE to transfer Business Card details via a custom Android phone app.

 

Back to Android Beam. It was through my travails getting my own phone App to work that I discovered that Android Beam is still alive and kicking on my phone, which I found out needs to be turned on for peer-to-peer mode. So, Android Beam did me a huge favour by demonstrating the process of switching to Bluetooth to transmit large data sets actually works technically, as this was the process I intended to use for my phone app. Once again, others have thought of this process first.

 

 

As can be seen in the diagram above, the data transfer process involves three steps.

 

The first, is NFC where an NDEF text message is exchange containing BLE connection information.

 

The second is BLE where the app connects to the PSoc 4 BLE module via a custom GATT service. This allows the user to move more freely about and provide time to input their contacts or grab the details from a contacts list (as shown in the demo video) or restore saved data via the app. When the user is ready they then click a button to transfer this information across Bluetooth LE.

 

The third part of the process is really a bridging method of taking the information received and sending this in a suitable format to the cloud server. This uses WiFi communication.

 

 

Back-Office Data Processing

 

For this project, Google's Firebase was used as the cloud-based back office platform. The beauty of Firebase in this case is that it is free to use for developing prototype apps and the way it is structured means that I actually do not need any server based code. The Firebase platform handles everything for me.

 

The realtime Firebase database is NoSQL type database. As such it lends itself very well to JSON. So all my code does is send a JSON string with the visitors information and this arrives in the Firebase database:

 

The final process in the Visitor Sign-In process is providing the visitor with a provisioned access card. Here I was using a MIFARE card for demo purposes.

 

To provision the MIFARE card, all that is required is for a valid token to be entered in the database. Once this data is updated the electronic Visitors Book Interface will receive notification that a new token is available and will ready itself to write this token to a MIFARE card only.

 

 

8.0     A Proof of Concept Project is never finished

 

That is the scope of my intended POC for the Element14 NFC monthly project, but as with these type of systems based projects there are many more parts needed to complete the full picture. I am hoping to add in the access control part and possibly the web-app part if can find the time for one more demo. Fingers crossed.

 

Other than that, this was an immensely rewarding project from my perspective as I gleaned loads about what NFC can do and how it works on the coding side. I spent way more time than I wanted but hey it was worth it.