Восстановлено из транскрипта сессии после потери рабочего дерева на сервере сборки. Что внутри: - четыре новых модуля прошивки (приём, сборка исходящего, меню Messages); - правки существующих файлов в виде скриптов, с порядком применения; - инструменты стенда: снятие экрана рации по USB, дамп кадров, эталонная сборка пакета; - NOTES.md: что проверено в эфире, что не доделано, где грабли. Работало в эфире в августе 2026: данные ходят в обе стороны в режиме хотспота, рация принимает SMS и показывает на экране. Отправка собрана и сверена с эталоном сервера побайтово, но в эфире не проверялась. Claude-Session: https://claude.ai/code/session_01GJtvG5WwqYNe1b7s9LLtgy
54 строки
2.0 KiB
Python
54 строки
2.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Show a received SMS on a proper message screen instead of a transient notification.
|
|
|
|
uiNotificationShow() draws over the current screen, but the normal screen redraw wipes
|
|
it again - which is why the text never appeared even though the message was received
|
|
and decoded correctly. The message box screen is a real menu: it stays until the user
|
|
dismisses it.
|
|
"""
|
|
W = "/home/viktor/ogd77rel/uv_src/OpenGD77_MDUV380_DM1701_20260130/MDUV380_firmware/application"
|
|
p = W + "/source/applicationMain.c"
|
|
s = open(p).read()
|
|
|
|
if "MESSAGEBOX_TYPE_INFO" in s and "smsMarkRead" in s and "MessageBox.message, MESSAGEBOX_MESSAGE_LEN_MAX, \"%u:" in s:
|
|
print("already patched")
|
|
raise SystemExit(0)
|
|
|
|
# Replace the notification-based display with a message box screen.
|
|
old_start = "\t\tif (smsHasUnread())\n\t\t{\n"
|
|
assert old_start in s, "unread block not found"
|
|
|
|
start = s.index(old_start)
|
|
# find the end of that block (the closing brace of the if, at the same indent)
|
|
end_marker = "\n\t\t}\n"
|
|
end = s.index(end_marker, start) + len(end_marker)
|
|
old_block = s[start:end]
|
|
assert "smsMarkRead" in old_block, "unexpected block contents: %r" % old_block[:200]
|
|
|
|
new_block = """ if (smsHasUnread())
|
|
{
|
|
const smsMessage_t *msg = smsGetLatest();
|
|
|
|
// Only interrupt the user when they are on a normal operating screen.
|
|
int currentMenu = menuSystemGetCurrentMenuNumber();
|
|
|
|
if ((msg != NULL) && ((currentMenu == UI_VFO_MODE) || (currentMenu == UI_CHANNEL_MODE)))
|
|
{
|
|
snprintf(uiDataGlobal.MessageBox.message, MESSAGEBOX_MESSAGE_LEN_MAX, "%u\\n%s",
|
|
(unsigned int)msg->srcId, msg->text);
|
|
uiDataGlobal.MessageBox.type = MESSAGEBOX_TYPE_INFO;
|
|
uiDataGlobal.MessageBox.decoration = MESSAGEBOX_DECORATION_FRAME;
|
|
uiDataGlobal.MessageBox.buttons = MESSAGEBOX_BUTTONS_OK;
|
|
uiDataGlobal.MessageBox.validatorCallback = NULL;
|
|
menuSystemPushNewMenu(UI_MESSAGE_BOX);
|
|
|
|
soundSetMelody(MELODY_ACK_BEEP);
|
|
smsMarkRead();
|
|
}
|
|
}
|
|
"""
|
|
|
|
s = s[:start] + new_block + s[end:]
|
|
open(p, "w").write(s)
|
|
print("applicationMain.c: incoming SMS now opens a message screen")
|