Восстановлено из транскрипта сессии после потери рабочего дерева на сервере сборки. Что внутри: - четыре новых модуля прошивки (приём, сборка исходящего, меню Messages); - правки существующих файлов в виде скриптов, с порядком применения; - инструменты стенда: снятие экрана рации по USB, дамп кадров, эталонная сборка пакета; - NOTES.md: что проверено в эфире, что не доделано, где грабли. Работало в эфире в августе 2026: данные ходят в обе стороны в режиме хотспота, рация принимает SMS и показывает на экране. Отправка собрана и сверена с эталоном сервера побайтово, но в эфире не проверялась. Claude-Session: https://claude.ai/code/session_01GJtvG5WwqYNe1b7s9LLtgy
64 строки
2.8 KiB
Python
64 строки
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Stop emitting voice LC headers in front of a packet data transmission.
|
|
|
|
TX_START_1/3/5 always sent three Voice LC Headers built from the radio's own DMR ID,
|
|
which is correct for a voice call but pollutes the air before an SMS: the receiving
|
|
end logs them as "RF user <id> rejected for using TG 0". When the queued frame is a
|
|
data burst we send standard Idle data bursts instead - a legitimate filler that
|
|
receivers discard silently.
|
|
"""
|
|
W = "/home/viktor/ogd77rel/uv_src/OpenGD77_MDUV380_DM1701_20260130/MDUV380_firmware/application"
|
|
p = W + "/source/hardware/HR-C6000.c"
|
|
s = open(p).read()
|
|
|
|
if "DT_IDLE << 4" in s:
|
|
print("already patched")
|
|
raise SystemExit(0)
|
|
|
|
# The three start steps share the same two lines; patch each occurrence.
|
|
old_variants = [
|
|
# TX_START_1 (preceded by the LED write and header call)
|
|
(""" hrc6000SendPcOrTgLCHeader();
|
|
SPI0WritePageRegByte(0x04, 0x41, 0x80); // Transmit during next Timeslot
|
|
SPI0WritePageRegByte(0x04, 0x50, 0x10); // Set Data Type to 0001 (Voice LC Header), Data, LCSS=00
|
|
""",
|
|
""" if (hrc.txDataType != HOTSPOT_TX_TYPE_VOICE)
|
|
{
|
|
// A data burst is queued: don't announce a voice call in front of it.
|
|
SPI0WritePageRegByte(0x04, 0x41, 0x80); // Transmit during next Timeslot
|
|
SPI0WritePageRegByte(0x04, 0x50, (DT_IDLE << 4)); // Idle data burst as filler
|
|
}
|
|
else
|
|
{
|
|
hrc6000SendPcOrTgLCHeader();
|
|
SPI0WritePageRegByte(0x04, 0x41, 0x80); // Transmit during next Timeslot
|
|
SPI0WritePageRegByte(0x04, 0x50, 0x10); // Set Data Type to 0001 (Voice LC Header), Data, LCSS=00
|
|
}
|
|
"""),
|
|
# TX_START_3 and TX_START_5 (no header call, just the two register writes)
|
|
(""" SPI0WritePageRegByte(0x04, 0x41, 0x80); // Transmit during Next Timeslot
|
|
SPI0WritePageRegByte(0x04, 0x50, 0x10); // Set Data Type to 0001 (Voice LC Header), Data, LCSS=00
|
|
""",
|
|
""" SPI0WritePageRegByte(0x04, 0x41, 0x80); // Transmit during Next Timeslot
|
|
SPI0WritePageRegByte(0x04, 0x50, ((hrc.txDataType != HOTSPOT_TX_TYPE_VOICE) ? (DT_IDLE << 4) : 0x10));// Voice LC Header, or Idle filler ahead of data
|
|
"""),
|
|
(""" SPI0WritePageRegByte(0x04, 0x41, 0x80); // Transmit during next Timeslot
|
|
SPI0WritePageRegByte(0x04, 0x50, 0x10); // Set Data Type to 0001 (Voice LC Header), Data, LCSS=00
|
|
""",
|
|
""" SPI0WritePageRegByte(0x04, 0x41, 0x80); // Transmit during next Timeslot
|
|
SPI0WritePageRegByte(0x04, 0x50, ((hrc.txDataType != HOTSPOT_TX_TYPE_VOICE) ? (DT_IDLE << 4) : 0x10));// Voice LC Header, or Idle filler ahead of data
|
|
"""),
|
|
]
|
|
|
|
count = 0
|
|
for old, new in old_variants:
|
|
if old in s:
|
|
s = s.replace(old, new, 1)
|
|
count += 1
|
|
|
|
if count == 0:
|
|
raise SystemExit("no TX_START patterns matched - aborting")
|
|
|
|
open(p, "w").write(s)
|
|
print("patched %d of 3 TX start steps" % count)
|