new mode --bin24

This commit is contained in:
awe
2026-08-17 14:06:49 +03:00
parent 2cf7543bbe
commit 428ba2a9e0
6 changed files with 392 additions and 14 deletions
+146
View File
@@ -31,6 +31,10 @@ def u16_to_i16(value: int) -> int:
return value - 0x1_0000 if (value & 0x8000) else value
def u24_to_i24(value: int) -> int:
return value - 0x100_0000 if (value & 0x80_0000) else value
def log_value_to_linear(value: int) -> float:
exponent = max(-LOG_EXP_LIMIT, min(LOG_EXP_LIMIT, float(value) * LOG_SCALER))
return float(LOG_BASE ** exponent)
@@ -606,6 +610,148 @@ class LegacyBinaryParser:
return events
class LegacyBinaryParser24(LegacyBinaryParser):
"""Byte-resynchronizing parser for 10-byte tty records with 24-bit I/Q values.
Same protocol as ``LegacyBinaryParser``'s tty family (markers 0x000A primary,
0x00A8 secondary, 0x00A3/0x00A4 DO1 low/high tagged), but each channel value
is a signed 24-bit little-endian integer, so a record is 10 bytes:
``marker(u16) | step(u16) | ch1_i24(3B) | ch2_i24(3B)``. The legacy 8-byte
(byte6==0x0A) and logdet (0x001A) record shapes do not exist here and are
omitted so int24 payload bytes cannot be mistaken for them.
"""
RECORD_SIZE = 10
def __init__(self):
super().__init__(batch_events=False)
@staticmethod
def _i24_at(buf: bytearray, offset: int) -> int:
u = int(buf[offset]) | (int(buf[offset + 1]) << 8) | (int(buf[offset + 2]) << 16)
return u24_to_i24(u)
def _try_emit_tty_batch(self, events: List[ParserEvent], *, require_not_legacy: bool) -> bool:
# int24 has no native numpy dtype; the scalar per-record path handles it.
return False
def _emit_tty_point24(self, events: List[ParserEvent], step: int, ch_1: int, ch_2: int) -> None:
self._prepare_bin_point(events, step=int(step), signal_kind="bin_iq")
ch_1 = int(ch_1)
ch_2 = int(ch_2)
events.append(
PointEvent(
ch=0,
x=int(step),
y=tty_ch_pair_to_sweep(ch_1, ch_2),
aux=(float(ch_1), float(ch_2)),
signal_kind="bin_iq",
)
)
def _emit_tty_tagged_point24(
self,
events: List[ParserEvent],
step: int,
ch_1: int,
ch_2: int,
do1_level: Do1Level,
) -> None:
self._prepare_bin_point(
events,
step=int(step),
signal_kind="bin_iq_do1_tagged",
do1_level=do1_level,
)
ch_1 = int(ch_1)
ch_2 = int(ch_2)
events.append(
PointEvent(
ch=0,
x=int(step),
y=tty_ch_pair_to_sweep(ch_1, ch_2),
aux=(float(ch_1), float(ch_2)),
signal_kind="bin_iq_do1_tagged",
do1_level=do1_level,
)
)
def _emit_secondary_point24(self, events: List[ParserEvent], step: int, ch_1: int, ch_2: int) -> None:
self._mode = "bin"
self._current_signal_kind = self._current_signal_kind or "bin_iq"
ch_1 = int(ch_1)
ch_2 = int(ch_2)
events.append(
PointEvent(
ch=0,
x=int(step),
y=0.0,
aux=(float(ch_1), float(ch_2)),
signal_kind="bin_iq",
is_secondary=True,
)
)
def feed(self, data: bytes) -> List[ParserEvent]:
if data:
self._buf += data
events: List[ParserEvent] = []
while len(self._buf) >= self.RECORD_SIZE:
w0 = self._u16_at(self._buf, 0)
w1 = self._u16_at(self._buf, 2)
is_tty_start = w0 == 0x000A and all(b == 0xFF for b in self._buf[2:10])
is_tty_point = w0 == 0x000A and w1 != 0xFFFF
is_tty_tagged_low_point = w0 == 0x00A3 and w1 != 0xFFFF
is_tty_tagged_high_point = w0 == 0x00A4 and w1 != 0xFFFF
is_secondary_point = w0 == 0x00A8 and w1 != 0xFFFF
if is_tty_start:
self._emit_tty_start(events)
del self._buf[:10]
continue
if is_tty_point:
self._emit_tty_point24(
events,
step=int(w1),
ch_1=self._i24_at(self._buf, 4),
ch_2=self._i24_at(self._buf, 7),
)
del self._buf[:10]
continue
if is_tty_tagged_low_point:
self._emit_tty_tagged_point24(
events,
step=int(w1),
ch_1=self._i24_at(self._buf, 4),
ch_2=self._i24_at(self._buf, 7),
do1_level="low",
)
del self._buf[:10]
continue
if is_tty_tagged_high_point:
self._emit_tty_tagged_point24(
events,
step=int(w1),
ch_1=self._i24_at(self._buf, 4),
ch_2=self._i24_at(self._buf, 7),
do1_level="high",
)
del self._buf[:10]
continue
if is_secondary_point:
self._emit_secondary_point24(
events,
step=int(w1),
ch_1=self._i24_at(self._buf, 4),
ch_2=self._i24_at(self._buf, 7),
)
del self._buf[:10]
continue
del self._buf[:1]
return events
class LogScaleBinaryParser32:
"""Byte-resynchronizing parser for 32-bit logscale pair records."""
+7
View File
@@ -12,6 +12,7 @@ from rfg_adc_plotter.io.sweep_parser_core import (
AsciiSweepParser,
ComplexAsciiSweepParser,
LegacyBinaryParser,
LegacyBinaryParser24,
LogScale16BitX2BinaryParser,
LogScaleBinaryParser32,
ParserTestStreamParser,
@@ -113,6 +114,7 @@ class SweepReader(threading.Thread):
stop_event: threading.Event,
fancy: bool = False,
bin_mode: bool = False,
bin24_mode: bool = False,
logscale: bool = False,
parser_16_bit_x2: bool = False,
parser_test: bool = False,
@@ -125,6 +127,7 @@ class SweepReader(threading.Thread):
self._stop_event = stop_event
self._fancy = bool(fancy)
self._bin_mode = bool(bin_mode)
self._bin24_mode = bool(bin24_mode)
self._logscale = bool(logscale)
self._parser_16_bit_x2 = bool(parser_16_bit_x2)
self._parser_test = bool(parser_test)
@@ -143,6 +146,8 @@ class SweepReader(threading.Thread):
return "parser_16_bit_x2"
if self._logscale:
return "logscale_32"
if self._bin24_mode:
return "legacy_10byte_i24"
if self._bin_mode:
return "legacy_8byte"
return "ascii"
@@ -156,6 +161,8 @@ class SweepReader(threading.Thread):
return LogScale16BitX2BinaryParser(), SweepAssembler(fancy=self._fancy, apply_inversion=False)
if self._logscale:
return LogScaleBinaryParser32(), SweepAssembler(fancy=self._fancy, apply_inversion=False)
if self._bin24_mode:
return LegacyBinaryParser24(), SweepAssembler(fancy=self._fancy, apply_inversion=True)
if self._bin_mode:
return LegacyBinaryParser(batch_events=True), SweepAssembler(fancy=self._fancy, apply_inversion=True)
return AsciiSweepParser(), SweepAssembler(fancy=self._fancy, apply_inversion=True)