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