DASP: drop the P-ION resend overrides, use standard 512-byte packets
The save and file-open requests used their own fixed resend intervals (5 s / 15 s) and the hello asked for 256-byte packets. Ontrol's Sedona Java stack does neither and works with the P-ION: the standard backoff (1, 2, 4, 8 s) sends a busy device a few copies with the same seqNum, which its receive window drops. Both are removed. Also fixes a race in SendWindow.send(): the packet entered the window before its payload and sent_time were set, so housekeeping could resend it with an empty payload, and the device would then drop the real one as a duplicate. Tested on a P-ION at 192.168.1.252, App > Get with File: save 3.2 s (2 resends), app.sab + kits.scode in 11.3 s with 500-byte chunks (was 14.6 s at 256), device stayed up, files identical to a 256-byte backup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -456,7 +456,7 @@ def _to_ack_more(seq_more, max_bytes):
|
||||
|
||||
class _Packet:
|
||||
__slots__ = ("seq_num", "payload", "acked", "enqueued_time",
|
||||
"sent_time", "send_attempts", "send_retry", "next")
|
||||
"sent_time", "send_attempts", "next")
|
||||
|
||||
def __init__(self):
|
||||
self.seq_num = 0
|
||||
@@ -465,7 +465,6 @@ class _Packet:
|
||||
self.enqueued_time = 0.0
|
||||
self.sent_time = 0.0
|
||||
self.send_attempts = 1
|
||||
self.send_retry = None # seconds; None = the window's own interval
|
||||
self.next = None
|
||||
|
||||
|
||||
@@ -507,17 +506,17 @@ class SendWindow:
|
||||
self._tail = None
|
||||
self._cond.notify_all()
|
||||
|
||||
def send(self, payload, send_retry=None):
|
||||
def send(self, payload):
|
||||
p = _Packet()
|
||||
p.send_retry = send_retry
|
||||
p.enqueued_time = _ticks()
|
||||
p.payload = payload
|
||||
with self._cond:
|
||||
p.seq_num = self._seq_num & 0xFFFF
|
||||
self._seq_num = (self._seq_num + 1) & 0xFFFF
|
||||
|
||||
# sent_time is stamped inside the lock: send_retries() must not see the
|
||||
# packet in the window as never sent and resend it before its first send.
|
||||
self._enqueue(p)
|
||||
p.payload = payload
|
||||
p.sent_time = _ticks()
|
||||
self._session._send_raw(self._to_msg(p))
|
||||
|
||||
def _enqueue(self, p):
|
||||
@@ -531,6 +530,7 @@ class SendWindow:
|
||||
else:
|
||||
self._tail.next = p
|
||||
self._tail = p
|
||||
p.sent_time = _ticks()
|
||||
self._size += 1
|
||||
self._cond.notify_all()
|
||||
|
||||
@@ -620,15 +620,9 @@ class SendWindow:
|
||||
p = self._head
|
||||
while p is not None:
|
||||
if not p.acked:
|
||||
if p.send_retry is not None:
|
||||
# A request the device is slow to take -- a P-ION saving its
|
||||
# app, opening a file -- is resent at its own steady interval:
|
||||
# the 1 s default resends it while the device is still busy.
|
||||
interval = p.send_retry
|
||||
else:
|
||||
backoff_shift = min(p.send_attempts - 1, 32)
|
||||
interval = min(self.send_retry * (1 << backoff_shift),
|
||||
self.max_retry_backoff)
|
||||
backoff_shift = min(p.send_attempts - 1, 32)
|
||||
interval = min(self.send_retry * (1 << backoff_shift),
|
||||
self.max_retry_backoff)
|
||||
if now - p.sent_time >= interval:
|
||||
self._resend(p)
|
||||
oldest = max(oldest, now - p.enqueued_time)
|
||||
@@ -784,11 +778,10 @@ class DaspSession:
|
||||
|
||||
# ── Send / Receive ──────────────────────────────────────────
|
||||
|
||||
def send(self, payload, send_retry=None):
|
||||
"""Queues a datagram. send_retry (seconds) overrides the resend interval."""
|
||||
def send(self, payload):
|
||||
if self.is_closed:
|
||||
raise DaspException(f"Session closed: {self.close_cause}")
|
||||
self.send_window.send(payload, send_retry)
|
||||
self.send_window.send(payload)
|
||||
|
||||
def receive(self, timeout=1.0):
|
||||
if self.is_closed:
|
||||
|
||||
Reference in New Issue
Block a user