DMR-данные (SMS) на TYT MD-UV380 под OpenGD77
Восстановлено из транскрипта сессии после потери рабочего дерева на сервере сборки. Что внутри: - четыре новых модуля прошивки (приём, сборка исходящего, меню Messages); - правки существующих файлов в виде скриптов, с порядком применения; - инструменты стенда: снятие экрана рации по USB, дамп кадров, эталонная сборка пакета; - NOTES.md: что проверено в эфире, что не доделано, где грабли. Работало в эфире в августе 2026: данные ходят в обе стороны в режиме хотспота, рация принимает SMS и показывает на экране. Отправка собрана и сверена с эталоном сервера побайтово, но в эфире не проверялась. Claude-Session: https://claude.ai/code/session_01GJtvG5WwqYNe1b7s9LLtgy
Этот коммит содержится в:
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Diagnostic build: make the radio show what its SMS assembler actually sees.
|
||||
|
||||
Three counters are surfaced on screen, so we can tell where reception stops:
|
||||
RX - data bursts handed to the assembler by the driver
|
||||
HDR - data headers parsed (with the announced block count)
|
||||
ASM - completed assemblies (all blocks collected)
|
||||
|
||||
If RX stays at zero the bursts never reach the module and the problem is in the
|
||||
driver-side capture conditions. If RX counts up but HDR does not, header parsing is
|
||||
rejecting them. If HDR appears but ASM does not, blocks are being lost.
|
||||
"""
|
||||
W = "/home/viktor/ogd77rel/uv_src/OpenGD77_MDUV380_DM1701_20260130/MDUV380_firmware/application"
|
||||
|
||||
# ---------------------------------------------------------------- sms.h
|
||||
p = W + "/include/functions/sms.h"
|
||||
s = open(p).read()
|
||||
if "smsGetDiagCounters" not in s:
|
||||
a = "bool smsHasUnread(void);\n"
|
||||
assert a in s
|
||||
s = s.replace(a, a + """
|
||||
// Diagnostics: how many bursts reached the assembler, how many headers were parsed,
|
||||
// and how many messages assembled completely.
|
||||
void smsGetDiagCounters(uint16_t *bursts, uint16_t *headers, uint16_t *assembled, uint8_t *lastBlocks);
|
||||
""", 1)
|
||||
open(p, "w").write(s)
|
||||
print("sms.h: diagnostics declared")
|
||||
|
||||
# ---------------------------------------------------------------- sms.c
|
||||
p = W + "/source/functions/sms.c"
|
||||
s = open(p).read()
|
||||
if "diagBursts" in s:
|
||||
print("sms.c: already instrumented")
|
||||
else:
|
||||
a = "static bool unread = false;\n"
|
||||
assert a in s
|
||||
s = s.replace(a, a + """
|
||||
static volatile uint16_t diagBursts = 0;
|
||||
static uint16_t diagHeaders = 0;
|
||||
static uint16_t diagAssembled = 0;
|
||||
static uint8_t diagLastBlocks = 0;
|
||||
""", 1)
|
||||
|
||||
# count every burst the driver hands us
|
||||
a = "\tmemcpy((uint8_t *)rxQueue[rxQueueWrite], payload, SMS_BLOCK_LENGTH);\n"
|
||||
assert a in s
|
||||
s = s.replace(a, "\tdiagBursts++;\n" + a, 1)
|
||||
|
||||
# count parsed headers, remembering the announced block count
|
||||
a = "\tblocksExpected = (uint8_t)(hdr[8] & 0x7FU);\n"
|
||||
assert a in s
|
||||
s = s.replace(a, a + "\tdiagHeaders++;\n\tdiagLastBlocks = blocksExpected;\n", 1)
|
||||
|
||||
# count completed assemblies
|
||||
a = "static void finishAssembly(void)\n{\n"
|
||||
assert a in s
|
||||
s = s.replace(a, a + "\tdiagAssembled++;\n", 1)
|
||||
|
||||
s += """
|
||||
void smsGetDiagCounters(uint16_t *bursts, uint16_t *headers, uint16_t *assembled, uint8_t *lastBlocks)
|
||||
{
|
||||
*bursts = diagBursts;
|
||||
*headers = diagHeaders;
|
||||
*assembled = diagAssembled;
|
||||
*lastBlocks = diagLastBlocks;
|
||||
}
|
||||
"""
|
||||
open(p, "w").write(s)
|
||||
print("sms.c: counters added")
|
||||
|
||||
# ------------------------------------------------------- applicationMain.c
|
||||
p = W + "/source/applicationMain.c"
|
||||
s = open(p).read()
|
||||
if "smsGetDiagCounters" in s:
|
||||
print("applicationMain.c: already showing diagnostics")
|
||||
else:
|
||||
a = "\t\tif (smsHasUnread())\n"
|
||||
assert a in s, "unread check not found"
|
||||
s = s.replace(a, """\t\t{
|
||||
\t\t\t// Diagnostics: show the assembler counters whenever they change, so we can see
|
||||
\t\t\t// how far a received message gets even when no text is produced.
|
||||
\t\t\tstatic uint16_t lastShownBursts = 0;
|
||||
\t\t\tstatic uint16_t lastShownHeaders = 0;
|
||||
\t\t\tuint16_t dBursts, dHeaders, dAssembled;
|
||||
\t\t\tuint8_t dBlocks;
|
||||
|
||||
\t\t\tsmsGetDiagCounters(&dBursts, &dHeaders, &dAssembled, &dBlocks);
|
||||
|
||||
\t\t\tif ((dBursts != lastShownBursts) || (dHeaders != lastShownHeaders))
|
||||
\t\t\t{
|
||||
\t\t\t\tchar diagLine[40];
|
||||
|
||||
\t\t\t\tlastShownBursts = dBursts;
|
||||
\t\t\t\tlastShownHeaders = dHeaders;
|
||||
\t\t\t\tsnprintf(diagLine, sizeof(diagLine), "RX%u HDR%u/%u ASM%u",
|
||||
\t\t\t\t\t\t(unsigned int)dBursts, (unsigned int)dHeaders,
|
||||
\t\t\t\t\t\t(unsigned int)dBlocks, (unsigned int)dAssembled);
|
||||
\t\t\t\tuiNotificationShow(NOTIFICATION_TYPE_MESSAGE, NOTIFICATION_ID_MESSAGE, 8000, diagLine, true);
|
||||
\t\t\t\tsoundSetMelody(MELODY_KEY_BEEP);
|
||||
\t\t\t}
|
||||
\t\t}
|
||||
|
||||
""" + a, 1)
|
||||
open(p, "w").write(s)
|
||||
print("applicationMain.c: diagnostics displayed")
|
||||
Ссылка в новой задаче
Block a user