Bluetooth Notification (with Fingerprint Approval)

GaTech ECE 4180 Group Members

  • Austin Terrell
  • Jacob Hancock

Introduction

https://os.mbed.com/media/uploads/jhancock3520/overview.png

This Bluetooth Notification device is meant to be a prototype of a wearable which is able to securely approve/decline push notifications from a smartphone with a built-in fingerprint scanner. There are currently no mainstream products on the market (as of early Dec. 2019) which provide such functionality. Such a device could be utilized to securely make decisions on time-sensitive actions like stock-trading or two-factor authentication.

Included Parts

https://os.mbed.com/media/uploads/jhancock3520/lpc1768.jpg.250x250_q85_x200.jpg

Mbed LPC1768: Used to support all the pins for the other modules

https://os.mbed.com/media/uploads/jhancock3520/ble_1_x200.jpg

Adafruit Bluefruit BLE: To connect to a Bluetooth connected device with internet capabilities

https://os.mbed.com/media/uploads/jhancock3520/11792-01a_1_x200.jpg

Fingerprint Scanner: Quick and secure authentication by scanning the user’s fingerprint

https://os.mbed.com/media/uploads/jhancock3520/00255-action_1_x200.jpg

Basic 16x2 Character LCD: Lower power consumption than the newer uLCD displays

https://os.mbed.com/media/uploads/jhancock3520/components_2305_iso_orig_2_x200.jpg https://os.mbed.com/media/uploads/jhancock3520/1201-01_1_x200.jpg

Haptic Feedback Motor: Alert the wearer of an incoming notification by a quick, short vibration from the motor module

https://os.mbed.com/media/uploads/jhancock3520/09117-03-l_1_x200.jpg

RPG (Rotary Encoder): Used to navigate and select from the menu display options on the LCD

https://os.mbed.com/media/uploads/jhancock3520/rgbledpins_1_x200.jpg

RGB LED: Visually alerts the user of a new notification by blinking purple. The LED also turns green whenever the user’s fingerprint is successfully verified, and it displays red if the fingerprint is not recognized.

https://os.mbed.com/media/uploads/jhancock3520/10811-01_300x300_1_x200.jpg

DC Barrel Jack Adapter

https://os.mbed.com/media/uploads/jhancock3520/09835-01a_1_x200.jpg

External Battery Holder: Used to power the device while remaining portable

Wiring

https://os.mbed.com/media/uploads/jhancock3520/4180_finalproject_schematic.png

Description

The device is be able to receive notifications from a smartphone over Bluetooth using UART, which is displayed on a basic character LCD. Notifications are then approved or declined and translated into an appropriate response back to the phone. A rotary pulse generator is used to scroll through menu items and select options. A fingerprint scanner (GT-511C3) performs identity verification to add new users, delete other users, or send responses back to the phone. The design also includes a haptic feedback motor for alerts along with a color-coded RGB LED to provide an additional visual indication for a pending notification. All powered by Mbed.

Demo

https://os.mbed.com/media/uploads/jhancock3520/thumbnail_screenshot_20191204-114815_-2-.jpg

Libraries

To drive the 16x2 Basic Character LCD:

Import libraryTextLCD

TextLCD library for controlling various LCD panels based on the HD44780 4-bit interface

To program the haptic feedback driver and motor:

Import libraryDRV2605

Basic I2C Driver for the TI DRV2605 Haptic Driver. Currently only supports Open-Loop ERM operation using internal Immersion TouchSense 2200 software/library, although user can use the Read/Write Byte methods to manually set registers and control the device.

To navigate menus with Rotary Pulse Generator:

Import libraryRPG

Simple RPG Library

To color and power the RGB LED:

Import libraryRGBLED

Example code taken from Wiki page: https://os.mbed.com/users/4180_1/notebook/rgb-leds/

To use and configure the GT511C3 fingerprint scanner:

Import libraryGT511C3

Fork of library forked by beanmachine44, which was originally written by tosihisa

Past 4180 project for a basic menu system on the 16x2 Basic Character LCD:

Import libraryMenu

Menu originally written by pyeh9 with some streamlining

Source Code

Import programBluetoothNotificationWithFingerprint

Demo of Bluetooth Notification (with Fingerprint Approval)

include the mbed library with this snippet

#include "mbed.h"
#include "GT511C3.hpp"
#include "TextLCD.h"
#include "DRV2605.h"
#include "RGBLED.h"
#include "Menu.h"
#include "Selection.h"
#include "Navigator.h"
using namespace std;

