Raspberry Pi, HIDAPI 0.7.0, MagTek Magnetic Swipe Reader and Raspbian Linux – How to make it work

By phunter | Posted May 19, 2016

If you are like me, hopefully by now you have had the same thought I had.. Keyless Entry Room with Magnetic Striped Cards. YES. Leonard Nimoy would approve of this level of geek-dom.  However, that’s not how this started, and I don’t like Star Trek.

This all started listening to my boss on a conference call explain our new Employee Clocking system, involving Employee ID Cards that double as internal credit cards that they can ‘buy’ stuff with, and auto deducting it from their check. What the rest of the participants said after that, I am not sure, but my bosses reply was something to do with ‘Raspberry Pi’ and ‘maybe we can make it work.’

Seeing as I am the MagTek expert in our tiny office of developers, I didn’t even wait until he got off the call to get started. I loaded up a blank image of Raspbian, and went to town. We use HIDAPI 0.7.0, which if you have ever tried to do HID Programming as a hobby, you may have heard of it. It comes out of the box as a cross-platform compatible API which you can move and build easily. We use it on Windows today and have heavily modified the code to do some security stuff. So naturally, I copied the chunk of junk over to the Pi, installed the dependencies (libusb-1.0, libudev, libudev-dev) and went to make it. It failed.

So I set out on the interwebs, and scoured all the missing pieces for our Makefile (adding ‘-lrt -lpthread’ to our CFLAGS line and CXXFLAGS line) on Raspberry Pi (or my version of gcc) and had it compiling within the hour. That was the easy part.

Once compiled I had some issues getting serial number information. Even with lsusb -v not showing any serial numbers. I know these are set because I have used MagTek’s USB MSR tool to set it in the past, and is how we address the readers to get data from a specific one. We also have a list switch that lists out the matching readers by VendorID 0801 and Product ID 0002. Even the list function yielded no results. Quick fix for that, run with sudo and we’re in business, again.

Then the swipe by serial number had problems. We would swipe and get back some of the information as described in MagTek’s technical reference document, like the Track’s success flags, and the lengths, which were all valid. But the most we could get was the 1st character of the 1st track.

Insert several hours of random google searched keywords, and nothing was helping. I even dragged my boss in to make sure it wasn’t our modifications that caused a hiccup, which to his assistance, we realized we were only getting the first 8 bytes of the data. Weird.

After sleeping on it, I came back in with a fresh mind. I did a lsusb -v again and look what I found!

wMaxPacketSize 0x0008 1x 8 bytes
So the device says the max packet length is 8 bytes, which matches what we were getting. So why does HIDAPI only get the 8 bytes? Vary up some of the keywords to something like ‘linux packets’ and look at that. There is a bug reported on Signal11’s GitHub page.

The problem with it is quite simple. The device is returning the packets properly, but HIDAPI is returning as soon as it receives the first one, and shouldn’t be. It gets the device’s max packet length and assumes that is the whole data length it will return.

What should happen (as described in the GitHub page), is get a report about the data, check the length, and then to set that to the max data. But it doesn’t. So instead of setting it to some large arbitrary number, they advised to set it to the maximum length of the report. A quick reference to the MagTek Specifications, and we know the max length is 336 bytes. Now were getting somewhere.

In the Linux directory, we open up the hid-libusb.c and so a search for ‘const size_t length’ and find the line in question:

const size_t length = dev->input_ep_max_packet_size;
I modified that line to something like this:

const size_t length = 336;
Recompile, and boom. We can now read cards.

The caveat to this is that if you are trying to do the same for other devices, you need to hunt down the max report length in their technical specification document. Most companies like Motorola, Microchip and MagTek provide these resources one way or another, to make their devices compatible for POS Software Developers. The last thing you want to be doing is guessing. Use the max report length as your length, and you too will be functioning.

If this helps, share the hell out of it. I might even get a fix in place that’s a little more permanent and submit it to Signal11 for consideration, if I have the time. Until then, use this handy little work around to get you going.