Advertisement
Guest User

magstripe.py

a guest
Jan 8th, 2011
616
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.41 KB | None | 0 0
  1. import serial
  2. import sys
  3. from threading import RLock
  4. import time
  5.  
  6. ##
  7. # @mainpage SEN-08634 Magnetic Card Reader/Writer
  8. # This script can be directly edited to accomplish interaction with the
  9. # SEN-08634 Card Reader/Writer or it may be imported as a module.
  10. # Sample Usage:
  11. # <pre>
  12. #    mag = MagStripe()
  13. #    if mag.connect():
  14. #        print("Successfully connected to the Card Reader/Writer")
  15. #        mag.write_tracks('HELLO WORLD','012345689','987654321')
  16. #        mag.peek()
  17. #    else:
  18. #        print("Unable to connect to the Card Reader/Writer")
  19. # </pre>
  20. #
  21. # Sample Output: <pre>
  22. # Successfully connected to the Card Reader/Writer
  23. # (2)[Header Flag]
  24. #  (25)[Track 1 Start]
  25. # HELLO WORLD (3f)[Track End]
  26. #  (3b)[Track  2 Start]
  27. # 012345689 (3f)[Track End]
  28. #  (3)[Trailer Flag]
  29. # </pre>
  30. # <a href="http://www.sparkfun.com/products/8634">SparkFun Product Page</a>
  31.  
  32.  
  33. ##
  34. # This value controls how much data is read from the device at a time (in bytes)
  35. MAX_READ_LENGTH = 255
  36.  
  37. ##
  38. # This class exposes the SEN-08634 Magnetic Card Reader/Writer as an object to
  39. # accomplish reading and writing of data.
  40. #
  41. # Sample Usage:
  42. # <pre>
  43. #    mag = MagStripe()
  44. #    if mag.connect():
  45. #        print("Successfully connected to the Card Reader/Writer")
  46. #        mag.write_tracks('HELLOWORLD','012345689','987654321')
  47. #        mag.peek()
  48. #    else:
  49. #        print("Unable to connect to the Card Reader/Writer")
  50. # </pre>
  51. class MagStripe:
  52.     ## Default serial port to use when no port is specified
  53.     PORT="/dev/ttyUSB0"
  54.     ## Default baud rate to use when no baud rate is specified
  55.     BAUD=9600
  56.     ## Timeout value to use when reading from a serial port
  57.     TIMEOUT=2
  58.  
  59.     ## Synchonrizes access to class members
  60.     lock = RLock()
  61.     ## Represents the current state of the device
  62.     connected = False
  63.     ## Holds a reference to the underlying serial port
  64.     serial = None
  65.     ## These are protocol commands and markup
  66.     commands = {'Warm Reset':'\x7F' ,
  67.          'Ping':'\x1B' ,
  68.          'About':'\x1B' ,
  69.          'Red LED on':'\x58' ,
  70.          'Red LED off':'\x59' ,
  71.          'Green LED on':'\x48' ,
  72.          'Green LED off':'\x49' ,
  73.          'Yellow LED on':'\x29' ,
  74.          'Yellow LED off':'\x28' ,
  75.          'Buzzer on':'\x4A' ,
  76.          'Arm to read':'\x44' ,
  77.          'Read T1, Standard T1 Format':'\x54' ,
  78.          'Read T2, Standard T2 Format':'\x4B' ,
  79.          'Read T3, Standard T3 Format':'\x5F' ,
  80.          'Arm to Write with RAW':'\x60' ,
  81.          'Write T1,Standard T1 Format':'\x64' ,
  82.          'Write T2, Standard T2 Format':'\x65' ,
  83.          'Write T3, Standard T3 Format':'\x66' ,
  84.          'Set Write Density for Specified Track':'\x67' ,
  85.          'Set 210 BPI for T1&T3':'\x68' ,
  86.          'Set 75 BPI for T1&T3':'\x69' ,
  87.          'Set 210 BPI for T2':'\x6A' ,
  88.          'Set 75 BPI for T2':'\x6B' ,
  89.          'Set Coercivity High Only':'\x75' ,
  90.          'Set Coercivity Low Only':'\x76' ,
  91.          'Arm to Erase':'\x70' ,
  92.          'Erase T1':'\x77' ,
  93.          'Erase T2':'\x78' ,
  94.          'Erase T3':'\x7D' ,
  95.          'Set Communication Baud Rate':'\x7E' ,
  96.          'Get firmware version':'\x39' ,
  97.          'Ack':'\x06',
  98.          'Nack':'\x15',
  99.          'Start Heading':'\x01', #these are straight from the ascii table
  100.          'Start Text':'\x02',
  101.          'Stop Text':'\x03'
  102.          }
  103.  
  104.     ##
  105.     # Constructs an instance that's ready to start reading, but cannot be used
  106.     # for writing until connect is called.
  107.     # @param port number or serial device (/dev/ttyUSB0, etc)
  108.     def __init__(self,port=PORT):
  109.         self.serial = serial.Serial(port)
  110.         self.serial.timeout = self.TIMEOUT
  111.         self.serial.baudrate = self.BAUD
  112.  
  113.     ##
  114.     # Used internally to read data from the serial device
  115.     # @param timeout Number of times to attempt the read
  116.     def _read(self,timeout = 5):
  117.         data = None
  118.         timeouts = 0
  119.         self.lock.acquire()
  120.         while data == None and timeouts < timeout:
  121.             timeout = timeout + 1
  122.             data = self.serial.read(MAX_READ_LENGTH)
  123.         self.lock.release()
  124.         return data
  125.  
  126.     ##
  127.     # Used internally to write data to the serial device
  128.     # @param value value to be written
  129.     def _write(self,value):
  130.         self.lock.acquire()
  131.         self.serial.write(value)
  132.         self.lock.release()
  133.  
  134.     ##
  135.     # Tells the writer to get ready to write the specified tracks and writes
  136.     # them as soon as a card is swiped.
  137.     # This function performs no validation on the values that are passed in for the
  138.     # various tracks, but the writer will fail to write if the data is invalid.
  139.     # @param track1 The string to write to track 1
  140.     # @param track2 The digits to write to track 2
  141.     # @param track3 The digits to write to track 3
  142.     # @note Sometimes it makes angry beeps even if it did write to the card.
  143.     def write_tracks( self, track1, track2, track3 ):
  144.         self.lock.acquire()
  145.         self.write_command('Start Text')
  146.         self._write( "%s%s\x3F;%s\x3f+%s\x3f\x03" % ('%',track1, track2, track3) )
  147.         self.write_command('Stop Text')
  148.         self.write_command('Start Heading')
  149.  
  150.     ##
  151.     # Tests to see if the device is currently in the connected state with the
  152.     # system.
  153.     # @returns true if connected, false otherwise
  154.     def is_connected(self):
  155.         self.lock.acquire()
  156.         conn = self.connected
  157.         self.lock.release()
  158.         return conn
  159.  
  160.     ##
  161.     # Sets the internal state to connected
  162.     def _connected(self,value=True):
  163.         self.lock.acquire()
  164.         self.connected = value
  165.         self.lock.release()
  166.  
  167.     ##
  168.     # Connects to the mag stripe reader and initializes it for further
  169.     # communications.  If there is already a connection, this will disconnect
  170.     # and reconnect.  Check the return value, if the device is ready to be used
  171.     # this function returns true.
  172.     # @returns true on successful connect, false on failure
  173.     def connect(self):
  174.         if self.is_connected():
  175.             self.disconnect()
  176.             self.lock.acquire()
  177.             self.serial.open()
  178.             self.lock.release()
  179.  
  180.         self.lock.acquire()
  181.         #throw away anything that might be waiting to be read
  182.         self.peek() #it seems to get into a funny state if we don't do this
  183.         self.write_command('Warm Reset') #does not respond to this command, so dont read yet...
  184.         self.peek() #it seems to get into a funny state if we don't do this
  185.         self.write_command('Ping')
  186.         read = self._read();
  187.         for c in read:
  188.             if c == self.commands['Ack']:
  189.                 self._connected()
  190.         self.lock.release()
  191.         return self.is_connected()
  192.  
  193.     ##
  194.     # This will flush the underlying buffers and close the serial port.
  195.     def disconnect(self):
  196.         self.lock.acquire()
  197.         self._connected(False)
  198.         self.serial.flush()
  199.         self.serial.close()
  200.         self.lock.release()
  201.  
  202.     ##
  203.     # Write the specified command to the Card Reader/Writer.
  204.     # This is a convenience method, call it with 'Reset', 'About', 'Write',
  205.     # etc.  For commands that take arguments, provide an optional value.
  206.     # ex: <pre>
  207.     # magstripe.write_command('Ping')
  208.     # magstripe.peek()
  209.     # </pre>
  210.     def write_command(self, command, value = None):
  211.         if command in self.commands:
  212.             self.lock.acquire()
  213.             self._write(self.commands[command])
  214.             if value != None:
  215.                 self._write("%s"%value)
  216.             self.lock.release()
  217.         else:
  218.             raise ValueError("Specified command [%s] is not in the command set.  Valid commands: %s" % (command,self.commands))
  219.  
  220.     ##
  221.     # Peeks at any data that may have been recently read
  222.     # and displays it in a semi-sane fashion.
  223.     # Sample output:  
  224.     # <pre>
  225.     # (2)[Header Flag]
  226.     #  (25)[Track 1 Start]
  227.     # HELLO WORLD (3f)[Track End]
  228.     #  (3b)[Track  2 Start]
  229.     # 012345689 (3f)[Track End]
  230.     #  (3)[Trailer Flag]
  231.     # </pre>
  232.     def peek(self):
  233.         response = mag._read()
  234.         if not response:
  235.             print("[no data waiting]")
  236.         else:
  237.             tokens = { '\x02': 'Header Flag', '\x03': 'Trailer Flag', '\x25': 'Track 1 Start', '\x3b': 'Track  2 Start', '\x2b':'Track 3 Start', '\x3F': 'Track End' }
  238.             for t,v in tokens.items():
  239.                 response = response.replace(t,' (%x)[%s]\n ' % (ord(t),v))
  240.             print response
  241.  
  242. if __name__ == "__main__":
  243.     mag = MagStripe('/dev/ttyUSB0')#'/dev/null')
  244.     if mag.connect():
  245.         print("Successfully connected to the Card Reader/Writer")
  246.         mag.write_tracks('HELLO WORLD','012345689','987654321')
  247.         mag.peek();
  248.  
  249.         mag.disconnect()
  250.     else:
  251.         print("Unable to connect to the Card Reader/Writer")
  252.  
  253. # These things don't seem to do anything, though they are all supposed to be valid.
  254. # (all attempted (of course) after a successful connect:
  255. #        print("red led on command...")
  256. #        mag.write_command( 'Red LED on' )
  257. #        mag.peek()
  258. #        print("yellow led on command...")
  259. #        mag.write_command( 'Yellow LED on' )
  260. #        mag.peek()
  261. #        print("about command...")
  262. #        mag.write_command( 'About' )
  263. #        mag.peek()
  264. #        print("Firmware version command...")
  265. #        mag.write_command('Get firmware version')
  266. #        mag.peek()
  267. #        print("buzzer command...")
  268. #        mag.write_command('Buzzer on')
  269. #        mag.peek()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement