#!/usr/bin/python
# Bitbanging code to use Parallax serial RFID reader
# Terry Sturtevant, May 9, 2017
import RPi.GPIO as GPIO
from datetime import datetime
import time
GPIO.setmode(GPIO.BCM)
ENABLE_PIN=5
#This could presumeably be modified for other serial devices
PORT_RATE=2400
BYTESIZE=8
PARITY="N"
STOP_BITS=1
END_LINE='\n'
# any GPIO pin can be used
SERIAL_PIN=27
START_LEVEL=False
STOP_LEVEL=True
HALF_BIT_TIME=1/float((2*PORT_RATE))
THREE_HALF_BIT_TIME=3*HALF_BIT_TIME
ONE_BIT_TIME=2*HALF_BIT_TIME
HALF_BIT_TIME_US=int(HALF_BIT_TIME*1000000)
THREE_HALF_BIT_TIME_US=int(1000000*THREE_HALF_BIT_TIME)
ONE_BIT_TIME_US=int(1000000*ONE_BIT_TIME)
#in seconds
ALLOWABLE_DEAD_TIME=1
CHAR_TIME_US=(BYTESIZE*2+STOP_BITS)*HALF_BIT_TIME_US
message=[]
chartimes=[]
#In order to be fast enough in Python, this routine just generates an array
# of transition times on the serial pin (in microseconds)
# At the beginning of each new character, the time is reset to zero
# (Number of transitions for a character must be odd)
##
def timeChar():
timestart=0
times=[]
# wait for start bit
input_value=GPIO.input(SERIAL_PIN)
while input_value != START_LEVEL:
input_value=GPIO.input(SERIAL_PIN)
# get data transition time of start bit
dt=datetime.now()
nowus=dt.microsecond
times.append(nowus)
timestart=nowus
#calculate time for the entire character
timeend=timestart+CHAR_TIME_US
# get data transition time of other bits
# stop when the time for the entire character has passed
while nowus<timeend:
oldLevel=input_value
input_value=GPIO.input(SERIAL_PIN)
while input_value == oldLevel:
input_value=GPIO.input(SERIAL_PIN)
dt=datetime.now()
nowus=dt.microsecond
times.append(nowus)
times.append(times[0])
# wait for stop bit
input_value=GPIO.input(SERIAL_PIN)
while input_value != STOP_LEVEL:
input_value=GPIO.input(SERIAL_PIN)
#now make times relative to the start of the character
#so the start bit is at 0, by definition
temptime=times[0]
for i in range(len(times)):
times[i]=times[i]-temptime
return times
# given an array of transition times, and knowing the time for a bit,
# and that the character starts with a START bit, the complete
# bit string can be generated
# The data comes in LSB first, so it gets reversed at the end
##
def convertChar(thesetimes):
bytestr=''
curtime=0
curLevel='1'
altLevel='0'
curBit=0
if thesetimes[1]<CHAR_TIME_US:
for i in range(len(times)):
while thesetimes[i]>curtime+THREE_HALF_BIT_TIME_US:
bytestr+=curLevel
curtime+=ONE_BIT_TIME_US
curBit+=1
tempLevel=curLevel
curLevel=altLevel
altLevel=tempLevel
return bytestr[::-1]
####################MAIN##################
#beginning of main code
#The reader has an ENABLE pin, which must be LOW to read
GPIO.setup(ENABLE_PIN,GPIO.OUT)
GPIO.setup(SERIAL_PIN,GPIO.IN)
#This just makes a flash of the LED
GPIO.output(ENABLE_PIN,GPIO.HIGH)
time.sleep(0.5)
GPIO.output(ENABLE_PIN,GPIO.LOW)
try:
charSpace=0
msgIndex=1
startTime=datetime.now()
msgTime=startTime-startTime
msgStarted=False
msgDone=False
#A message will be assumed to be complete if there
# hasn't been a transition in ALLOWABLE_DEAD_TIME (seconds)
#Processing of transisiton times isn't done until AFTER
# the message is complete to allow a higher baud rate
while not msgDone:
#wait for activity
input_value=GPIO.input(SERIAL_PIN)
if input_value == STOP_LEVEL:
thisTime=datetime.now()
if not msgStarted:
startTime=thisTime
msgTime=thisTime-startTime
if msgTime.seconds>ALLOWABLE_DEAD_TIME:
msgDone=True
else:
# get a character
chartimes=timeChar()
startTime=datetime.now()
msgStarted=True
message.append(chartimes)
msgIndex+=1
#message is done, so disable reader
GPIO.output(ENABLE_PIN,GPIO.HIGH)
#now process transition times
charstr=''
for i in range(msgIndex-1):
times=message[i]
value=convertChar(times)
ascval= int(value,2)
charstr+= chr(ascval)
times=[]
print charstr
except KeyboardInterrupt:
pass
GPIO.cleanup()

Wilfrid Laurier University
© 2019 Wilfrid Laurier University