2011-03-28 22:28:14 +08:00
|
|
|
""" Copyright (C) 2010-2011 ST-Ericsson SA """
|
2011-03-24 21:33:01 +08:00
|
|
|
|
2011-03-28 22:28:14 +08:00
|
|
|
""" Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson. """
|
2011-03-24 21:33:01 +08:00
|
|
|
|
|
|
|
""" This program is free software; you can redistribute it and/or modify """
|
|
|
|
""" it under the terms of the GNU General Public License as published by """
|
|
|
|
""" the Free Software Foundation; either version 2 of the License, or """
|
|
|
|
""" (at your option) any later version. """
|
|
|
|
|
|
|
|
""" This program is distributed in the hope that it will be useful, """
|
|
|
|
""" but WITHOUT ANY WARRANTY; without even the implied warranty of """
|
|
|
|
""" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the """
|
|
|
|
""" GNU General Public License for more details. """
|
|
|
|
|
|
|
|
""" You should have received a copy of the GNU General Public License """
|
|
|
|
""" along with this program; if not, write to the Free Software """
|
|
|
|
""" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """
|
|
|
|
|
|
|
|
from array import array
|
|
|
|
from bluetooth import *
|
|
|
|
import time
|
|
|
|
import re
|
|
|
|
|
|
|
|
class SAPParam:
|
|
|
|
""" SAP Parameter Class """
|
|
|
|
|
|
|
|
MaxMsgSize = 0x00
|
|
|
|
ConnectionStatus = 0x01
|
|
|
|
ResultCode = 0x02
|
|
|
|
DisconnectionType = 0x03
|
|
|
|
CommandAPDU = 0x04
|
|
|
|
ResponseAPDU = 0x05
|
|
|
|
ATR = 0x06
|
|
|
|
CardReaderStatus = 0x07
|
|
|
|
StatusChange = 0x08
|
|
|
|
TransportProtocol = 0x09
|
|
|
|
CommandAPDU7816 = 0x10
|
|
|
|
|
|
|
|
def __init__(self, name, id, value = None):
|
|
|
|
self.name = name
|
|
|
|
self.id = id
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
def _padding(self, buf):
|
|
|
|
pad = array('B')
|
|
|
|
while ( (len(buf) + len(pad)) % 4 ) != 0:
|
|
|
|
pad.append(0)
|
|
|
|
return pad
|
|
|
|
|
|
|
|
def _basicCheck(self, buf):
|
|
|
|
if len(buf) < 4 or (len(buf) % 4) != 0 or buf[1] != 0:
|
|
|
|
return (-1, -1)
|
|
|
|
if buf[0] != self.id:
|
|
|
|
return (-1, -1)
|
|
|
|
plen = buf[2] * 256 + buf[3] + 4
|
|
|
|
if plen > len(buf):
|
|
|
|
return (-1, -1)
|
|
|
|
pad = plen
|
|
|
|
while (pad % 4) != 0:
|
|
|
|
if buf[pad] != 0:
|
|
|
|
return (-1, -1)
|
|
|
|
pad+=1
|
|
|
|
return (plen, pad)
|
|
|
|
|
|
|
|
def getID(self):
|
|
|
|
return self.id
|
|
|
|
|
|
|
|
def getValue(self):
|
|
|
|
return self.value
|
|
|
|
|
|
|
|
def getContent(self):
|
|
|
|
return "%s(id=0x%.2X), value=%s \n" % (self.name, self.id, self.value)
|
|
|
|
|
|
|
|
def serialize(self):
|
|
|
|
a = array('B', '\00\00\00\00')
|
|
|
|
a[0] = self.id
|
|
|
|
a[1] = 0 # reserved
|
|
|
|
a[2] = 0 # length
|
|
|
|
a[3] = 1 # length
|
|
|
|
a.append(self.value)
|
|
|
|
a.extend(self._padding(a))
|
|
|
|
return a
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
p = self._basicCheck(buf)
|
|
|
|
if p[0] == -1:
|
|
|
|
return -1
|
|
|
|
self.id = buf[0]
|
|
|
|
self.value = buf[4]
|
|
|
|
return p[1]
|
|
|
|
|
|
|
|
|
|
|
|
class SAPParam_MaxMsgSize(SAPParam):
|
|
|
|
"""MaxMsgSize Param """
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
SAPParam.__init__(self,"MaxMsgSize", SAPParam.MaxMsgSize, value)
|
|
|
|
self.__validate()
|
|
|
|
|
|
|
|
def __validate(self):
|
|
|
|
if self.value > 0xFFFF:
|
|
|
|
self.value = 0xFFFF
|
|
|
|
|
|
|
|
def serialize(self):
|
|
|
|
a = array('B', '\00\00\00\00')
|
|
|
|
a[0] = self.id
|
|
|
|
a[3] = 2
|
|
|
|
a.append(self.value / 256)
|
|
|
|
a.append(self.value % 256)
|
|
|
|
a.extend(self._padding(a))
|
|
|
|
return a
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
p = self._basicCheck(buf)
|
|
|
|
if p[0] == -1 :
|
|
|
|
return -1
|
|
|
|
self.value = buf[4] * 256 + buf[5]
|
|
|
|
return p[1]
|
|
|
|
|
|
|
|
class SAPParam_CommandAPDU(SAPParam):
|
|
|
|
def __init__(self, value = None):
|
|
|
|
if value is None:
|
|
|
|
SAPParam.__init__(self, "CommandAPDU", SAPParam.CommandAPDU, array('B'))
|
|
|
|
else:
|
|
|
|
SAPParam.__init__(self, "CommandAPDU", SAPParam.CommandAPDU, array('B', value))
|
|
|
|
|
|
|
|
def serialize(self):
|
|
|
|
a = array('B', '\00\00\00\00')
|
|
|
|
a[0] = self.id
|
|
|
|
plen = len(self.value)
|
|
|
|
a[2] = plen / 256
|
|
|
|
a[3] = plen % 256
|
|
|
|
a.extend(self.value)
|
|
|
|
a.extend(self._padding(a))
|
|
|
|
return a
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
p = self._basicCheck(buf)
|
|
|
|
if p[0] == -1:
|
|
|
|
return -1
|
|
|
|
self.value = buf[4:p[0]]
|
|
|
|
return p[1]
|
|
|
|
|
|
|
|
class SAPParam_ResponseAPDU(SAPParam_CommandAPDU):
|
|
|
|
"""ResponseAPDU Param """
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
if value is None:
|
|
|
|
SAPParam.__init__(self, "ResponseAPDU", SAPParam.ResponseAPDU, array('B'))
|
|
|
|
else:
|
|
|
|
SAPParam.__init__(self, "ResponseAPDU", SAPParam.ResponseAPDU, array('B', value))
|
|
|
|
|
|
|
|
class SAPParam_ATR(SAPParam_CommandAPDU):
|
|
|
|
"""ATR Param """
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
if value is None:
|
|
|
|
SAPParam.__init__(self, "ATR", SAPParam.ATR, array('B'))
|
|
|
|
else:
|
|
|
|
SAPParam.__init__(self, "ATR", SAPParam.ATR, array('B', value))
|
|
|
|
|
|
|
|
class SAPParam_CommandAPDU7816(SAPParam_CommandAPDU):
|
|
|
|
"""Command APDU7816 Param."""
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
if value is None:
|
|
|
|
SAPParam.__init__(self, "CommandAPDU7816", SAPParam.CommandAPDU7816, array('B'))
|
|
|
|
else:
|
|
|
|
SAPParam.__init__(self, "CommandAPDU7816", SAPParam.CommandAPDU7816, array('B', value))
|
|
|
|
|
|
|
|
|
|
|
|
class SAPParam_ConnectionStatus(SAPParam):
|
|
|
|
"""Connection status Param."""
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
SAPParam.__init__(self,"ConnectionStatus", SAPParam.ConnectionStatus, value)
|
|
|
|
self.__validate()
|
|
|
|
|
|
|
|
def __validate(self):
|
|
|
|
if self.value is not None and self.value not in (0x00, 0x01, 0x02, 0x03, 0x04):
|
|
|
|
print "Warning. ConnectionStatus value in reserved range (0x%x)" % self.value
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
ret = SAPParam.deserialize(self, buf)
|
|
|
|
if ret == -1:
|
|
|
|
return -1
|
|
|
|
self.__validate()
|
|
|
|
return ret
|
|
|
|
|
|
|
|
class SAPParam_ResultCode(SAPParam):
|
|
|
|
""" Result Code Param """
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
SAPParam.__init__(self,"ResultCode", SAPParam.ResultCode, value)
|
|
|
|
self.__validate()
|
|
|
|
|
|
|
|
def __validate(self):
|
|
|
|
if self.value is not None and self.value not in (0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07):
|
|
|
|
print "Warning. ResultCode value in reserved range (0x%x)" % self.value
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
ret = SAPParam.deserialize(self, buf)
|
|
|
|
if ret == -1:
|
|
|
|
return -1
|
|
|
|
self.__validate()
|
|
|
|
return ret
|
|
|
|
|
|
|
|
class SAPParam_DisconnectionType(SAPParam):
|
|
|
|
"""Disconnection Type Param."""
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
SAPParam.__init__(self,"DisconnectionType", SAPParam.DisconnectionType, value)
|
|
|
|
self.__validate()
|
|
|
|
|
|
|
|
def __validate(self):
|
|
|
|
if self.value is not None and self.value not in (0x00, 0x01):
|
|
|
|
print "Warning. DisconnectionType value in reserved range (0x%x)" % self.value
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
ret = SAPParam.deserialize(self, buf)
|
|
|
|
if ret == -1:
|
|
|
|
return -1
|
|
|
|
self.__validate()
|
|
|
|
return ret
|
|
|
|
|
|
|
|
class SAPParam_CardReaderStatus(SAPParam_CommandAPDU):
|
|
|
|
"""Card reader Status Param."""
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
if value is None:
|
|
|
|
SAPParam.__init__(self, "CardReaderStatus", SAPParam.CardReaderStatus, array('B'))
|
|
|
|
else:
|
|
|
|
SAPParam.__init__(self, "CardReaderStatus", SAPParam.CardReaderStatus, array('B', value))
|
|
|
|
|
|
|
|
class SAPParam_StatusChange(SAPParam):
|
|
|
|
"""Status Change Param """
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
SAPParam.__init__(self,"StatusChange", SAPParam.StatusChange, value)
|
|
|
|
|
|
|
|
def __validate(self):
|
|
|
|
if self.value is not None and self.value not in (0x00, 0x01, 0x02, 0x03, 0x04, 0x05):
|
|
|
|
print "Warning. StatusChange value in reserved range (0x%x)" % self.value
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
ret = SAPParam.deserialize(self, buf)
|
|
|
|
if ret == -1:
|
|
|
|
return -1
|
|
|
|
self.__validate()
|
|
|
|
return ret
|
|
|
|
|
|
|
|
class SAPParam_TransportProtocol(SAPParam):
|
|
|
|
"""Transport Protocol Param """
|
|
|
|
|
|
|
|
def __init__(self, value = None):
|
|
|
|
SAPParam.__init__(self,"TransportProtocol", SAPParam.TransportProtocol, value)
|
|
|
|
self.__validate()
|
|
|
|
|
|
|
|
def __validate(self):
|
|
|
|
if self.value is not None and self.value not in (0x00, 0x01):
|
|
|
|
print "Warning. TransportProtoco value in reserved range (0x%x)" % self.value
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
ret = SAPParam.deserialize(self, buf)
|
|
|
|
if ret == -1:
|
|
|
|
return -1
|
|
|
|
self.__validate()
|
|
|
|
return ret
|
|
|
|
|
|
|
|
class SAPMessage:
|
|
|
|
|
|
|
|
CONNECT_REQ = 0x00
|
|
|
|
CONNECT_RESP = 0x01
|
|
|
|
DISCONNECT_REQ = 0x02
|
|
|
|
DISCONNECT_RESP =0x03
|
|
|
|
DISCONNECT_IND = 0x04
|
|
|
|
TRANSFER_APDU_REQ = 0x05
|
|
|
|
TRANSFER_APDU_RESP = 0x06
|
|
|
|
TRANSFER_ATR_REQ = 0x07
|
|
|
|
TRANSFER_ATR_RESP = 0x08
|
|
|
|
POWER_SIM_OFF_REQ = 0x09
|
|
|
|
POWER_SIM_OFF_RESP = 0x0A
|
|
|
|
POWER_SIM_ON_REQ = 0x0B
|
|
|
|
POWER_SIM_ON_RESP = 0x0C
|
|
|
|
RESET_SIM_REQ = 0x0D
|
|
|
|
RESET_SIM_RESP = 0x0E
|
|
|
|
TRANSFER_CARD_READER_STATUS_REQ = 0x0F
|
|
|
|
TRANSFER_CARD_READER_STATUS_RESP = 0x10
|
|
|
|
STATUS_IND = 0x11
|
|
|
|
ERROR_RESP = 0x12
|
|
|
|
SET_TRANSPORT_PROTOCOL_REQ = 0x13
|
|
|
|
SET_TRANSPORT_PROTOCOL_RESP = 0x14
|
|
|
|
|
|
|
|
def __init__(self, name, id):
|
|
|
|
self.name = name
|
|
|
|
self.id = id
|
|
|
|
self.params = []
|
|
|
|
self.buf = array('B')
|
|
|
|
|
|
|
|
def _basicCheck(self, buf):
|
|
|
|
if len(buf) < 4 or (len(buf) % 4) != 0 :
|
|
|
|
return False
|
|
|
|
|
|
|
|
if buf[0] != self.id:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def getID(self):
|
|
|
|
return self.id
|
|
|
|
|
|
|
|
def getContent(self):
|
|
|
|
s = "%s(id=0x%.2X) " % (self.name, self.id)
|
|
|
|
if len( self.buf): s = s + "[%s]" % re.sub("(.{2})", "0x\\1 " , self.buf.tostring().encode("hex").upper(), re.DOTALL)
|
|
|
|
s = s + "\n\t"
|
|
|
|
for p in self.params:
|
|
|
|
s = s + "\t" + p.getContent()
|
|
|
|
return s
|
|
|
|
|
|
|
|
def getParams(self):
|
|
|
|
return self.params
|
|
|
|
|
|
|
|
def addParam(self, param):
|
|
|
|
self.params.append(param)
|
|
|
|
|
|
|
|
def serialize(self):
|
|
|
|
ret = array('B', '\00\00\00\00')
|
|
|
|
ret[0] = self.id
|
|
|
|
ret[1] = len(self.params)
|
|
|
|
ret[2] = 0 # reserved
|
|
|
|
ret[3] = 0 # reserved
|
|
|
|
for p in self.params:
|
|
|
|
ret.extend(p.serialize())
|
|
|
|
|
|
|
|
self.buf = ret
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
return len(buf) == 4 and buf[1] == 0 and self._basicCheck(buf)
|
|
|
|
|
|
|
|
|
|
|
|
class SAPMessage_CONNECT_REQ(SAPMessage):
|
|
|
|
def __init__(self, MaxMsgSize = None):
|
|
|
|
SAPMessage.__init__(self,"CONNECT_REQ", SAPMessage.CONNECT_REQ)
|
|
|
|
if MaxMsgSize is not None:
|
|
|
|
self.addParam(SAPParam_MaxMsgSize(MaxMsgSize))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) == 1:
|
|
|
|
if self.params[0].getID() == SAPParam.MaxMsgSize:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
p = SAPParam_MaxMsgSize()
|
|
|
|
if p.deserialize(buf[4:]) == len(buf[4:]):
|
|
|
|
self.addParam(p)
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
class SAPMessage_CONNECT_RESP(SAPMessage):
|
|
|
|
def __init__(self, ConnectionStatus = None, MaxMsgSize = None):
|
|
|
|
SAPMessage.__init__(self,"CONNECT_RESP", SAPMessage.CONNECT_RESP)
|
|
|
|
if ConnectionStatus is not None:
|
|
|
|
self.addParam(SAPParam_ConnectionStatus(ConnectionStatus))
|
|
|
|
if MaxMsgSize is not None:
|
|
|
|
self.addParam(SAPParam_MaxMsgSize(MaxMsgSize))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) > 0:
|
|
|
|
if self.params[0] .getID() == SAPParam.ConnectionStatus:
|
|
|
|
if self.params[0].getValue() == 0x02:
|
|
|
|
if len(self.params) == 2:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
if len(self.params) == 1:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
p = SAPParam_ConnectionStatus()
|
|
|
|
r = p.deserialize(buf[4:])
|
|
|
|
if r != -1:
|
|
|
|
self.addParam(p)
|
|
|
|
if buf[1] == 2:
|
|
|
|
p = SAPParam_MaxMsgSize()
|
|
|
|
r = p.deserialize(buf[4+r:])
|
|
|
|
if r != -1:
|
|
|
|
self.addParam(p)
|
|
|
|
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
class SAPMessage_DISCONNECT_REQ(SAPMessage):
|
|
|
|
def __init__(self):
|
|
|
|
SAPMessage.__init__(self,"DISCONNECT_REQ", SAPMessage.DISCONNECT_REQ)
|
|
|
|
|
|
|
|
class SAPMessage_DISCONNECT_RESP(SAPMessage):
|
|
|
|
def __init__(self):
|
|
|
|
SAPMessage.__init__(self,"DISCONNECT_RESP", SAPMessage.DISCONNECT_RESP)
|
|
|
|
|
|
|
|
class SAPMessage_DISCONNECT_IND(SAPMessage):
|
|
|
|
def __init__(self, Type = None):
|
|
|
|
SAPMessage.__init__(self,"DISCONNECT_IND", SAPMessage.DISCONNECT_IND)
|
|
|
|
if Type is not None:
|
|
|
|
self.addParam(SAPParam_DisconnectionType(Type))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) == 1:
|
|
|
|
if self.params[0].getID() == SAPParam.DisconnectionType:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
p = SAPParam_DisconnectionType()
|
|
|
|
if p.deserialize(buf[4:]) == len(buf[4:]):
|
|
|
|
self.addParam(p)
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
class SAPMessage_TRANSFER_APDU_REQ(SAPMessage):
|
|
|
|
def __init__(self, APDU = None, T = False):
|
|
|
|
SAPMessage.__init__(self,"TRANSFER_APDU_REQ", SAPMessage.TRANSFER_APDU_REQ)
|
|
|
|
if APDU is not None:
|
|
|
|
if T :
|
|
|
|
self.addParam(SAPParam_CommandAPDU(APDU))
|
|
|
|
else:
|
|
|
|
self.addParam(SAPParam_CommandAPDU7816(APDU))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) == 1:
|
|
|
|
if self.params[0].getID() == SAPParam.CommandAPDU or self.params[0].getID() == SAPParam.CommandAPDU7816:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
|
|
|
|
p = SAPParam_CommandAPDU()
|
|
|
|
p2 = SAPParam_CommandAPDU7816()
|
|
|
|
if p.deserialize(buf[4:]) == len(buf[4:]):
|
|
|
|
self.addParam(p)
|
|
|
|
return self._validate()
|
|
|
|
elif p2.deserialize(buf[4:]) == len(buf[4:]):
|
|
|
|
self.addParam(p2)
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
class SAPMessage_TRANSFER_APDU_RESP(SAPMessage):
|
|
|
|
def __init__(self, ResultCode = None, Response = None):
|
|
|
|
SAPMessage.__init__(self,"TRANSFER_APDU_RESP", SAPMessage.TRANSFER_APDU_RESP)
|
|
|
|
if ResultCode is not None:
|
|
|
|
self.addParam(SAPParam_ResultCode(ResultCode))
|
|
|
|
if Response is not None:
|
|
|
|
self.addParam(SAPParam_ResponseAPDU(Response))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) > 0:
|
|
|
|
if self.params[0] .getID() == SAPParam.ResultCode:
|
|
|
|
if self.params[0].getValue() == 0x00:
|
|
|
|
if len(self.params) == 2:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
if len(self.params) == 1:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
p = SAPParam_ResultCode()
|
|
|
|
r = p.deserialize(buf[4:])
|
|
|
|
if r != -1:
|
|
|
|
self.addParam(p)
|
|
|
|
if buf[1] == 2:
|
|
|
|
p = SAPParam_ResponseAPDU()
|
|
|
|
r = p.deserialize(buf[4+r:])
|
|
|
|
if r != -1:
|
|
|
|
self.addParam(p)
|
|
|
|
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
class SAPMessage_TRANSFER_ATR_REQ(SAPMessage):
|
|
|
|
def __init__(self):
|
|
|
|
SAPMessage.__init__(self,"TRANSFER_ATR_REQ", SAPMessage.TRANSFER_ATR_REQ)
|
|
|
|
|
|
|
|
class SAPMessage_TRANSFER_ATR_RESP(SAPMessage):
|
|
|
|
def __init__(self, ResultCode = None, ATR = None):
|
|
|
|
SAPMessage.__init__(self,"TRANSFER_ATR_RESP", SAPMessage.TRANSFER_ATR_RESP)
|
|
|
|
if ResultCode is not None:
|
|
|
|
self.addParam(SAPParam_ResultCode(ResultCode))
|
|
|
|
if ATR is not None:
|
|
|
|
self.addParam(SAPParam_ATR(ATR))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) > 0:
|
|
|
|
if self.params[0] .getID() == SAPParam.ResultCode:
|
|
|
|
if self.params[0].getValue() == 0x00:
|
|
|
|
if len(self.params) == 2:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
if len(self.params) == 1:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
|
|
|
|
p = SAPParam_ResultCode()
|
|
|
|
r = p.deserialize(buf[4:])
|
|
|
|
|
|
|
|
if r != -1:
|
|
|
|
|
|
|
|
self.addParam(p)
|
|
|
|
if buf[1] == 2:
|
|
|
|
|
|
|
|
p = SAPParam_ATR()
|
|
|
|
r = p.deserialize(buf[4+r:])
|
|
|
|
if r != -1:
|
|
|
|
self.addParam(p)
|
|
|
|
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
class SAPMessage_POWER_SIM_OFF_REQ(SAPMessage):
|
|
|
|
def __init__(self):
|
|
|
|
SAPMessage.__init__(self,"POWER_SIM_OFF_REQ", SAPMessage.POWER_SIM_OFF_REQ)
|
|
|
|
|
|
|
|
class SAPMessage_POWER_SIM_OFF_RESP(SAPMessage):
|
|
|
|
def __init__(self, ResultCode = None):
|
|
|
|
SAPMessage.__init__(self,"POWER_SIM_OFF_RESP", SAPMessage.POWER_SIM_OFF_RESP)
|
|
|
|
if ResultCode is not None:
|
|
|
|
self.addParam(SAPParam_ResultCode(ResultCode))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) == 1:
|
|
|
|
if self.params[0].getID() == SAPParam.ResultCode:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
p = SAPParam_ResultCode()
|
|
|
|
if p.deserialize(buf[4:]) == len(buf[4:]):
|
|
|
|
self.addParam(p)
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
class SAPMessage_POWER_SIM_ON_REQ(SAPMessage):
|
|
|
|
def __init__(self):
|
|
|
|
SAPMessage.__init__(self,"POWER_SIM_ON_REQ", SAPMessage.POWER_SIM_ON_REQ)
|
|
|
|
|
|
|
|
class SAPMessage_POWER_SIM_ON_RESP(SAPMessage_POWER_SIM_OFF_RESP):
|
|
|
|
def __init__(self, ResultCode = None):
|
|
|
|
SAPMessage.__init__(self,"POWER_SIM_ON_RESP", SAPMessage.POWER_SIM_ON_RESP)
|
|
|
|
if ResultCode is not None:
|
|
|
|
self.addParam(SAPParam_ResultCode(ResultCode))
|
|
|
|
|
|
|
|
class SAPMessage_RESET_SIM_REQ(SAPMessage):
|
|
|
|
def __init__(self):
|
|
|
|
SAPMessage.__init__(self,"RESET_SIM_REQ", SAPMessage.RESET_SIM_REQ)
|
|
|
|
|
|
|
|
class SAPMessage_RESET_SIM_RESP(SAPMessage_POWER_SIM_OFF_RESP):
|
|
|
|
def __init__(self, ResultCode = None):
|
|
|
|
SAPMessage.__init__(self,"RESET_SIM_RESP", SAPMessage.RESET_SIM_RESP)
|
|
|
|
if ResultCode is not None:
|
|
|
|
self.addParam(SAPParam_ResultCode(ResultCode))
|
|
|
|
|
|
|
|
class SAPMessage_STATUS_IND(SAPMessage):
|
|
|
|
def __init__(self, StatusChange = None):
|
|
|
|
SAPMessage.__init__(self,"STATUS_IND", SAPMessage.STATUS_IND)
|
|
|
|
if StatusChange is not None:
|
|
|
|
self.addParam(SAPParam_StatusChange(StatusChange))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) == 1:
|
|
|
|
if self.params[0].getID() == SAPParam.StatusChange:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
p = SAPParam_StatusChange()
|
|
|
|
if p.deserialize(buf[4:]) == len(buf[4:]):
|
|
|
|
self.addParam(p)
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
class SAPMessage_TRANSFER_CARD_READER_STATUS_REQ(SAPMessage):
|
|
|
|
def __init__(self):
|
|
|
|
SAPMessage.__init__(self,"TRANSFER_CARD_READER_STATUS_REQ", SAPMessage.TRANSFER_CARD_READER_STATUS_REQ)
|
|
|
|
|
|
|
|
class SAPMessage_TRANSFER_CARD_READER_STATUS_RESP(SAPMessage):
|
|
|
|
def __init__(self, ResultCode = None, Status = None):
|
|
|
|
SAPMessage.__init__(self,"TRANSFER_CARD_READER_STATUS_RESP", SAPMessage.TRANSFER_CARD_READER_STATUS_RESP)
|
|
|
|
if ResultCode is not None:
|
|
|
|
self.addParam(SAPParam_ResultCode(ResultCode))
|
|
|
|
if Status is not None:
|
|
|
|
self.addParam(SAPParam_CardReaderStatus(Status))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) > 0:
|
|
|
|
if self.params[0] .getID() == SAPParam.ResultCode:
|
|
|
|
if self.params[0].getValue() == 0x00:
|
|
|
|
if len(self.params) == 2:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
if len(self.params) == 1:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
p = SAPParam_ResultCode()
|
|
|
|
r = p.deserialize(buf[4:])
|
|
|
|
if r != -1:
|
|
|
|
self.addParam(p)
|
|
|
|
if buf[1] == 2:
|
|
|
|
p = SAPParam_CardReaderStatus()
|
|
|
|
r = p.deserialize(buf[4+r:])
|
|
|
|
if r != -1:
|
|
|
|
self.addParam(p)
|
|
|
|
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
class SAPMessage_ERROR_RESP(SAPMessage):
|
|
|
|
def __init__(self):
|
|
|
|
SAPMessage.__init__(self,"ERROR_RESP", SAPMessage.ERROR_RESP)
|
|
|
|
|
|
|
|
|
|
|
|
class SAPMessage_SET_TRANSPORT_PROTOCOL_REQ(SAPMessage):
|
|
|
|
def __init__(self, protocol = None):
|
|
|
|
SAPMessage.__init__(self,"SET_TRANSPORT_PROTOCOL_REQ", SAPMessage.SET_TRANSPORT_PROTOCOL_REQ)
|
|
|
|
if protocol is not None:
|
|
|
|
self.addParam(SAPParam_TransportProtocol(protocol))
|
|
|
|
|
|
|
|
def _validate(self):
|
|
|
|
if len(self.params) == 1:
|
|
|
|
if self.params[0].getID() == SAPParam.TransportProtocol:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def deserialize(self, buf):
|
|
|
|
self.buf = buf
|
|
|
|
self.params[:] = []
|
|
|
|
if SAPMessage._basicCheck(self, buf):
|
|
|
|
p = SAPParam_TransportProtocol()
|
|
|
|
if p.deserialize(buf[4:]) == len(buf[4:]):
|
|
|
|
self.addParam(p)
|
|
|
|
return self._validate()
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
class SAPMessage_SET_TRANSPORT_PROTOCOL_RESP(SAPMessage_POWER_SIM_OFF_RESP):
|
|
|
|
def __init__(self, ResultCode = None):
|
|
|
|
SAPMessage.__init__(self,"SET_TRANSPORT_PROTOCOL_RESP", SAPMessage.SET_TRANSPORT_PROTOCOL_RESP)
|
|
|
|
if ResultCode is not None:
|
|
|
|
self.addParam(SAPParam_ResultCode(ResultCode))
|
|
|
|
|
|
|
|
|
|
|
|
class SAPClient:
|
|
|
|
|
|
|
|
CONNECTED = 1
|
|
|
|
DISCONNECTED = 0
|
|
|
|
|
|
|
|
uuid = "0000112D-0000-1000-8000-00805F9B34FB"
|
|
|
|
bufsize = 1024
|
|
|
|
timeout = 20
|
|
|
|
state = DISCONNECTED
|
|
|
|
|
|
|
|
def __init__(self, host = None, port = None):
|
|
|
|
self.sock = None
|
|
|
|
|
|
|
|
if host is None or is_valid_address(host):
|
|
|
|
self.host = host
|
|
|
|
else:
|
|
|
|
raise BluetoothError ("%s is not a valid BT address." % host)
|
|
|
|
self.host = None
|
|
|
|
return
|
|
|
|
|
|
|
|
if port is None:
|
|
|
|
self.__discover()
|
|
|
|
else:
|
|
|
|
self.port = port
|
|
|
|
|
|
|
|
self.__connectRFCOMM()
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
self.__disconnectRFCOMM()
|
|
|
|
|
|
|
|
def __disconnectRFCOMM(self):
|
|
|
|
if self.sock is not None:
|
|
|
|
self.sock.close()
|
|
|
|
self.state = self.DISCONNECTED
|
|
|
|
|
|
|
|
def __discover(self):
|
|
|
|
service_matches = find_service(self.uuid, self.host)
|
|
|
|
|
|
|
|
if len(service_matches) == 0:
|
|
|
|
raise BluetoothError ("No SAP service found")
|
|
|
|
return
|
|
|
|
|
|
|
|
first_match = service_matches[0]
|
|
|
|
self.port = first_match["port"]
|
|
|
|
self.host = first_match["host"]
|
|
|
|
|
|
|
|
print "SAP Service found on %s(%s)" % first_match["name"] % self.host
|
|
|
|
|
|
|
|
def __connectRFCOMM(self):
|
|
|
|
self.sock=BluetoothSocket( RFCOMM )
|
|
|
|
self.sock.connect((self.host, self.port))
|
|
|
|
self.sock.settimeout(self.timeout)
|
|
|
|
self.state = self.CONNECTED
|
|
|
|
|
|
|
|
def __sendMsg(self, msg):
|
|
|
|
if isinstance(msg, SAPMessage):
|
|
|
|
s = msg.serialize()
|
|
|
|
print "\tTX: " + msg.getContent()
|
|
|
|
return self.sock.send(s.tostring())
|
|
|
|
|
|
|
|
def __rcvMsg(self, msg):
|
|
|
|
if isinstance(msg, SAPMessage):
|
|
|
|
print "\tRX Wait: %s(id = 0x%.2x)" % (msg.name, msg.id)
|
|
|
|
data = self.sock.recv(self.bufsize)
|
|
|
|
if data:
|
|
|
|
if msg.deserialize(array('B',data)):
|
|
|
|
print "\tRX: len(%d) %s" % (len(data), msg.getContent())
|
|
|
|
return msg
|
|
|
|
else:
|
|
|
|
print "msg: %s" % array('B',data)
|
|
|
|
raise BluetoothError ("Message deserialization failed.")
|
|
|
|
else:
|
|
|
|
raise BluetoothError ("Timeout. No data received.")
|
|
|
|
|
|
|
|
def connect(self):
|
|
|
|
self.__connectRFCOMM()
|
|
|
|
|
|
|
|
def disconnect(self):
|
|
|
|
self.__disconnectRFCOMM()
|
|
|
|
|
|
|
|
def isConnected(self):
|
|
|
|
return self.state
|
|
|
|
|
|
|
|
def proc_connect(self):
|
|
|
|
try:
|
|
|
|
self.__sendMsg(SAPMessage_CONNECT_REQ(self.bufsize))
|
|
|
|
params = self.__rcvMsg(SAPMessage_CONNECT_RESP()).getParams()
|
|
|
|
|
|
|
|
if params[0].getValue() in (0x00, 0x04):
|
|
|
|
pass
|
|
|
|
elif params[0].getValue() == 0x02:
|
|
|
|
self.bufsize = params[1].getValue()
|
|
|
|
|
|
|
|
self.__sendMsg(SAPMessage_CONNECT_REQ(self.bufsize))
|
|
|
|
params = self.__rcvMsg(SAPMessage_CONNECT_RESP()).getParams()
|
|
|
|
|
|
|
|
if params[0].getValue() not in (0x00, 0x04):
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
|
|
|
|
if params[0].getValue() == 0x00:
|
|
|
|
return False
|
|
|
|
elif params[0].getValue() == 0x01:
|
|
|
|
"""OK, Card reset"""
|
|
|
|
return self.proc_transferATR()
|
|
|
|
elif params[0].getValue() == 0x02:
|
|
|
|
"""T0 not supported"""
|
|
|
|
if self.proc_transferATR():
|
|
|
|
return self.proc_setTransportProtocol(1)
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_disconnectByClient(self, timeout=0):
|
|
|
|
try:
|
|
|
|
self.__sendMsg(SAPMessage_DISCONNECT_REQ())
|
|
|
|
self.__rcvMsg(SAPMessage_DISCONNECT_RESP())
|
|
|
|
time.sleep(timeout) # let srv to close rfcomm
|
|
|
|
self.__disconnectRFCOMM()
|
|
|
|
return True
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_disconnectByServer(self, timeout=0):
|
|
|
|
try:
|
|
|
|
params = self.__rcvMsg(SAPMessage_DISCONNECT_IND()).getParams()
|
|
|
|
|
2011-07-02 23:32:40 +08:00
|
|
|
"""graceful"""
|
2011-03-24 21:33:01 +08:00
|
|
|
if params[0].getValue() == 0x00:
|
|
|
|
if not self.proc_transferAPDU():
|
|
|
|
return False
|
|
|
|
|
|
|
|
return self.proc_disconnectByClient(timeout)
|
|
|
|
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_transferAPDU(self, apdu = "Sample APDU command"):
|
|
|
|
try:
|
|
|
|
self.__sendMsg(SAPMessage_TRANSFER_APDU_REQ(apdu))
|
|
|
|
params = self.__rcvMsg(SAPMessage_TRANSFER_APDU_RESP()).getParams()
|
|
|
|
return True
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_transferATR(self):
|
|
|
|
try:
|
|
|
|
self.__sendMsg(SAPMessage_TRANSFER_ATR_REQ())
|
|
|
|
params = self.__rcvMsg(SAPMessage_TRANSFER_ATR_RESP()).getParams()
|
|
|
|
return True
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_powerSimOff(self):
|
|
|
|
try:
|
|
|
|
self.__sendMsg(SAPMessage_POWER_SIM_OFF_REQ())
|
|
|
|
params = self.__rcvMsg(SAPMessage_POWER_SIM_OFF_RESP()).getParams()
|
|
|
|
return True
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_powerSimOn(self):
|
|
|
|
try:
|
|
|
|
self.__sendMsg(SAPMessage_POWER_SIM_ON_REQ())
|
|
|
|
params = self.__rcvMsg(SAPMessage_POWER_SIM_ON_RESP()).getParams()
|
|
|
|
if params[0].getValue() == 0x00:
|
|
|
|
return self.proc_transferATR()
|
|
|
|
|
|
|
|
return True
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_resetSim(self):
|
|
|
|
try:
|
|
|
|
self.__sendMsg(SAPMessage_RESET_SIM_REQ())
|
|
|
|
params = self.__rcvMsg(SAPMessage_RESET_SIM_RESP()).getParams()
|
|
|
|
if params[0].getValue() == 0x00:
|
|
|
|
return self.proc_transferATR()
|
|
|
|
|
|
|
|
return True
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_reportStatus(self):
|
|
|
|
try:
|
|
|
|
params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_transferCardReaderStatus(self):
|
|
|
|
try:
|
|
|
|
self.__sendMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_REQ())
|
|
|
|
params = self.__rcvMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_RESP()).getParams()
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_errorResponse(self):
|
|
|
|
try:
|
|
|
|
""" send malformed message, no mandatory maxmsgsize parameter"""
|
|
|
|
self.__sendMsg(SAPMessage_CONNECT_REQ())
|
|
|
|
|
|
|
|
params = self.__rcvMsg(SAPMessage_ERROR_RESP()).getParams()
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def proc_setTransportProtocol(self, protocol = 0):
|
|
|
|
try:
|
|
|
|
self.__sendMsg(SAPMessage_SET_TRANSPORT_PROTOCOL_REQ(protocol))
|
|
|
|
params = self.__rcvMsg(SAPMessage_SET_TRANSPORT_PROTOCOL_RESP()).getParams()
|
|
|
|
|
|
|
|
if params[0].getValue() == 0x00:
|
|
|
|
params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
|
|
|
|
if params[0].getValue() in (0x01, 0x02):
|
|
|
|
return self.proc_transferATR()
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
"""return False ???"""
|
|
|
|
elif params[0].getValue == 0x07:
|
|
|
|
"""not supported"""
|
|
|
|
return True
|
|
|
|
"""return False ???"""
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
except BluetoothError , e:
|
|
|
|
print "Error. " +str(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
pass
|