ToheedNathalie Chan King Choy
Published © Apache-2.0

Loyalty Badge Reader: Solving Coffee Conundrum with Ultra96

The office cafe’s stamp cards are easy to lose. This tracks purchases by work ID badge so I don’t miss out on my free coffee anymore!

IntermediateFull instructions provided3 hours943
Loyalty Badge Reader: Solving Coffee Conundrum with Ultra96

Things used in this project

Hardware components

Ultra96-V1
Avnet Ultra96-V1
Ultra96 V1 board (not tested on V2)
×1
Avnet AES-ACC-U96-PWR
Power supply for Ultra96
×1
RFIDEAS, PCPROX PLUS ENROLL BLACK USB READER RDR-80581AKU
Buy through a distributor or on Ebay. The PCPROX PLUS model was chosen because the company has old and new types of badges at the office, so it needs to support multiple card types
×1
Sensors
96Boards Sensors
×1
Grove LCD RGB Backlight
×1
On/off button
Optional. This is if you decide to put everything inside a case.
×1
Custom plastic case
Optional. For good looks. Custom 4"(width) x 4"(length) x 3"(height) Worked with the local machine shop to laser cut the holes to accommodate ON/OFF button, USB connectors as well as the Power Cord. In the Bay Area: https://www.laseralliance.com/ Initially attempted to use a Dremel to cut the holes, but that caused the plastic to crack.
×1
USB Cable Assembly, USB Type A Plug to Micro USB Type B Plug
USB Cable Assembly, USB Type A Plug to Micro USB Type B Plug
×1
Micro SD card with default Ultra96 image
This card has a PetaLinux boot image on it. NOT the Pynq image.
×1
Sample badges of all the types you plan to accept with your badge reader
×1

Software apps and online services

RFIDeas PCPROX configuration utility

Story

Read more

Schematics

This project doesn't have any schematic

This project doesn't have any schematic

Code

hashrfid.py

Python
Copy hashrfid.py onto a USB stick, then follow the project instructions to access the USB stick on the Ultra96 and copy hashrfid.py to the correct location
##########################################################################
#
#    Copyright 2019 Xilinx
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
#
#    Author:	Toheed Ashraf
#
##########################################################################

from upm import pyupm_jhd1313m1 as lcd
import time
import hashlib
import sys
import re
import sqlite3
import evdev
from evdev import InputDevice, categorize, ecodes
from multiprocessing import Process

# *EVENTS* Update the events based on what you saw got assigned in
# /dev/input/by-id and /dev/input/by-path when plugging in the badge readers
dev1 = InputDevice('/dev/input/event1')
dev2 = InputDevice('/dev/input/event2') # *1BR* Comment out if 1 badge reader

print(dev1)
print(dev2) # *1BR* Comment out if only 1 badge reader
subText1 = "KEY_"
subText2 = "),"
buzzer = 4

# create database
sqlite_file = 'cafehash_db.sqlite'    # name of the sqlite database file
table_name1 = 'coffee'  # name of the table to be created
table_name2 = 'juice'  # name of the table to be created
new_field = 'Tnum' # name of the column
new_column1 = 'Tpid'  # name of the new column
new_column2 = 'Tcnt'  # name of the new column
field_type = 'INTEGER'  # column data type
index_name1 = 'my_pid1'  # name for the new unique index
index_name2 = 'my_pid2'  # name for the new unique index

def printLCD(line1,line2,red,green,blue):
    # LCD address is 0x3E and RGB control adddress is 0x62
    myLcd = lcd.Jhd1313m1(0, 0x3E, 0x62)

    myLcd.setColor(red,green,blue)
    myLcd.setCursor(0,1);
    myLcd.write(line1)
    myLcd.setCursor(1,1)
    myLcd.write(line2)


