Files
opengd77-uv380-sms/patches/patch_rx2.py
T
viktor b5a8e92e45 DMR-данные (SMS) на TYT MD-UV380 под OpenGD77
Восстановлено из транскрипта сессии после потери рабочего дерева на сервере сборки.

Что внутри:
- четыре новых модуля прошивки (приём, сборка исходящего, меню Messages);
- правки существующих файлов в виде скриптов, с порядком применения;
- инструменты стенда: снятие экрана рации по USB, дамп кадров, эталонная сборка пакета;
- NOTES.md: что проверено в эфире, что не доделано, где грабли.

Работало в эфире в августе 2026: данные ходят в обе стороны в режиме хотспота,
рация принимает SMS и показывает на экране. Отправка собрана и сверена с эталоном
сервера побайтово, но в эфире не проверялась.

Claude-Session: https://claude.ai/code/session_01GJtvG5WwqYNe1b7s9LLtgy
2026-09-11 02:39:24 +09:00

52 строки
2.2 KiB
Python

#!/usr/bin/env python3
"""Patch 2 of RX support: hand received data bursts to the MMDVM host."""
W = "/home/viktor/ogd77rel/uv_src/OpenGD77_MDUV380_DM1701_20260130/MDUV380_firmware/application"
p = W + "/source/functions/hotspot.c"
s = open(p).read()
if "sendDataFrameToHost" in s:
print("already patched")
raise SystemExit(0)
# --- 1. MS sourced data sync pattern (frames we originate towards the host) ---
a = "static const uint8_t MS_SOURCED_AUDIO_SYNC[] = { 0x07, 0xF7, 0xD5, 0xDD, 0x57, 0xDF, 0xD0 };\n"
assert a in s, "sync constant anchor missing"
s = s.replace(a, a + "static const uint8_t MS_SOURCED_DATA_SYNC[] = { 0x0D, 0x5D, 0x7F, 0x77, 0xFD, 0x75, 0x70 };\n", 1)
# --- 2. the function itself, placed right before the voice header builder ---
anchor = "static bool sendVoiceHeaderLC_Frame(volatile const uint8_t *receivedDMRDataAndAudio)\n{"
assert anchor in s, "sendVoiceHeaderLC_Frame not found"
func = '''// Rebuild a packet data burst that was received off air and pass it to the MMDVM host.
//
// The HR-C6000 hands us the decoded 96 bit payload (it strips the FEC itself), while the
// host expects a complete 33 byte DMR burst. So we run the payload back through BPTC,
// stamp the data sync pattern and the Slot Type (colour code + data type) into the middle
// of the burst, and send it as a normal DMR data frame.
static void sendDataFrameToHost(volatile const uint8_t *receivedData, uint8_t dataType)
{
\tuint8_t frameData[DMR_FRAME_LENGTH_BYTES + MMDVM_HEADER_LENGTH + 2] = {MMDVM_FRAME_START, (DMR_FRAME_LENGTH_BYTES + MMDVM_HEADER_LENGTH + 2), MMDVM_DMR_DATA2, DMR_SYNC_DATA | dataType};
\tBPTCglobalsInit();
\tBPTCencode((uint8_t *)receivedData, frameData + MMDVM_HEADER_LENGTH);
\t// data sync pattern goes into the middle of the burst
\tfor (uint8_t i = 0; i < 7; i++)
\t{
\t\tframeData[i + EMBEDDED_DATA_OFFSET + MMDVM_HEADER_LENGTH] =
\t\t\t\t(frameData[i + EMBEDDED_DATA_OFFSET + MMDVM_HEADER_LENGTH] & ~SYNC_MASK[i]) | MS_SOURCED_DATA_SYNC[i];
\t}
\tDMRSlotTypeEncode(trxGetDMRColourCode(), dataType, frameData + MMDVM_HEADER_LENGTH);
\tsetRSSIToFrame(frameData);
\tenqueueUSBData(frameData, frameData[1]);
}
'''
s = s.replace(anchor, func + anchor, 1)
open(p, "w").write(s)
print("hotspot.c: sendDataFrameToHost added")