Восстановлено из транскрипта сессии после потери рабочего дерева на сервере сборки. Что внутри: - четыре новых модуля прошивки (приём, сборка исходящего, меню Messages); - правки существующих файлов в виде скриптов, с порядком применения; - инструменты стенда: снятие экрана рации по USB, дамп кадров, эталонная сборка пакета; - NOTES.md: что проверено в эфире, что не доделано, где грабли. Работало в эфире в августе 2026: данные ходят в обе стороны в режиме хотспота, рация принимает SMS и показывает на экране. Отправка собрана и сверена с эталоном сервера побайтово, но в эфире не проверялась. Claude-Session: https://claude.ai/code/session_01GJtvG5WwqYNe1b7s9LLtgy
68 строки
2.8 KiB
Python
68 строки
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Patch 3 of RX support: dispatch in the hotspot state machine, and read the
|
|
payload out of the HR-C6000 when a data burst arrives off air."""
|
|
W = "/home/viktor/ogd77rel/uv_src/OpenGD77_MDUV380_DM1701_20260130/MDUV380_firmware/application"
|
|
|
|
# ---------------------------------------------------------------- hotspot.c
|
|
p = W + "/source/functions/hotspot.c"
|
|
s = open(p).read()
|
|
|
|
if "case HOTSPOT_RX_DATA_FRAME:" in s:
|
|
print("hotspot.c: dispatch already present")
|
|
else:
|
|
a = "\t\t\t\t\t\tcase HOTSPOT_RX_STOP:\n"
|
|
assert a in s, "RX_STOP case not found"
|
|
case = """\t\t\t\t\t\tcase HOTSPOT_RX_DATA_FRAME:
|
|
\t\t\t\t\t\t\t// Packet data burst (SMS, position report...) received off air.
|
|
\t\t\t\t\t\t\t// The data type the HR-C6000 reported is stored right after the frame.
|
|
\t\t\t\t\t\t\tsendDataFrameToHost(audioAndHotspotDataBuffer.hotspotBuffer[rfFrameBufReadIdx],
|
|
\t\t\t\t\t\t\t\t\taudioAndHotspotDataBuffer.hotspotBuffer[rfFrameBufReadIdx][AMBE_AUDIO_LENGTH + LC_DATA_LENGTH + 1]);
|
|
\t\t\t\t\t\t\tlastRxState = HOTSPOT_RX_DATA_FRAME;
|
|
\t\t\t\t\t\t\trxFrameTime = ticksGetMillis();
|
|
\t\t\t\t\t\t\tbreak;
|
|
|
|
"""
|
|
s = s.replace(a, case + a, 1)
|
|
open(p, "w").write(s)
|
|
print("hotspot.c: RX_DATA_FRAME dispatch added")
|
|
|
|
# ------------------------------------------------------------- HR-C6000.c
|
|
p = W + "/source/hardware/HR-C6000.c"
|
|
s = open(p).read()
|
|
|
|
if "HOTSPOT_RX_DATA_FRAME" in s:
|
|
print("HR-C6000.c: already patched")
|
|
raise SystemExit(0)
|
|
|
|
# Hook in right after the terminator handling, which is the existing example of
|
|
# "this is a data sync burst" handling in this interrupt.
|
|
a = """ if (hrc6000CrcIsValid() && (slotState != DMR_STATE_IDLE) && (hrc.skipCount > 0) && (rxSyncClass != SYNC_CLASS_DATA) && ((rxDataType & 0x07) == 0x01))
|
|
{
|
|
hrc.skipCount--;
|
|
}
|
|
"""
|
|
assert a in s, "skipCount anchor missing"
|
|
|
|
block = """ // Packet data bursts (SMS, position reports, CSBK). Stock firmware reads nothing off the
|
|
// chip for these, which is why data never reached the host. The HR-C6000 has already
|
|
// removed the FEC, so the 96 bit payload can be read from the same register page that
|
|
// carries LC data, and handed to the hotspot code to be rebuilt into a full burst.
|
|
if ((settingsUsbMode == USB_MODE_HOTSPOT) && hrc6000CrcIsValid() && (rxSyncClass == SYNC_CLASS_DATA) &&
|
|
((rxDataType == DT_CSBK) || (rxDataType == DT_DATA_HEADER) || (rxDataType == DT_RATE_12_DATA)) &&
|
|
hrc6000CheckColourCodeFilter())
|
|
{
|
|
if (SPI0ReadPageRegByteArray(0x02, 0x00, (uint8_t *)DMR_frame_buffer, LC_DATA_LENGTH) == kStatus_Success)
|
|
{
|
|
DMR_frame_buffer[AMBE_AUDIO_LENGTH + LC_DATA_LENGTH] = HOTSPOT_RX_DATA_FRAME;
|
|
DMR_frame_buffer[AMBE_AUDIO_LENGTH + LC_DATA_LENGTH + 1] = rxDataType;
|
|
hrc.hotspotDMRRxFrameBufferAvailable = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
"""
|
|
|
|
s = s.replace(a, block + a, 1)
|
|
open(p, "w").write(s)
|
|
print("HR-C6000.c: data burst capture added")
|