Skip to content

Commit a5f940c

Browse files
committed
feat(ble): Add BLE RSSI room mapper example.
1 parent 694a2aa commit a5f940c

1 file changed

Lines changed: 206 additions & 0 deletions

File tree

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
//
3+
// BleRssiMapper — record RSSI measurements at different positions in a room.
4+
//
5+
// Place 2-3 STeaMi boards running BleBeacon at known positions.
6+
// Move around the room with this board and send 'r' via Serial to record
7+
// the current RSSI of all visible beacons as a CSV row.
8+
// Send 's' to stop and print the full CSV.
9+
//
10+
// CSV format: point_id,beacon_name,rssi
11+
//
12+
// Open the serial monitor at 115200 baud.
13+
// Commands:
14+
// r → record current RSSI for all visible beacons
15+
// s → stop and print full CSV
16+
// h → print help
17+
18+
#include <Arduino.h>
19+
#include <STM32duinoBLE.h>
20+
21+
// === Configuration ===
22+
static const char* BEACON_NAMES[] = {
23+
"Beacon_M1",
24+
"Beacon_M2",
25+
"Beacon_M3",
26+
};
27+
static const int BEACON_COUNT = 3;
28+
static const int RSSI_SAMPLES = 5;
29+
static const int MAX_POINTS = 50; // max measurement points
30+
static const int MAX_ROWS = MAX_POINTS * BEACON_COUNT;
31+
32+
// === RSSI smoothing per beacon ===
33+
static int rssiHistory[3][RSSI_SAMPLES] = {{0}};
34+
static int rssiIndex[3] = {0};
35+
static int rssiCount[3] = {0};
36+
static int currentRssi[3];
37+
static bool beaconSeen[3] = {false};
38+
39+
// === CSV storage (in RAM) ===
40+
struct CsvRow {
41+
int pointId;
42+
char beaconName[16];
43+
int rssi;
44+
};
45+
static CsvRow csvData[MAX_ROWS];
46+
static int rowCount = 0;
47+
static int pointId = 0;
48+
static bool recording = true;
49+
50+
// =============================================================================
51+
// === HELPERS =================================================================
52+
// =============================================================================
53+
54+
int beaconIndex(const String& name) {
55+
for (int i = 0; i < BEACON_COUNT; i++) {
56+
if (name == BEACON_NAMES[i])
57+
return i;
58+
}
59+
return -1;
60+
}
61+
62+
void smoothRssi(int idx, int newRssi) {
63+
rssiHistory[idx][rssiIndex[idx]] = newRssi;
64+
rssiIndex[idx] = (rssiIndex[idx] + 1) % RSSI_SAMPLES;
65+
if (rssiCount[idx] < RSSI_SAMPLES)
66+
rssiCount[idx]++;
67+
int sum = 0;
68+
for (int i = 0; i < rssiCount[idx]; i++)
69+
sum += rssiHistory[idx][i];
70+
currentRssi[idx] = sum / rssiCount[idx];
71+
}
72+
73+
void printHelp() {
74+
Serial.println("=== BLE RSSI Room Mapper ===");
75+
Serial.println("r → record current point");
76+
Serial.println("s → stop and print CSV");
77+
Serial.println("h → help");
78+
Serial.println("============================");
79+
}
80+
81+
void printCurrentScan() {
82+
Serial.print("Point #");
83+
Serial.print(pointId + 1);
84+
Serial.print(" | Beacons: ");
85+
for (int i = 0; i < BEACON_COUNT; i++) {
86+
if (beaconSeen[i]) {
87+
Serial.print(BEACON_NAMES[i]);
88+
Serial.print("=");
89+
Serial.print(currentRssi[i]);
90+
Serial.print("dBm ");
91+
}
92+
}
93+
Serial.println();
94+
}
95+
96+
void recordPoint() {
97+
int seen = 0;
98+
for (int i = 0; i < BEACON_COUNT; i++) {
99+
if (beaconSeen[i])
100+
seen++;
101+
}
102+
103+
if (seen == 0) {
104+
Serial.println("No beacon seen — move closer and retry.");
105+
return;
106+
}
107+
108+
pointId++;
109+
Serial.print("Recording point #");
110+
Serial.print(pointId);
111+
Serial.print(" (");
112+
Serial.print(seen);
113+
Serial.println(" beacons)");
114+
115+
for (int i = 0; i < BEACON_COUNT; i++) {
116+
if (beaconSeen[i] && rowCount < MAX_ROWS) {
117+
csvData[rowCount].pointId = pointId;
118+
strncpy(csvData[rowCount].beaconName, BEACON_NAMES[i], 15);
119+
csvData[rowCount].rssi = currentRssi[i];
120+
rowCount++;
121+
122+
Serial.print(" ");
123+
Serial.print(BEACON_NAMES[i]);
124+
Serial.print(", ");
125+
Serial.println(currentRssi[i]);
126+
}
127+
}
128+
}
129+
130+
void printCsv() {
131+
Serial.println();
132+
Serial.println("=== CSV OUTPUT — copy and save as rssi_map.csv ===");
133+
Serial.println("point_id,beacon_name,rssi");
134+
for (int i = 0; i < rowCount; i++) {
135+
Serial.print(csvData[i].pointId);
136+
Serial.print(",");
137+
Serial.print(csvData[i].beaconName);
138+
Serial.print(",");
139+
Serial.println(csvData[i].rssi);
140+
}
141+
Serial.println("=== END OF CSV ===");
142+
Serial.print("Total: ");
143+
Serial.print(pointId);
144+
Serial.print(" points, ");
145+
Serial.print(rowCount);
146+
Serial.println(" rows.");
147+
}
148+
149+
// =============================================================================
150+
// === SETUP / LOOP ============================================================
151+
// =============================================================================
152+
153+
void setup() {
154+
Serial.begin(115200);
155+
while (!Serial && millis() < 2000)
156+
;
157+
158+
if (!BLE.begin()) {
159+
Serial.println("BLE init failed!");
160+
while (true)
161+
;
162+
}
163+
164+
BLE.scan(true);
165+
printHelp();
166+
Serial.println("Scanning for beacons...");
167+
}
168+
169+
void loop() {
170+
// Handle Serial commands
171+
if (Serial.available()) {
172+
char cmd = Serial.read();
173+
if (cmd == 'r' && recording) {
174+
recordPoint();
175+
} else if (cmd == 's') {
176+
recording = false;
177+
BLE.stopScan();
178+
printCsv();
179+
} else if (cmd == 'h') {
180+
printHelp();
181+
} else if (cmd != '\n' && cmd != '\r') {
182+
Serial.println("Unknown command. Send 'h' for help.");
183+
}
184+
}
185+
186+
// Update RSSI from scan results
187+
if (recording) {
188+
BLEDevice device = BLE.available();
189+
if (device) {
190+
int idx = beaconIndex(device.localName());
191+
if (idx >= 0) {
192+
smoothRssi(idx, device.rssi());
193+
beaconSeen[idx] = true;
194+
}
195+
}
196+
197+
// Print current scan status every 2s
198+
static unsigned long lastPrint = 0;
199+
if (millis() - lastPrint > 2000) {
200+
lastPrint = millis();
201+
printCurrentScan();
202+
}
203+
}
204+
205+
BLE.poll();
206+
}

0 commit comments

Comments
 (0)