// Devices
GT511C3     scanner(p9,p10);
TextLCD     lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD16x2);
RPG         rpg(p21,p22,p23);
RGBLed      rgb(p24,p25,p26);
DRV2605     haptics(p28, p27);
Serial      blue(p13, p14);

// Globals
Navigator   *navPtr;
Menu        mainMenu("1");
Menu        notificationsMenu("2");
Menu        settingsMenu("2");
Menu        notification("3");
char        text[16];
char        *textPtr = text;
int         userID = 1;
bool        notificationPresent = false;
bool        led = false;
Ticker      t;

// Prototypes
void    receive();
void    print(char *msg);
int     progress(int status, char *msg);
void    refreshMenu();
void    gotoMainMenu();
bool    verifyUser();
void    approve();
void    decline();
void    enroll();
void    deleteUsers();
void    blinker();

int main()
{       
    // Locals
    unsigned char data[498]; // Fingerprint template
    
    /* DEVICE SETUP */
    
    // Setup haptic feedback
    haptics.init(3.3);
    haptics.load_waveform_sequence(45,65);
    haptics.play();
    while(haptics.i2cReadByte(GO));
    
    // Configure Bluetooth
    blue.baud(9600);
    blue.attach(&receive);
    
    // Start blinker
    t.attach(&blinker, 0.4);
    
    /* MENU SETUP */
    
    // Make menus
    notificationsMenu.add(Selection(NULL, &mainMenu, " None..."));
    
    // Build settings menu
    settingsMenu.add(Selection(&enroll, NULL, " Enroll User"));
    settingsMenu.add(Selection(&deleteUsers, NULL, " Delete Users"));
    settingsMenu.add(Selection(NULL, &mainMenu, " Main Menu"));
    
    // Build main Menu
    mainMenu.add(Selection(NULL, &notificationsMenu, " Notification"));
    mainMenu.add(Selection(NULL, &settingsMenu, " Settings"));
    
    // Add notification options
    notification.add(Selection(&approve, NULL, " Approve"));
    notification.add(Selection(&decline, NULL, " Decline"));
    notification.add(Selection(NULL, &mainMenu, " Cancel"));
    
    // Build navigator to browse menus
    Navigator navigator(&mainMenu, rpg, &lcd);
    navPtr = &navigator;
    
    /* FINGERPRINT SCANNER SETUP */
    
    // Start fingerprint scanner
    if(scanner.Open() != 0) {
        lcd.cls();
        lcd.printf("Fingerprint Scanner FAILED.\n\r");
        exit(0);
    }

    // Deletes All Fingerprints enrolled in the database
    scanner.DeleteAllIDs();
    
    // Turn on scanner
    scanner.CmosLed(1);
    
    // Add inital user
    print("Scan New\nUser's Finger...");
    scanner.WaitPress(1);
    scanner.Enroll(-1, progress);
    scanner.RecvData(data, 498);
    scanner.SetTemplate(userID, data, 498);
    
    // Turn off scanner
    scanner.CmosLed(0);
    
    // Show menu
    refreshMenu();
    
    // Poll navigator for menu
    while(1) {    
        navigator.poll();
    }
}

// Reads bluetooth and posts notification
void receive()
{
    // Locals
    int i = 1;
    
    // Make first char a space
    memset(text, 0, sizeof(text));
    text[0] = ' ';
    
    // Read serial from bluetooth
    while(blue.readable() && (i < 15)) {
        text[i] += blue.getc();
        i++;
        wait(0.1);
    }
    text[i] = '\0'; // Null terminate
    
    // Post notification
    notificationsMenu.selections[0].childMenu = &notification;
    notificationsMenu.selections[0].selText = text;
    
    // Show notificaiton for a couple seconds
    lcd.cls();
    lcd.locate(0,0);
    lcd.printf("%s\n", text);
    rgb.write(0.5, 0.0, 0.5);
    haptics.play();
    wait(2);
    refreshMenu();
    notificationPresent = true;
}

// Print message to LCD
void print(char *msg)
{
    lcd.cls();
    lcd.printf("%s\n", msg);
}

// Prints enrollment progress
int progress(int status, char *msg)
{
    lcd.cls();
    lcd.printf("%s\n", msg);
    return 0;
}

// Re-display menu
void refreshMenu()
{
    navPtr->printMenu();
    navPtr->printCursor();
}

