PageRenderTime 51ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/sm130/test.py

https://bitbucket.org/johboh/raspberry
Python | 381 lines | 348 code | 10 blank | 23 comment | 8 complexity | d3b8e3d9010f6c56a4222fc58ad6242f MD5 | raw file
  1. import serial
  2. import time
  3. import array
  4. import urllib2
  5. import sys
  6. #
  7. #******************************************************************************************************************************
  8. #* RFID reader, SM130
  9. #* From https://www.sparkfun.com/datasheets/Sensors/ID/SM130.pdf
  10. #* package sent by the host
  11. #* HEADER:RESERVED:LENGTH (1 byte + data length):COMMAND:DATA (N bytes):CSUM (add all bytes except header)
  12. #* 0xFF:0x00:0xx:0xx:0xxx
  13. #*
  14. #* package sent by the sm130
  15. #* HEADER:RESERVED:LENGTH (1 on failure, 16 on success):COMMAND (same as sent):RESPONSE:CSUM (add all bytes except header)
  16. #* 0xFF:0x00:0xx:0xx:0xxx
  17. #*
  18. #* Default baud rate 19200bps
  19. #******************************************************************************************************************************
  20. #
  21. # Reference:
  22. # SM130 https://www.sparkfun.com/datasheets/Sensors/ID/SM130.pdf
  23. # Smart Poster Record Type Definition: http://www.cardsys.dk/download/NFC_Docs/NFC%20Smart%20Poster%20Record%20Type%20Definition%20Technical%20Specification.pdf
  24. # TLV tag types: http://apps4android.org/nfc-specifications/NFCForum-TS-Type-2-Tag_1.1.pdf
  25. # MIFARE MAD: http://www.nxp.com/documents/application_note/AN10787.pdf
  26. # NDEF: https://learn.adafruit.com/adafruit-pn532-rfid-nfc/ndef
  27. #
  28. HEADER = 0xFF
  29. RESERVED = 0x00
  30. CMD_RESET = 0x80
  31. CMD_FIRMWARE_VER = 0x81
  32. CMD_SEEK_FOR_TAG = 0x82
  33. CMD_AUTHENTICATE = 0x85
  34. CMD_READ_BLOCK = 0x86
  35. CMD_KEY_A = 0xAA
  36. CMD_KEY_B = 0xBB
  37. CMD_KEY_TRANSPORT = 0xFF
  38. ERR_SEEK_FOR_TAG_SUCCESS = 0x4C
  39. ERR_SEEK_FOR_TAG_RF_OFF = 0x55
  40. STANDARD_KEY_A = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
  41. MAD_KEY_A = [0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5]
  42. NDEF_KEY_A = [0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7]
  43. TYPE_MIFARE_UL = 0x01
  44. TYPE_MIFARE_1K = 0x02
  45. TYPE_MIFARE_4K = 0x03
  46. MIFARE_UL_BLOCKS = 16
  47. MIFARE_UL_C_BLOCKS = 48
  48. MIFARE_1K_BLOCKS = 64
  49. TLV_NULL = 0x00
  50. TLV_LOCK = 0x01
  51. TLV_NDEF = 0x03
  52. TLV_PROP = 0xFD
  53. TLV_TERM = 0xFE
  54. SERIAL_READ_TIMEOUT = 0.02
  55. RESET_TIMER_S = 3
  56. def rfidWriteCustomCommand(ser, command):
  57. barr = array.array('B', command)
  58. chk = 0
  59. for i in range(2, len(barr)):
  60. chk = chk + barr[i]
  61. barr.append(chk & 0xFF)
  62. ser.write(barr);
  63. print "Writing %s" % barr
  64. # Write simple zero payload command
  65. def rfidWriteSimpleCommand(ser, command):
  66. rfidWriteCustomCommand(ser, [HEADER, RESERVED, 0x01, command])
  67. def getRecordTypePrefix(record_type_indicator, record_field):
  68. if record_field == 0x00:
  69. return ""
  70. if record_field == 0x01:
  71. return "http://www."
  72. if record_field == 0x02:
  73. return "https://www."
  74. if record_field == 0x03:
  75. return "http://"
  76. if record_field == 0x04:
  77. return "https://"
  78. if record_field == 0x05:
  79. return "tel:"
  80. if record_field == 0x06:
  81. return "mailto:"
  82. if record_field == 0x07:
  83. return "ftp://anonymous:anonymous@"
  84. if record_field == 0x08:
  85. return "ftp://ftp."
  86. if record_field == 0x09:
  87. return "ftps://"
  88. if record_field == 0x0A:
  89. return "sftp://"
  90. if record_field == 0x0B:
  91. return "smb://"
  92. if record_field == 0x0C:
  93. return "nfs://"
  94. if record_field == 0x0D:
  95. return "ftp://"
  96. if record_field == 0x0E:
  97. return "dav://"
  98. if record_field == 0x0F:
  99. return "news:"
  100. if record_field == 0x10:
  101. return "telnet://"
  102. if record_field == 0x11:
  103. return "imap:"
  104. if record_field == 0x12:
  105. return "rtsp://"
  106. if record_field == 0x13:
  107. return "urn:"
  108. if record_field == 0x14:
  109. return "pop:"
  110. if record_field == 0x15:
  111. return "sip:"
  112. if record_field == 0x16:
  113. return "sips:"
  114. if record_field == 0x17:
  115. return "tftp:"
  116. if record_field == 0x18:
  117. return "btspp://"
  118. if record_field == 0x19:
  119. return "btl2cap://"
  120. if record_field == 0x1A:
  121. return "btgoep://"
  122. if record_field == 0x1B:
  123. return "tcpobex://"
  124. if record_field == 0x1C:
  125. return "irdaobex://"
  126. if record_field == 0x1D:
  127. return "file://"
  128. if record_field == 0x1E:
  129. return "urn:epc:id:"
  130. if record_field == 0x1F:
  131. return "urn:epc:tag:"
  132. if record_field == 0x20:
  133. return "urn:epc:pat:"
  134. if record_field == 0x21:
  135. return "urn:epc:raw:"
  136. if record_field == 0x22:
  137. return "urn:epc:"
  138. if record_field == 0x23:
  139. return "urn:nfc:"
  140. def processTarget(target):
  141. print "Handling target %s" % target
  142. uri = urllib2.urlopen(target).read()
  143. urllib2.urlopen("http://127.0.0.1:666/1/%s/play" % uri).read()
  144. print "uri: %s" % uri
  145. def rfidProcessNdef(ndef):
  146. print "Processing ndef: %s" % "".join("%02x" % b for b in ndef)
  147. # Record header
  148. ndef_header = ndef.pop(0)
  149. h_tnf = ndef_header & 0x07
  150. # We only support 0x01, Well known Record
  151. if h_tnf != 0x01:
  152. print "NDEF does not contain a well known record"
  153. return
  154. h_il = (ndef_header >> 3) & 1
  155. h_sr = (ndef_header >> 4) & 1
  156. h_cf = (ndef_header >> 5) & 1
  157. h_me = (ndef_header >> 6) & 1
  158. h_mb = (ndef_header >> 7) & 1
  159. print "NDEF: message begin: %d, message end: %d, chunk: %d, short: %d, length present: %d, tnf: %d" % (h_mb, h_me, h_cf, h_sr, h_il, h_tnf)
  160. # Only handle short messages and non chunked.
  161. if h_cf == 1 or h_sr == 0:
  162. print "Long or chunked messages currently unsupported"
  163. return
  164. type_length = ndef.pop(0)
  165. payload_length = ndef.pop(0)
  166. if h_il == 1:
  167. id_length = ndef.pop(0)
  168. else:
  169. id_length = 0
  170. record_type_indicator = "".join( chr( val ) for val in ndef[0:type_length] )
  171. del ndef[0:type_length]
  172. #Skip id, if any
  173. if id_length > 0:
  174. del ndef[0:id_length]
  175. print "type_length: %d, id_length: %d, record_type_indicator: %s" % (type_length, id_length, record_type_indicator)
  176. # We only support record types U and Sp (Smart poster)
  177. if record_type_indicator == "U":
  178. # Uri
  179. record_field = ndef.pop(0)
  180. # Rest of data is payload
  181. prefix = getRecordTypePrefix(record_type_indicator, record_field)
  182. print "Record prefix: %s " % prefix
  183. payload_part = ndef[0:payload_length-1] # -1 for the record field
  184. del ndef[0:payload_length-1]
  185. payload_str = "".join( chr( val ) for val in payload_part )
  186. print "Payload %s" % payload_str
  187. together = "%s%s" % (prefix, payload_str)
  188. print "Together: %s" % together
  189. # Just for now, if fjun, open.
  190. if "fjun.com" in together:
  191. processTarget(together)
  192. if len(ndef) > 0:
  193. # There is more
  194. rfidProcessNdef(ndef)
  195. elif record_type_indicator == "T":
  196. # Text
  197. status_length = ndef.pop(0)
  198. language_code = ndef[0:status_length]
  199. del ndef[0:status_length]
  200. payload_part = ndef[0:payload_length-1-status_length]
  201. del ndef[0:payload_length-1-status_length]
  202. payload_str = "".join( chr( val ) for val in payload_part )
  203. print "Payload %s" % payload_str
  204. if len(ndef) > 0:
  205. # There is more
  206. rfidProcessNdef(ndef)
  207. elif record_type_indicator == "Sp":
  208. # This is a poster, restart Ndef message
  209. rfidProcessNdef(ndef)
  210. else:
  211. print "Unsupported record type indicator %s" % record_type_indicator
  212. return
  213. def rfidProcessData(payload):
  214. print "Processing data: %s" % "".join("%02x" % ord(b) for b in payload)
  215. # Convert to ord
  216. for i in range(0, len(payload)):
  217. payload[i] = ord(payload[i])
  218. while True:
  219. # search for TLV record.
  220. tlv_type = payload.pop(0)
  221. if tlv_type == TLV_NULL:
  222. print "Found null TLV, going to next."
  223. continue
  224. elif tlv_type == TLV_LOCK:
  225. tlv_length = payload.pop(0)
  226. print "Found lock TLV with length %d, will ignore it." % tlv_length
  227. del payload[0:tlv_length]
  228. elif tlv_type == TLV_NDEF:
  229. tlv_length = payload.pop(0)
  230. print "Found ndef TLV with length %d" % tlv_length
  231. ndef = payload[0:tlv_length]
  232. del payload[0:tlv_length]
  233. rfidProcessNdef(ndef)
  234. elif tlv_type == TLV_PROP:
  235. print "Found lock TLV"
  236. tlv_length = payload.pop(0)
  237. elif tlv_type == TLV_TERM:
  238. print "Found term TLV, stopping"
  239. break
  240. def rfidRead(ser, end):
  241. payload = []
  242. buffer = []
  243. type = 0x00
  244. block = 0x00
  245. reset_counter = 0
  246. while True:
  247. byte = ser.read(1)
  248. if byte == "":
  249. if end:
  250. break
  251. reset_counter = reset_counter + 1
  252. if reset_counter > (RESET_TIMER_S / SERIAL_READ_TIMEOUT):
  253. reset_counter = 0
  254. rfidWriteSimpleCommand(ser, CMD_SEEK_FOR_TAG)
  255. else:
  256. reset_counter = 0
  257. buffer.append(ord(byte))
  258. print "byte: %x" % ord(byte)
  259. if len(buffer) >= 4:
  260. length = buffer[2]
  261. command = buffer[3]
  262. print "Command: %x with length: %d" % (command, length)
  263. # Read bytes + checksum
  264. data = list(ser.read(length))
  265. dummy = ser.read(1)
  266. buffer = []
  267. # Handle commands.
  268. if command == CMD_SEEK_FOR_TAG and length >= 6:
  269. # Got card.
  270. type = ord(data.pop(0))
  271. print "Got card with type %d and id: %s" % (type, "".join("%02x" % ord(b) for b in data))
  272. block = 0x04
  273. payload = []
  274. # Try to authenticate if Mifare 1k or 4k
  275. if type == TYPE_MIFARE_1K or type == TYPE_MIFARE_4K:
  276. if block >= 0x00 and block <= 0x03:
  277. rfidWriteCustomCommand(ser, [HEADER, RESERVED, 0x09, CMD_AUTHENTICATE, block, CMD_KEY_A, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5]) #MAD
  278. else:
  279. rfidWriteCustomCommand(ser, [HEADER, RESERVED, 0x09, CMD_AUTHENTICATE, block, CMD_KEY_A, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7]) #NDEF
  280. elif type == TYPE_MIFARE_UL:
  281. # ultralight, no authenticate needed, just read.
  282. rfidWriteCustomCommand(ser, [HEADER, RESERVED, 0x02, CMD_READ_BLOCK, block])
  283. if command == CMD_AUTHENTICATE and length >= 2:
  284. print "CMD_AUTHENTICATE: %s" % "".join("%02x" % ord(b) for b in data)
  285. # Try to read
  286. rfidWriteCustomCommand(ser, [HEADER, RESERVED, 0x02, CMD_READ_BLOCK, block])
  287. if command == CMD_READ_BLOCK and length >= 2:
  288. # Remove first block number and last chk
  289. lblock = ord(data.pop(0))
  290. chk = ord(data.pop(len(data)-1))
  291. # For now, all zero? stop.
  292. oneNotZero = False
  293. for d in data:
  294. if ord(d) != 0:
  295. oneNotZero = True
  296. if oneNotZero:
  297. payload.extend(data)
  298. print "CMD_READ_BLOCK (block: %d): %s" % (lblock, "".join("%02x" % ord(b) for b in data))
  299. if type == TYPE_MIFARE_UL:
  300. block = block + 4
  301. if block < MIFARE_UL_C_BLOCKS:
  302. rfidWriteCustomCommand(ser, [HEADER, RESERVED, 0x02, CMD_READ_BLOCK, block])
  303. else:
  304. rfidProcessData(payload)
  305. else:
  306. block = block + 1
  307. # Skip last block in each section.
  308. if (block+1) % 4 == 0:
  309. block = block + 1
  310. if block < MIFARE_1K_BLOCKS:
  311. rfidWriteCustomCommand(ser, [HEADER, RESERVED, 0x09, CMD_AUTHENTICATE, block, CMD_KEY_A, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7]) #NDEF
  312. else:
  313. rfidProcessData(payload)
  314. else:
  315. rfidProcessData(payload)
  316. # Ultralight, record type URI record is 0x55 ('U')
  317. #data = [0x01, 0x03, 0xa0, 0x0c, 0x34, 0x03, 0x35, 0xd1, 0x01, 0x31, 0x55, 0x02, 0x74, 0x61, 0x67, 0x6f, 0x6e, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x36, 0x34, 0x44, 0x45, 0x33, 0x33, 0x35, 0x43, 0x2d, 0x42, 0x38, 0x31, 0x41, 0x2d, 0x34, 0x36, 0x44, 0x36, 0x2d, 0x42, 0x38, 0x39, 0x46, 0x2d, 0x43, 0x43, 0x39, 0x42, 0x39, 0x35, 0x34, 0x31, 0x39, 0x46, 0x31, 0x33, 0xfe, 0x00]
  318. #for i in range(0, len(data)):
  319. # data[i] = chr(data[i])
  320. #rfidProcessData(data)
  321. # Mifare 1k, record type 0x53, 0x70
  322. #data = [0x00, 0x00, 0x03, 0x31, 0xd1, 0x02, 0x2c, 0x53, 0x70, 0x91, 0x01, 0x1d, 0x55, 0x03, 0x66, 0x6a, 0x75, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6e, 0x66, 0x63, 0x2f, 0x67, 0x65, 0x74, 0x2e, 0x70, 0x68, 0x70, 0x3f, 0x69, 0x64, 0x3d, 0x31, 0x32, 0x33, 0x34, 0x51, 0x01, 0x07, 0x54, 0x02, 0x73, 0x76, 0x74, 0x65, 0x64, 0x74, 0xfe, 0x00]
  323. #for i in range(0, len(data)):
  324. # data[i] = chr(data[i])
  325. #rfidProcessData(data)
  326. #exit(1)
  327. port = "COM5"
  328. if len(sys.argv) > 1:
  329. port = sys.argv[1]
  330. ser = serial.Serial(
  331. port=port,
  332. baudrate=19200,
  333. parity=serial.PARITY_NONE,
  334. stopbits=serial.STOPBITS_ONE,
  335. bytesize=serial.EIGHTBITS,
  336. xonxoff=False,
  337. rtscts=False,
  338. dsrdtr=False,
  339. timeout=SERIAL_READ_TIMEOUT
  340. )
  341. print ser # check which port was really used
  342. print ser.isOpen()
  343. rfidWriteSimpleCommand(ser, CMD_RESET)
  344. time.sleep(1)
  345. rfidRead(ser, True)
  346. rfidWriteSimpleCommand(ser, CMD_SEEK_FOR_TAG)
  347. rfidRead(ser, True)
  348. rfidRead(ser, False)
  349. ser.close() # close port