Monday, February 25, 2013

Parallax RFID Reader/Writer & the Raspberry Pi

The Parallax RFID Reader/Writer is a serial device for reading from and writing to writable 125 kHz RFID tags. Since it's a serial device, it is fairly easy to connect to the Pi. It is a 5 volt device, however, so a logic level converter is required.

Freeing Serial Port ttyAMA0:


The RXD pin on the Pi connects to the Linux serial device ttyAMA0. By default, though, this device is used for console output. Follow the 3 steps on the Adafruit Learning System page, "Freeing UART on the Pi."

Connections:


Parallax  Logic Lvl Conv (HV Side)
VCC       HV
SIN       TX0
SOUT      RX1
GND       GND

RPi       Logic Lvl Conv (LV Side)
3V3       LV
GND       GND
RXD       RX0
TXD       TX1

The Raspberry Pi's 5V0 is also connected to the same breadboard row as the logic level converter's HV.    

The following code reads and prints the card or tag's serial number. If this first phase is successful, it writes the current time in seconds since epoch (midnight, January 1st, 1970) to one of the tag's data areas. It then reads the time data just written to show that it was stored correctly.   

When testing this code, I do find that I need to hold the tag/card just a hair's breadth away from the antenna.


Python Code:


import math
import serial
import struct
import time

CMD_HEADER = "!RW"
READ_CMD = "\x01"
WRITE_CMD = "\x02"
SERIAL_NUM_ADDR = "\x20"
DATA_ADDR = "\x03"
STATUS_OK = "01"

serial = serial.Serial("/dev/ttyAMA0", baudrate=9600)
while True:
    # Time iin seconds since epoch, dropping fraction of second
    t = math.floor(time.time())
    # Send command header & read card number
    serial.write(CMD_HEADER)
    serial.write(READ_CMD) 
    serial.write(SERIAL_NUM_ADDR)
    # If successful, read card number & write time to card
    if serial.inWaiting > 0:
        read_result = serial.read()
        if read_result.encode('hex') == STATUS_OK :
            card = serial.read(size=4)
            print "Card: " + card.encode('hex')
            serial.write(CMD_HEADER)
            serial.write(WRITE_CMD) 
            serial.write(DATA_ADDR)
            data = list(struct.pack("!I", t))
            serial.write(data[0])
            serial.write(data[1])
            serial.write(data[2])
            serial.write(data[3])
            if serial.inWaiting > 0:
                write_result = serial.read()
                print "Write result: " + write_result.encode('hex')
        else:
            serial.flushInput() # ignore errors, no data
    # Send command header & read stored time data from card
    serial.write(CMD_HEADER)
    serial.write(READ_CMD) 
    serial.write(DATA_ADDR)
    if serial.inWaiting > 0:
        read_result = serial.read()
        if read_result.encode('hex') == STATUS_OK :
            # Read all 4 bytes of data
            card_data = serial.read(size=4)
            print "Time: " + str(t)
            # Read data as hexadecimal, convert to decimal, then print
            print "Data: " + str(int(card_data.encode('hex'), 16))
            print 
        else:
            serial.flushInput() # ignore errors, no data
        time.sleep(1) # Pause for 1 second