add legacy nordic DFU service

This commit is contained in:
liquidraver committed 2026-06-06 23:55:15 +02:00
1 parent ffe9ea652d
commit 9ef6774d6a
4 files changed
+85

No files matched your search

+11
View File
@@ -280,6 +280,17 @@ config ZEPHCORE_BLE_ADV_SLOW_INTERVAL
Advertising interval in 0.625ms units.
338 = 211.25ms (Apple-compliant, used after 60s fast window).
config ZEPHCORE_BLE_DFU
bool "Buttonless BLE DFU (legacy Nordic/Adafruit OTA jump)"
default y if SOC_SERIES_NRF52X || SOC_SERIES_NRF52
help
Register the legacy Nordic DFU service (00001530/00001531) in the
running companion app so a paired phone can trigger the jump into the
Adafruit bootloader's BLE OTA mode without pressing a button. On a write
of 0x01 to the control point the device sets the bootloader GPREGRET
magic (0xA8) and resets; the bootloader then advertises for DFU and the
phone's DFU tool reconnects to flash. nRF52 only.
endmenu # BLE Configuration
menu "Linux Companion Transport (native_sim)"
+61
View File
@@ -237,6 +237,67 @@ BT_GATT_SERVICE_DEFINE(secure_nus_svc,
NULL, secure_nus_rx_write, NULL),
);
#if IS_ENABLED(CONFIG_ZEPHCORE_BLE_DFU)
/* ========== Legacy Nordic/Adafruit buttonless DFU service ==========
*
* Mirrors Adafruit BLEDfu (Arduino MeshCore >=1.15.0) so the same DFU tools
* interoperate: a paired phone writes 0x01 to the control point and the device
* resets into the bootloader's BLE OTA mode. We use the *unbonded* OTA reset
* (GPREGRET 0xA8, same as `start ota`): the bootloader comes up as a fresh DFU
* target and the tool re-scans for it (the legacy buttonless flow). Adafruit's
* 0xB1 bonded-resume path needs SoftDevice peer-data enrollment we can't
* replicate on Zephyr, so the phone makes a fresh connection to the bootloader.
*/
static struct bt_uuid_128 dfu_svc_uuid = BT_UUID_INIT_128(
BT_UUID_128_ENCODE(0x00001530, 0x1212, 0xefde, 0x1523, 0x785feabcd123));
static struct bt_uuid_128 dfu_ctrl_uuid = BT_UUID_INIT_128(
BT_UUID_128_ENCODE(0x00001531, 0x1212, 0xefde, 0x1523, 0x785feabcd123));
static void dfu_jump_work_fn(struct k_work *work);
static K_WORK_DELAYABLE_DEFINE(dfu_jump_work, dfu_jump_work_fn);
static void dfu_jump_work_fn(struct k_work *work)
{
ARG_UNUSED(work);
if (ble_cbs && ble_cbs->on_dfu_request) {
ble_cbs->on_dfu_request(); /* sets GPREGRET + resets; never returns */
}
}
static ssize_t dfu_ctrl_write(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
{
ARG_UNUSED(conn);
ARG_UNUSED(attr);
ARG_UNUSED(offset);
ARG_UNUSED(flags);
/* Adafruit BLEDfu jump command: first byte 0x01 (1-2 byte write). */
if (len >= 1 && ((const uint8_t *)buf)[0] == 0x01) {
LOG_INF("buttonless DFU requested - rebooting to BLE OTA");
/* Defer so the ATT write response flushes and the DFU tool can
* arm its disconnect/rescan before we reset. */
k_work_schedule(&dfu_jump_work, K_MSEC(250));
}
return len;
}
static void dfu_ctrl_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
ARG_UNUSED(attr);
ARG_UNUSED(value);
}
BT_GATT_SERVICE_DEFINE(dfu_svc,
BT_GATT_PRIMARY_SERVICE(&dfu_svc_uuid),
BT_GATT_CHARACTERISTIC(&dfu_ctrl_uuid.uuid,
BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_WRITE_AUTHEN,
NULL, dfu_ctrl_write, NULL),
BT_GATT_CCC(dfu_ctrl_ccc_changed,
BT_GATT_PERM_READ_AUTHEN | BT_GATT_PERM_WRITE_AUTHEN),
);
#endif /* CONFIG_ZEPHCORE_BLE_DFU */
/* ========== Work items ========== */
static void tx_drain_work_fn(struct k_work *work);
+3
View File
@@ -27,6 +27,9 @@ struct ble_callbacks {
void (*on_connected)(void);
/* BLE disconnected */
void (*on_disconnected)(void);
/* Buttonless DFU control-point write — defer reboot into the
* bootloader's BLE OTA mode. May be NULL (feature disabled). */
void (*on_dfu_request)(void);
};
enum zephcore_iface {
+10
View File
@@ -241,11 +241,21 @@ static void ble_on_disconnected(void)
ui_notify(UI_EVENT_BLE_DISCONNECTED);
}
#if IS_ENABLED(CONFIG_ZEPHCORE_BLE_DFU)
static void ble_on_dfu_request(void)
{
mesh_reboot_to_ota_dfu(); /* GPREGRET 0xA8 + reset; never returns */
}
#endif
static const struct ble_callbacks ble_cbs = {
.on_rx_frame = ble_on_rx_frame,
.on_tx_idle = ble_on_tx_idle,
.on_connected = ble_on_connected,
.on_disconnected = ble_on_disconnected,
#if IS_ENABLED(CONFIG_ZEPHCORE_BLE_DFU)
.on_dfu_request = ble_on_dfu_request,
#endif
};
/* ========== Frame send/receive (mesh ↔ BLE/USB) ========== */