diff --git a/.vscode/arduino.json b/.vscode/arduino.json index cc0c5fa..d524625 100644 --- a/.vscode/arduino.json +++ b/.vscode/arduino.json @@ -1,7 +1,4 @@ { "port": "COM3", - "configuration": "JTAGAdapter=default,PSRAM=disabled,FlashMode=qio,FlashSize=4M,LoopCore=1,EventsCore=1,USBMode=hwcdc,CDCOnBoot=default,MSCOnBoot=default,DFUOnBoot=default,UploadMode=default,PartitionScheme=default,CPUFreq=240,UploadSpeed=921600,DebugLevel=none,EraseFlash=none", - "board": "esp32:esp32:esp32s3", - "programmer": "esptool", - "sketch": "code\\arduino\\Wii-Balance-Board\\Wii-Balance-Board.ino" + "board": "esp32:esp32:esp32s3" } \ No newline at end of file diff --git a/code/src/Fitbot/app/src/main/AndroidManifest.xml b/code/src/Fitbot/app/src/main/AndroidManifest.xml index 661bcbd..42194b2 100644 --- a/code/src/Fitbot/app/src/main/AndroidManifest.xml +++ b/code/src/Fitbot/app/src/main/AndroidManifest.xml @@ -8,6 +8,11 @@ + + + + + . + */ + + package com.example.fitbot.bluetooth; + + /** + * In very basic structure, all bluetooth devices have an address that the connection + * is associated with. + */ + public interface BluetoothDevice { + + /** + * The fixed address of the device. + * Constant throughout the connection of the device. + */ + public String getBluetoothAddress(); + + } \ No newline at end of file diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java index e51033a..177920f 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java @@ -1,6 +1,7 @@ package com.example.fitbot.ui.activities; import android.annotation.SuppressLint; +import android.bluetooth.BluetoothAdapter; import android.os.Bundle; import android.support.design.widget.NavigationView; import android.support.v4.app.ActivityCompat; @@ -13,13 +14,18 @@ import android.support.v7.widget.Toolbar; import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; -import com.example.fitbot.bluetooth.BluetoothManager; +import android.util.Log; + +import com.example.fitbot.bluetooth.BluetoothDevice; +import com.example.fitbot.wiiboard.WiiBoard; +import com.example.fitbot.wiiboard.WiiBoardDiscoverer; +import com.example.fitbot.wiiboard.WiiBoardDiscoveryListener; import com.example.fitbot.R; public class MainActivity extends AppCompatActivity { private static final int REQUEST_LOCATION_PERMISSION = 1; - BluetoothManager bluetoothManager; + private WiiBoardDiscoverer wiiBoardDiscoverer; //Variables DrawerLayout drawerLayout; @@ -32,22 +38,51 @@ public class MainActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - bluetoothManager = new BluetoothManager(this); + // Check if the device supports Bluetooth + if (BluetoothAdapter.getDefaultAdapter() == null) { + Log.i("WiiBoardDiscoverer", "Device doesn't support Bluetooth. Exiting."); + return; + } - // Check if Bluetooth is supported and enabled - if (bluetoothManager.isBluetoothSupported() && bluetoothManager.isBluetoothEnabled()) { - // Check for location permission which is required for Bluetooth discovery on Android 6.0 and above - if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION); - } else { - // Start Bluetooth discovery - bluetoothManager.startDiscovery(); - } + // Request location permissions for Bluetooth discovery on Android 6.0 and above + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION); + } else { + // Initialize WiiBoardDiscoverer + wiiBoardDiscoverer = new WiiBoardDiscoverer(this); } setUpUi(); } + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQUEST_LOCATION_PERMISSION && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // Permission granted, initialize WiiBoardDiscoverer + wiiBoardDiscoverer = new WiiBoardDiscoverer(this); + } else { + // Handle the case where the user denies the location permission + Log.i("WiiBoardDiscoverer", "Location permission is required for Bluetooth discovery."); + } + } + + @Override + protected void onResume() { + super.onResume(); + if (wiiBoardDiscoverer != null) { + wiiBoardDiscoverer.startWiiBoardSearch(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (wiiBoardDiscoverer != null) { + wiiBoardDiscoverer.stopWiiBoardSearch(); + } + } + private void setUpUi() { /*---Hooks---*/ drawerLayout = findViewById(R.id.drawer_layout); @@ -75,24 +110,4 @@ public class MainActivity extends AppCompatActivity { {super.onBackPressed(); } } - - @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (requestCode == REQUEST_LOCATION_PERMISSION && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // Permission granted, start Bluetooth discovery - bluetoothManager.startDiscovery(); - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - // Unregister the receiver to prevent memory leaks - try { - unregisterReceiver(bluetoothManager.receiver); - } catch (IllegalArgumentException e) { - // Handle case where receiver is not registered. - } - } } diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/wiiboard/WiiBoard.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/wiiboard/WiiBoard.java new file mode 100644 index 0000000..15fa973 --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/wiiboard/WiiBoard.java @@ -0,0 +1,48 @@ +package com.example.fitbot.wiiboard; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSocket; +import android.util.Log; + +import java.io.IOException; +import java.lang.reflect.Method; + +public class WiiBoard { + private static final String TAG = "WiiBoard"; + + public static void connectToExtension(String address) { + BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address); + BluetoothSocket socket = null; + final int maxTries = 3; + int currentTry = 0; + + while (currentTry < maxTries) { + try { + // Use reflection to create a BluetoothSocket without UUID + Method m = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class}); + socket = (BluetoothSocket) m.invoke(device, 1); + + bluetoothAdapter.cancelDiscovery(); + socket.connect(); + + Log.i(TAG, "Connected to WiiBoard"); + // Handle your communication here + + return; // Exit the method upon successful connection + } catch (Exception e) { // Catching Exception to handle reflection exceptions too + Log.e(TAG, "Attempt " + (currentTry + 1) + " failed to connect", e); + currentTry++; + try { + // Wait a bit before retrying + Thread.sleep(1000); + } catch (InterruptedException ie) { + Log.e(TAG, "Interrupted while waiting to retry connection", ie); + } + } + } + + Log.e(TAG, "Could not connect to WiiBoard after " + maxTries + " attempts."); + } +} \ No newline at end of file diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/wiiboard/WiiBoardDiscoverer.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/wiiboard/WiiBoardDiscoverer.java new file mode 100644 index 0000000..43095fd --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/wiiboard/WiiBoardDiscoverer.java @@ -0,0 +1,66 @@ +package com.example.fitbot.wiiboard; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.util.Log; + +public class WiiBoardDiscoverer { + private BluetoothAdapter bluetoothAdapter; + private Context context; + private String discoveredAddress; + private boolean isSearching; + + private final BroadcastReceiver receiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (BluetoothDevice.ACTION_FOUND.equals(action)) { + BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + String name = device.getName(); + if ("Nintendo RVL-WBC-01".equals(name)) { + discoveredAddress = device.getAddress(); + Log.i("WiiBoardDiscoverer", "Discovered " + name + " " + discoveredAddress + "."); + isSearching = false; + bluetoothAdapter.cancelDiscovery(); + context.unregisterReceiver(this); // Important to unregister + WiiBoard.connectToExtension(discoveredAddress); + } + } + } + }; + + public WiiBoardDiscoverer(Context context) { + this.context = context; + this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (bluetoothAdapter == null) { + Log.i("WiiBoardDiscoverer", "Device doesn't support Bluetooth. Exiting."); + System.exit(0); + } + } + + public void startWiiBoardSearch() { + if (!isSearching && !bluetoothAdapter.isDiscovering()) { + isSearching = true; + IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); + context.registerReceiver(receiver, filter); + bluetoothAdapter.startDiscovery(); + Log.i("WiiBoardDiscoverer", "WiiBoard Discovery Started"); + } + } + + public void stopWiiBoardSearch() { + if (bluetoothAdapter.isDiscovering()) { + bluetoothAdapter.cancelDiscovery(); + } + isSearching = false; + try { + context.unregisterReceiver(receiver); + } catch (IllegalArgumentException e) { + // This can happen if the receiver was not registered or already unregistered + Log.i("WiiBoardDiscoverer", "Receiver was not registered or already unregistered"); + } + } +} \ No newline at end of file diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/wiiboard/WiiBoardDiscoveryListener.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/wiiboard/WiiBoardDiscoveryListener.java new file mode 100644 index 0000000..bbb9bad --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/wiiboard/WiiBoardDiscoveryListener.java @@ -0,0 +1,13 @@ +package com.example.fitbot.wiiboard; + +/** + * Implement this interface to be notified of WiiBoards that are connected to. Register your + * listener with an instance of WiiBoardDiscoverer. + */ +public interface WiiBoardDiscoveryListener { + + /** + * Is called by a WiiBoardDiscoverer when a WiiBoard has been found and successfully connected to. + */ + public void wiiBoardDiscovered(WiiBoard wiiboard); +} \ No newline at end of file