mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-20 17:22:01 +00:00
142 lines
5.7 KiB
Python
142 lines
5.7 KiB
Python
"""Apply nRF52 Bluefruit fixes in private build copies of framework sources.
|
|
|
|
Keep bonded CCCD persistence enabled, including Full Companions. The global
|
|
SoftDeviceSvcCompat.h guard protects the framework's system-attribute queries
|
|
from LTO miscompilation. The previous Full-only RAM workaround lost client
|
|
notification subscriptions after reboot while retaining the pairing keys.
|
|
Keep the RAM cache as a warm reconnect optimization, with the framework's
|
|
persistent bond record as the cold boot fallback.
|
|
Patch a private build copy; never edit PlatformIO's shared framework cache.
|
|
With the pinned GCC 14/LTO toolchain, the optimized Bluefruit.begin() fails
|
|
on the RAK4631 repeater: S140 rejects a valid single-peripheral role request
|
|
with NRF_ERROR_RESOURCES. The unoptimized method starts DFU successfully.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
OLD_SAVE = """ {
|
|
conn->saveCccd();
|
|
}
|
|
"""
|
|
FIXED_SAVE = """ {
|
|
// SoftDeviceSvcCompat.h protects system-attribute query side effects.
|
|
conn->saveCccd();
|
|
}
|
|
"""
|
|
OLD_LOAD = " if ( !loadCccd() ) sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0);\n"
|
|
FIXED_LOAD = """#if defined(COMPANION_RADIO_FULL) && COMPANION_RADIO_FULL
|
|
if ( !mesh_nrf52_restore_ram_cccd(_conn_hdl, &_bond_id_addr) &&
|
|
!loadCccd() )
|
|
{
|
|
sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0);
|
|
}
|
|
#else
|
|
if ( !loadCccd() ) sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0);
|
|
#endif
|
|
"""
|
|
OLD_CONNECTION_INCLUDE = '#include "bluefruit.h"\n'
|
|
FIXED_CONNECTION_INCLUDE = """#include "bluefruit.h"
|
|
|
|
#if defined(COMPANION_RADIO_FULL) && COMPANION_RADIO_FULL
|
|
bool mesh_nrf52_restore_ram_cccd(uint16_t conn_handle,
|
|
const ble_gap_addr_t* peer);
|
|
#endif
|
|
"""
|
|
OLD_BEGIN = "bool AdafruitBluefruit::begin(uint8_t prph_count, uint8_t central_count)"
|
|
FIXED_BEGIN = (
|
|
'bool __attribute__((noinline, optimize("O0"))) '
|
|
'AdafruitBluefruit::begin(uint8_t prph_count, uint8_t central_count)'
|
|
)
|
|
|
|
|
|
def patched_source(source):
|
|
source = source.replace("\r\n", "\n")
|
|
if FIXED_SAVE in source and OLD_SAVE not in source:
|
|
return source
|
|
if source.count(OLD_SAVE) != 1:
|
|
raise RuntimeError(
|
|
"nRF52 BLE CCCD fix: unrecognized framework source; review before building"
|
|
)
|
|
return source.replace(OLD_SAVE, FIXED_SAVE)
|
|
|
|
|
|
def patched_connection_source(source):
|
|
source = source.replace("\r\n", "\n")
|
|
if FIXED_LOAD in source and FIXED_CONNECTION_INCLUDE in source:
|
|
return source
|
|
if source.count(OLD_LOAD) != 1 or source.count(OLD_CONNECTION_INCLUDE) != 1:
|
|
raise RuntimeError(
|
|
"nRF52 BLE CCCD fix: unrecognized BLEConnection source; review before building"
|
|
)
|
|
return source.replace(OLD_CONNECTION_INCLUDE, FIXED_CONNECTION_INCLUDE).replace(
|
|
OLD_LOAD, FIXED_LOAD
|
|
)
|
|
|
|
|
|
def patched_bluefruit_source(source):
|
|
source = source.replace("\r\n", "\n")
|
|
if FIXED_BEGIN in source and OLD_BEGIN not in source:
|
|
return source
|
|
if source.count(OLD_BEGIN) != 1:
|
|
raise RuntimeError(
|
|
"nRF52 BLE startup fix: unrecognized framework source; review before building"
|
|
)
|
|
return source.replace(OLD_BEGIN, FIXED_BEGIN)
|
|
|
|
|
|
def patched_trace_source(source):
|
|
"""Bracket real BLE dispatch in diagnostic builds, including stuck handlers."""
|
|
include = '#include "bluefruit.h"\n'
|
|
entry = 'void AdafruitBluefruit::_ble_handler(ble_evt_t* evt)\n{\n'
|
|
exit_marker = ' if (_event_cb) _event_cb(evt);\n'
|
|
marker = '// MeshCore diagnostic dispatch trace'
|
|
if marker in source:
|
|
return source
|
|
if any(source.count(value) != 1 for value in (include, entry, exit_marker)):
|
|
raise RuntimeError("nRF52 BLE trace: unrecognized event dispatcher")
|
|
source = source.replace(include, include + '''
|
|
#if defined(MESH_NRF52_BLE_TRACE) && MESH_NRF52_BLE_TRACE
|
|
#include <helpers/nrf52/BleDebugTrace.h>
|
|
#endif
|
|
''')
|
|
source = source.replace(entry, entry + ''' // MeshCore diagnostic dispatch trace
|
|
#if defined(MESH_NRF52_BLE_TRACE) && MESH_NRF52_BLE_TRACE
|
|
meshBleTraceDispatchEnter(evt->header.evt_id, evt->evt.common_evt.conn_handle);
|
|
#endif
|
|
''')
|
|
return source.replace(exit_marker, exit_marker + '''#if defined(MESH_NRF52_BLE_TRACE) && MESH_NRF52_BLE_TRACE
|
|
meshBleTraceDispatchExit(evt->header.evt_id, evt->evt.common_evt.conn_handle);
|
|
#endif
|
|
''')
|
|
|
|
|
|
def replace_framework_source(build_env, node):
|
|
source = Path(node.srcnode().get_abspath())
|
|
if source.name not in ("BLEGatt.cpp", "BLEConnection.cpp", "bluefruit.cpp") or source.parent.name != "src":
|
|
return node
|
|
original = source.read_text(encoding="utf-8")
|
|
if source.name == "BLEGatt.cpp":
|
|
patched = patched_source(original)
|
|
elif source.name == "BLEConnection.cpp":
|
|
patched = patched_connection_source(original)
|
|
else:
|
|
patched = patched_bluefruit_source(original)
|
|
if "MESH_NRF52_BLE_TRACE" in str(build_env.get("CPPDEFINES", [])):
|
|
patched = patched_trace_source(patched)
|
|
build_env.AppendUnique(CPPPATH=[build_env.subst("$PROJECT_DIR/src")])
|
|
build_env.AppendUnique(CPPPATH=[str(source.parent)])
|
|
destination = Path(build_env.subst("$BUILD_DIR")) / "patched-nrf52-ble" / source.name
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
if not destination.exists() or destination.read_text(encoding="utf-8") != patched:
|
|
destination.write_text(patched, encoding="utf-8")
|
|
print(f"nRF52 BLE: private framework fix in {source.name}")
|
|
return build_env.File(str(destination))
|
|
|
|
|
|
if "Import" in globals():
|
|
Import("env")
|
|
env.AddBuildMiddleware(replace_framework_source, "*BLEGatt.cpp")
|
|
env.AddBuildMiddleware(replace_framework_source, "*BLEConnection.cpp")
|
|
env.AddBuildMiddleware(replace_framework_source, "*bluefruit.cpp")
|