def FindSubString(strText, strSubString, Offset=None):
    try:
        Start = strText.find(strSubString)
        if Start == -1:
            return -1 # Not Found
        else:
            if Offset == None:
                Result = strText[Start+len(strSubString):]
            elif Offset == 0:
                return Start
            else:
                AfterSubString = Start+len(strSubString)
                Result = strText[AfterSubString:AfterSubString + int(Offset)]
            return Result
    except:
        return -1


def MultiDeviceRead(device_name):
    dev = device_name
    i = 0
    final = 0
    PID = 0
    hashPID = 0
    ID = ""
    CID = ""
    FID = ""

    for event in dev.read_loop():
        if event.type == ecodes.EV_KEY:
            text = str(categorize(event))

            AfterText1 = FindSubString(text, subText1, 3)
            BeforText2 = FindSubString(text, subText2, 3)

            if i == 1:
                final = 1
                if AfterText1[0] == "1":
                    java = 0
                    FID = ""
                    print("juice")
                else:
                    java = 1
                    CID = ""
                    print("coffee")

            if AfterText1[0:3] != "ENT":
                ID = ID + AfterText1[0]
                if i % 2 != 0:
                    if i > 1:
                        if java == 1:
                            CID = CID + AfterText1[0]
                        else:
                            FID = FID + AfterText1[0]
                i = i + 1
            elif final == 1:
                # Connecting to the database file
                conn = sqlite3.connect(sqlite_file)
                c = conn.cursor()

                if java == 1:
                    PID = hex(int(CID,16) + 0x0000FFFF) #removing this from submission
                    print PID
                    hashPID = hashlib.sha256(PID).hexdigest()
                    print hashPID
                    PID = hashPID
                    sql = "SELECT * FROM coffee_table WHERE coffee=?"
                    c.execute(sql,[PID])
                    id_exists = c.fetchone()
                    if id_exists:
                        print('{}'.format(id_exists))
                        cnt = id_exists[1]
                        cnt = cnt + 1
                        print cnt
                        if cnt < 11:
                            if cnt == 10:
                                printLCD("<<< COFFEE >>>", "NEXT ONE FREE!",0,0,50)
                            else:
                                printLCD("<<< COFFEE >>>", str(cnt),250,240,10)
                            c.execute("UPDATE coffee_table SET count=? WHERE coffee=?", (cnt,PID))
                        else:
                            cnt = 0
                            c.execute("UPDATE coffee_table SET count=? WHERE coffee=?", (cnt,PID))
                            printLCD("<<< COFFEE >>>", " FREE COFFEE!",100,0,0)

                        conn.commit()
                    else:
                        print('{} does not exist'.format(PID))
                        c.execute("INSERT INTO coffee_table VALUES (?,?)", (PID,1))
                        printLCD("<<< COFFEE >>>", "   11th FREE",250,240,10)
                        conn.commit()
                else:
                    PID = hex(int(FID,16) + 0xFFFF0000) #removing this from submission
                    print PID
                    hashPID = hashlib.sha256(PID).hexdigest()
                    print hashPID
                    PID = hashPID
                    sql = "SELECT * FROM juice_table WHERE juice=?"
                    c.execute(sql,[PID])
                    id_exists = c.fetchone()
                    if id_exists:
                        print('{}'.format(id_exists))
                        cnt = id_exists[1]
                        cnt = cnt + 1
                        print cnt
                        if cnt < 6:
                            if cnt == 5:
                                printLCD("<< SMOOTHIE >>", "NEXT ONE FREE!",0,0,50)
                            else:
                                printLCD("<< SMOOTHIE >>", str(cnt),35,255,35)
                            c.execute("UPDATE juice_table SET count=? WHERE juice=?", (cnt,PID))
                        else:
                            cnt = 0
                            c.execute("UPDATE juice_table SET count=? WHERE juice=?", (cnt,PID))
                            printLCD("<< SMOOTHIE >>", "FREE SMOOTHIE!",100,0,0)
                        conn.commit()
                    else:
                        print('{} does not exist'.format(PID))
                        c.execute("INSERT INTO juice_table VALUES (?,?)", (PID,1))
                        printLCD("<< SMOOTHIE >>", "    6th FREE",35,255,35)
                        conn.commit()
                i = 0
                final = 0
                ID = ""
                conn.close()



