esp32/main/main.c
raw ยท 4990 bytes
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "esp_err.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_gap.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "services/gap/ble_svc_gap.h"
#define DEVICE_NAME "homekey-reader"
#define ADV_DURATION_MS 2000
/*
* Canonical UUID:
* 7b1e0001-7b1e-4a11-9abc-0123456789ab
*
* BLE advertising puts 128-bit UUIDs on the wire least-significant byte first.
*/
static const uint8_t service_uuid_le[16] = {
0xab, 0x89, 0x67, 0x45,
0x23, 0x01, 0xbc, 0x9a,
0x11, 0x4a, 0x1e, 0x7b,
0x01, 0x00, 0x1e, 0x7b,
};
static const char *TAG = "homekey-reader";
static uint8_t own_addr_type;
static uint16_t mock_seq;
static void start_advertising(void);
static int gap_event(struct ble_gap_event *event, void *arg)
{
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
if (event->connect.status == 0) {
ESP_LOGI(TAG, "BLE central connected, handle=%u",
event->connect.conn_handle);
} else {
ESP_LOGW(TAG, "BLE connection failed, status=%d",
event->connect.status);
start_advertising();
}
return 0;
case BLE_GAP_EVENT_DISCONNECT:
ESP_LOGI(TAG, "BLE central disconnected, reason=%d",
event->disconnect.reason);
start_advertising();
return 0;
case BLE_GAP_EVENT_ADV_COMPLETE:
/*
* Change the sequence number so Home Assistant sees changing
* service data instead of deduplicating identical advertisements.
*/
mock_seq++;
start_advertising();
return 0;
default:
return 0;
}
}
static void build_adv_data(uint8_t adv[29])
{
size_t p = 0;
/* Flags AD structure: general discoverable, BR/EDR not supported. */
adv[p++] = 0x02;
adv[p++] = 0x01;
adv[p++] = 0x06;
/*
* 128-bit Service Data AD structure (type 0x21):
*
* UUID[16]
* version[1] = 1
* type[1] = 1 (mock PN532 tag)
* seq[2] = little endian
* data[4] = fake NFCID1 / UID: DE:AD:BE:EF
*
* AD length is 1 byte type + 16 byte UUID + 8 byte payload = 25.
*/
adv[p++] = 25;
adv[p++] = 0x21;
memcpy(&adv[p], service_uuid_le, sizeof(service_uuid_le));
p += sizeof(service_uuid_le);
adv[p++] = 1; /* protocol version */
adv[p++] = 1; /* message type: mock PN532 tag */
adv[p++] = (uint8_t)(mock_seq & 0xff);
adv[p++] = (uint8_t)(mock_seq >> 8);
adv[p++] = 0xde;
adv[p++] = 0xad;
adv[p++] = 0xbe;
adv[p++] = 0xef;
assert(p == 29);
}
static void start_advertising(void)
{
uint8_t adv[29];
struct ble_gap_adv_params params = {0};
int rc;
build_adv_data(adv);
rc = ble_gap_adv_set_data(adv, sizeof(adv));
if (rc != 0) {
ESP_LOGE(TAG, "ble_gap_adv_set_data failed: %d", rc);
return;
}
params.conn_mode = BLE_GAP_CONN_MODE_UND;
params.disc_mode = BLE_GAP_DISC_MODE_GEN;
params.itvl_min = BLE_GAP_ADV_ITVL_MS(250);
params.itvl_max = BLE_GAP_ADV_ITVL_MS(300);
rc = ble_gap_adv_start(
own_addr_type,
NULL,
ADV_DURATION_MS,
¶ms,
gap_event,
NULL
);
if (rc != 0) {
ESP_LOGE(TAG, "ble_gap_adv_start failed: %d", rc);
return;
}
ESP_LOGI(TAG,
"advertising mock PN532 packet: seq=%u uid=DE:AD:BE:EF",
mock_seq);
}
static void on_reset(int reason)
{
ESP_LOGE(TAG, "NimBLE reset, reason=%d", reason);
}
static void on_sync(void)
{
int rc;
uint8_t addr[6];
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
rc = ble_hs_id_infer_auto(0, &own_addr_type);
assert(rc == 0);
rc = ble_hs_id_copy_addr(own_addr_type, addr, NULL);
assert(rc == 0);
ESP_LOGI(TAG,
"BLE address %02X:%02X:%02X:%02X:%02X:%02X",
addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
start_advertising();
}
static void host_task(void *param)
{
ESP_LOGI(TAG, "NimBLE host started");
nimble_port_run();
nimble_port_freertos_deinit();
}
void app_main(void)
{
esp_err_t err;
int rc;
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES ||
err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
err = nimble_port_init();
if (err != ESP_OK) {
ESP_LOGE(TAG, "nimble_port_init failed: %s", esp_err_to_name(err));
return;
}
ble_hs_cfg.reset_cb = on_reset;
ble_hs_cfg.sync_cb = on_sync;
ble_svc_gap_init();
rc = ble_svc_gap_device_name_set(DEVICE_NAME);
assert(rc == 0);
ESP_LOGI(TAG, "starting BLE mock PN532 transmitter");
nimble_port_freertos_init(host_task);
}