initial commit via gitinitshit

This commit is contained in:
2025-11-25 11:48:54 -07:00
commit 7346346920
20 changed files with 565 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "."
PRIV_REQUIRES nvs_flash bt ulp
)
+60
View File
@@ -0,0 +1,60 @@
menu "GoogleFindMyTools Config"
config ADVERTISEMENT_INTERVAL
int "Interval between advertisements in milliseconds"
default 10240
range 12 10240
help
Int number of milliseconds (ms) in between advertisements min 12 max 1240
config ADVERTISEMENT_INTERVAL_JITTER_MS
int "Max Jitter to add to Advertisement Interval in milliseconds"
default 0
range 0 500
help
Int number of milliseconds (ms) max jitter to add to advertisement interval min 0 max 2000
config ADVERTISEMENT_KEY
string "Your Advertisement Key"
default ""
help
Your advertisement key, see https://github.com/leonboe1/GoogleFindMyTools
config DEVICE_NAME
string "BLE Device Name"
default "PrincesiPiTracker"
help
The Bluetooth device name that will be broadcasted.
config TAG
string "Logging Tag"
default "PrincessPiTracker"
help
The tag used in logging messages.
config RANDOM_MAC_ADDRESS
bool "Use Random MAC Address"
default n
help
Enable this option to use a random MAC address for BLE advertising instead of the public MAC address.
config DEEP_SLEEP_BURST_MODE
bool "Enable Deep Sleep Burst Mode"
default n
help
Enable this option to wake up, send multiple advertisements in a burst, then go back to deep sleep.
config DEEP_SLEEP_BURST_COUNT
int "Number of Advertisements per Burst"
default 5
range 1 100
depends on DEEP_SLEEP_BURST_MODE
help
Int number of advertisements to send per burst min 1 max 100
config DEEP_SLEEP_DURATION_S
int "Deep Sleep Duration in seconds"
default 60
range 0 86400
depends on DEEP_SLEEP_BURST_MODE
help
Int number of seconds (s) to deep sleep between advertisement cycles min 0 max 86400 (24 hours)
endmenu
+5
View File
@@ -0,0 +1,5 @@
## IDF Component Manager Manifest File
dependencies:
## Required IDF version
idf:
version: ">=4.1.0"
+292
View File
@@ -0,0 +1,292 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <math.h> // for the round function
#include "esp_log.h" // For ESP_LOGI and other logging functions
#include "nvs_flash.h" // For NVS functions like nvs_flash_init
#include "esp_err.h" // For error handling
#if CONFIG_DEEP_SLEEP_BURST_MODE
#include "soc/soc_caps.h" // malloc and shit if lmao
#include "esp_sleep.h" // For deep sleep functions
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define DEEP_SLEEP_BURST_DELAY (CONFIG_DEEP_SLEEP_BURST_COUNT * CONFIG_ADVERTISEMENT_INTERVAL)
#define DEEP_SLEEP_BURST_DELAY_MICROS (CONFIG_DEEP_SLEEP_DURATION_S * 1000000)
#endif
// macro to round float to int
#define ROUND(x) ((int)((x) >= 0.0 ? floor((x) + 0.5) : ceil((x) - 0.5)))
// handle da minutes config and round to da nearest integer
#define ADVERTISE_INTERVAL_MIN ROUND((CONFIG_ADVERTISEMENT_INTERVAL / 0.625))
#define ADVERTISE_INTERVAL_MAX (ADVERTISE_INTERVAL_MIN + ROUND((CONFIG_ADVERTISEMENT_INTERVAL_JITTER_MS / 0.625)))
// repoting tag
#define TAG CONFIG_TAG
// module configs
//// esp32 classic
#if defined(CONFIG_IDF_TARGET_ESP32)
#include "esp_bt.h" // For esp_bt_controller_* functions
#include "esp_bt_main.h" // For esp_bluedroid_* functions
#include "esp_gap_ble_api.h"
//// esp32c3
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
#include "esp_nimble_hci.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "services/gap/ble_svc_gap.h"
//// esp32c6 and esp32s3
#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S3)
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "services/gap/ble_svc_gap.h"
//// unsupported
#else
#error "Unsupported target"
#endif
// RTC_SLOW_ATTR static struct timeval sleep_enter_time;
// This is the advertisement key / EID. Change it to your own EID.
const char *eid_string = CONFIG_ADVERTISEMENT_KEY;
// Find My Device Network (FMDN) advertisement
// Octet Value Description
// 0 0x02 Length
// 1 0x01 Flags data type value
// 2 0x06 Flags data
// 3 0x18 or 0x19 Length
// 4 0x16 Service data data type value
// 5 0xAA 16-bit service UUID
// 6 0xFE 16-bit service UUID
// 7 0x40 or 0x41 FMDN frame type with unwanted tracking protection mode indication
// 8..27 Random 20-byte ephemeral identifier
// 28 Hashed flags
uint8_t adv_raw_data[31] = {
0x02, // Length
0x01, // Flags data type value
0x06, // Flags data
0x19, // Length
0x16, // Service data data type value
0xAA, // 16-bit service UUID
0xFE, // 16-bit service UUID
0x41, // FMDN frame type with unwanted tracking protection mode indication
// 20-byte ephemeral identifier (inserted below)
// Hashed flags (implicitly initialized to 0)
};
// Function to convert a hex string into a byte array
void hex_string_to_bytes(const char *hex, uint8_t *bytes, size_t len) {
for (size_t i = 0; i < len; i++) {
sscanf(hex + 2 * i, "%2hhx", &bytes[i]);
}
}
// esp32c3, esp32c6, and esp32s3
#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S3)
// BLE advertising callback
static int ble_advertise_cb(struct ble_gap_event *event, void *arg) {
switch (event->type) {
case BLE_GAP_EVENT_ADV_COMPLETE:
ESP_LOGI(TAG, "Advertising completed");
break;
default:
break;
}
return 0;
}
// Set up and start advertising
static void ble_start_advertising(uint8_t *adv_raw_data, size_t adv_raw_data_len) {
struct ble_gap_adv_params adv_params = {
.conn_mode = BLE_GAP_CONN_MODE_NON,
.disc_mode = BLE_GAP_DISC_MODE_GEN,
// use calculated interval depending on config
.itvl_min = ADVERTISE_INTERVAL_MIN,
.itvl_max = ADVERTISE_INTERVAL_MAX,
// for testing purposes, use fixed 32 cycles as interval (20ms)
//// .itvl_min = 0x20,
//// .itvl_max = 0x20
};
// set name
ble_svc_gap_device_name_set(CONFIG_DEVICE_NAME);
// set da data
ble_gap_adv_set_data(adv_raw_data, adv_raw_data_len);
// Start advertising
#if CONFIG_RANDOM_MAC_ADDRESS
ESP_LOGI(TAG, "Using Random MAC Address for advertising");
ble_gap_adv_start(BLE_OWN_ADDR_RANDOM, NULL, BLE_HS_FOREVER, &adv_params, ble_advertise_cb, NULL);
#else
ESP_LOGI(TAG, "Using Public MAC Address for advertising");
ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params, ble_advertise_cb, NULL);
#endif
ESP_LOGI(TAG, "Started advertising with interval %d ms", CONFIG_ADVERTISEMENT_INTERVAL);
}
static void ble_host_task(void *param)
{
ESP_LOGI(TAG, "BLE Host Task Started");
// run advertisement
nimble_port_run();
nimble_port_freertos_deinit();
}
// Sync callback
static void on_sync(void) {
// Set device name
ble_svc_gap_device_name_set(CONFIG_DEVICE_NAME);
// Start advertising
ble_start_advertising(adv_raw_data, sizeof(adv_raw_data));
//print adv raw data
ESP_LOGI(TAG, "adv_raw_data: %s", adv_raw_data);
}
static void ble_init(void) {
ESP_LOGI(TAG, "Initializing BLE");
// 20-byte ephemeral identifier
uint8_t eid_bytes[20];
hex_string_to_bytes(eid_string, eid_bytes, 20);
memcpy(&adv_raw_data[8], eid_bytes, 20);
// Initialize NimBLE - ESP-IDF v5.3 style
ESP_ERROR_CHECK(nimble_port_init());
// Initialize the NimBLE host configuration
ble_hs_cfg.sync_cb = on_sync;
// Initialize GAP service
ble_svc_gap_init();
// Create host task
nimble_port_freertos_init(ble_host_task);
}
#if CONFIG_DEEP_SLEEP_BURST_MODE
static void ble_deinit(void) {
ESP_LOGI(TAG, "Deinitializing BLE");
nimble_port_stop();
nimble_port_deinit();
nimble_port_freertos_deinit();
}
static void deep_sleep_register_rtc_timer_wakeup(void) {
ESP_LOGI(TAG, "Woke up deep sleep, re-initializing BLE");
ble_init();
// const int wakeup_time_sec = CONFIG_DEEP_SLEEP_DURATION_S;
// ESP_LOGI(TAG, "Enabling timer wakeup, %ds\n", CONFIG_DEEP_SLEEP_DURATION_S);
// ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(DEEP_SLEEP_BURST_DELAY_MICROS));
}
static void deep_sleep_wait_to_sleep() {
vTaskDelay(pdMS_TO_TICKS(DEEP_SLEEP_BURST_DELAY));
ESP_LOGI(TAG, "Waited %d ms, preparing to enter deep sleep\n", DEEP_SLEEP_BURST_DELAY);
ESP_LOGI(TAG, "Deiniting BTLE before deep sleep");
ble_deinit();
ESP_LOGI(TAG, "Entering deep sleep\n\tDuration %d ms\n\tburst count %d\n\tburst delay %d ms\n", CONFIG_DEEP_SLEEP_DURATION_S * 1000, CONFIG_DEEP_SLEEP_BURST_COUNT,DEEP_SLEEP_BURST_DELAY);
ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(DEEP_SLEEP_BURST_DELAY_MICROS));
esp_deep_sleep_start();
}
#endif
#endif
void app_main() {
// validate eid_string length
const size_t length = strlen(eid_string);
if (length == 0) {
ESP_LOGE(TAG, "Advertisement Key is not set. Please set CONFIG_ADVERTISEMENT_KEY in the project configuration.");
return;
}
else if (length != 40) {
ESP_LOGE(TAG, "Invalid Advertisement Key length. It must be 40 hexadecimal characters (20 bytes) Length given: %d", length);
return;
}
// only show the key in debug mode
ESP_LOGD(TAG, "Advertisement Key (EID): \"%s\"\n", eid_string);
// interval infors
ESP_LOGI(TAG, "length: %d", length);
ESP_LOGI(TAG, "Advertisement Calculated Interval Cycles: %d cycles\n", ADVERTISE_INTERVAL_MIN);
ESP_LOGI(TAG, "Advertisement Interval Min: %d Milliseconds\n", CONFIG_ADVERTISEMENT_INTERVAL);
ESP_LOGI(TAG, "Advertisement Interval Max: %d Milliseconds (%d ms jitter)\n", CONFIG_ADVERTISEMENT_INTERVAL + CONFIG_ADVERTISEMENT_INTERVAL_JITTER_MS, CONFIG_ADVERTISEMENT_INTERVAL_JITTER_MS);
ESP_LOGI(TAG, "BLE Device Name: %s\n", CONFIG_DEVICE_NAME);
#if CONFIG_RANDOM_MAC_ADDRESS
ESP_LOGI(TAG, "Using Random MAC Address for advertising\n");
#else
ESP_LOGI(TAG, "Using Public MAC Address for advertising\n");
#endif
// Initialize NVS (required for BLE initialization)
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// esp32c3, esp32c6, and esp32s3
#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S3)
#if CONFIG_DEEP_SLEEP_BURST_MODE
// Initialize sleep wait task
ESP_LOGI(TAG, "Initializing slweep wait task");
xTaskCreate(deep_sleep_wait_to_sleep, "deep_sleep_wait_to_sleep", 4096, NULL, 6, NULL);
ESP_LOGI(TAG, "Initializing Timer Wakeup");
deep_sleep_register_rtc_timer_wakeup();
#else
ble_init();
#endif
// esp32 classic
#elif defined(CONFIG_IDF_TARGET_ESP32)
// Initialize Bluetooth controller
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
// Initialize Bluedroid stack
ESP_ERROR_CHECK(esp_bluedroid_init());
ESP_ERROR_CHECK(esp_bluedroid_enable());
// Set BLE TX power to 9 dBm
ESP_ERROR_CHECK(esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P9));
ESP_ERROR_CHECK(esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9));
ESP_LOGI(TAG, "Set BLE TX Power to 9 dBm");
ESP_ERROR_CHECK(esp_ble_gap_config_adv_data_raw(adv_raw_data, sizeof(adv_raw_data)));
// Configure advertisement parameters
esp_ble_adv_params_t adv_params = {
// change those if you want to save power
.adv_int_min = ADVERTISE_INTERVAL_MIN,
.adv_int_max = ADVERTISE_INTERVAL_MAX,
.adv_type = ADV_TYPE_NONCONN_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
// Start advertising
ESP_ERROR_CHECK(esp_ble_gap_start_advertising(&adv_params));
ESP_LOGI(TAG, "BLE advertising started.");
#endif
}