Skip to content

Commit f40a5f3

Browse files
author
orin03
committed
bind controller by mac to avoid a multiple-bind situation
1 parent f6fca48 commit f40a5f3

1 file changed

Lines changed: 150 additions & 8 deletions

File tree

src/joystick/joystick_driver.cc

Lines changed: 150 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ bool IsJetsonDevice() {
7979

8080
// Forward declarations
8181
bool IsBluetoothControllerConnected();
82+
string GetPairedControllerMAC();
83+
string GetConnectedControllerMAC();
84+
bool ConnectToController(const string& mac_address);
85+
void SaveControllerMAC(const string& mac_address);
86+
string LoadSavedControllerMAC();
8287
void EnableBluetoothPairingMode();
8388
bool WaitForBluetoothController(int timeout_seconds);
8489

@@ -196,6 +201,93 @@ void PrintJoystickList(const vector<JoystickInfo>& joysticks) {
196201
}
197202
}
198203

204+
// Function to get the MAC address of a paired controller
205+
string GetPairedControllerMAC() {
206+
FILE* pipe = popen("bluetoothctl devices Paired 2>/dev/null | grep -i -E '(controller|gamepad|joystick|xbox|playstation|dualshock|dualsense|joy-con|nintendo|wireless controller)' | head -n 1 | awk '{print $2}'", "r");
207+
if (!pipe) return "";
208+
209+
char buffer[128];
210+
string result = "";
211+
if (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
212+
result = buffer;
213+
// Remove trailing newline
214+
result.erase(result.find_last_not_of(" \n\r\t") + 1);
215+
}
216+
pclose(pipe);
217+
return result;
218+
}
219+
220+
// Function to get the MAC address of a connected controller
221+
string GetConnectedControllerMAC() {
222+
FILE* pipe = popen("bluetoothctl devices Connected 2>/dev/null | grep -i -E '(controller|gamepad|joystick|xbox|playstation|dualshock|dualsense|joy-con|nintendo|wireless controller)' | head -n 1 | awk '{print $2}'", "r");
223+
if (!pipe) return "";
224+
225+
char buffer[128];
226+
string result = "";
227+
if (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
228+
result = buffer;
229+
// Remove trailing newline
230+
result.erase(result.find_last_not_of(" \n\r\t") + 1);
231+
}
232+
pclose(pipe);
233+
return result;
234+
}
235+
236+
// Function to connect to a specific controller by MAC address
237+
bool ConnectToController(const string& mac_address) {
238+
if (mac_address.empty()) return false;
239+
240+
std::cout << "Attempting to connect to saved controller: " << mac_address << std::endl;
241+
242+
// Trust the device to ensure automatic connection
243+
string trust_cmd = "bluetoothctl trust " + mac_address + " 2>/dev/null";
244+
system(trust_cmd.c_str());
245+
246+
// Try to connect
247+
string connect_cmd = "bluetoothctl connect " + mac_address + " 2>/dev/null";
248+
int ret = system(connect_cmd.c_str());
249+
250+
if (ret == 0) {
251+
std::cout << "Successfully connected to controller." << std::endl;
252+
// Disable discoverable mode to prevent other controllers from connecting
253+
system("bluetoothctl discoverable off 2>/dev/null");
254+
return true;
255+
}
256+
257+
return false;
258+
}
259+
260+
// Function to save the controller MAC address to a file
261+
void SaveControllerMAC(const string& mac_address) {
262+
if (mac_address.empty()) return;
263+
264+
string config_file = string(getenv("HOME")) + "/roboracer_ws/car/joystick_controller_mac.txt";
265+
std::ofstream file(config_file);
266+
if (file.is_open()) {
267+
file << mac_address << std::endl;
268+
file.close();
269+
std::cout << "Saved controller MAC address: " << mac_address << std::endl;
270+
}
271+
}
272+
273+
// Function to load the saved controller MAC address from a file
274+
string LoadSavedControllerMAC() {
275+
string config_file = string(getenv("HOME")) + "/roboracer_ws/car/joystick_controller_mac.txt";
276+
std::ifstream file(config_file);
277+
if (file.is_open()) {
278+
string mac_address;
279+
std::getline(file, mac_address);
280+
file.close();
281+
// Remove any whitespace
282+
mac_address.erase(mac_address.find_last_not_of(" \n\r\t") + 1);
283+
if (!mac_address.empty()) {
284+
std::cout << "Found saved controller MAC address: " << mac_address << std::endl;
285+
return mac_address;
286+
}
287+
}
288+
return "";
289+
}
290+
199291
// Function to check if any Bluetooth controllers are connected
200292
bool IsBluetoothControllerConnected() {
201293
// Check if any connected Bluetooth devices appear to be controllers
@@ -240,6 +332,8 @@ void EnableBluetoothPairingMode() {
240332
std::cout << "For PS4/PS5 controllers: Hold Share + PS button until light flashes." << std::endl;
241333
std::cout << "For Xbox controllers: Hold Xbox + Connect button until light flashes." << std::endl;
242334
std::cout << "Waiting for controller connection..." << std::endl;
335+
std::cout << "\nNOTE: Once paired, this computer will remember THIS controller only." << std::endl;
336+
std::cout << "To pair a different controller, delete: ~/roboracer_ws/car/joystick_controller_mac.txt" << std::endl;
243337
}
244338

245339
// Function to wait for a Bluetooth controller to connect
@@ -252,6 +346,22 @@ bool WaitForBluetoothController(int timeout_seconds = 60) {
252346
while (std::chrono::steady_clock::now() - start_time < timeout_duration) {
253347
if (IsBluetoothControllerConnected()) {
254348
std::cout << "Bluetooth controller connected successfully!" << std::endl;
349+
350+
// Get the MAC address of the newly connected controller
351+
string mac_address = GetConnectedControllerMAC();
352+
if (!mac_address.empty()) {
353+
// Save it for future use
354+
SaveControllerMAC(mac_address);
355+
356+
// Trust this controller for automatic reconnection
357+
string trust_cmd = "bluetoothctl trust " + mac_address + " 2>/dev/null";
358+
system(trust_cmd.c_str());
359+
360+
// Disable discoverable mode to prevent other controllers from pairing
361+
system("bluetoothctl discoverable off 2>/dev/null");
362+
std::cout << "Discoverable mode disabled. This computer will only connect to this controller." << std::endl;
363+
}
364+
255365
// Give it a moment to create the joystick device
256366
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
257367
return true;
@@ -281,17 +391,49 @@ int main(int argc, char** argv) {
281391
if (is_jetson) {
282392
std::cout << "Running on Jetson device - checking for Bluetooth controllers..." << std::endl;
283393

284-
// Check if a Bluetooth controller is already connected
285-
if (!IsBluetoothControllerConnected()) {
286-
std::cout << "No Bluetooth controller connected." << std::endl;
287-
EnableBluetoothPairingMode();
394+
// First, check if we have a saved controller MAC address
395+
string saved_mac = LoadSavedControllerMAC();
396+
397+
if (!saved_mac.empty()) {
398+
// We have a saved controller - try to connect to it specifically
399+
std::cout << "This computer is configured to use controller: " << saved_mac << std::endl;
288400

289-
// Wait for a controller to connect
290-
if (!WaitForBluetoothController()) {
291-
std::cout << "Proceeding to check for wired controllers..." << std::endl;
401+
if (!IsBluetoothControllerConnected()) {
402+
std::cout << "Saved controller not connected. Attempting to reconnect..." << std::endl;
403+
404+
// Try to connect to the saved controller
405+
if (ConnectToController(saved_mac)) {
406+
std::cout << "Successfully reconnected to saved controller." << std::endl;
407+
} else {
408+
std::cout << "Could not reconnect to saved controller." << std::endl;
409+
std::cout << "Make sure the controller is powered on and in range." << std::endl;
410+
std::cout << "To pair a different controller, delete: ~/roboracer_ws/car/joystick_controller_mac.txt" << std::endl;
411+
}
412+
} else {
413+
std::cout << "Saved controller is already connected." << std::endl;
414+
// Ensure discoverable mode is off to prevent other controllers from connecting
415+
system("bluetoothctl discoverable off 2>/dev/null");
292416
}
293417
} else {
294-
std::cout << "Bluetooth controller already connected." << std::endl;
418+
// No saved controller - check if one is already connected or enable pairing
419+
if (!IsBluetoothControllerConnected()) {
420+
std::cout << "No saved controller found and no controller connected." << std::endl;
421+
EnableBluetoothPairingMode();
422+
423+
// Wait for a controller to connect
424+
if (!WaitForBluetoothController()) {
425+
std::cout << "Proceeding to check for wired controllers..." << std::endl;
426+
}
427+
} else {
428+
// A controller is connected but not saved - save it now
429+
std::cout << "Bluetooth controller already connected." << std::endl;
430+
string connected_mac = GetConnectedControllerMAC();
431+
if (!connected_mac.empty()) {
432+
SaveControllerMAC(connected_mac);
433+
system("bluetoothctl discoverable off 2>/dev/null");
434+
std::cout << "Saved this controller for future use." << std::endl;
435+
}
436+
}
295437
}
296438
}
297439

0 commit comments

Comments
 (0)