Skip to content

Commit 9cbb15d

Browse files
committed
Restructure to use Future
1 parent 65243c8 commit 9cbb15d

File tree

3 files changed

+44
-26
lines changed

3 files changed

+44
-26
lines changed

buildhat/devices.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import sys
55
import weakref
6+
from concurrent.futures import Future
67

78
from .exc import DeviceError
89
from .serinterface import BuildHAT
@@ -202,11 +203,10 @@ def get(self):
202203
idx = self._combimode
203204
else:
204205
raise DeviceError("Not in simple or combimode")
206+
ftr = Future()
207+
self._hat.portcond[self.port].append(ftr)
205208
self._write(f"port {self.port} ; selonce {idx}\r")
206-
# wait for data
207-
with Device._instance.portcond[self.port]:
208-
Device._instance.portcond[self.port].wait()
209-
return self._conn.data
209+
return ftr.result()
210210

211211
def mode(self, modev):
212212
"""Set combimode or simple mode

buildhat/motors.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import threading
44
import time
55
from collections import deque
6+
from concurrent.futures import Future
67
from enum import Enum
78
from threading import Condition
89

@@ -205,9 +206,10 @@ def _run_positional_ramp(self, pos, newpos, speed):
205206
cmd = (f"port {self.port}; combi 0 {self._combi} ; select 0 ; selrate {self._interval}; "
206207
f"pid {self.port} 0 1 s4 0.0027777778 0 5 0 .1 3; "
207208
f"set ramp {pos} {newpos} {dur} 0\r")
209+
ftr = Future()
210+
self._hat.rampcond[self.port].append(ftr)
208211
self._write(cmd)
209-
with self._hat.rampcond[self.port]:
210-
self._hat.rampcond[self.port].wait()
212+
ftr.result()
211213
if self._release:
212214
time.sleep(0.2)
213215
self.coast()
@@ -228,9 +230,7 @@ def run_for_degrees(self, degrees, speed=None, blocking=True):
228230
if not (speed >= -100 and speed <= 100):
229231
raise MotorError("Invalid Speed")
230232
if not blocking:
231-
th = threading.Thread(target=self._run_for_degrees, args=(degrees, speed))
232-
th.daemon = True
233-
th.start()
233+
Device._instance.mqueue.put((self._run_for_degrees, (degrees, speed)))
234234
else:
235235
self._run_for_degrees(degrees, speed)
236236

@@ -251,9 +251,7 @@ def run_to_position(self, degrees, speed=None, blocking=True, direction="shortes
251251
if degrees < -180 or degrees > 180:
252252
raise MotorError("Invalid angle")
253253
if not blocking:
254-
th = threading.Thread(target=self._run_to_position, args=(degrees, speed, direction))
255-
th.daemon = True
256-
th.start()
254+
Device._instance.mqueue.put((self._run_to_position, (degrees, speed, direction)))
257255
else:
258256
self._run_to_position(degrees, speed, direction)
259257

@@ -262,9 +260,10 @@ def _run_for_seconds(self, seconds, speed):
262260
cmd = (f"port {self.port} ; combi 0 {self._combi} ; select 0 ; selrate {self._interval}; "
263261
f"pid {self.port} 0 0 s1 1 0 0.003 0.01 0 100; "
264262
f"set pulse {speed} 0.0 {seconds} 0\r")
263+
ftr = Future()
264+
self._hat.pulsecond[self.port].append(ftr)
265265
self._write(cmd)
266-
with self._hat.pulsecond[self.port]:
267-
self._hat.pulsecond[self.port].wait()
266+
ftr.result()
268267
if self._release:
269268
self.coast()
270269
self._runmode = MotorRunmode.NONE
@@ -283,9 +282,7 @@ def run_for_seconds(self, seconds, speed=None, blocking=True):
283282
if not (speed >= -100 and speed <= 100):
284283
raise MotorError("Invalid Speed")
285284
if not blocking:
286-
th = threading.Thread(target=self._run_for_seconds, args=(seconds, speed))
287-
th.daemon = True
288-
th.start()
285+
Device._instance.mqueue.put((self._run_for_seconds, (seconds, speed)))
289286
else:
290287
self._run_for_seconds(seconds, speed)
291288

buildhat/serinterface.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ def __init__(self, firmware, signature, version, device="/dev/serial0", debug=Fa
9898

9999
for _ in range(4):
100100
self.connections.append(Connection())
101-
self.portcond.append(Condition())
102-
self.pulsecond.append(Condition())
103-
self.rampcond.append(Condition())
101+
self.portcond.append([])
102+
self.pulsecond.append([])
103+
self.rampcond.append([])
104104

105105
self.ser = serial.Serial(device, 115200, timeout=5)
106106
# Check if we're in the bootloader or the firmware
@@ -150,6 +150,11 @@ def __init__(self, firmware, signature, version, device="/dev/serial0", debug=Fa
150150
self.cb.daemon = True
151151
self.cb.start()
152152

153+
self.mqueue = queue.Queue()
154+
self.ml = threading.Thread(target=self.motorloop, args=(self.mqueue,))
155+
self.ml.daemon = True
156+
self.ml.start()
157+
153158
# Drop timeout value to 1s
154159
listevt = threading.Event()
155160
self.ser.timeout = 1
@@ -266,6 +271,7 @@ def shutdown(self):
266271
self.running = False
267272
self.th.join()
268273
self.cbqueue.put(())
274+
self.mqueue.put((None, None))
269275
self.cb.join()
270276
turnoff = ""
271277
for p in range(4):
@@ -278,6 +284,18 @@ def shutdown(self):
278284
self.write(f"{turnoff}\r".encode())
279285
self.write(b"port 0 ; select ; port 1 ; select ; port 2 ; select ; port 3 ; select ; echo 0\r")
280286

287+
def motorloop(self, q):
288+
"""Event handling for non-blocking motor commands
289+
290+
:param q: Queue of motor functions
291+
"""
292+
while self.running:
293+
func, data = q.get()
294+
if func is None:
295+
break
296+
else:
297+
func(*data)
298+
281299
def callbackloop(self, q):
282300
"""Event handling for callbacks
283301

@@ -330,11 +348,11 @@ def loop(self, cond, uselist, q, listevt):
330348
if uselist and listevt.is_set():
331349
count += 1
332350
elif cmp(msg, BuildHAT.RAMPDONE):
333-
with self.rampcond[portid]:
334-
self.rampcond[portid].notify()
351+
ftr = self.rampcond[portid].pop()
352+
ftr.set_result(True)
335353
elif cmp(msg, BuildHAT.PULSEDONE):
336-
with self.pulsecond[portid]:
337-
self.pulsecond[portid].notify()
354+
ftr = self.pulsecond[portid].pop()
355+
ftr.set_result(True)
338356

339357
if uselist and count == 4:
340358
with cond:
@@ -362,8 +380,11 @@ def runit():
362380
if callit is not None:
363381
q.put((callit, newdata))
364382
self.connections[portid].data = newdata
365-
with self.portcond[portid]:
366-
self.portcond[portid].notify()
383+
try:
384+
ftr = self.portcond[portid].pop()
385+
ftr.set_result(newdata)
386+
except IndexError:
387+
pass
367388

368389
if len(line) >= 5 and line[1] == "." and line.endswith(" V"):
369390
vin = float(line.split(" ")[0])

0 commit comments

Comments
 (0)