Interfacing Magtek Card Reader using Python on Windows

Interfacing Magtek Card Reader using Python on Windows

Interfacing Magtek Card Reader using Python on Windows

A former client contacted me to extend their POS to support membership using Magtek card reader. Before, I have this feature in one of my inventory application but it is using an ActiveX control. This time the client requires a Python desktop apps to read the card in the background and parse all pertinent data back to the main application.

To start off with this project we need 3 softwares.

  1. PyUSB library
  2. (optional) Magtek driver
  3. libusb library

First, you need to install the PyUSB library on your system. You can install it using pip by running the command:

pip install pyusb

PyUSB depends on the libusb library to communicate with USB devices. To install libusb on Windows, you can download the Windows binary package from the libusb website (https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/) and install it.

Connect the Magtek USB device you want to communicate with the computer. Windows should detect the card reader and install the device driver automatically. But if not you may need to provide the driver from the manufacturer. If everything goes well at this point, you need to find the product ID and vendor ID of the device. You have 3 ways of doing this:

  1.  use Windows Device Manager or a USB device information tool to find the vendor ID and product ID of the USB device. The card reader will shows up in Device Manager as a Human interface device/USB Input Device. The vendor ID and device ID for Magtek card readers may vary depending on the specific model and version of the device. However, a common vendor ID for Magtek card readers is "0x0801"
  2.  Run the program 'inf-wizard.exe' which is located in the installation directory of the LibUSB. (i.e. C:\Program Files\LibUSB-Win32\bin\inf-wizard.exe) The INF Wizard is needed to install a device driver that allows libusb to communicate with the USB device. This is because libusb uses its own device driver to communicate with USB devices, and this driver needs to be installed on the system in order for the USB device to be recognized and used with libusb.
  3.   If all else fails, you can consult the documentation or contact the manufacturer to obtain the vendor ID and device ID for your specific Magtek card reader model.

The vendor ID and product ID are needed to open and communicate with the device using PyUSB

After we've installed all the necessary library and hardware drivers, it's now possible to read data from the card reader using Python. The following code is based off of Micah Carrick's MagTek Credit Card Reader in Linux. I just took out the hiddev kernel driver part as it's a Linux specific HID Driver.


#!/usr/bin/python
"""
Read a MagTek USB HID Swipe Reader in Linux. A description of this
code can be found at: http://www.micahcarrick.com/credit-card-reader-pyusb.html

https://github.com/MicahCarrick/magtek-pyusb


You must be using the new PyUSB 1.0 branch and not the 0.x branch.

Copyright (c) 2010 - Micah Carrick
"""
import sys
import usb.core
import usb.util

VENDOR_ID = 0x0801
PRODUCT_ID = 0x0002
DATA_SIZE = 337

# find the MagTek reader

device = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID)

if device is None:
    sys.exit("Could not find MagTek USB HID Swipe Reader.")

# make sure the hiddev kernel driver is not active
''' start comment this for windows
if device.is_kernel_driver_active(0):
    try:
        device.detach_kernel_driver(0)
    except usb.core.USBError as e:
        sys.exit("Could not detach kernel driver: %s" % str(e))

end of comment
'''
# set configuration

try:
    # device.reset()
    device.set_configuration()
    # device.reset()
except usb.core.USBError as e:
    sys.exit("Could not set configuration: %s" % str(e))
    
endpoint = device[0][(0,0)][0]

# wait for swipe

data = []
swiped = False
print ("Please swipe your card...")

while 1:
    try:
        data += device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize)
        if not swiped: 
            print ("Reading...")
        swiped = True
        if len(data) >= DATA_SIZE:
            break
        
    except usb.core.USBError as e:
        if e.args == ('Operation timed out',) and swiped:
            if len(data) < DATA_SIZE:
                print ("Bad swipe, try again. (%d bytes)" % len(data))
                print ("Data: %s" % ''.join(map(chr, data)))
                data = []
                swiped = False
                continue
            else:
                break   # we got it!

# now we have the binary data from the MagReader! 

enc_formats = ('ISO/ABA', 'AAMVA', 'CADL', 'Blank', 'Other', 'Undetermined', 'None')

print ("Card Encoding Type: %s" % enc_formats[data[6]])

print ("Track 1 Decode Status: %r" % bool(not data[0]))
print ("Track 1 Data Length: %d bytes" % data[3])
print ("Track 1 Data: %s" % ''.join(map(chr, data[7:116])))

print ("Track 2 Decode Status: %r" % bool(not data[1]))
print ("Track 2 Data Length: %d bytes" % data[4])
print ("Track 2 Data: %s" % ''.join(map(chr, data[117:226])))

print ("Track 3 Decode Status: %r" % bool(not data[2]))
print ("Track 3 Data Length: %d bytes" % data[5])
print ("Track 3 Data: %s" % ''.join(map(chr, data[227:336])))

# since this is a bank card we can parse out the cardholder data

track = ''.join(map(chr, data[7:116]))

info = {}

i = track.find('^', 1)
info['account_number'] = track[2:i].strip()
j = track.find('/', i)
info['last_name'] = track[i+1:j].strip()
k = track.find('^', j)
info['first_name'] = track[j+1:k].strip()
info['exp_year'] = track[k+1:k+3]
info['exp_month'] = track[k+3:k+5]

print ("Bank card info: ", info)

The script start's by setting the device configuration using device.set_configuration() command and gets the endpoint for reading data from the device.

It then enters a loop to wait for the user to swipe a card. It reads data from the device using the device.read() method and adds it to a list. When enough data has been read, the loop exits.

Finally, the script parses the data from the card and prints out the card encoding type, track decode status, track data length, and track data for each of the three tracks on the card. It then uses some string manipulation to extract account holder information from the data and prints it out as well.

 


Share This