@@ -79,6 +79,11 @@ bool IsJetsonDevice() {
7979
8080// Forward declarations
8181bool IsBluetoothControllerConnected ();
82+ string GetPairedControllerMAC ();
83+ string GetConnectedControllerMAC ();
84+ bool ConnectToController (const string& mac_address);
85+ void SaveControllerMAC (const string& mac_address);
86+ string LoadSavedControllerMAC ();
8287void EnableBluetoothPairingMode ();
8388bool 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
200292bool 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 << " \n NOTE: 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