Skip to content

Commit

Permalink
refactor state updating logic to avoid timeout in threaded behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
falkecarlsen committed Aug 14, 2024
1 parent 8a18f2a commit 09633b3
Showing 1 changed file with 56 additions and 55 deletions.
111 changes: 56 additions & 55 deletions py_driver/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,62 @@ def alive(self):
def ready(self):
return not self.busy

def update_state(self, tube=None, quick=False):
"""Get the last state of the device. If cached state is outdated, a new sensor reading is requested."""
# Return cached state if not outdated nor unstable.
if not self.state.dynamic and self.state.last_update >= datetime.now() - timedelta(COMMUNICATION_TIMEOUT):
return self.state

arg = ""

if quick:
arg += "2"
else:
arg += "1"

if tube:
arg += f" {tube};"
else:
arg += ";"

# while busy, wait
while not self.ready():
sleep(1)

# Ask for new state reading.
size_buffer = self.last_printed_buf_line

self.write(arg)
self.busy = True

# Wait for the state to be received.
total_wait = 0
while True:
# wait for device to be ready again after requesting state
while not self.ready():
sleep(0.1)

# todo: not robust looking for {
if self.last_printed_buf_line > size_buffer and self.read_buffer[-2][0] == '{':
# If we received a line starting with {, we have received the new state.
break

sleep(0.1)
total_wait += 0.1

if total_wait > COMMUNICATION_TIMEOUT and not self.busy:
raise RuntimeError("Waiting too long for state to be communicated.")

# New state retrieved, parse it.
state = self.get_last_raw_state()
if state:
# Convert distance to water level
state["Tube1_sonar_dist_mm"] = round(self.state.convert_distance_to_level(state["Tube1_sonar_dist_mm"]), 1)
state["Tube2_sonar_dist_mm"] = round(self.state.convert_distance_to_level(state["Tube2_sonar_dist_mm"]), 1)
self.state = ClaireState(state)
return True
return False

def _underflow_check(self):
TAG = "UNDERFLOW_CHECK"
while True:
Expand Down Expand Up @@ -290,61 +346,6 @@ def check_version(self):
# check if device is ready
assert self.ready()

def update_state(self, tube=None, quick=False):
"""Get the last state of the device. If cached state is outdated, a new sensor reading is requested."""
# Return cached state if not outdated nor unstable.
if not self.state.dynamic and self.state.last_update >= datetime.now() - timedelta(COMMUNICATION_TIMEOUT):
return self.state

# Ask for new state reading.
size_buffer = self.last_printed_buf_line

arg = ""

if quick:
arg += "2"
else:
arg += "1"

if tube:
arg += f" {tube};"
else:
arg += ";"

# while busy, wait
while not self.ready():
sleep(1)

self.write(arg)

# Wait for the state to be received.
total_wait = 0
while True:
# Fixme: not robust looking for {
if self.last_printed_buf_line > size_buffer and self.read_buffer[-2][0] == '{':
# If we received a line starting with {, we have received the new state.
break

sleep(0.1)
# do not incur waiting time if device is busy
if not self.ready():
continue

total_wait += 0.1

if total_wait > COMMUNICATION_TIMEOUT and not self.busy:
raise RuntimeError("Waiting too long for state to be communicated.")

# New state retrieved, parse it.
state = self.get_last_raw_state()
if state:
# Convert distance to water level
state["Tube1_sonar_dist_mm"] = round(self.state.convert_distance_to_level(state["Tube1_sonar_dist_mm"]), 1)
state["Tube2_sonar_dist_mm"] = round(self.state.convert_distance_to_level(state["Tube2_sonar_dist_mm"]), 1)
self.state = ClaireState(state)
return True
return False

def get_last_raw_state(self):
"""Get the last raw state of the device without polling."""
# take buf backwards and try to coerce every line into dict
Expand Down

0 comments on commit 09633b3

Please sign in to comment.