code cleanup
Some checks failed
ESP-IDF Build / build (esp32c6, release-v5.4) (push) Has been cancelled
ESP-IDF Build / build (esp32c6, release-v5.5) (push) Has been cancelled
ESP-IDF Build / build (esp32s3, release-v5.4) (push) Has been cancelled
ESP-IDF Build / build (esp32s3, release-v5.5) (push) Has been cancelled

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2025-12-20 20:41:55 +01:00
parent 387b9d4c65
commit e16cfbd03c
68 changed files with 927 additions and 74637 deletions

View File

@@ -0,0 +1,324 @@
#include "ble/ble_scanner.h"
#include "ble/ble_device.h"
#include "led_status.h"
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <host/ble_hs.h>
#include <host/util/util.h>
#include <nimble/nimble_port.h>
#include <nimble/nimble_port_freertos.h>
#include <services/gap/ble_svc_gap.h>
#include <stdint.h>
static const char *TAG = "ble_scanner";
// List of allowed manufacturer IDs
static const uint16_t ALLOWED_MANUFACTURERS[] = {
0xC0DE, // mars3142
};
static const size_t NUM_MANUFACTURERS = sizeof(ALLOWED_MANUFACTURERS) / sizeof(uint16_t);
static bool scanning = false;
static bool is_manufacturer_allowed(uint16_t company_id)
{
for (size_t i = 0; i < NUM_MANUFACTURERS; i++)
{
if (ALLOWED_MANUFACTURERS[i] == company_id)
{
return true;
}
}
return false;
}
static int ble_central_gap_event(struct ble_gap_event *event, void *arg);
/**
* Starts the BLE scan process.
*/
void start_scan(void)
{
led_behavior_t led_behavior = {
.on_time_ms = 200,
.off_time_ms = 200,
.color = {.red = 0, .green = 0, .blue = 50},
.index = 1,
.mode = LED_MODE_BLINK,
};
led_status_set_behavior(led_behavior);
struct ble_gap_disc_params disc_params = {
.filter_policy = 0,
.limited = 0,
.passive = 0,
.filter_duplicates = 1,
};
int32_t duration_ms = 10000; // 10 seconds
int rc = ble_gap_disc(BLE_OWN_ADDR_PUBLIC, duration_ms, &disc_params, ble_central_gap_event, NULL);
if (rc != 0)
{
ESP_LOGE(TAG, "Error starting scan; rc=%d", rc);
}
scanning = true;
}
#define MAX_DEVICES 40
static device_info_t devices[MAX_DEVICES];
static int device_count = 0;
// Helper function to find or create a device entry
static device_info_t *find_or_create_device(const ble_addr_t *addr)
{
// Search for existing device
for (int i = 0; i < device_count; i++)
{
if (memcmp(&devices[i].addr, addr, sizeof(ble_addr_t)) == 0)
{
return &devices[i];
}
}
// Add new device
if (device_count < MAX_DEVICES)
{
memset(&devices[device_count], 0, sizeof(device_info_t));
memcpy(&devices[device_count].addr, addr, sizeof(ble_addr_t));
devices[device_count].has_manufacturer = false;
devices[device_count].has_name = false;
strcpy(devices[device_count].name, "Unknown");
return &devices[device_count++];
}
return NULL;
}
static int ble_central_gap_event(struct ble_gap_event *event, void *arg)
{
struct ble_gap_disc_desc *disc;
struct ble_hs_adv_fields fields;
switch (event->type)
{
case BLE_GAP_EVENT_DISC: {
disc = &event->disc;
// Find or create device
device_info_t *device = find_or_create_device(&disc->addr);
if (device == NULL)
{
return 0;
}
// Update RSSI
device->rssi = disc->rssi;
// Parse advertising data
memset(&fields, 0, sizeof(fields));
ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data);
// Process manufacturer data
if (fields.mfg_data != NULL && fields.mfg_data_len >= 2)
{
uint16_t company_id = fields.mfg_data[0] | (fields.mfg_data[1] << 8);
device->manufacturer_id = company_id;
device->has_manufacturer = true;
// Store complete manufacturer data (incl. Company ID)
device->manufacturer_data_len = fields.mfg_data_len;
memcpy(device->manufacturer_data, fields.mfg_data, fields.mfg_data_len);
}
// Process name
if (fields.name != NULL && fields.name_len > 0)
{
size_t copy_len = fields.name_len < sizeof(device->name) - 1 ? fields.name_len : sizeof(device->name) - 1;
memcpy(device->name, fields.name, copy_len);
device->name[copy_len] = '\0';
device->has_name = true;
}
// Process 16-bit Service UUIDs
if (fields.uuids16 != NULL && fields.num_uuids16 > 0)
{
for (int i = 0; i < fields.num_uuids16 && device->service_uuids_16_count < 10; i++)
{
// Check if UUID already exists
bool exists = false;
for (int j = 0; j < device->service_uuids_16_count; j++)
{
if (device->service_uuids_16[j] == fields.uuids16[i].value)
{
exists = true;
break;
}
}
if (!exists)
{
device->service_uuids_16[device->service_uuids_16_count++] = fields.uuids16[i].value;
}
}
}
// Process 128-bit Service UUIDs
if (fields.uuids128 != NULL && fields.num_uuids128 > 0)
{
for (int i = 0; i < fields.num_uuids128 && device->service_uuids_128_count < 5; i++)
{
// Check if UUID already exists
bool exists = false;
for (int j = 0; j < device->service_uuids_128_count; j++)
{
if (memcmp(&device->service_uuids_128[j], &fields.uuids128[i], sizeof(ble_uuid128_t)) == 0)
{
exists = true;
break;
}
}
if (!exists)
{
memcpy(&device->service_uuids_128[device->service_uuids_128_count++], &fields.uuids128[i],
sizeof(ble_uuid128_t));
}
}
}
// Check if we have all data and the device is allowed
if (device->has_name && device->has_manufacturer && is_manufacturer_allowed(device->manufacturer_id))
{
ESP_LOGI(TAG, "*** Allowed device found ***");
ESP_LOGI(TAG, " Name: %s", device->name);
ESP_LOGI(TAG, " Address: %02X:%02X:%02X:%02X:%02X:%02X", device->addr.val[5], device->addr.val[4],
device->addr.val[3], device->addr.val[2], device->addr.val[1], device->addr.val[0]);
ESP_LOGI(TAG, " Manufacturer ID: 0x%04X", device->manufacturer_id);
ESP_LOGI(TAG, " RSSI: %d dBm", device->rssi);
// Print Service UUIDs
if (device->service_uuids_16_count > 0)
{
ESP_LOGI(TAG, " 16-bit Service UUIDs (%d):", device->service_uuids_16_count);
for (int i = 0; i < device->service_uuids_16_count; i++)
{
const char *name = "";
// Known Service UUIDs
switch (device->service_uuids_16[i])
{
case 0x180A:
name = " (Device Information)";
break;
case 0x180F:
name = " (Battery Service)";
break;
case 0x1801:
name = " (Generic Attribute)";
break;
case 0x1800:
name = " (Generic Access)";
break;
case 0x181A:
name = " (Environmental Sensing)";
break;
default:
if (device->service_uuids_16[i] >= 0xA000)
{
name = " (Custom)";
}
break;
}
ESP_LOGI(TAG, " - 0x%04X%s", device->service_uuids_16[i], name);
}
}
if (device->service_uuids_128_count > 0)
{
ESP_LOGI(TAG, " 128-bit Service UUIDs (%d):", device->service_uuids_128_count);
for (int i = 0; i < device->service_uuids_128_count; i++)
{
char uuid_str[37]; // UUID string format
snprintf(uuid_str, sizeof(uuid_str),
"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
device->service_uuids_128[i].value[15], device->service_uuids_128[i].value[14],
device->service_uuids_128[i].value[13], device->service_uuids_128[i].value[12],
device->service_uuids_128[i].value[11], device->service_uuids_128[i].value[10],
device->service_uuids_128[i].value[9], device->service_uuids_128[i].value[8],
device->service_uuids_128[i].value[7], device->service_uuids_128[i].value[6],
device->service_uuids_128[i].value[5], device->service_uuids_128[i].value[4],
device->service_uuids_128[i].value[3], device->service_uuids_128[i].value[2],
device->service_uuids_128[i].value[1], device->service_uuids_128[i].value[0]);
ESP_LOGI(TAG, " - %s", uuid_str);
}
}
// Print manufacturer data (without Company ID, i.e., from byte 2)
if (device->manufacturer_data_len > 2)
{
int payload_len = device->manufacturer_data_len - 2;
ESP_LOGI(TAG, " Manufacturer Data (%d bytes):", payload_len);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, &device->manufacturer_data[2], payload_len, ESP_LOG_INFO);
// Print data byte by byte for better readability
ESP_LOGI(TAG, " Data interpretation:");
for (int i = 0; i < payload_len; i++)
{
ESP_LOGI(TAG, " - Byte %d: 0x%02X (%d)", i, device->manufacturer_data[i + 2],
device->manufacturer_data[i + 2]);
}
// Optional: Interpret data as 16-bit values (if the number of bytes is even)
if (payload_len >= 2 && (payload_len % 2 == 0))
{
ESP_LOGI(TAG, " As 16-bit values:");
for (int i = 0; i < payload_len; i += 2)
{
uint16_t value = device->manufacturer_data[i + 2] | (device->manufacturer_data[i + 3] << 8);
ESP_LOGI(TAG, " - Word %d: 0x%04X (%d)", i / 2, value, value);
}
}
}
else
{
ESP_LOGI(TAG, " No manufacturer payload data");
}
}
return 0;
}
case BLE_GAP_EVENT_DISC_COMPLETE: {
led_behavior_t led_behavior = {
.index = 1,
.mode = LED_MODE_OFF,
};
led_status_set_behavior(led_behavior);
ESP_LOGI(TAG, "Discovery complete");
scanning = false;
return 0;
}
default:
break;
}
return 0;
}
device_info_t *get_device(int index)
{
if (index < 0 || index >= device_count || !is_manufacturer_allowed(devices[index].manufacturer_id))
{
return NULL;
}
return &devices[index];
}
int get_device_count(void)
{
if (!scanning)
{
return device_count;
}
return 0;
}