Skip to content

Commit

Permalink
Merge pull request #3 from fourdigits/add-timeout-support
Browse files Browse the repository at this point in the history
Add timeout support
  • Loading branch information
MikeOverkamp authored Jun 14, 2017
2 parents e0a9f3d + ef74d17 commit 6f6edf3
Showing 1 changed file with 52 additions and 24 deletions.
76 changes: 52 additions & 24 deletions eSSP/eSSP.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,22 @@ class eSSP(object): # noqa
"""General class for talking to an eSSP device."""

def __init__(self, serialport='/dev/ttyUSB0', eSSPId=0, timeout=None): # noqa
"""Initialize a new eSSP object."""
self.__ser = serial.Serial(serialport, 9600, timeout=timeout)
"""
Initialize a new eSSP object.
The timeout parameter corresponds to the pySerial timeout parameter,
but is used a bit different internally. When the parameter isn't set
to None (blocking, no timeout) or 0, (non-blocking, return directly),
we set a timeout of 0.1 seconds on the serial port, and perform reads
until the specified timeout is expired. When the timeout is reached
before the requested data is read, a eSSPTimeoutError will be raised.
"""
if timeout is None or timeout == 0:
serial_timeout = timeout
else:
serial_timeout = 0.1
self.timeout = timeout
self.__ser = serial.Serial(serialport, 9600, timeout=serial_timeout)
self.__eSSPId = eSSPId
self.__sequence = '0x80'

Expand Down Expand Up @@ -67,7 +81,7 @@ def setup_request(self):
# 2 = Std Security
# 3 = High Security
# 4 = Inhibited
result = self.send([self.getseq(), '0x1', '0x5'], 1)
result = self.send([self.getseq(), '0x1', '0x5'], False)

unittype = int(result[4], 16)

Expand Down Expand Up @@ -132,7 +146,7 @@ def poll(self):
0xE3 = Cash Box Removed (Protocol v3)
0xE4 = Cash Box Replaced (Protocol v3)
"""
result = self.send([self.getseq(), '0x1', '0x7'], 1)
result = self.send([self.getseq(), '0x1', '0x7'], False)

poll_data = []
for i in range(3, int(result[2], 16) + 3):
Expand Down Expand Up @@ -167,7 +181,7 @@ def enable(self):

def serial_number(self):
"""Return formatted serialnumber."""
result = self.send([self.getseq(), '0x1', '0xC'], 1)
result = self.send([self.getseq(), '0x1', '0xC'], False)

serial = 0
for i in range(4, 8):
Expand All @@ -182,7 +196,7 @@ def unit_data(self):
# Country-Code
# Value-Multiplier
# Protocol-Version
result = self.send([self.getseq(), '0x1', '0xD'], 1)
result = self.send([self.getseq(), '0x1', '0xD'], False)

unittype = int(result[4], 16)

Expand Down Expand Up @@ -211,7 +225,7 @@ def channel_values(self):
- Number of Channels
- Values of Channels
"""
result = self.send([self.getseq(), '0x1', '0xE'], 1)
result = self.send([self.getseq(), '0x1', '0xE'], False)

channels = int(result[4], 16)

Expand All @@ -235,7 +249,7 @@ def channel_security(self):
3 = High Security
4 = Inhibited
"""
result = self.send([self.getseq(), '0x1', '0xF'], 1)
result = self.send([self.getseq(), '0x1', '0xF'], False)

channels = int(result[4], 16)

Expand All @@ -253,7 +267,7 @@ def channel_reteach(self):
Number of Channels
Value of Reteach-Date array()
"""
result = self.send([self.getseq(), '0x1', '0x10'], 1)
result = self.send([self.getseq(), '0x1', '0x10'], False)

channels = int(result[4], 16)

Expand Down Expand Up @@ -310,7 +324,7 @@ def last_reject(self):
0x19 = Width Detect Fail
0x1A = Short Note Detected
"""
result = self.send([self.getseq(), '0x1', '0x17'], 1)
result = self.send([self.getseq(), '0x1', '0x17'], False)
return result[4]

def hold(self):
Expand Down Expand Up @@ -365,7 +379,7 @@ def crc(self, command):
crc = [hex((crc & 0xFF)), hex(((crc >> 8) & 0xFF))]
return crc

def send(self, command, no_process=0):
def send(self, command, process=True):
crc = self.crc(command)

prepedstring = '7F'
Expand All @@ -379,29 +393,43 @@ def send(self, command, no_process=0):
prepedstring += command[i][2:]

self._logger.debug("OUT: 0x" + ' 0x'.join([prepedstring[x:x + 2]
for x in xrange(0, len(prepedstring), 2)]))
for x in range(0, len(prepedstring), 2)]))

prepedstring = prepedstring.decode('hex')

self.__ser.write(prepedstring)

if no_process == 1:
response = self.read(1)
else:
response = self.read()
response = self.read(process)
return response

def read(self, no_process=0):
response = self.__ser.read(3)
if len(response) < 3:
# we need the response length in order to continue
raise eSSPTimeoutError()
response += self.__ser.read(ord(response[2]) + 2)
def read(self, process=True):
"""Read the requested data from the serial port."""
bytes_read = []
# initial response length is only the header.
expected_bytes = 3
timeout_expired = datetime.datetime.now() + datetime.timedelta(seconds=self.timeout)
while True:
byte = self.__ser.read()
if byte:
bytes_read += byte
else:
# when the socket doesn't give us any data, evaluate the timeout
if datetime.datetime.now() > timeout_expired:
raise eSSPTimeoutError('Unable to read the expected response of {} bytes within {} seconds'.format(
expected_bytes, self.timeout))

if expected_bytes == 3 and len(bytes_read) >= 3:
# extract the actual message length
expected_bytes += ord(bytes_read[2]) + 2

if expected_bytes > 3 and len(bytes_read) == expected_bytes:
# we've read the complete response
break

response = self.arrayify_response(response)
response = self.arrayify_response(bytes_read)
self._logger.debug("IN: " + ' '.join(response))

if no_process == 0:
if process:
response = self.process_response(response)
return response

Expand Down

0 comments on commit 6f6edf3

Please sign in to comment.