# -*- coding: utf-8 -*- | |
''' | |
Created on 2011-9-29 | |
读卡库程序 | |
@author: cheng.tang | |
''' | |
from ctypes import * | |
import codecs | |
import traceback | |
def _b(v): | |
if isinstance(v, unicode): | |
return v.encode('latin_1') | |
else: | |
return v | |
class CardOperatorError(Exception): | |
def __init__(self, msg): | |
Exception.__init__(self, msg) | |
self.msg = msg | |
class py_decard(object): | |
# M1 卡密钥 | |
KEY_A = 1 | |
KEY_B = 2 | |
# 寻卡模式 | |
MODE_ALL = 1 | |
MODE_IDLE = 0 | |
# | |
ERROR_RET_NONE = 0 | |
ERROR_RAISE_EXP = 1 | |
dll_handle = None | |
dll_name = 'dcrf32.dll' | |
device_handle = None | |
error_method = ERROR_RET_NONE | |
@staticmethod | |
def _do_load_dll(): | |
if py_decard.dll_handle != None: | |
return | |
py_decard.dll_handle = windll.LoadLibrary(py_decard.dll_name) | |
@staticmethod | |
def setup(**kwdargs): | |
if 'error_method' in kwdargs: | |
py_decard.error_method = kwdargs["error_method"] | |
#################################################################### | |
def __init__(self, port=None, baud=None): | |
py_decard._do_load_dll() | |
self.card_mode = 'contactless' | |
self.ic_port = 0 | |
if port: | |
if not self.open_port(port, baud): | |
raise RuntimeError(u"不能打开读卡器port=%d,baud=%d" % (port, baud)) | |
self.beep() | |
def set_card_mode(self, mode='cotactless', icport=-1): | |
self.card_mode = mode | |
if self.card_mode != 'contactless': | |
self.ic_port = icport | |
def setsamport(self, port): | |
self.sam_port = self._get_sam_port(port) | |
ats_buffer = create_string_buffer('\000' * 256) | |
ats_len = c_char('\000') | |
py_decard.dll_handle.dc_setcpu(py_decard.device_handle, self.sam_port) | |
ret = py_decard.dll_handle.dc_cpureset(py_decard.device_handle, | |
byref(ats_len), ats_buffer) | |
if ret != 0: | |
return self.error('CPUCard ats error') | |
l = ord(ats_len.value) | |
r = ats_buffer.raw[:l] | |
#print codecs.encode(r,'hex') | |
return r | |
def error(self, error): | |
if py_decard.error_method == py_decard.ERROR_RET_NONE: | |
return None | |
raise CardOperatorError(error) | |
def open_port(self, port, baud): | |
if py_decard.dll_handle == None: | |
raise RuntimeError(py_decard.dll_name + ' not load ') | |
if py_decard.device_handle != None: | |
return True | |
dev_handle = py_decard.dll_handle.dc_init(port, baud) | |
if dev_handle <= 0: | |
return False | |
py_decard.device_handle = dev_handle | |
return True | |
def close_port(self): | |
if py_decard.device_handle == None: | |
return | |
py_decard.dll_handle.dc_exit(py_decard.device_handle) | |
py_decard.device_handle = None | |
def request_card(self): | |
if self.card_mode == 'contactless': | |
py_decard.dll_handle.dc_reset(py_decard.device_handle, 1) | |
cardphyno = create_string_buffer('\000' * 64) | |
ret = py_decard.dll_handle.dc_card_hex(py_decard.device_handle, | |
py_decard.MODE_ALL, | |
cardphyno) | |
if ret == 0: | |
return cardphyno.value | |
return self.error('Request Card Error') | |
else: | |
return '' | |
def cpucard_ats(self): | |
ats_buffer = create_string_buffer('\000' * 256) | |
ats_len = c_char('\000') | |
if self.card_mode == 'contactless': | |
py_decard.dll_handle.dc_pro_reset.restype = c_short | |
ret = py_decard.dll_handle.dc_pro_reset(py_decard.device_handle, | |
byref(ats_len), ats_buffer) | |
if ret != 0: | |
return self.error('CPUCard ats error') | |
l = ord(ats_len.value) | |
r = ats_buffer.raw[:l] | |
#print codecs.encode(r,'hex') | |
return r | |
else: | |
py_decard.dll_handle.dc_setcpu(py_decard.device_handle, | |
self._get_sam_port(self.ic_port)) | |
ret = py_decard.dll_handle.dc_cpureset(py_decard.device_handle, | |
byref(ats_len), ats_buffer) | |
if ret != 0: | |
return self.error('CPUCard ats error') | |
l = ord(ats_len.value) | |
r = ats_buffer.raw[:l] | |
#print codecs.encode(r,'hex') | |
return r | |
def _get_sam_port(self, port): | |
if port == 1: | |
return 0x0c | |
elif port == 2: | |
return 0x0d | |
elif port == 3: | |
return 0x0e | |
elif port == 4: | |
return 0x0f | |
else: | |
self.error('samport error') | |
def _do_apdu(self, command): | |
response = create_string_buffer('\000' * 256) | |
resplen = c_char('\000') | |
if self.card_mode == 'contactless': | |
py_decard.dll_handle.dc_pro_commandlink.restype = c_short | |
ret = py_decard.dll_handle.dc_pro_commandlink(py_decard.device_handle, len(command), | |
command, byref(resplen), response, 7, 56) | |
else: | |
ret = py_decard.dll_handle.dc_cpuapdu(py_decard.device_handle, len(command), | |
command, byref(resplen), response) | |
if ret != 0: | |
command_header = codecs.encode(command, 'hex') | |
return self.error('CPUCard apdu command : %s ,ret=%d' % (command_header, ret)) | |
return response.raw[:ord(resplen.value)] | |
def cpucard_apdu(self, command): | |
current_resp = self._do_apdu(command) | |
if ord(current_resp[-2]) == 0x61 and ord(current_resp[-1]) > 0x00: | |
cmd = '\x00\xC0\x00\x00' + current_resp[-1] | |
#print "get response : %s" % codecs.encode(cmd,'hex') | |
return self._do_apdu(cmd) | |
else: | |
return current_resp | |
def cpucard_apdu_hex(self, command): | |
cmd_result = command.replace(' ', '') | |
resp = self.cpucard_apdu(codecs.decode(cmd_result, 'hex')) | |
if resp == None: | |
return None | |
return codecs.encode(resp, 'hex').upper() | |
def _do_sam_apdu(self, command): | |
response = create_string_buffer('\000' * 256) | |
resplen = c_char('\000') | |
ret = py_decard.dll_handle.dc_cpuapdu(py_decard.device_handle, len(command), | |
command, byref(resplen), response) | |
if ret != 0: | |
command_header = codecs.encode(command, 'hex') | |
return self.error('CPUCard apdu command : %s ,ret=%d' % (command_header, ret)) | |
return response.raw[:ord(resplen.value)] | |
def sam_apdu(self, command): | |
current_resp = self._do_sam_apdu(command) | |
if ord(current_resp[-2]) == 0x61 and ord(current_resp[-1]) > 0x00: | |
cmd = '\x00\xC0\x00\x00' + current_resp[-1] | |
#print "get response : %s" % codecs.encode(cmd,'hex') | |
return self._do_sam_apdu(cmd) | |
else: | |
return current_resp | |
def sam_apdu_hex(self, command): | |
cmd_result = command.replace(' ', '') | |
resp = self.sam_apdu(codecs.decode(cmd_result, 'hex')) | |
if resp == None: | |
return None | |
return codecs.encode(resp, 'hex').upper() | |
def beep(self, time=10): | |
py_decard.dll_handle.dc_beep(py_decard.device_handle, time) | |
def auth_card(self, sectno, key, key_type): | |
assert key_type in (py_decard.KEY_A, py_decard.KEY_B), u"密钥类型错误" | |
if key_type == py_decard.KEY_A: | |
key_type = 0 | |
else: | |
key_type = 4 | |
r = py_decard.dll_handle.dc_authentication_pass(py_decard.device_handle, | |
key_type, sectno, key) | |
if r != 0: | |
return False | |
return True | |
def read_block(self, block_no): | |
data = create_string_buffer('\000' * 16) | |
r = py_decard.dll_handle.dc_read(py_decard.device_handle, | |
block_no, data) | |
if r != 0: | |
return None | |
return data.raw[:16] | |
def write_block(self, block_no, data): | |
data = _b(data) | |
r = py_decard.dll_handle.dc_write(py_decard.device_handle, | |
block_no, data) | |
if r != 0: | |
return False | |
return True | |
def __enter__(self): | |
if not py_decard.device_handle: | |
raise RuntimeError(u"Device not open") | |
py_decard.setup(error_method=self.ERROR_RAISE_EXP) | |
return self | |
def __exit__(self, exc_type, exc_value, tb): | |
try: | |
self.close_port() | |
except: | |
pass | |
if exc_type: | |
traceback.print_exception(exc_type, exc_value, tb) | |
return True |