test is able to recieve data once

This commit is contained in:
SebasKoedam
2024-05-21 15:51:04 +02:00
parent 0153b70578
commit 49f97b57dd
9 changed files with 175 additions and 366 deletions

View File

@@ -2,39 +2,45 @@
#include <BLEUtils.h>
#include <BLEServer.h>
// Define the BLE service and characteristic UUIDs
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define LDR 15
BLECharacteristic *pCharacteristic;
void setup() {
// Initialize the BLE environment
BLEDevice::init("ESP32-S3");
Serial.begin(115200);
// Create a BLE server
BLEServer *pServer = BLEDevice::createServer();
pinMode(LDR, INPUT);
Serial.println("Starting BLE work!");
// Create a BLE service
BLEService *pService = pServer->createService(SERVICE_UUID);
BLEDevice::init("ESP32-Pepper");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
// Create a BLE characteristic
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
// Set the initial value of the characteristic
pCharacteristic->setValue("Hello, World!");
// Start the service
pService->start();
// Start advertising the BLE service
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->start();
pCharacteristic->setValue("Hello World");
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06);
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
// Nothing to do here for this example
int ldrValue = analogRead(LDR);
Serial.println(ldrValue);
char ldrValueChar[50];
sprintf(ldrValueChar, "%d", ldrValue);
pCharacteristic->setValue(ldrValueChar);
delay(2000);
}

View File

@@ -1,34 +0,0 @@
/*
Copyright 2008 Nedim Jackman
This file is part of Wiiboard Simple
Wiiboard Simple is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Wiiboard Simple is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Wiiboard Simple. If not, see <http://www.gnu.org/licenses/>.
*/
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();
}

View File

@@ -1,133 +0,0 @@
package com.example.fitbot.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Context;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.UUID;
public class BluetoothManager {
private BluetoothAdapter bluetoothAdapter;
private Context context;
public BluetoothManager(Context context) {
this.context = context;
this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
public boolean isBluetoothSupported() {
return bluetoothAdapter != null;
}
public boolean isBluetoothEnabled() {
return bluetoothAdapter.isEnabled();
}
public void startDiscovery() {
if (!isBluetoothEnabled()) {
Log.e("BluetoothManager", "Bluetooth is not enabled");
return;
}
if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
Log.d("BluetoothManager", "Cancelling current discovery process...");
}
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
context.registerReceiver(receiver, filter);
bluetoothAdapter.startDiscovery();
Log.d("BluetoothManager", "Starting discovery process...");
}
public 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);
if (device.getName() != null && device.getName().contains("Nintendo RVL-WBC-01")) {
Log.d("BluetoothManager", "Wii Balance Board found: " + device.getName() + " [" + device.getAddress() + "]");
connectToDevice(device);
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
context.unregisterReceiver(this);
Log.d("BluetoothManager", "Discovery finished.");
}
}
};
public void connectToDevice(BluetoothDevice device) {
new Thread(() -> {
BluetoothSocket socket = null;
final int MAX_RETRIES = 3;
final long RETRY_DELAY_MS = 1000;
boolean isConnected = false;
for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
try {
UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
socket = device.createRfcommSocketToServiceRecord(SPP_UUID);
bluetoothAdapter.cancelDiscovery();
byte[] pinBytes = getPinBytes(device.getAddress());
try {
Method setPinMethod = device.getClass().getDeclaredMethod("setPin", byte[].class);
setPinMethod.invoke(device, pinBytes);
Log.d("BluetoothManager", "PIN set successfully");
} catch (Exception e) {
Log.e("BluetoothManager", "Failed to set PIN", e);
}
socket.connect();
Log.d("BluetoothManager", "Connected to Wii Balance Board");
isConnected = true;
break;
} catch (IOException e) {
Log.e("BluetoothManager", "Connection attempt " + attempt + " failed", e);
if (attempt < MAX_RETRIES) {
try {
Thread.sleep(RETRY_DELAY_MS);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
break;
}
}
} finally {
if (!isConnected && socket != null) {
try {
socket.close();
} catch (IOException ex) {
Log.e("BluetoothManager", "Could not close the client socket", ex);
}
}
}
}
if (!isConnected) {
Log.e("BluetoothManager", "All connection attempts failed.");
}
}).start();
}
private byte[] getPinBytes(String address) {
String[] addrParts = address.split(":");
byte[] pin = new byte[addrParts.length];
for (int i = 0; i < addrParts.length; i++) {
pin[i] = (byte) Integer.parseInt(addrParts[addrParts.length - 1 - i], 16);
}
Log.i("BluetoothManager", "PIN: " + pin);
return pin;
}
}

