Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for reading pCards #3

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 56 additions & 4 deletions sireader.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ def byte2int(x):
from binascii import hexlify
import os, re, sys

deep_debug = False

class SIReader(object):
"""Base protocol functions and constants to interact with SI Stations.
This class has a lot of Constants defined that are not (yet) used.
Expand Down Expand Up @@ -273,6 +275,22 @@ class SIReader(object):
'PTL': 3,
'BC' : 2,
},
'pCard':{'CN2': 25,
'CN1': 26,
'CN0': 27,
'ST' : 14,
'FT' : 18,
'CT' : 10,
'LT' : None,
'RC' : 22,
'P1' : 176,
'PL' : 4,
'PM' : 20,
'CN' : 1,
'PTH': 2,
'PTL': 3,
'BC' : 2,
},
'SI10':{'CN2': 25, # Same data structure for SI11
'CN1': 26,
'CN0': 27,
Expand Down Expand Up @@ -348,9 +366,11 @@ def guessSerialPorts(cls, ttyS=False):
for i in range(256):
try:
com_port = "COM{:d}".format(i)
#print ("Trying {}".format(com_port))
s = Serial(com_port)
found.append(s.portstr)
s.close()
#print ("{} appears ok".format(com_port))
except SerialException:
pass
else:
Expand Down Expand Up @@ -619,11 +639,18 @@ def _crc(s):
a reimplementation of the Java function in the SI Programmers
manual examples."""

#print (f"Compute checksum of {s}.")

def twochars(s):
"""generator that split a string into parts of two chars"""
if len(s) == 0:
# immediately stop on empty string
raise StopIteration
# I don't know why, but raising the StopIteration caused
# problems when I moved this code to Python3, though it worked
# fine with Python2. Making this a return seems to have solved
# things, at least for Python3
return
#raise StopIteration

# add 0 to the string and make it even length
if len(s)%2 == 0:
Expand Down Expand Up @@ -750,6 +777,17 @@ def _append_punch(list, station, timedata, reftime):
if time is not None:
list.append((station, time))

@staticmethod
def _print_bytes(label, offset, byte_string):
if deep_debug:
#print("Raw data is {} bytes long:\n".format(len(byte_string)))
data_array = []
for byte in range(len(byte_string)):
data_array.append("{:d}:{:x}".format(byte, SIReader._to_int(byte_string[byte:byte+1])))
#print("{:02x},".format(SIReader._to_int(raw_data[byte:byte+1])))
print(label + " ({} @ {}) : ".format(len(byte_string), offset) + ",".join(data_array))
#print("\n\n")

@staticmethod
def _decode_carddata(data, card_type, reftime = None):
"""Decodes a data record read from an SI Card."""
Expand All @@ -759,14 +797,20 @@ def _decode_carddata(data, card_type, reftime = None):

# the slicing of data is necessary for Python 3 to get a bytes object instead
# of an int
SIReader._print_bytes("card #", card['CN2'], data[card['CN2']:card['CN2']+1]
+ data[card['CN1']:card['CN1']+1]
+ data[card['CN0']:card['CN0']+1])
ret['card_number'] = SIReader._decode_cardnr(b'\x00'
+ data[card['CN2']:card['CN2']+1]
+ data[card['CN1']:card['CN1']+1]
+ data[card['CN0']:card['CN0']+1])
SIReader._print_bytes("start", card['ST'], data[card['ST']:card['ST']+2])
ret['start'] = SIReader._decode_time(data[card['ST']:card['ST']+2],
reftime)
SIReader._print_bytes("finish", card['FT'], data[card['FT']:card['FT']+2])
ret['finish'] = SIReader._decode_time(data[card['FT']:card['FT']+2],
reftime)
SIReader._print_bytes("check", card['CT'], data[card['CT']:card['CT']+2])
ret['check'] = SIReader._decode_time(data[card['CT']:card['CT']+2],
reftime)
if card['LT'] is not None:
Expand All @@ -775,6 +819,7 @@ def _decode_carddata(data, card_type, reftime = None):
else:
ret['clear'] = None # SI 5 and 9 cards don't store the clear time

SIReader._print_bytes("punch count", card['RC'], data[card['RC']:card['RC']+1])
punch_count = byte2int(data[card['RC']:card['RC']+1])
if card_type == 'SI5':
# RC is the index of the next punch on SI5
Expand All @@ -786,10 +831,12 @@ def _decode_carddata(data, card_type, reftime = None):
ret['punches'] = []
p = 0
i = card['P1']
#SIReader._print_bytes("first punch", data[card['P1']:card['P1']+1])
while p < punch_count:
if card_type == 'SI5' and i % 16 == 0:
# first byte of each block is reserved for punches 31-36
i += 1
SIReader._print_bytes("punch {}".format(p), card['CN'] + i, data[i + card['CN']:i+card['CN']+1])

SIReader._append_punch(ret['punches'],
byte2int(data[i + card['CN']]),
Expand Down Expand Up @@ -925,12 +972,13 @@ def read_sicard(self, reftime=None):
raw_data += self._read_command()[1][1:]
raw_data += self._read_command()[1][1:]
return SIReader._decode_carddata(raw_data, self.cardtype)
elif self.cardtype in ('SI8', 'SI9'):
elif self.cardtype in ('SI8', 'SI9', 'pCard'):
raw_data = b''
for b in range(SIReader.CARD[self.cardtype]['BC']):
raw_data += self._send_command(SIReader.C_GET_SI9,
int2byte(b))[1][1:]

self._print_bytes("raw data", 0, raw_data)

return SIReader._decode_carddata(raw_data, self.cardtype)
elif self.cardtype == 'SI10':
# Reading out SI10 cards block by block proved to be unreliable and slow
Expand Down Expand Up @@ -981,10 +1029,14 @@ def _read_command(self, timeout=None):
self.cardtype = 'SI8'
elif self.sicard >= 1000000 and self.sicard <= 1999999:
self.cardtype = 'SI9'
elif self.sicard >= 4000000 and self.sicard <= 4999999: # pCard
self.cardtype = 'pCard'
# elif self.sicard >= 6000000 and self.sicard <= 6999999: # tCard
# self.cardtype = 'SI9'
elif self.sicard >= 7000000 and self.sicard <= 9999999:
self.cardtype = 'SI10'
else:
raise SIReaderException('Unknown cardtype!')
raise SIReaderException('Unknown cardtype: {}'.format(self.sicard))
raise SIReaderCardChanged("SI-Card inserted during command.")

return (cmd, data)
Expand Down