Get with File on P-ION: connect and transfer the way Ontrol's Niagara driver does

A real P-ION (fw 1.32) restarted on every Sox file get. Ontrol's Niagara 4
driver gets app.sab from the same device, so its settings are copied:
- DASP hello asks for 256-byte packets (idealMax/absMax), so file chunks
  are 238 bytes
- the message-length header (0x81) goes to Orion only, decided once the
  platform id is read
- the app is saved on the device before app.sab is read, the save resent
  every 5 s rather than 1 s (a P-ION save takes 2-3+ s)
- the file open is resent every 15 s; DASP gains a per-packet resend
  interval for this

Tested on a P-ION at 192.168.1.252: save 3.2 s, app.sab + kits.scode +
app.sax in 15.8 s, no resends, device stayed up. The unsaved-changes
question became a notice, since the app is now always saved first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 08:15:12 +03:00
co-authored by Claude Opus 5.5
parent 6b23bafffc
commit 2880c2a6f2
6 changed files with 80 additions and 37 deletions
+16 -7
View File
@@ -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", "next")
"sent_time", "send_attempts", "send_retry", "next")
def __init__(self):
self.seq_num = 0
@@ -465,6 +465,7 @@ 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
@@ -506,8 +507,9 @@ class SendWindow:
self._tail = None
self._cond.notify_all()
def send(self, payload):
def send(self, payload, send_retry=None):
p = _Packet()
p.send_retry = send_retry
p.enqueued_time = _ticks()
with self._cond:
p.seq_num = self._seq_num & 0xFFFF
@@ -618,9 +620,15 @@ class SendWindow:
p = self._head
while p is not None:
if not p.acked:
backoff_shift = min(p.send_attempts - 1, 32)
interval = min(self.send_retry * (1 << backoff_shift),
self.max_retry_backoff)
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)
if now - p.sent_time >= interval:
self._resend(p)
oldest = max(oldest, now - p.enqueued_time)
@@ -776,10 +784,11 @@ class DaspSession:
# ── Send / Receive ──────────────────────────────────────────
def send(self, payload):
def send(self, payload, send_retry=None):
"""Queues a datagram. send_retry (seconds) overrides the resend interval."""
if self.is_closed:
raise DaspException(f"Session closed: {self.close_cause}")
self.send_window.send(payload)
self.send_window.send(payload, send_retry)
def receive(self, timeout=1.0):
if self.is_closed: