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