ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
ota_adafruit_ble.cpp
Go to the documentation of this file.
1#include "ota_adafruit_ble.h"
2
3#if defined(USE_ZEPHYR) && defined(USE_NRF52)
5#include "esphome/core/log.h"
6
7#include <cstring>
8#include <hal/nrf_power.h>
9#include <zephyr/bluetooth/gatt.h>
10
12
13ESPHOME_LOG_TAG(TAG, "adafruit_ble");
14
15// Written by the upload tool (dfu.py) to ask for a restart into the bootloader,
16// which then serves the DFU transfer. The bootloader only advertises its own DFU
17// service while it is in DFU mode, so this service is what identifies the
18// running application.
19static constexpr uint8_t DFU_TRIGGER_MAGIC[] = {'D', 'F', 'U'};
20// GPREGRET value the Adafruit nRF52 bootloader reads to enter OTA (BLE DFU) mode
21static constexpr uint8_t DFU_GPREGRET_OTA = 0xA8;
22
23// Matches the MCUmgr BLE transport default: a paired (authenticated) link once pairing is enabled
24#ifdef CONFIG_BT_SMP
25static constexpr uint16_t DFU_TRIGGER_PERM = BT_GATT_PERM_WRITE_AUTHEN;
26#else
27static constexpr uint16_t DFU_TRIGGER_PERM = BT_GATT_PERM_WRITE;
28#endif
29
30static OTAComponent *global_ota_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
31
32static ssize_t dfu_trigger_write(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len,
33 uint16_t offset, uint8_t flags) {
34 if (offset != 0) {
35 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
36 }
37 if (len != sizeof(DFU_TRIGGER_MAGIC) || memcmp(buf, DFU_TRIGGER_MAGIC, sizeof(DFU_TRIGGER_MAGIC)) != 0) {
38 return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
39 }
40 global_ota_component->request_dfu_mode();
41 return len;
42}
43
44// Registered by bt_enable(), which zephyr_ble_server calls during its setup.
46 dfu_trigger_svc,
47 BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xe5b10001, 0x9c3a, 0x4f5d, 0x8a1b,
48 0x2c3d4e5f6071))),
49 BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xe5b10002, 0x9c3a, 0x4f5d, 0x8a1b, 0x2c3d4e5f6071)),
50 BT_GATT_CHRC_WRITE, DFU_TRIGGER_PERM, nullptr, dfu_trigger_write, nullptr));
51
52OTAComponent::OTAComponent() { global_ota_component = this; }
53
55 // Restart from the main loop, so the OTA listeners run there and the write is answered first
56 this->defer([this]() {
57 ESP_LOGI(TAG, "DFU mode requested, restarting into the bootloader");
58#ifdef USE_OTA_STATE_LISTENER
59 this->notify_state_(ota::OTA_STARTED, 0.0f, 0);
60#endif
61 // NOLINTNEXTLINE(clang-analyzer-core.FixedAddressDereference) -- NRF_POWER is MMIO at a fixed address
62 NRF_POWER->GPREGRET = DFU_GPREGRET_OTA;
63 App.reboot();
64 });
65}
66
68 ESP_LOGCONFIG(TAG, "Over-The-Air Updates:\n"
69 " bootloader: Adafruit nRF52 (BLE DFU)");
70}
71
72} // namespace esphome::adafruit_ble
73#endif
void defer(const char *name, std::function< void()> &&f)
Defer a callback to the next loop() call with a const char* name.
void notify_state_(OTAState state, float progress, uint8_t error)
uint16_t flags
__int64 ssize_t
Definition httplib.h:178
BT_GATT_SERVICE_DEFINE(dfu_trigger_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xe5b10001, 0x9c3a, 0x4f5d, 0x8a1b, 0x2c3d4e5f6071))), BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xe5b10002, 0x9c3a, 0x4f5d, 0x8a1b, 0x2c3d4e5f6071)), BT_GATT_CHRC_WRITE, DFU_TRIGGER_PERM, nullptr, dfu_trigger_write, nullptr))
ESPHOME_LOG_TAG(TAG, "adafruit_ble")
const void size_t len
Definition hal.h:68
Application App
Global storage of Application pointer - only one Application can exist.