DMR-данные (SMS) на TYT MD-UV380 под OpenGD77
Восстановлено из транскрипта сессии после потери рабочего дерева на сервере сборки. Что внутри: - четыре новых модуля прошивки (приём, сборка исходящего, меню Messages); - правки существующих файлов в виде скриптов, с порядком применения; - инструменты стенда: снятие экрана рации по USB, дамп кадров, эталонная сборка пакета; - NOTES.md: что проверено в эфире, что не доделано, где грабли. Работало в эфире в августе 2026: данные ходят в обе стороны в режиме хотспота, рация принимает SMS и показывает на экране. Отправка собрана и сверена с эталоном сервера побайтово, но в эфире не проверялась. Claude-Session: https://claude.ai/code/session_01GJtvG5WwqYNe1b7s9LLtgy
Этот коммит содержится в:
@@ -0,0 +1,63 @@
|
||||
#!/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)
|
||||
Ссылка в новой задаче
Block a user