Skip to content

Commit

Permalink
Correct the way that timeout handling works during pump wakeup
Browse files Browse the repository at this point in the history
The code was sending repeated radio broadcasts, but not correctly waiting for a
response. Instead it was expecting a response from the radio - which wouldn't
happen as expected, since the radio was busy sending hundreds of packets.
  • Loading branch information
oskarpearson committed Apr 23, 2016
1 parent 1668c8c commit dc2b9fd
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 8 deletions.
31 changes: 24 additions & 7 deletions mmeowlink/handlers/stick.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def done (self):
def respond (self, resp):
if resp.valid and resp.serial == self.command.serial:
if resp.op == 0x06 and self.sent_params:
self.command.respond(bytearray(64))
self.command.respond(bytearray(64))
elif resp.op == self.command.code:
self.unframe(resp)

Expand Down Expand Up @@ -162,26 +162,38 @@ def __call__ (self, command):

class Repeater (Sender):

def __call__ (self, command, repetitions=None, ack_wait_seconds=None, retry_count=None):
def __call__ (self, command, repetitions=None, ack_wait_seconds=None):
self.command = command

start = time.time()
pkt = Packet.fromCommand(self.command, serial=self.command.serial)
buf = pkt.assemble( )
log.debug('Sending repeated message %s' % (str(buf).encode('hex')))

self.link.write(buf, repetitions=repetitions)

# The radio takes a while to send all the packets, so wait for a bit before
# trying to talk to the radio, otherwise we can interrupt it.
#
# This multiplication factor is based on
# testing, which shows that it takes 8.04 seconds to send 500 packets
# (8.04/500 =~ 0.016 packets per second).
# We don't want to miss the reply, so take off a bit:
time.sleep((repetitions * 0.016) - 2.2)

# Sometimes the first packet received will be mangled by the simultaneous
# transmission of a CGMS and the pump. We thus retry on invalid packets
# being received. Note how ever that we do *not* retry on timeouts, since
# our wait period is typically very long here, which would lead to long
# waits with no activity. It's better to fail and retry externally
for retry_count in range(retry_count):
while (time.time() <= start + ack_wait_seconds):
try:
self.wait_for_ack(timeout=ack_wait_seconds)
self.wait_for_ack()
return True
except InvalidPacketReceived:
log.error("Invalid Packet Received - retrying: %s of %s" % (retry_count, self.STANDARD_RETRY_COUNT))
except CommsException, InvalidPacketReceived:
log.error("Response not received - retrying at %s" % time.time)

return False

class Pump (session.Pump):
STANDARD_RETRY_COUNT = 3
Expand All @@ -197,7 +209,12 @@ def power_control (self, minutes=None):
self.command = commands.PowerControl(**dict(minutes=minutes, serial=self.serial))
repeater = Repeater(self.link)

repeater(self.command, repetitions=500, ack_wait_seconds=15, retry_count=2)
status = repeater(self.command, repetitions=500, ack_wait_seconds=20)

if status:
return True
else:
raise CommsException("No acknowledgement from pump on wakeup. Is it out of range or is the battery too low?")

def execute (self, command):
command.serial = self.serial
Expand Down
2 changes: 1 addition & 1 deletion mmeowlink/vendors/serial_rf_spy.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def __init__(self, ser):
self.buf = bytearray()

def do_command(self, command, param="", timeout=0):
self.send_command(command, param)
self.send_command(command, param, timeout=timeout)
return self.get_response(timeout=timeout)

def send_command(self, command, param="", timeout=1):
Expand Down
5 changes: 5 additions & 0 deletions mmeowlink/vendors/subg_rfspy_link.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ def handle_response( self, resp ):
if not resp:
raise CommsException("Did not get a response, or response is too short: %s" % len(resp))

# In some cases the radio will respond with 'OK', which is an ack that the radio is responding,
# we treat this as a retryable Comms error so that the caller can deal with it
if len(resp) == 2 and resp == "OK":
raise CommsException("Received null/OK response")

# If the length is less than or equal to 2, then it means we've received an error
if len(resp) <= 2:
raise CommsException("Received an error response %s" % self.RFSPY_ERRORS[ resp[0] ])
Expand Down

0 comments on commit dc2b9fd

Please sign in to comment.