/* * 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 #include #include #include #include #include #include #include #include #include #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; }