Haskell with SparkFun Simultaneous RFID Reader

Posted on June 6, 2017

A couple of months ago, I bought a SparkFun Simultaneous RFID Reader board. As always, I’d rather program it in Haskell, so my first task was to write a Haskell binding to the C library (“Mercury API”) that the manufacturer provides.

I recently finished my Haskell binding and released it to Hackage. My binding supports all the basic operations you’d want to do to a tag: reading, writing, locking, unlocking, and killing. It works on Linux (including Raspberry Pi), Mac OS X, and Windows.

Along the way, I found a few bugs in the Mercury API C code, and I have some patches for them, which I’ve also submitted upstream to ThingMagic.

So, counting my Haskell binding, Mercury API is now available in five languages:

Here is a short example in Haskell that reads tags at maximum power for 1 second, and then prints the results:

{-# LANGUAGE OverloadedStrings #-} import qualified Data.Text.IO as T import qualified System.Hardware.MercuryApi as TMR import qualified System.Hardware.MercuryApi.Params as TMR main = do rdr <- TMR.create "tmr:///dev/ttyUSB0" TMR.paramSetTransportTimeout rdr 10000 TMR.connect rdr TMR.paramSetBasics rdr TMR.REGION_NA2 2700 TMR.sparkFunAntennas tags <- TMR.read rdr 1000 putStrLn $ "read " ++ show (length tags) ++ " tags" mapM_ T.putStrLn $ concatMap TMR.displayTagReadData tags TMR.destroy rdr

My goal is to use RFID tags to tag my stuff. For example, I lost my Bananagrams for several months, and it turned out they had been at the bottom of my backpack all along! So now I can stick an RFID tag in my Bananagrams, with the string “Bananagrams” written to the user bank of the tag. With the right antenna, I should be able to read the tag from 16 feet away. Unfortunately, that antenna isn’t available yet. Hopefully SparkFun will start shipping it soon!

In order to read the user bank (where I’m storing the names of my things), it’s necessary to create a ReadData tagop:

readUser = TMR.TagOp_GEN2_ReadData { TMR.opBank = TMR.GEN2_BANK_USER , TMR.opExtraBanks = [] , TMR.opWordAddress = 0 , TMR.opLen = 32 }

and then insert this tagop into the read plan, by adding this line before the TMR.read :