#!/usr/bin/env python3 """Expose the SMS diagnostics through a RAM window that can be read over USB. Drawing counters on the screen turned out to be unreliable: the notification is overwritten by the normal screen redraw, so a screenshot usually shows nothing even when reception is happening. Instead the counters are mirrored into the tail of the raw audio buffer, which the CPS protocol can read out at any moment (area 7). Layout at rawBuffer[2376..2399]: 'S' 'M' 'S' 'D' magic, so a stale buffer cannot be mistaken for data u16 bursts data bursts handed to the assembler u16 headers data headers parsed u16 assembled messages assembled completely u16 lastBlocks block count announced by the last header u16 collected blocks collected for the message in progress u16 state 0 = idle, 1 = collecting u16 textLen length of the last extracted text """ W = "/home/viktor/ogd77rel/uv_src/OpenGD77_MDUV380_DM1701_20260130/MDUV380_firmware/application" p = W + "/source/functions/sms.c" s = open(p).read() if "SMS_DIAG_OFFSET" in s: print("already patched") raise SystemExit(0) s = s.replace('#include "functions/ticks.h"\n', '#include "functions/ticks.h"\n#include "functions/sound.h"\n', 1) anchor = "void smsInit(void)\n" assert anchor in s helper = """// Diagnostics mirror: the tail of the raw audio buffer is readable over USB (CPS area 7), // which is far more dependable than trying to keep text on the screen. #define SMS_DIAG_OFFSET 2376 static void smsDiagPublish(void) { volatile uint8_t *d = &audioAndHotspotDataBuffer.rawBuffer[SMS_DIAG_OFFSET]; uint16_t values[7]; values[0] = diagBursts; values[1] = diagHeaders; values[2] = diagAssembled; values[3] = diagLastBlocks; values[4] = blocksCollected; values[5] = (uint16_t)rxState; values[6] = diagTextLen; d[0] = 'S'; d[1] = 'M'; d[2] = 'S'; d[3] = 'D'; for (uint8_t i = 0; i < 7; i++) { d[4 + (i * 2)] = (uint8_t)(values[i] & 0xFF); d[5 + (i * 2)] = (uint8_t)(values[i] >> 8); } } """ s = s.replace(anchor, helper + anchor, 1) # track the extracted text length too s = s.replace("static uint8_t diagLastBlocks = 0;\n", "static uint8_t diagLastBlocks = 0;\nstatic uint16_t diagTextLen = 0;\n", 1) s = s.replace("\tlatest.text[t] = '\\0';\n", "\tlatest.text[t] = '\\0';\n\tdiagTextLen = t;\n", 1) # publish on every tick, so a read over USB always sees the current state s = s.replace("void smsTick(void)\n{\n", "void smsTick(void)\n{\n\tsmsDiagPublish();\n\n", 1) open(p, "w").write(s) print("sms.c: diagnostics mirrored into the readable RAM window")