171 lines
5.9 KiB
C
Executable File
171 lines
5.9 KiB
C
Executable File
/*
|
|
* noise_radar.c -- BLE Device Radar Scanner module
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*
|
|
* v1.5: Restored from v1.3. Uses BlueZ HCI inquiry (with RSSI when
|
|
* available, standard inquiry fallback) to discover BLE devices.
|
|
* Displays up to 4 nodes with RSSI-based heatmap coloring on a
|
|
* 19-cell hexagonal grid.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/socket.h>
|
|
#include <bluetooth/bluetooth.h>
|
|
#include <bluetooth/hci.h>
|
|
#include <bluetooth/hci_lib.h>
|
|
#include <linux/input.h>
|
|
#include "h2_ui.h"
|
|
#include "log_manager.h"
|
|
|
|
#define MAX_CELLS 19
|
|
#define SCAN_INTERVAL 8
|
|
#define RSSI_UNKNOWN 0
|
|
|
|
typedef struct {
|
|
bdaddr_t addr;
|
|
int8_t rssi;
|
|
uint8_t active;
|
|
} ble_node_t;
|
|
|
|
static ble_node_t nodes[MAX_CELLS];
|
|
static int node_count;
|
|
|
|
static int scan_ble_nodes(int dev_id) {
|
|
int max_rsp = 255, len = 8, flags = IREQ_CACHE_FLUSH;
|
|
int num_rsp, new_count = 0;
|
|
|
|
inquiry_info_with_rssi *rssi_info = NULL;
|
|
num_rsp = hci_inquiry_with_rssi(dev_id, len, max_rsp, NULL, &rssi_info, flags);
|
|
if (num_rsp >= 0) {
|
|
for (int i = 0; i < num_rsp && new_count < MAX_CELLS; i++) {
|
|
memcpy(&nodes[new_count].addr, &rssi_info[i].bdaddr, sizeof(bdaddr_t));
|
|
nodes[new_count].rssi = rssi_info[i].rssi;
|
|
nodes[new_count].active = 1;
|
|
new_count++;
|
|
}
|
|
free(rssi_info);
|
|
return new_count;
|
|
}
|
|
|
|
inquiry_info *std_info = NULL;
|
|
num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &std_info, flags);
|
|
if (num_rsp < 0) return num_rsp;
|
|
for (int i = 0; i < num_rsp && new_count < MAX_CELLS; i++) {
|
|
memcpy(&nodes[new_count].addr, &std_info[i].bdaddr, sizeof(bdaddr_t));
|
|
nodes[new_count].rssi = RSSI_UNKNOWN;
|
|
nodes[new_count].active = 1;
|
|
new_count++;
|
|
}
|
|
free(std_info);
|
|
return new_count;
|
|
}
|
|
|
|
static lv_color_t rssi_to_color(int8_t rssi) {
|
|
if (rssi == RSSI_UNKNOWN) return COLOR_MUTED;
|
|
if (rssi > -50) return lv_color_make(50, 255, 100);
|
|
if (rssi > -70) return COLOR_ACCENT;
|
|
return COLOR_PRIMARY;
|
|
}
|
|
|
|
static void format_rssi(char *buf, size_t len, int8_t rssi) {
|
|
if (rssi == RSSI_UNKNOWN) snprintf(buf, len, "rssi:?");
|
|
else snprintf(buf, len, "rssi:%d", (int)rssi);
|
|
}
|
|
|
|
int main(void) {
|
|
init_h2_graphics_runtime("BLE RADAR SCANNER");
|
|
LOG_INF("radar module started");
|
|
|
|
lv_obj_t *scr = lv_scr_act();
|
|
|
|
lv_obj_t *title = lv_label_create(scr);
|
|
lv_label_set_text(title, "BLE DEVICE RADAR");
|
|
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 10);
|
|
lv_obj_set_style_text_color(title, COLOR_PRIMARY, LV_PART_MAIN);
|
|
|
|
lv_obj_t *console = lv_label_create(scr);
|
|
lv_obj_set_width(console, 300);
|
|
lv_label_set_long_mode(console, LV_LABEL_LONG_WRAP);
|
|
lv_obj_align(console, LV_ALIGN_CENTER, 0, 20);
|
|
|
|
lv_obj_t *hex_grid[MAX_CELLS];
|
|
int start_x = 160, start_y = 120, spacing_x = 32, spacing_y = 28;
|
|
int cell_count = 0;
|
|
|
|
for (int r = -2; r <= 2; r++) {
|
|
int max_c = 5 - abs(r);
|
|
for (int c = 0; c < max_c; c++) {
|
|
if (cell_count >= MAX_CELLS) break;
|
|
hex_grid[cell_count] = lv_obj_create(scr);
|
|
lv_obj_set_size(hex_grid[cell_count], 26, 26);
|
|
lv_obj_set_style_radius(hex_grid[cell_count], LV_RADIUS_CIRCLE, LV_PART_MAIN);
|
|
int px = start_x + (c * spacing_x) - ((max_c - 1) * spacing_x / 2);
|
|
int py = start_y + (r * spacing_y);
|
|
lv_obj_set_pos(hex_grid[cell_count], px - 13, py - 13);
|
|
lv_obj_set_style_bg_color(hex_grid[cell_count], lv_color_make(30, 40, 50), LV_PART_MAIN);
|
|
cell_count++;
|
|
}
|
|
}
|
|
|
|
lv_obj_t *status = lv_label_create(scr);
|
|
lv_obj_align(status, LV_ALIGN_BOTTOM_MID, 0, -8);
|
|
lv_obj_set_style_text_color(status, COLOR_MUTED, LV_PART_MAIN);
|
|
|
|
int dev_id = hci_get_route(NULL);
|
|
int h_fd = (dev_id >= 0) ? hci_open_dev(dev_id) : -1;
|
|
if (h_fd < 0) LOG_WRN("cannot open HCI device");
|
|
int scan_tick = 0;
|
|
|
|
int input_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK);
|
|
struct input_event ev;
|
|
|
|
while (1) {
|
|
lv_timer_handler();
|
|
|
|
scan_tick++;
|
|
if (scan_tick >= SCAN_INTERVAL && h_fd >= 0) {
|
|
scan_tick = 0;
|
|
memset(nodes, 0, sizeof(nodes));
|
|
node_count = scan_ble_nodes(dev_id);
|
|
|
|
for (int i = 0; i < cell_count; i++)
|
|
lv_obj_set_style_bg_color(hex_grid[i], lv_color_make(30, 40, 50), LV_PART_MAIN);
|
|
for (int i = 0; i < node_count && i < cell_count; i++)
|
|
lv_obj_set_style_bg_color(hex_grid[i], rssi_to_color(nodes[i].rssi), LV_PART_MAIN);
|
|
|
|
char addr_str[24], buf[256];
|
|
buf[0] = '\0';
|
|
for (int i = 0; i < node_count && i < 4; i++) {
|
|
ba2str(&nodes[i].addr, addr_str);
|
|
char rssi_str[16];
|
|
format_rssi(rssi_str, sizeof(rssi_str), nodes[i].rssi);
|
|
char line[64];
|
|
snprintf(line, sizeof(line), "%s %s\n", addr_str, rssi_str);
|
|
strlcat(buf, line, sizeof(buf));
|
|
}
|
|
if (node_count == 0) snprintf(buf, sizeof(buf), "No BLE devices in range");
|
|
lv_label_set_text(console, buf);
|
|
|
|
char count_str[48];
|
|
if (node_count > 0 && nodes[0].rssi == RSSI_UNKNOWN)
|
|
snprintf(count_str, sizeof(count_str), "Scan: %d node(s) [RSSI n/a]", node_count);
|
|
else
|
|
snprintf(count_str, sizeof(count_str), "Scan: %d node(s)", node_count);
|
|
lv_label_set_text(status, count_str);
|
|
}
|
|
|
|
if (input_fd >= 0 && read(input_fd, &ev, sizeof(struct input_event)) > 0) {
|
|
if (ev.type == EV_KEY && ev.code == H2_KEY_BACK && ev.value == 1) break;
|
|
}
|
|
usleep(40000);
|
|
}
|
|
|
|
if (h_fd >= 0) close(h_fd);
|
|
if (input_fd >= 0) close(input_fd);
|
|
LOG_INF("radar module exited");
|
|
return 0;
|
|
} |