fix
This commit is contained in:
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"cmake.sourceDirectory": "/home/awe/Documents/radar_system/data_acq_and_processing/gpr_cpp"
|
||||
}
|
||||
+2
-1
@@ -5,6 +5,7 @@
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
"ms-vscode.cpptools-extension-pack",
|
||||
"pioarduino.pioarduino-ide"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ handshake-кадром IDENT (роль + версия протокола). Дл
|
||||
import argparse
|
||||
import hmac
|
||||
import logging
|
||||
import select
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
@@ -128,7 +129,13 @@ def run_tx(args, key):
|
||||
log.info("tx: %s -> UDP %s:%d", ser.port, *peer)
|
||||
sent = 0
|
||||
while True:
|
||||
for ftype, payload in parser.feed(ser.read(256)):
|
||||
# read(1) блокирует до первого байта, затем забираем всё доступное —
|
||||
# кадр уходит в сеть сразу, без ожидания таймаута чтения (иначе каждый
|
||||
# кадр задерживался бы до таймаута порта).
|
||||
data = ser.read(1)
|
||||
if ser.in_waiting:
|
||||
data += ser.read(ser.in_waiting)
|
||||
for ftype, payload in parser.feed(data):
|
||||
if ftype == lp.CONTROL:
|
||||
sock.sendto(seal(payload, key), peer)
|
||||
sent += 1
|
||||
@@ -149,7 +156,7 @@ def run_rx(args, key):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.bind(bind)
|
||||
sock.settimeout(lp.FRAME_PERIOD_MS / 1000.0)
|
||||
sock.setblocking(False)
|
||||
parser = lp.FrameParser()
|
||||
log.info("rx: UDP %s:%d -> %s", bind[0], bind[1], ser.port)
|
||||
|
||||
@@ -160,37 +167,55 @@ def run_rx(args, key):
|
||||
in_failsafe = False
|
||||
rejects = 0 # подряд отброшенных по seq -> признак перезапуска источника
|
||||
|
||||
def accept(datagram, addr):
|
||||
"""Проверить пакет и обновить состояние; вернуть payload принятого
|
||||
свежего кадра либо None."""
|
||||
nonlocal last_seq, last_net, in_failsafe, rejects
|
||||
if allowed_host and addr[0] != allowed_host:
|
||||
log.warning("пакет с неожиданного адреса %s отброшен", addr[0])
|
||||
return None
|
||||
payload = unseal(datagram, key)
|
||||
if not payload or len(payload) != lp.CONTROL_LEN:
|
||||
log.warning("битый/неаутентичный пакет отброшен")
|
||||
return None
|
||||
c = lp.unpack_control(payload)
|
||||
# Принять свежий seq ИЛИ новую сессию: источник (STM-TX) после ребута
|
||||
# начинает seq заново с 0, и без сброса last_seq поток завис бы в
|
||||
# failsafe навсегда. Новую сессию распознаём по пачке подряд «несвежих»
|
||||
# пакетов (устойчиво к одиночным reorder/dup).
|
||||
fresh = last_seq is None or seq_newer(c["seq"], last_seq)
|
||||
if not fresh:
|
||||
rejects += 1
|
||||
if rejects >= SEQ_RESET_AFTER:
|
||||
log.warning("seq откатился (%d -> %d): новая сессия", last_seq, c["seq"])
|
||||
fresh = True
|
||||
if not fresh:
|
||||
return None # устаревший/повторный — anti-replay
|
||||
rejects = 0
|
||||
last_seq = c["seq"]
|
||||
last_net = time.monotonic()
|
||||
if in_failsafe:
|
||||
log.info("связь восстановлена")
|
||||
in_failsafe = False
|
||||
return payload
|
||||
|
||||
while True:
|
||||
try:
|
||||
datagram, addr = sock.recvfrom(2048)
|
||||
if allowed_host and addr[0] != allowed_host:
|
||||
log.warning("пакет с неожиданного адреса %s отброшен", addr[0])
|
||||
datagram = None
|
||||
payload = unseal(datagram, key) if datagram else None
|
||||
if payload and len(payload) == lp.CONTROL_LEN:
|
||||
c = lp.unpack_control(payload)
|
||||
# Принять свежий seq ИЛИ новую сессию: источник (STM-TX) после
|
||||
# ребута начинает seq заново с 0, и без сброса last_seq поток
|
||||
# завис бы в failsafe навсегда. Новую сессию распознаём по пачке
|
||||
# подряд «несвежих» пакетов (устойчиво к одиночным reorder/dup).
|
||||
fresh = last_seq is None or seq_newer(c["seq"], last_seq)
|
||||
if not fresh:
|
||||
rejects += 1
|
||||
if rejects >= SEQ_RESET_AFTER:
|
||||
log.warning("seq откатился (%d -> %d): новая сессия", last_seq, c["seq"])
|
||||
fresh = True
|
||||
if fresh:
|
||||
rejects = 0
|
||||
last_seq = c["seq"]
|
||||
last_net = time.monotonic()
|
||||
if in_failsafe:
|
||||
log.info("связь восстановлена")
|
||||
in_failsafe = False
|
||||
ser.write(lp.build_frame(lp.CONTROL, payload))
|
||||
elif datagram is not None:
|
||||
log.warning("битый/неаутентичный пакет отброшен")
|
||||
except socket.timeout:
|
||||
pass
|
||||
# Ждём пакет до 20 мс (пауза цикла), затем БЕЗ блокировки выгребаем всю
|
||||
# накопившуюся очередь сокета и шлём на STM только самый свежий кадр
|
||||
# (latest-wins): так задержка не растёт, даже если пакеты пришли пачкой.
|
||||
newest = None
|
||||
ready = select.select([sock], [], [], lp.FRAME_PERIOD_MS / 2000.0)[0]
|
||||
while ready:
|
||||
try:
|
||||
datagram, addr = sock.recvfrom(2048)
|
||||
except BlockingIOError:
|
||||
break
|
||||
p = accept(datagram, addr)
|
||||
if p is not None:
|
||||
newest = p
|
||||
ready = select.select([sock], [], [], 0)[0]
|
||||
if newest is not None:
|
||||
ser.write(lp.build_frame(lp.CONTROL, newest))
|
||||
|
||||
# сетевой failsafe: тишина -> активная нейтраль на STM в темпе 20 Гц
|
||||
now = time.monotonic()
|
||||
@@ -203,10 +228,11 @@ def run_rx(args, key):
|
||||
fs_seq = (fs_seq + 1) & 0xFFFFFFFF
|
||||
last_fs = now
|
||||
|
||||
# дренируем входящие LOG/IDENT от STM-RX
|
||||
for ftype, payload in parser.feed(ser.read(256)):
|
||||
if ftype == lp.LOG:
|
||||
log.info("STM-RX: %s", payload.decode("ascii", "replace"))
|
||||
# неблокирующий дренаж входящих LOG от STM-RX
|
||||
if ser.in_waiting:
|
||||
for ftype, payload in parser.feed(ser.read(ser.in_waiting)):
|
||||
if ftype == lp.LOG:
|
||||
log.info("STM-RX: %s", payload.decode("ascii", "replace"))
|
||||
|
||||
|
||||
# ---------------- общее ----------------
|
||||
|
||||
Reference in New Issue
Block a user