Восстановлено из транскрипта сессии после потери рабочего дерева на сервере сборки. Что внутри: - четыре новых модуля прошивки (приём, сборка исходящего, меню Messages); - правки существующих файлов в виде скриптов, с порядком применения; - инструменты стенда: снятие экрана рации по USB, дамп кадров, эталонная сборка пакета; - NOTES.md: что проверено в эфире, что не доделано, где грабли. Работало в эфире в августе 2026: данные ходят в обе стороны в режиме хотспота, рация принимает SMS и показывает на экране. Отправка собрана и сверена с эталоном сервера побайтово, но в эфире не проверялась. Claude-Session: https://claude.ai/code/session_01GJtvG5WwqYNe1b7s9LLtgy
75 строки
3.1 KiB
Python
75 строки
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Fix: a stale "this frame is packet data" marker could suppress the Voice LC Header
|
|
of an ordinary voice transmission.
|
|
|
|
hrc.txDataType is only ever set on the hotspot path, and was only cleared after a data
|
|
burst was actually sent. If a data transmission was cut short before that, the marker
|
|
stayed set - and the next PTT from the radio itself started without a Voice LC Header,
|
|
so receivers never recognised the call.
|
|
|
|
Two guards:
|
|
- the start-of-transmission checks now only apply while acting as a hotspot modem;
|
|
- the marker is cleared whenever a normal (non-hotspot) transmission begins.
|
|
"""
|
|
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 "isHotspotDataTx" in s:
|
|
print("already patched")
|
|
raise SystemExit(0)
|
|
|
|
# 1. helper right after the struct instance, so all three call sites can use it
|
|
anchor = "\t\t.txDataType = HOTSPOT_TX_TYPE_VOICE,\n"
|
|
assert anchor in s, "hrc initialiser not found"
|
|
|
|
# find the end of the initialiser block to place the helper after it
|
|
marker = "static void hrc6000SendPcOrTgLCHeader(void);"
|
|
assert marker in s, "forward declaration anchor not found"
|
|
helper = """// True only when the frame about to be sent is a packet data burst queued by the host.
|
|
// Outside hotspot mode there is no such thing, so ordinary voice transmissions are never
|
|
// affected by a leftover marker.
|
|
static inline bool isHotspotDataTx(void)
|
|
{
|
|
return ((settingsUsbMode == USB_MODE_HOTSPOT) && (hrc.txDataType != HOTSPOT_TX_TYPE_VOICE));
|
|
}
|
|
|
|
"""
|
|
s = s.replace(marker, marker + "\n" + helper, 1)
|
|
|
|
# 2. use it in the three start-of-transmission checks
|
|
a1 = "\t\t\tif (hrc.txDataType != HOTSPOT_TX_TYPE_VOICE)\n\t\t\t{\n\t\t\t\t// A data burst is queued: don't announce a voice call in front of it."
|
|
assert a1 in s, "TX_START_1 check not found"
|
|
s = s.replace(a1, "\t\t\tif (isHotspotDataTx())\n\t\t\t{\n\t\t\t\t// A data burst is queued: don't announce a voice call in front of it.", 1)
|
|
|
|
a2 = "((hrc.txDataType != HOTSPOT_TX_TYPE_VOICE) ? (DT_IDLE << 4) : 0x10)"
|
|
n2 = s.count(a2)
|
|
assert n2 == 2, "expected 2 shared checks, found %d" % n2
|
|
s = s.replace(a2, "(isHotspotDataTx() ? (DT_IDLE << 4) : 0x10)")
|
|
|
|
# 3. and in the ongoing-TX branch, so a stale marker cannot divert voice frames either
|
|
a3 = "\t\t\t\t\tif (hrc.txDataType != HOTSPOT_TX_TYPE_VOICE)\n"
|
|
assert a3 in s, "TX_2 data branch not found"
|
|
s = s.replace(a3, "\t\t\t\t\tif (isHotspotDataTx())\n", 1)
|
|
|
|
# 4. belt and braces: clear the marker when a non-hotspot transmission starts
|
|
a4 = """ if (settingsUsbMode != USB_MODE_HOTSPOT)
|
|
{
|
|
codecInit(false);
|
|
}
|
|
else
|
|
{
|
|
hrc.hotspotPostponedFrameHandling = (HS_NUM_OF_SILENCE_SEQ_ON_STARTUP * 6);"""
|
|
assert a4 in s, "TX start branch not found"
|
|
s = s.replace(a4, """ if (settingsUsbMode != USB_MODE_HOTSPOT)
|
|
{
|
|
hrc.txDataType = HOTSPOT_TX_TYPE_VOICE;// plain voice call: never a data burst
|
|
codecInit(false);
|
|
}
|
|
else
|
|
{
|
|
hrc.hotspotPostponedFrameHandling = (HS_NUM_OF_SILENCE_SEQ_ON_STARTUP * 6);""", 1)
|
|
|
|
open(p, "w").write(s)
|
|
print("HR-C6000.c: voice transmissions can no longer be suppressed by a stale data marker")
|