// Go to main menu
void gotoMainMenu()
{
    navPtr->activeMenu = &notificationsMenu;
    navPtr->bottom = navPtr->activeMenu->selections.size();
    navPtr->cursorPos = 0;
    navPtr->cursorLine = 1;
    navPtr->printMenu();
    navPtr->printCursor();
}

// Read finger and verify identity
bool verifyUser()
{
    // Locals
    int attempts = 0;
    
    // Turn on scanner
    scanner.CmosLed(1);
    
    // Allow 3 attempts
    while (attempts < 3) {
        print("Please Verify\nIdentity...");
        scanner.WaitPress(1);
        scanner.Capture(1);
        
        // If finger in database
        if (scanner.Identify() != -1) 
        {
            print("Thank You.\nRemove Finger...");
            if (scanner.IsPress()) scanner.WaitPress(0);
            
            // Turn off
            scanner.CmosLed(0);
            return true;
        } 
        else 
        {
            print("User Unknown.\nRemove Finger...");
            if (scanner.IsPress()) scanner.WaitPress(0);
            attempts++;
        }
    }
    
    // Turn off
    scanner.CmosLed(0);
    return false;
    
}

// Approve notification
void approve()
{
    // Turn off blinker
    notificationPresent = false;
    
    // If identity checks-out
    if (verifyUser()) 
    {
        // Send approval
        blue.puts("Approved.\n");
        
        // Feedback
        print("Approved.\nThank You.");
        rgb.write(0.0, 1.0, 0.0);
        wait(2);
        rgb.write(0.0, 0.0, 0.0);
    }
    else
    {
        // Send error
        blue.puts("User Identity Unknown.\n");
        
        // Feedback
        print("Error.\nUser Unknown.");
        rgb.write(1.0, 0.0, 0.0);
        wait(2);
        rgb.write(0.0, 0.0, 0.0);
    }
    
    // Clear notification
    notificationsMenu.selections[0].childMenu = &mainMenu;
    notificationsMenu.selections[0].selText = " None...";
    gotoMainMenu();
}

// Decline notification
void decline()
{
    // Turn off blinker
    notificationPresent = false;
    
    // If identity checks-out
    if (verifyUser()) 
    {
        // Send declination
        blue.puts("Declined.\n");
        
        // Feedback
        print("Declined.\nThank You.");
        rgb.write(0.0, 1.0, 0.0);
        wait(2);
        rgb.write(0.0, 0.0, 0.0);
    }
    else
    {
        // Send error
        blue.puts("User Identity Unknown.\n");
        
        // Feedback
        print("Error.\nUser Unknown.");
        rgb.write(1.0, 0.0, 0.0);
        wait(2);
        rgb.write(0.0, 0.0, 0.0);
    }
    
    // Clear notification
    notificationsMenu.selections[0].childMenu = &mainMenu;
    notificationsMenu.selections[0].selText = " None...";
    gotoMainMenu();
}

// Add a new user to the scanner
void enroll()
{
    unsigned char data[498]; // Fingerprint template

    if (verifyUser()) {
        
        // New user
        userID++;
        
        // Turn on scanner
        scanner.CmosLed(1);
        
        // Add user
        print("Scan New\nUser's Finger...");
        scanner.WaitPress(1);
        scanner.Enroll(-1, progress);
        scanner.RecvData(data, 498);
        scanner.SetTemplate(userID, data, 498);
        
        // Turn off scanner
        scanner.CmosLed(0);
    }

    refreshMenu();
}

// Remove all users from scanner
void deleteUsers()
{
    unsigned char data[498]; // Fingerprint template

    if (verifyUser()) {
        
        // Reset user IDs
        userID = 1;
        
        // Deletes All Fingerprints enrolled in the database
        scanner.DeleteAllIDs();
        
        // Turn on scanner
        scanner.CmosLed(1);
        
        // Add inital user
        print("Scan New\nUser's Finger...");
        scanner.WaitPress(1);
        scanner.Enroll(-1, progress);
        scanner.RecvData(data, 498);
        scanner.SetTemplate(userID, data, 498);
        
        // Turn off scanner
        scanner.CmosLed(0);
    }

    refreshMenu();
}

// Persistent notification led
void blinker()
{
    // If there is a notification
    if (notificationPresent) {
        
        // If led is not on
        if (!led) {
            rgb.write(0.5, 0.0, 0.5);
        }
        else {
            rgb.write(0.0, 0.0, 0.0);
        }   
        led = !led;     
    }
}


Please log in to post comments.