if __name__ == "__main__":
    # Connecting to the database file
    conn = sqlite3.connect(sqlite_file)
    c = conn.cursor()

    # create a table
    c.execute("""CREATE TABLE IF NOT EXISTS coffee_table
                              (coffee INTEGER, count INTEGER)
                   """)
    c.execute("""CREATE UNIQUE INDEX IF NOT EXISTS idx_coffee_pid ON coffee_table (coffee)
                   """)

    c.execute("""CREATE TABLE IF NOT EXISTS juice_table
                              (juice INTEGER, count INTEGER)
                   """)
    c.execute("""CREATE UNIQUE INDEX IF NOT EXISTS idx_juice_pid ON juice_table (juice)
                   """)


    # Committing changes and closing the connection to the database file
    conn.commit()
    conn.close()

    p1 = Process (target=MultiDeviceRead, args=(dev1,))
    p1.start()

# *1BR* Comment out p2 lines if you only have 1 badge reader
    p2 = Process (target=MultiDeviceRead, args=(dev2,))
    p2.start()

    printLCD("  LET's GO!!!", "",255,255,255)

coffee_smoothie.sh

SH
Copy coffee_smoothie.sh to a USB stick, then follow the project instructions to access the USB stick on the Ultra96 and copy coffee_smoothie.sh to the correct location
#!/bin/sh
##########################################################################
#
#    Copyright 2019 Xilinx
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
#
##########################################################################

cd /usr/share/coffee_smoothie
python hashrfid.py

ultra96-coffee-smoothie-setup.sh

SH
Copy ultra96-coffee-smoothie-setup.sh onto a USB stick, then follow the project instructions to access the USB stick on the Ultra96 and copy ultra96-coffee-smoothie-setup.sh to the correct location
#! /bin/sh

##########################################################################
#
#    Copyright 2019 Xilinx
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
#
##########################################################################

### BEGIN INIT INFO
# Provides: Coffee/Smoothie loyalty application on Ultra96
# Required-Start:
# Required-Stop:
# Default-Start:S
# Default-Stop:
# Short-Description: Starts Coffee/Smoothie loyalty application on Ultra96
# Description:       This script starts the Coffee/Smoothie loyalty application
#                    on Ultra96.  It assumes 2 USB badge readers are plugged in
#                    and come up on /dev/inputs/event1 and /dev/inputs/event2
### END INIT INFO

DESC="ultra96-coffee-smoothie-setup.sh will start badge readers on ultra96"
COFFEEUTIL="/usr/share/coffee_smoothie/coffee_smoothie.sh"
COFFEEUTIL_PID_NAME="ultra96-coffee-smoothie-setup"

test -x "$COFFEEUTIL" || exit 0


case "$1" in
  start)
    echo -n "Starting Ultra96 coffee smoothie setup daemon"
    start-stop-daemon --start --quiet --background --make-pidfile --pidfile /var/run/$COFFEEUTIL_PID_NAME.pid --exec $COFFEEUTIL
    echo "."
    ;;
  stop)
    echo -n "Stopping Ultra96 coffee smoothie setup daemon"
    start-stop-daemon --stop --quiet --pidfile /var/run/$COFFEEUTIL_PID_NAME.pid
    ;;
  *)
    echo "Usage: /etc/init.d/ultra96-coffee-smoothie-setup.sh {start|stop}"
    exit 1
esac

exit 0

Credits

Toheed

Toheed

1 project • 0 followers
Serial hacker, FPGA designer, hardware & product developer. Currently leading a team of systems engineers at Xilinx.
Nathalie Chan King Choy

Nathalie Chan King Choy

2 projects • 9 followers
Project Manager, Developer Community consultant, Engineer. Managed Open Source & Inner Source teams. Worked on Zynq-7000 & Ultra96 products.

Comments