Saturday, August 20, 2016

RFIDler revisited: RFIDling with Proximity card UID collection


My first few projects scripting for the RFIDler were an exploratory effort. As you can see from my integration post and my first auto-capture script there were a number of features I breezed passed. The main one I want to discuss now is the RFIDler python class.

 The class exposes a connect() method and a command() method which do exactly what there name states. One thing of note is that command calls an 'internal' method send_command() which just handles some message interpretation and passes the result back up to command() which does more useful interpretation. Command and send_command both pass raw commands to the board which means essentially with just these methods your script can take full advantage of any command available in API mode.

The drawback is: unless you thread a program, calling continuous commands (like SNIFFER) will block it. Even in threaded programs synchronizing communications becomes troublesome. There is a way to get around this and I will cover that below.
Finally, there is the cleanup method disconnect() which is always good to call at the end of any open resource. 

As a side note: The code for the RFIDler class is very easy to read. If you are interested in knowing more, it is a very approachable source of information.

Now on to the good bits. How do we take this class and make some Python magick to give us the best chance of capturing card UIDs. First lets look at how I imagine Adam Laurie thought we'd use it. The designed work-flow probably goes something like this: 
  • Your script should take as input a hardware device (or serial port), a card type, and one or more API commands like AUTOTAG. 
  • The underlying class dresses it up for serial and passes it along to the device you give it using the connect command 
  • it returns a result Boolean and (if applicable) a data response as a List object. Your script parses this output and feeds it to Unicorns. 
  • Lather, Rinse, Repeat as needed.
Since that covers all strictly necessary functions I started thinking about what things I could speed up by adding into the Class as opposed to each of my scripts.
One that I came up with nearly immediately was the LED control methods. Simply put the more LEDs that are on, the more power draw. Since I regularly use this on a battery pack fed system, I want to conserve as much power as possible. The RFIDler has 6 controllable LEDs and they can be controlled with two types of commands:

LEDON <led number 1-6> and LEDOFF <LED number 1-6> can be used to set the desired state explicitly. note the numbering starts from 1 and not 0.

LED <led number 1-6> will toggle the given LED

So I added three methods to the RFIDler __init__.py
    def toggleLED(self,ledId):
        pn = int(ledId)
        if pn < 1:
            ledpin = 1;
        elif pn > 6:
            ledpin = 6;
        else:
            ledpin = pn;
        self.command("LED %d" % ledpin)
    def ledOn(self,ledId):
        pn = int(ledId)
        if pn < 1:
            ledpin = 1;
        elif pn > 6:
            ledpin = 6;
        else:
            ledpin = pn;
        self.command("LEDON %d" % ledpin)
    def ledOff(self,ledId):
        pn = int(ledId)
        if pn < 1:
            ledpin = 1;
        elif pn > 6:
            ledpin = 6;
        else:
            ledpin = pn;
        self.command("LEDOFF %d" % ledpin)
In my scripts I add a function called go_dark() which will cycle through all the LEDs and turn them off.
def go_dark():
    for i in range(1,7):
        rfidler.ledOff(i)
I can still use the LEDs as a signal work is being done if I chose. You will see this in the next part.

Now to get around the blocking calls to things like SNIFFER, READER, etc., I first looked at their outputs. Next, I figured out which API one-shot command was most equivalent. For example: READER will send a continuous stream of UID signals read from the coil. If it were to only run once, the output would be the same as calling UID once. Therefore we can emulate the READER command locally simply by calling UID in a loop. The bonus is: we can of course stream this output to a file much easier. The drawback is a slight decrease in sample rate. The code below could be sped up slightly by removing the led calls. In practice this has not been a considerable factor, though. It is still fast enough to constitute 'nearly' live capture.
    go_dark()
    of = open(options.outFile,'w')
   
    while True:
        rfidler.toggleLED(3)
        result, data=rfidler.command('set tag %s ' % options.cardType)
        result, uid=rfidler.command('uid')
        print uid[0]
        of.write(uid[0]+"\n")
        rfidler.toggleLED(2)

That it. No really, I swear. Sure I shortened it by removing the optparser code but you can figure them out fairly easily by looking at the code. The outFile output is a line-by-line stream of UIDs similar to the output of READER.
7FFFFFFFFEFFFFFFFFFDFFFFFFFFFBFFFFFFFFF3FFFFDFFFEFFFF7FFFFDFEFFF
7FFBFFFFFFFFEFF7FFFFFFDFFFFFFFFFFFFFFFFFFF7FFFFFFFFEFFFFFFFFFDFF
7FFFFFFFFEFFFFFFFFFDFFFFFFFFFBFFFFFFFFF7FFFFFFFFEFFFFFFFFFDFFFFF
3FFFFFFFFEFFFFFFFFFDFFFFFFFFFBFFFFFFFFF7FFFFFFFFEFFFFFFFFFDFFFFF
3FFFFFFFFEFFFFFFFFFDFFFFF7FFFBFFFFFFFFF7FFFFFFFFEFFFFFFFFFDFFFFF
7FFFFFFFFEFFFFFFFFFEFFFFFFFFF9FFFFFFFFFBFFFFFFFFFFFFFFFFFFDFFFFF
555555555556659A6A95969AAAA95555555555555556659A6A95969AAAA95555
555555555556659A6A95969AAAA95555555555555556659A6A95969AAAA95555
555555555556659A6A95969AAAA95555555555555556659A6A95969AAAA95555
555555555556659A6A95969AAAA95555555555555556659A6A95969AAAA95555
7FFFFFFFFFFFFFFFFFFDFFFFFFFFFBFFFFFFFFF7BFFFFFFFEFFFFFFFFFDFFFFF
7FFFFFFFFEFFFFFFFFFDFFFFFFFFF9FFFFFFFFF7FFFFFFFFE7FFFFFFFFDFFFFF
7FFFFFFFFEFFFFFFFFFDFFFFFFFFFBFFFFFFFFF7FFFFFFFFFFFFFFFFFFCFFFFF
3FFFFFFFFF7FFFFFFFFEFFFFFFFFFDFFFFFFFFFBFFFEFFFFB7FFFFFFDFA7FFFF
4FFFFFFFBFDFFFFFEFFFBFFFDFFFFF7FDFBFFFFEEFFFFFFFFBFFFFFFFFFBFFFF
FFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFF7FFFFFFFFE7FFFFFFFFDFFFFF
3FFFFFFFFEFFFFFFFFFDFFFFFFFFFBFFDFFFFFF7FFFFFFFFEFFFFFFFFFFFFFFF
7FFFFFFFFFFFFFFFFFFDFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFEF7F7F
1FFFFFFFFF7FFFFFFFFDFFFFFFFFFBFFFFFFFFF7FFFFFFFFE7FFFFFFFFDFFFFF
I say similar because of the addition of the \n character after each UID. This is to make it easier for me to parse it in other scripts. Intersetingly SNIFFER is similar to READER, except for a couple small things.It doesn't require you to set the card type like READER does and it's output is formatted in lines similar to the above. So my implementation with the \n can be seen as the best of both worlds.

No comments:

Post a Comment