#!/usr/bin/env python3 """Leave modem mode when the USB host goes away, instead of after a fixed timeout. Stock firmware dropped out of hotspot mode if the host was quiet for 20 seconds, which made the radio unusable as a permanently attached modem - so that timeout was disabled on request. The side effect was that the radio then stayed a modem forever and had to be power cycled by hand after every test. This ties the exit to the actual USB connection state instead: while the host is present the radio stays a modem no matter how quiet it is, and as soon as the cable is pulled (or the host stops enumerating it) the radio returns to normal operation by itself. """ W = "/home/viktor/ogd77rel/uv_src/OpenGD77_MDUV380_DM1701_20260130/MDUV380_firmware/application" p = W + "/source/functions/hotspot.c" s = open(p).read() if "usbHostIsAttached" in s: print("already patched") raise SystemExit(0) # a small helper next to the other statics anchor = "static const uint32_t MMDVMHOST_TIMEOUT = MMDVMHOST_TIMEOUT_DISABLED;\n" assert anchor in s, "timeout constant not found" helper = anchor + """ // The USB device handle tells us whether a host is actually enumerating us. Losing that // is what "the computer went away" really means; host silence alone is not. extern USBD_HandleTypeDef hUsbDeviceFS; static bool usbHostIsAttached(void) { return (hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED); } """ s = s.replace(anchor, helper, 1) # make sure the USB device header is included if '#include "usb_device.h"' not in s: inc_anchor = '#include "functions/ticks.h"\n' assert inc_anchor in s, "include anchor missing" s = s.replace(inc_anchor, inc_anchor + '#include "usb_device.h"\n', 1) # both inactivity checks now also fire when the host has disconnected old = """ if ((MMDVMHOST_TIMEOUT != 0) && (nonVolatileSettings.hotspotType == HOTSPOT_TYPE_MMDVM) && ((ticksGetMillis() - mmdvmHostLastActiveTime) > MMDVMHOST_TIMEOUT)) """ new = """ if ((nonVolatileSettings.hotspotType == HOTSPOT_TYPE_MMDVM) && ((usbHostIsAttached() == false) || ((MMDVMHOST_TIMEOUT != 0) && ((ticksGetMillis() - mmdvmHostLastActiveTime) > MMDVMHOST_TIMEOUT)))) """ count = s.count(old) assert count == 2, "expected 2 inactivity checks, found %d" % count s = s.replace(old, new) open(p, "w").write(s) print("hotspot.c: modem mode now ends when the USB host disconnects (%d checks)" % count)