def read(self, timeout=TIMEOUT_T2): """ reads a message packet. any errors are raised directly. """ # if in 5 seconds no message appears, we respond with a nak and raise an error. self.connection.timeout = timeout apdu = [] crc = None header = self.connection.read(2) header = conv.bs2hl(header) # test if there was a transmission: if header == []: raise common.TransportLayerException('Reading Header Timeout') # test our header to be valid if header != [DLE, STX]: self.slog(header, True) raise common.TransportLayerException("Header Error: %s" % header) # read until DLE, ETX is reached. dle = False # timeout to T1 after header. self.connection.timeout = TIMEOUT_T1 while not crc: b = ord(self.connection.read(1)) # read a byte. if b is None: # timeout raise common.TransportLayerException( "Timeout T1 reading stream.") if b == ETX and dle: # dle was set, and this is ETX, so we are at the end. # we read the CRC now. crc = self.connection.read(2) if not crc: raise common.TransportLayerException( "Timeout T1 reading CRC") else: crc = conv.bs2hl(crc) # and break continue elif b == DLE: if not dle: # this is a dle dle = True continue else: # this is the second dle. we take it. dle = False elif dle: # dle was set, but we got no etx here. # this seems to be an error. raise common.TransportLayerException( "DLE without sense detected.") # we add this byte to our apdu. apdu += [b] self.slog(header + apdu + [DLE, ETX] + crc, True) return crc, apdu
def read(self, timeout=TIMEOUT_T2): """ reads a message packet. any errors are raised directly. """ # if in 5 seconds no message appears, we respond with a nak and raise an error. self.connection.setTimeout(timeout) apdu = [] crc = None header = self.connection.read(2) header = conv.bs2hl(header) # test if there was a transmission: if header == []: raise common.TransportLayerException, 'Reading Header Timeout' # test our header to be valid if header != [DLE, STX]: self.slog(header, True) raise common.TransportLayerException, "Header Error: %s" % header # read until DLE, ETX is reached. dle = False # timeout to T1 after header. self.connection.setTimeout(TIMEOUT_T1) while not crc: b = ord(self.connection.read(1)) # read a byte. if b is None: # timeout raise common.TransportLayerException, "Timeout T1 reading stream." if b == ETX and dle: # dle was set, and this is ETX, so we are at the end. # we read the CRC now. crc = self.connection.read(2) if not crc: raise common.TransportLayerException, "Timeout T1 reading CRC" else: crc = conv.bs2hl(crc) # and break continue elif b == DLE: if not dle: # this is a dle dle = True continue else: # this is the second dle. we take it. dle = False elif dle: # dle was set, but we got no etx here. # this seems to be an error. raise common.TransportLayerException, "DLE without sense detected." # we add this byte to our apdu. apdu += [b] self.slog(header + apdu + [DLE, ETX] + crc, True) return crc, apdu
def send_message(self, message, tries=0, no_wait=False): """ sends input with write returns output with read. if skip_read is True, it only returns true, you have to read yourself. """ if message: self.write(message.as_bin()) acknowledge = b'' ts_start = time() while not acknowledge: acknowledge = self.connection.read(1) # With ingenico devices, acknowledge is often empty. # Just retrying seems to help. if time() - ts_start > 1: break self.slog(acknowledge, True) # if nak, we retry, if ack, we read, if other, we raise. if acknowledge == ensure_bytes(chr(ACK)): # everything alright. if no_wait: return True return self.receive() elif acknowledge == ensure_bytes(chr(NAK)): # not everything allright. # if tries < 3: # return self.send_message(message, tries + 1, no_answer) # else: raise TransportLayerException('Could not send message') elif not acknowledge: raise TransportTimeoutException('No Answer, Possible Timeout') else: raise TransportLayerException( 'Unknown Acknowledgment Byte %s' % bs2hl(acknowledge))
def ecr_log(data, incoming=False): try: if incoming: incoming = '<' else: incoming = '>' if isinstance(data, basestring): data = conv.bs2hl(data) # logit to the logfile try: _logfile.write('%s %s\n' % (incoming, conv.toHexString(data))) except: pass try: data = repr(parse_represented_data(data)) _logfile.write('= %s\n' % data) except Exception as e: print("DEBUG: Cannot be represented: %s" % data) print(e) _logfile.write('? did not understand ?\n') data = conv.toHexString(data) print("%s %s" % (incoming, data)) except: import traceback traceback.print_exc() print("| error in log")
def send_message(self, message, tries=0, no_wait=False): """ sends input with write returns output with read. if skip_read is True, it only returns true, you have to read yourself. """ if message: self.write(message.as_bin()) # time.sleep(0.1) acknowledge = self.connection.read(1) self.slog(acknowledge, True) # if nak, we retry, if ack, we read, if other, we raise. if acknowledge == ensure_bytes(chr(ACK)): # everything alright. if not no_wait: return self.receive() return True elif acknowledge == ensure_bytes(chr(NAK)): # not everything allright. #if tries < 3: # return self.send_message(message, tries + 1, no_answer) #else: raise common.TransportLayerException("Could not send message") elif not acknowledge: # this happens quite a lot with the ingenico devices. # possibly a workaround would be nice. raise common.TransportTimeoutException( "No Answer, Possible Timeout") else: raise common.TransportLayerException( "Unknown Acknowledgment Byte %s" % conv.bs2hl(acknowledge))
def ecr_log(data, incoming=False): try: if incoming: incoming = '<' else: incoming = '>' if is_stringlike(data): data = bs2hl(data) # logit to the logfile try: _logfile.write('%s %s\n' % (incoming, toHexString(data))) except Exception: pass try: data = repr(parse_represented_data(data)) _logfile.write('= %s\n' % data) except Exception as e: print('DEBUG: Cannot be represented: %s' % data) print(e) _logfile.write('? did not understand ?\n') data = toHexString(data) print('%s %s' % (incoming, data)) except Exception: import traceback traceback.print_exc() print('| error in log')
def std_serial_log(instance, data, incoming=False): try: if isinstance(incoming, basestring): data = conv.bs2hl(data) if incoming: print "< %s" % conv.toHexString(data) else: print "> %s" % conv.toHexString(data) except: print "| error in log"
def std_serial_log(instance, data, incoming=False): try: if is_stringlike(incoming): data = bs2hl(data) if incoming: print('< %s' % toHexString(data)) else: print('> %s' % toHexString(data)) except Exception: print('| error in log')
def std_serial_log(instance, data, incoming=False): try: if is_stringlike(incoming): data = conv.bs2hl(data) if incoming: print("< %s" % conv.toHexString(data)) else: print("> %s" % conv.toHexString(data)) except: print("| error in log")
def receive(self, timeout=None, *args, **kwargs) -> Tuple[bool, APDUPacket]: """ Receive data, return success status and ADPUPacket instance. """ self.sock.settimeout(timeout) data = self._receive() self.slog(data=bs2hl(binstring=data), incoming=True) return True, APDUPacket.parse(blob=data)
def decode_bcd(cls, something): """ BCDs save two numbers per byte @param something: might be a string or list of bytes @return: a list of numbers. """ if is_stringlike(something): something = conv.bs2hl(something) ret = [] for x in something: ret += list(cls.bcd_split(x)) return ret
def decode_bcd(cls, something): """ BCDs save two numbers per byte @param something: might be a string or list of bytes @return: a list of numbers. """ if isinstance(something, basestring): something = conv.bs2hl(something) ret = [] for x in something: ret += list(cls.bcd_split(x)) return ret
def send(self, apdu, tries: int = 0, no_wait: bool = False): """Send data.""" to_send = bytes(apdu.to_list()) self.slog(data=bs2hl(binstring=to_send), incoming=False) total_sent = 0 msglen = len(to_send) while total_sent < msglen: sent = self.sock.send(to_send[total_sent:]) if self._packetdebug: print('sent', sent, 'bytes of', hexformat(data=to_send[total_sent:])) if sent == 0: raise RuntimeError('Socket connection broken.') total_sent += sent if no_wait: return True return self.receive()
def dump(self): # dump the bytes. """ dumps the bytes of the LVAR as one list. the minimum length of the length header can be set with self.LL """ ret = [] if self._id: ret = [ self._id ] lines = [ self._data, ] for line in lines: l = LVAR.length(len(line)) while len(l) < self.LL: l = [ 0xF0 ] + l if isinstance(line, basestring): ret += l + conv.bs2hl(line) elif isinstance(line, list): ret += l + line else: raise TypeError, "Line has unsupported type in LVAR: %s" % type(line) return ret
def ecr_log(data, incoming=False): try: if incoming: incoming = '<' else: incoming = '>' if isinstance(data, basestring): data = conv.bs2hl(data) # logit to the logfile try: _logfile.write('%s %s\n' % (incoming, conv.toHexString(data))) except: pass try: data = repr(parse_represented_data(data)) _logfile.write('= %s\n' % data) except Exception, e: print "DEBUG: Cannot be represented: %s" % data print e _logfile.write('? did not understand ?\n') data = conv.toHexString(data) print "%s %s" % (incoming, data)
def dump(self): # dump the bytes. """ dumps the bytes of the LVAR as one list. the minimum length of the length header can be set with self.LL """ ret = [] if self._id: ret = [self._id] lines = [ self._data, ] for line in lines: length = LVAR.length(len(line)) while len(length) < self.LL: length = [0xF0] + length if is_stringlike(line): ret += length + conv.bs2hl(line) elif isinstance(line, list): ret += length + line else: raise TypeError("Line has unsupported type in LVAR: %s" % type(line)) return ret
def __init__(self, data=None): if is_stringlike(data): self._data = conv.bs2hl(data) self._rangecheck() else: super(LVAR, self).__init__(self._data)
def int_word_split(x, endian='>'): # default big endian. """ splits 2byte integer (sometimes called a word) into 2 byte list""" return conv.bs2hl(pack('%sH' % endian, x & 0xFFFF))
def enrich_fixed(self): # take attribute first bs = [self.fixed_values.get('attribute', 0)] bs += bs2hl(self.fixed_values.get('text', '')) return bs
def get_end_of_day_information(self): """ if this status information is sent in an end of day cycle, it contains the end of day information, making it a type of subpacket of itself. @returns: a dictionary holding end-of-day information. - returns an empty dictionary if there is no total amount - returns total amount at least in key 'amount' - tries to decipher credit card data into following format: number-<creditcard>, turnover-<creditcard> creditcard being [ec-card, jcb, eurocard, amex, visa, diners, remaining] - receipt-number-start, receipt-number-end contain the range of receipts """ ret = {} # create a dictionary of bitmaps: bdict = self.bitmaps_as_dict() # at least amount should be present: if 'amount' not in bdict.keys(): return {} else: ret = { 'amount': int(bdict['amount'].value()), } # bitmap 0x60 (totals) contains the required information. # another bitmap (amount) holds the amount if 'totals' not in bdict.keys(): # this packet holds no detail information but an amount. return ret totals = bdict['totals'] totals_list = totals.value() # totals_list = str(bdict['totals']) # now we build our real data our of it. # rebuild date and time. my_time = None my_date = None if 'time' in bdict.keys(): # print bdict['time'].value() mt = str(bdict['time'].value()) my_time = datetime.time(hour=int(mt[0:2]), minute=int(mt[2:4]), second=int(mt[4:6])) if 'date_day' in bdict.keys(): # print bdict['date'].value() md = str(bdict['date_day'].value()) my_date = datetime.date(year=datetime.datetime.now().year, month=int(md[0:2]), day=int(md[2:4])) ret = { 'receipt-number-start': BCD.as_int(BCD.decode_bcd(totals_list[0:2])), 'receipt-number-end': BCD.as_int(BCD.decode_bcd(totals_list[2:4])), 'number-ec-card': bs2hl(totals_list[4])[0], 'turnover-ec-card': BCD.as_int(BCD.decode_bcd(totals_list[5:5 + 6])), 'number-jcb': bs2hl(totals_list[11])[0], 'turnover-jcb': BCD.as_int(BCD.decode_bcd(totals_list[12:12 + 6])), 'number-eurocard': bs2hl(totals_list[18])[0], 'turnover-eurocard': BCD.as_int(BCD.decode_bcd(totals_list[19:19 + 6])), 'number-amex': bs2hl(totals_list[25])[0], 'turnover-amex': BCD.as_int(BCD.decode_bcd(totals_list[26:26 + 6])), 'number-visa': bs2hl(totals_list[32])[0], 'turnover-visa': BCD.as_int(BCD.decode_bcd(totals_list[33:33 + 6])), 'number-diners': bs2hl(totals_list[39])[0], 'turnover-diners': BCD.as_int(BCD.decode_bcd(totals_list[40:40 + 6])), 'number-remaining': bs2hl(totals_list[46])[0], 'turnover-remaining': BCD.as_int(BCD.decode_bcd(totals_list[47:47 + 6])), 'amount': int(bdict['amount'].value()), 'turnover-amount': int(bdict['amount'].value()), 'date': my_date, 'time': my_time, 'number-total': 0, } # time holds simply HHMMSS (BCD) # date holds simply mmdd (BCD) # adding a formatted version tn = 0 float_version = {} for key, value in ret.items(): if key.startswith('turnover-'): key_id = key.replace('turnover-', '') # add a key with a formatted representation. v = float(value) / 100.0 float_version['float-%s' % key_id] = v elif key.startswith('number-'): # add total numbers. tn += int(value) ret['number-total'] = tn ret.update(float_version) return ret
def get_end_of_day_information(self): """ if this status information is sent in an end of day cycle, it contains the end of day information, making it a type of subpacket of itself. @returns: a dictionary holding end-of-day information. - returns an empty dictionary if there is no total amount - returns total amount at least in key 'amount' - tries to decipher credit card data into following format: number-<creditcard>, turnover-<creditcard> creditcard being [ec-card, jcb, eurocard, amex, visa, diners, remaining] - receipt-number-start, receipt-number-end contain the range of receipts """ ret = {} # create a dictionary of bitmaps: bdict = self.bitmaps_as_dict() # at least amount should be present: if not 'amount' in bdict.keys(): return {} else: ret = {'amount': int(bdict['amount'].value()),} # bitmap 0x60 (totals) contains the required information. # another bitmap (amount) holds the amount if not 'totals' in bdict.keys(): # this packet holds no detail information but an amount. return ret totals = bdict['totals'] totals_list = totals.value() #totals_list = str(bdict['totals']) # now we build our real data our of it. # rebuild date and time. my_time = None my_date = None if 'time' in bdict.keys(): #print bdict['time'].value() mt = str(bdict['time'].value()) my_time = datetime.time( hour=int(mt[0:2]), minute=int(mt[2:4]), second=int(mt[4:6]), ) if 'date_day' in bdict.keys(): #print bdict['date'].value() md = str(bdict['date_day'].value()) my_date = datetime.date( year=datetime.datetime.now().year, month=int(md[0:2]), day=int(md[2:4]), ) ret = {'receipt-number-start': BCD.as_int( BCD.decode_bcd( totals_list[0:2] ) ), 'receipt-number-end': BCD.as_int( BCD.decode_bcd( totals_list[2:4] ) ), 'number-ec-card': conv.bs2hl( totals_list[4] )[0], 'turnover-ec-card': BCD.as_int( BCD.decode_bcd( totals_list[5:5+6] ) ), 'number-jcb': conv.bs2hl(totals_list[11])[0], 'turnover-jcb': BCD.as_int( BCD.decode_bcd( totals_list[12:12+6] ) ), 'number-eurocard': conv.bs2hl(totals_list[18])[0], 'turnover-eurocard': BCD.as_int( BCD.decode_bcd( totals_list[19:19+6] ) ), 'number-amex': conv.bs2hl(totals_list[25])[0], 'turnover-amex': BCD.as_int( BCD.decode_bcd( totals_list[26:26+6] ) ), 'number-visa': conv.bs2hl(totals_list[32])[0], 'turnover-visa': BCD.as_int( BCD.decode_bcd( totals_list[33:33+6] ) ), 'number-diners': conv.bs2hl(totals_list[39])[0], 'turnover-diners': BCD.as_int( BCD.decode_bcd( totals_list[40:40+6] ) ), 'number-remaining': conv.bs2hl(totals_list[46])[0], 'turnover-remaining': BCD.as_int( BCD.decode_bcd( totals_list[47:47+6] ) ), 'amount': int(bdict['amount'].value()), 'turnover-amount': int(bdict['amount'].value()), 'date': my_date, 'time': my_time, 'number-total': 0, } # time holds simply HHMMSS (BCD) # date holds simply mmdd (BCD) # adding a formatted version tn = 0 for key, value in ret.items(): if key.startswith('turnover-'): key_id = key.replace('turnover-', '') # add a key with a formatted representation. v = float(value) / 100.0 ret['float-%s' % key_id] = v elif key.startswith('number-'): # add total numbers. tn += int(value) ret['number-total'] = tn return ret
def write(self, something=None): if something: try: self.slog(conv.bs2hl(something)) finally: self.connection.write(ensure_bytes(something)) # !?
def __init__(self, data=None): if isinstance(data, basestring): self._data = conv.bs2hl(data) self._rangecheck() else: super(LVAR, self).__init__(self._data)
def send_message(self, message, tries=0, no_wait=False): """ sends input with write returns output with read. if skip_read is True, it only returns true, you have to read yourself. """ if message: self.write(message.as_bin()) # time.sleep(0.1) acknowledge = self.connection.read(1) self.slog(acknowledge, True) # if nak, we retry, if ack, we read, if other, we raise. if acknowledge == chr(ACK): # everything alright. if not no_wait: return self.receive() return True elif acknowledge == chr(NAK): # not everything allright. #if tries < 3: # return self.send_message(message, tries + 1, no_answer) #else: raise common.TransportLayerException, "Could not send message" elif not acknowledge: # this happens quite a lot with the ingenico devices. # possibly a workaround would be nice. raise common.TransportTimeoutException, "No Answer, Possible Timeout" else: raise common.TransportLayerException, "Unknown Acknowledgmenet Byte %s" % conv.bs2hl(acknowledge)
def int_word_split(x, endian='>'): # default big endian. """ splits 2byte integer (sometimes called a word) into 2 byte list""" return conv.bs2hl(struct.pack('%sH' % endian, x & 0xFFFF))
def write(self, something=None): if something: try: self.slog(conv.bs2hl(something)) finally: self.connection.write(something) # !?
def enrich_fixed(self): # take attribute first bs = [ self.fixed_values.get('attribute', 0) ] bs += conv.bs2hl(self.fixed_values.get('text', '')) return bs