#!/usr/bin/env python3

# Copyright 2023 Sergey Stolyarov <sergei@regolit.com>
#
# Distributed under New BSD License.
#
# https://opensource.org/license/bsd-3-clause/


from smartcard.System import readers
from smartcard.CardRequest import CardRequest
from smartcard.util import toHexString, toBytes


def main() -> int:
	reader = readers()[0]
	print('Connected reader: {0}'.format(reader))
	cardrequest = CardRequest(timeout=None, readers=[reader])
	print('Waiting for card...')

	cardservice = cardrequest.waitforcard()
	cardservice.connection.connect()

	print('Card connected')

	atr = cardservice.connection.getATR()

	# check ATR header, it must be 3B
	if atr[0] != 0x3B:
		print('Not supported card, exiting')
		return 1

	# extract length of Historical bytes field
	hb_len = atr[1] & 0xF

	# extract Historical bytes
	hb = atr[4:hb_len+4]

	if hb[:2] != [0x80, 0x4F]:
		print('Unsupported card type')
		return 1

	if hb[3:8] != [0xA0, 0x00, 0x00, 0x03, 0x06]:
		print('Unsupported card type')
		return 1

	standard_byte = hb[8]
	cardname_bytes = hb[9:11]

	if standard_byte not in KNOWN_STANDARDS:
		print('Unknown standard')
		return 1
	print('Card standard:', KNOWN_STANDARDS[standard_byte])

	cardname_word = 256*cardname_bytes[0] + cardname_bytes[1]
	if cardname_word not in KNOWN_CARD_NAMES:
		print('Unknown card name:', toHexString(cardname_bytes))
		return 1
	print('Card name:', KNOWN_CARD_NAMES[cardname_word])

	return 0


# see PC/SC, Interoperability Specification for ICCs and Personal Computer Systems Part 3. Supplemental Document
KNOWN_STANDARDS = {
	1: 'ISO 14443 A, part 1',
	2: 'ISO 14443 A, part 2',
	3: 'ISO 14443 A, part 3',
	# 4: 'RFU'
	5: 'ISO 14443 B, part 1',
	6: 'ISO 14443 B, part 2',
	7: 'ISO 14443 B, part 3',
	# 8: 'RFU'
	9: 'ISO 15693, part 1',
	10: 'ISO 15693, part 2',
	11: 'ISO 15693, part 3',
	12: 'ISO 15693, part 4',
	13: 'Contact (7816-10) I2C',
	14: 'Contact (7816-10) Extended I2C',
	15: 'Contact (7816-10) 2WBP',
	16: 'Contact (7816-10) 3WBP',
	17: 'FeliCa',
	# RFU
	64: 'Low frequency contactless cards'
	# RFU
}

KNOWN_CARD_NAMES = {
	0x0000: 'No information given',
	0x0001: 'Mifare Standard 1K',
	0x0002: 'Mifare Standard 4K',
	0x0003: 'Mifare Ultra light',
	0x0004: 'SLE55R_XXXX',
	0x0006: 'SR176',
	0x0007: 'SRI X4K',
	0x0008: 'AT88RF020',
	0x0009: 'AT88SC0204CRF',
	0x000A: 'AT88SC0808CRF',
	0x000B: 'AT88SC1616CRF',
	0x000C: 'AT88SC3216CRF',
	0x000D: 'AT88SC6416CRF',
	0x000E: 'SRF55V10P',
	0x000F: 'SRF55V02P',
	0x0010: 'SRF55V10S',
	0x0011: 'SRF55V02S',
	0x0012: 'TAG_IT',
	0x0013: 'LRI512',
	0x0014: 'ICODESLI',
	0x0015: 'TEMPSENS',
	0x0016: 'I.CODE1',
	0x0017: 'PicoPass 2K',
	0x0018: 'PicoPass 2KS',
	0x0019: 'PicoPass 16K',
	0x001A: 'PicoPass 16Ks',
	0x001B: 'PicoPass 16K(8x2)',
	0x001C: 'PicoPass 16KS(8x2)',
	0x001D: 'PicoPass 32KS(16+16)',
	0x001E: 'PicoPass 32KS(16+8x2)',
	0x001F: 'PicoPass 32KS(8x2+16)',
	0x0020: 'PicoPass 32KS(8x2+8x2)',
	0x0021: 'LRI64',
	0x0022: 'I.CODE UID',
	0x0023: 'I.CODE EPC',
	0x0024: 'LRI12',
	0x0025: 'LRI128',
	0x0026: 'Mifare Mini',
	0x0027: 'my-d move (SLE 66R01P)',
	0x0028: 'my-d NFC (SLE 66RxxP)',
	0x0029: 'my-d proximity 2 (SLE 66RxxS)',
	0x002A: 'my-d proximity enhanced (SLE 55RxxE)',
	0x002B: 'my-d light (SRF 55V01P))',
	0x002C: 'PJM Stack Tag (SRF 66V10ST)',
	0x002D: 'PJM Item Tag (SRF 66V10IT)',
	0x002E: 'PJM Light (SRF 66V01ST)',
	0x002F: 'Jewel Tag',
	0x0030: 'Topaz NFC Tag',
	0x0031: 'AT88SC0104CRF',
	0x0032: 'AT88SC0404CRF',
	0x0033: 'AT88RF01C',
	0x0034: 'AT88RF04C',
	0x0035: 'i-Code SL2',
	0x0036: 'MIFARE Plus SL1_2K',
	0x0037: 'MIFARE Plus SL1_4K',
	0x0038: 'MIFARE Plus SL2_2K',
	0x0039: 'MIFARE Plus SL2_4K',
	0x003A: 'MIFARE Ultralight C',
	0x003B: 'FeliCa',
	0x003C: 'Melexis Sensor Tag (MLX90129)',
	0x003D: 'MIFARE Ultralight EV1'
	
}


if __name__ == '__main__':
	main()