Bluetooth Notification (with Fingerprint Approval)
GaTech ECE 4180 Group Members
- Austin Terrell
- Jacob Hancock
Introduction

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

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

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

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

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

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

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

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.


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

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
![]()
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, ¬ificationsMenu, " 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 = ¬ification;
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 = ¬ificationsMenu;
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.
