I am designing a sensor system with a sensor and an Android device on the receiving end:
For now, since the sensor is not available I am using another android device as the BLE advertiser. Notice that I do not connect to the device, I just read the advertisement package.
On the transmitter side, I am creating a packet that contains the name of the device, the UUID and the data of the specific UUID:
private void advertise() {
BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode( AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY )
.setTxPowerLevel( AdvertiseSettings.ADVERTISE_TX_POWER_HIGH )
.setConnectable(false)
.build();
ParcelUuid pUuid = new ParcelUuid( UUID.fromString( getString( R.string.ble_uuid ) ) );
byte[] mdata = "Hello".getBytes(Charset.forName("UTF-8"));
AdvertiseData data = new AdvertiseData.Builder()
.setIncludeDeviceName( true )
.addServiceUuid( pUuid )
.addServiceData( pUuid, mdata )
.build();
AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
}
@Override
public void onStartFailure(int errorCode) {
Log.e( "BLE", "Advertising onStartFailure: " + errorCode );
super.onStartFailure(errorCode);
}
};
This part works well, because the Raw data that I receive using the BLE scanner app, are the ones that I want to send.
The problem is on the receiving side. There what I do is:
private void discover() {
List<ScanFilter> filters = new ArrayList<ScanFilter>();
ScanFilter filter = new ScanFilter.Builder()
.setServiceUuid( new ParcelUuid(UUID.fromString( getString(R.string.ble_uuid ) ) ) )
.build();
filters.add( filter );
ScanSettings settings = new ScanSettings.Builder()
.setScanMode( ScanSettings.SCAN_MODE_LOW_LATENCY )
.build();
mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mBluetoothLeScanner.stopScan(mScanCallback);
}
}, 10000);
}
My scanCallBack function is the following:
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if( result == null
|| result.getDevice() == null
|| TextUtils.isEmpty(result.getDevice().getName()) )
return;
StringBuilder builder = new StringBuilder( result.getDevice().getName());
for(int j = 0; j < result.getScanRecord().getServiceUuids().size(); j++){
builder.append("\n");
builder.append("Result no. " + j);
builder.append("\n");
builder.append(result.getScanRecord().getServiceUuids().get(j));
builder.append("\n");
builder.append("Service data: ");
builder.append("\n");
builder.append(result.getScanRecord().getServiceData(result.getScanRecord().getServiceUuids().get(j)));
}
mText.setText(builder.toString());
}
This code always returns null, at the point where I try to read my data.
Overall, I can read the device's name and the UUID of the device, but not the data.
Please give me some wisdom on the matter.
I found out that android uses 16-bit UUIDS, meaning that it translates a 128-bit UUID in the following way:
This the original 128-bit UUID:
01122334-4556-6778-899A-ABBCCDDEEFF0
.
The data are sent using this UUID.
Once this UUID is received from android, android only keeps 2334 and dumps the rest.
Then it creates a new 128-bit UUID, in a default way:
0000XXXX-0000-1000-8000-00805f9b34fb
.
Where XXXX is my 16-bit UUID 2334.
So in order to access my data I need to look for the 128-bit UUID that android gave to my data, in this case:
00002334-0000-1000-8000-00805f9b34fb
.
So in my case it was very practical to send my data on the 128-bit UUID that android assigned to my own.
I am not sure why this is happening, but now it works perfectly.