| """ Copyright (C) 2010-2011 ST-Ericsson SA """ |
| |
| """ Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson. """ |
| |
| """ 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() |
| |
| """graceful""" |
| 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 |