Skip to content

Commit 154bbba

Browse files
Merge pull request #39 from amelchio/v6-ack-revert
Reliability fixes for v6 bridge
2 parents 9dd30f1 + 7bd0e01 commit 154bbba

File tree

2 files changed

+24
-41
lines changed

2 files changed

+24
-41
lines changed

limitlessled/bridge.py

+23-40
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
0xaf, 0xfe, 0xf7, 0x00, 0x00, 0x1e]
2727
KEEP_ALIVE_COMMAND_PREAMBLE = [0xD0, 0x00, 0x00, 0x00, 0x02]
2828
KEEP_ALIVE_RESPONSE_PREAMBLE = [0xd8, 0x0, 0x0, 0x0, 0x07]
29-
COMMAND_RESPONSE_PREAMBLE = [0x88, 0x00, 0x00, 0x00, 0x03, 0x00]
3029
KEEP_ALIVE_TIME = 5
3130
RECONNECT_TIME = 5
3231
SOCKET_TIMEOUT = 5
@@ -86,7 +85,6 @@ def __init__(self, ip, port=BRIDGE_PORT, version=BRIDGE_VERSION,
8685
self._socket.settimeout(SOCKET_TIMEOUT)
8786
self._socket.connect((ip, port))
8887
self._command_queue = queue.Queue()
89-
self._ack_queue = queue.Queue()
9088
self._lock = threading.Lock()
9189
self.active = 0
9290
self._selected_number = None
@@ -169,11 +167,10 @@ def send(self, command, reps=REPS, wait=MIN_WAIT):
169167
self._command_queue.put((command, reps, wait))
170168
# Wait before accepting another command.
171169
# This keeps individual groups relatively synchronized.
172-
if self.version < 6:
173-
sleep = reps * wait * self.active
174-
if command.select and self._selected_number != command.group_number:
175-
sleep += SELECT_WAIT
176-
time.sleep(sleep)
170+
sleep = reps * wait * self.active
171+
if command.select and self._selected_number != command.group_number:
172+
sleep += SELECT_WAIT
173+
time.sleep(sleep)
177174

178175
def _consume(self):
179176
""" Consume commands from the queue.
@@ -211,21 +208,13 @@ def _consume(self):
211208
self.is_ready = False
212209

213210
# Repeat command as necessary.
214-
command_bytes = command.get_bytes(self)
215-
todo = reps
216-
while todo > 0 and self.is_ready:
217-
if self._send_raw(command_bytes):
218-
try:
219-
while self.sn != self._ack_queue.get(timeout=wait):
220-
pass
221-
222-
# ACK received, stop repeating
223-
todo = 0
224-
except queue.Empty:
225-
todo = todo - 1
226-
else:
227-
# Stop sending on socket error
228-
self.is_ready = False
211+
for _ in range(reps):
212+
if self.is_ready:
213+
if self._send_raw(command.get_bytes(self)):
214+
time.sleep(wait)
215+
else:
216+
# Stop sending on socket error
217+
self.is_ready = False
229218

230219
# Wait if bridge is not ready, we're only reading is_ready, no lock needed
231220
if not self.is_ready and not self.is_closed:
@@ -242,19 +231,13 @@ def _send_raw(self, command):
242231
"""
243232
try:
244233
self._socket.send(bytearray(command))
234+
self._sn = (self._sn + 1) % 256
245235
return True
246236
except (socket.error, socket.timeout):
247237
# We can get a socket.error or timeout exception if the bridge is disconnected,
248238
# but we are still sending data. In that case, return False to indicate that data is not sent.
249239
return False
250240

251-
def next_sn(self):
252-
"""
253-
Increases the sequential byte and returns it.
254-
"""
255-
self._sn = (self._sn + 1) % 256
256-
return self._sn
257-
258241
def _init_connection(self):
259242
"""
260243
Requests the session ids of the bridge.
@@ -270,7 +253,7 @@ def _init_connection(self):
270253
self._wb1 = response[19]
271254
self._wb2 = response[20]
272255
self.is_ready = True
273-
except socket.timeout:
256+
except (socket.error, socket.timeout):
274257
# Connection timed out, bridge is not ready for us
275258
self.is_ready = False
276259
finally:
@@ -291,8 +274,7 @@ def _reconnect(self):
291274

292275
def _keep_alive(self):
293276
"""
294-
Send keep alive messages continuously to bridge and
295-
handle command responses.
277+
Send keep alive messages continuously to bridge.
296278
"""
297279
send_next_keep_alive_at = 0
298280
while not self.is_closed:
@@ -309,14 +291,15 @@ def _keep_alive(self):
309291
timeout = max(0, need_response_by - time.monotonic())
310292
ready = select.select([self._socket], [], [], timeout)
311293
if ready[0]:
312-
response = bytearray(12)
313-
self._socket.recv_into(response)
314-
315-
if response.startswith(bytearray(KEEP_ALIVE_RESPONSE_PREAMBLE)):
316-
send_next_keep_alive_at = need_response_by
317-
elif response.startswith(bytearray(COMMAND_RESPONSE_PREAMBLE)):
318-
sn = response[len(COMMAND_RESPONSE_PREAMBLE)]
319-
self._ack_queue.put(sn)
294+
try:
295+
response = bytearray(12)
296+
self._socket.recv_into(response)
297+
298+
if response[:5] == bytearray(KEEP_ALIVE_RESPONSE_PREAMBLE):
299+
send_next_keep_alive_at = need_response_by
300+
except (socket.error, socket.timeout):
301+
with self._lock:
302+
self.is_ready = False
320303
elif send_next_keep_alive_at < need_response_by:
321304
# Acquire the lock to make sure we don't change self.is_ready
322305
# while _consume() is sending commands

limitlessled/group/commands/v6.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def get_bytes(self, bridge):
4141

4242
wb1 = bridge.wb1
4343
wb2 = bridge.wb2
44-
sn = bridge.next_sn()
44+
sn = bridge.sn
4545

4646
preamble = [0x80, 0x00, 0x00, 0x00, 0x11, wb1, wb2, 0x00, sn, 0x00]
4747
cmd = [0x31, self.PASSWORD_BYTE1, self.PASSWORD_BYTE2,

0 commit comments

Comments
 (0)