Восстановлено из транскрипта сессии после потери рабочего дерева на сервере сборки. Что внутри: - четыре новых модуля прошивки (приём, сборка исходящего, меню Messages); - правки существующих файлов в виде скриптов, с порядком применения; - инструменты стенда: снятие экрана рации по USB, дамп кадров, эталонная сборка пакета; - NOTES.md: что проверено в эфире, что не доделано, где грабли. Работало в эфире в августе 2026: данные ходят в обе стороны в режиме хотспота, рация принимает SMS и показывает на экране. Отправка собрана и сверена с эталоном сервера побайтово, но в эфире не проверялась. Claude-Session: https://claude.ai/code/session_01GJtvG5WwqYNe1b7s9LLtgy
150 строки
3.6 KiB
Python
150 строки
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Add Inbox/Outbox storage to the SMS module."""
|
|
W = "/home/viktor/ogd77rel/uv_src/OpenGD77_MDUV380_DM1701_20260130/MDUV380_firmware/application"
|
|
|
|
# ------------------------------------------------------------------ header
|
|
p = W + "/include/functions/sms.h"
|
|
s = open(p).read()
|
|
if "smsInboxCount" in s:
|
|
print("sms.h: already has storage API")
|
|
else:
|
|
s = s.replace(
|
|
"// Most recently received message, or NULL when nothing has been received yet.\n",
|
|
"""// How many messages each folder keeps. Older ones are dropped when full.
|
|
#define SMS_INBOX_SIZE 10
|
|
#define SMS_OUTBOX_SIZE 10
|
|
|
|
// Inbox: messages received off air. Newest first.
|
|
uint8_t smsInboxCount(void);
|
|
const smsMessage_t *smsInboxGet(uint8_t index);
|
|
void smsInboxClear(void);
|
|
uint8_t smsInboxUnreadCount(void);
|
|
|
|
// Outbox: messages we sent. Newest first.
|
|
uint8_t smsOutboxCount(void);
|
|
const smsMessage_t *smsOutboxGet(uint8_t index);
|
|
void smsOutboxClear(void);
|
|
void smsOutboxAdd(uint32_t dstId, bool isPrivate, const char *text);
|
|
|
|
// Most recently received message, or NULL when nothing has been received yet.
|
|
""", 1)
|
|
open(p, "w").write(s)
|
|
print("sms.h: storage API declared")
|
|
|
|
# ------------------------------------------------------------------ source
|
|
p = W + "/source/functions/sms.c"
|
|
s = open(p).read()
|
|
if "smsInboxCount" in s:
|
|
print("sms.c: already has storage")
|
|
raise SystemExit(0)
|
|
|
|
a = "static smsMessage_t latest;\n"
|
|
assert a in s
|
|
s = s.replace(a, a + """
|
|
// Message folders. Index 0 is always the newest; adding shifts the rest down.
|
|
static smsMessage_t inbox[SMS_INBOX_SIZE];
|
|
static uint8_t inboxCount = 0;
|
|
static smsMessage_t outbox[SMS_OUTBOX_SIZE];
|
|
static uint8_t outboxCount = 0;
|
|
""", 1)
|
|
|
|
# clear folders on init
|
|
s = s.replace("\tmemset(&latest, 0, sizeof(latest));\n",
|
|
"\tmemset(&latest, 0, sizeof(latest));\n"
|
|
"\tinboxCount = 0;\n"
|
|
"\toutboxCount = 0;\n", 1)
|
|
|
|
# store a completed message into the inbox
|
|
a = "\thaveMessage = (t > 0);\n"
|
|
assert a in s, "completion point not found"
|
|
s = s.replace(a, """ if (t > 0)
|
|
{
|
|
// Newest first: shift the existing entries down, dropping the oldest if full.
|
|
for (int8_t i = (int8_t)((inboxCount < SMS_INBOX_SIZE) ? inboxCount : (SMS_INBOX_SIZE - 1)); i > 0; i--)
|
|
{
|
|
inbox[i] = inbox[i - 1];
|
|
}
|
|
|
|
inbox[0] = latest;
|
|
|
|
if (inboxCount < SMS_INBOX_SIZE)
|
|
{
|
|
inboxCount++;
|
|
}
|
|
}
|
|
|
|
""" + a, 1)
|
|
|
|
s += """
|
|
|
|
uint8_t smsInboxCount(void)
|
|
{
|
|
return inboxCount;
|
|
}
|
|
|
|
const smsMessage_t *smsInboxGet(uint8_t index)
|
|
{
|
|
return ((index < inboxCount) ? &inbox[index] : NULL);
|
|
}
|
|
|
|
void smsInboxClear(void)
|
|
{
|
|
inboxCount = 0;
|
|
unread = false;
|
|
haveMessage = false;
|
|
}
|
|
|
|
uint8_t smsInboxUnreadCount(void)
|
|
{
|
|
uint8_t n = 0;
|
|
|
|
for (uint8_t i = 0; i < inboxCount; i++)
|
|
{
|
|
if (inbox[i].unread)
|
|
{
|
|
n++;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
uint8_t smsOutboxCount(void)
|
|
{
|
|
return outboxCount;
|
|
}
|
|
|
|
const smsMessage_t *smsOutboxGet(uint8_t index)
|
|
{
|
|
return ((index < outboxCount) ? &outbox[index] : NULL);
|
|
}
|
|
|
|
void smsOutboxClear(void)
|
|
{
|
|
outboxCount = 0;
|
|
}
|
|
|
|
void smsOutboxAdd(uint32_t dstId, bool isPrivate, const char *text)
|
|
{
|
|
for (int8_t i = (int8_t)((outboxCount < SMS_OUTBOX_SIZE) ? outboxCount : (SMS_OUTBOX_SIZE - 1)); i > 0; i--)
|
|
{
|
|
outbox[i] = outbox[i - 1];
|
|
}
|
|
|
|
memset(&outbox[0], 0, sizeof(smsMessage_t));
|
|
outbox[0].dstId = dstId;
|
|
outbox[0].isPrivate = isPrivate;
|
|
outbox[0].unread = false;
|
|
strncpy(outbox[0].text, text, SMS_MAX_TEXT_LENGTH);
|
|
outbox[0].text[SMS_MAX_TEXT_LENGTH] = '\\0';
|
|
|
|
if (outboxCount < SMS_OUTBOX_SIZE)
|
|
{
|
|
outboxCount++;
|
|
}
|
|
}
|
|
"""
|
|
|
|
open(p, "w").write(s)
|
|
print("sms.c: inbox/outbox storage added")
|