Haskell with SparkFun Simultaneous RFID Reader
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:
- C - officially supported by Mercury API
- Java - officially supported by Mercury API
- C# - officially supported by Mercury API
- Python binding by Petr Gotthard
- My Haskell binding
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
:
TMR.paramSetReadPlanTagop rdr (Just readUser)