Восстановлено из транскрипта сессии после потери рабочего дерева на сервере сборки. Что внутри: - четыре новых модуля прошивки (приём, сборка исходящего, меню Messages); - правки существующих файлов в виде скриптов, с порядком применения; - инструменты стенда: снятие экрана рации по USB, дамп кадров, эталонная сборка пакета; - NOTES.md: что проверено в эфире, что не доделано, где грабли. Работало в эфире в августе 2026: данные ходят в обе стороны в режиме хотспота, рация принимает SMS и показывает на экране. Отправка собрана и сверена с эталоном сервера побайтово, но в эфире не проверялась. Claude-Session: https://claude.ai/code/session_01GJtvG5WwqYNe1b7s9LLtgy
52 строки
2.2 KiB
Python
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")
|