View File

@@ -0,0 +1,134 @@
package com.example.fitbot.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
public class DeviceScanner {
private Context context;
private static final UUID CORRECT_CHARACTERISTIC_UUID = UUID.fromString("beb5483e-36e1-4688-b7f5-ea07361b26a8");
private BluetoothAdapter bluetoothAdapter;
private BluetoothLeScanner bluetoothLeScanner;
private boolean scanning;
private Handler handler = new Handler();
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
public DeviceScanner(Context context) {
this.context = context;
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
}
public void scanLeDevice() {
if (!scanning) {
// Stops scanning after a predefined scan period.
handler.postDelayed(new Runnable() {
@Override
public void run() {
scanning = false;
bluetoothLeScanner.stopScan(leScanCallback);
Log.i("DeviceScanner", "Stopped scanning after scan period");
}
}, SCAN_PERIOD);
scanning = true;
bluetoothLeScanner.startScan(leScanCallback);
Log.i("DeviceScanner", "Started scanning");
} else {
scanning = false;
bluetoothLeScanner.stopScan(leScanCallback);
Log.i("DeviceScanner", "Stopped scanning");
}
}
public void stopScan() {
if (scanning) {
scanning = false;
bluetoothLeScanner.stopScan(leScanCallback);
Log.i("DeviceScanner", "Stopped scanning");
}
}
// Device scan callback.
private ScanCallback leScanCallback =
new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
BluetoothDevice device = result.getDevice();
if (device.getName() != null && device.getName().equals("ESP32-Pepper")) {
Log.i("DeviceScanner", "Device found: " + device.getName() + " (" + device.getAddress() + ")");
connectToDevice(device);
}
};
};
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i("DeviceScanner", "Connected to GATT server");
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("DeviceScanner", "Disconnected from GATT server");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
for (BluetoothGattService service : gatt.getServices()) {
for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
if (isCorrectCharacteristic(characteristic)) {
gatt.setCharacteristicNotification(characteristic, true);
gatt.readCharacteristic(characteristic);
}
}
}
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("DeviceScanner", "Characteristic read: " + new String(characteristic.getValue(), StandardCharsets.UTF_8));
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.i("DeviceScanner", "Characteristic changed: " + new String(characteristic.getValue(), StandardCharsets.UTF_8));
}
};
public void connectToDevice(BluetoothDevice device) {
BluetoothGatt gatt = device.connectGatt(context, false, gattCallback);
}
private boolean isCorrectCharacteristic(BluetoothGattCharacteristic characteristic) {
// Log the UUID of the characteristic
Log.i("DeviceScanner", String.valueOf(characteristic.getUuid()));
// Check if the characteristic has the correct UUID
if (characteristic.getUuid().equals(CORRECT_CHARACTERISTIC_UUID)) {
Log.i("DeviceScanner", "Correct characteristic found");
return true;
}
return false;
}
}

View File

@@ -19,74 +19,37 @@ import android.content.pm.PackageManager;
import android.os.Bundle;
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;
import com.example.fitbot.bluetooth.DeviceScanner;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_LOCATION_PERMISSION = 1;
private WiiBoardDiscoverer wiiBoardDiscoverer;
//Variables
DrawerLayout drawerLayout;
NavigationView navigationView;
Toolbar toolbar;
Button startButton;
private DeviceScanner deviceScanner;
@SuppressLint("WrongViewCast")
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main );
// Check if the device supports Bluetooth
if (BluetoothAdapter.getDefaultAdapter() == null) {
Log.i("WiiBoardDiscoverer", "Device doesn't support Bluetooth. Exiting.");
return;
// Check if we have the necessary permissions, if not, request them
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
// 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);
}
deviceScanner = new DeviceScanner(this);
deviceScanner.scanLeDevice();
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);

View File

@@ -1,48 +0,0 @@
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.");
}
}

View File

@@ -1,66 +0,0 @@
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");
}
}
}

View File

@@ -1,13 +0,0 @@
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);
}

View File

@@ -83,7 +83,7 @@ To be added
## References
To be added
[Bluetooth Discovery](https://developer.android.com/develop/connectivity/bluetooth/find-bluetooth-devices)
## Appendices