我有能够扫描作为临时传感器的BLE devies的源代码,但是在扫描时它不会显示任何其他BLE决定。我想修改附加的代码,以便我可以扫描和查看所有BLE设备,无论它是否是温度传感器。有人可以解释我或告诉我如何做到这一点。以下是获取BLE Temp传感器数据的代码片段。
package no.nordicsemi.android.nrftemp.ble;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import no.nordicsemi.android.nrftemp.ble.parser.TemperatureData;
import no.nordicsemi.android.nrftemp.ble.parser.TemperatureDataParser;
import no.nordicsemi.android.nrftemp.database.DatabaseHelper;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.os.Handler;
public class TemperatureManager implements BluetoothAdapter.LeScanCallback {
/** An minimal interval between each data row in the database for a single device */
private static final long DATA_INTERVAL = 60 * 5 * 1000L; // ms
private BluetoothAdapter mBluetoothAdapter;
private DatabaseHelper mDatabaseHelper;
private List<TemperatureManagerCallback> mListeners;
public TemperatureManager(final Context context, final DatabaseHelper databaseHelper) {
final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
mDatabaseHelper = databaseHelper;
mListeners = new ArrayList<TemperatureManagerCallback>(2);
}
public void addCallback(final TemperatureManagerCallback callback) {
mListeners.add(callback);
}
public void removeCallback(final TemperatureManagerCallback callback) {
mListeners.remove(callback);
}
private void fireOnDevicesScanned() {
for (TemperatureManagerCallback callback : mListeners)
callback.onDevicesScaned();
}
private void fireOnRssiUpdate(final long sensorId, final int rssi) {
for (TemperatureManagerCallback callback : mListeners)
callback.onRssiUpdate(sensorId, rssi);
}
/**
* Starts scanning for temperature data. Call {@link #stopScan()} when done to save the power.
*/
public void startScan() {
mBluetoothAdapter.startLeScan(this);
}
/**
* Starts scanning for temperature data. Call {@link #stopScan()} when done to save the power.
*/
public void startScan(final long period) {
mBluetoothAdapter.startLeScan(this);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
stopScan();
}
}, period);
}
/**
* Stops scanning for temperature data from BLE sensors.
*/
public void stopScan() {
mBluetoothAdapter.stopLeScan(this);
}
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
final TemperatureData td = TemperatureDataParser.parse(device, scanRecord);
if (!td.isValid())
return;
final long now = Calendar.getInstance().getTimeInMillis();
final long then = mDatabaseHelper.getLastTimestamp(td.getAddress());
if (now - then > DATA_INTERVAL) {
mDatabaseHelper.addNewSensorData(device.getAddress(), device.getName(), now,
td.getTemp(), td.getBattery());
fireOnDevicesScanned();
}
final long sensorId = mDatabaseHelper.findSensor(device.getAddress());
final int rssiPercent = (int) (100.0f * (127.0f + rssi) / 127.0f + 20.0f);
mDatabaseHelper.updateSensorRssi(sensorId, rssiPercent);
fireOnRssiUpdate(sensorId, rssiPercent);
}
/**
* Return <code>true</code> if Bluetooth is currently enabled and ready for use.
*
* @return <code>true</code> if the local adapter is turned on
*/
public boolean isEnabled() {
return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
}
}
package no.nordicsemi.android.nrftemp.ble.parser;
import android.bluetooth.BluetoothDevice;
/**
* Domain class contains data obtained from a single advertising package from a temperature sensor.
*/
public class TemperatureData {
/** The device address */
private final String address;
/** The device name */
private String name;
/** The temperature value */
private double temp;
/** Battery status (number 0-100 in percent) */
private int battery = 0xFF; // unknown value
/**
* The flag whether the data are valid (holds real temperature measurement or not)
*/
private boolean valid;
public TemperatureData(BluetoothDevice device) {
address = device.getAddress();
name = device.getName();
}
public String getAddress() {
return address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getTemp() {
return temp;
}
public void setTemp(double temp) {
this.temp = temp;
this.valid = true;
}
public int getBattery() {
return battery;
}
public void setBattery(int battery) {
this.battery = battery;
}
public boolean isValid() {
return valid;
}
}
package no.nordicsemi.android.nrftemp.ble.parser;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import android.bluetooth.BluetoothDevice;
import android.util.Log;
public class TemperatureDataParser {
private static final String TAG = "TemperatureDataParser";
private static final int FLAGS = 0x02; // "Flags" Data Type (See section 18.1 of Core_V4.0.pdf)
private static final int LOCAL_NAME = 0x09; // "Complete Local Name" Data Type (See section 18.3 of Core_V4.0.pdf)
private static final int SERVICE_DATA = 0x16; // "Service Data" Data Type (See section 18.10 of Core_V4.0.pdf)
private static final short TEMPERATURE_SERVICE_UUID = 0x1809;
private static final short BATTERY_SERVICE_UUID = 0x180F;
private static final short DEVICE_INFORMATION_SERVICE_UUID = 0x180A;
/**
* Parses the advertising package obtained by BLE device
*
* @param data
* the data obtained (EIR data). Read Bluetooth Core Specification v4.0 (Core_V4.0.pdf -> Vol.3 -> Part C -> Section 8) for details
* @return the parsed temperature data
* @throws ParseException
* thrown when the given data does not fit the expected format
*/
public static TemperatureData parse(final BluetoothDevice device, final byte[] data) {
final TemperatureData td = new TemperatureData(device);
/*
* First byte of each EIR Data Structure has it's length (1 octet).
* There comes the EIR Data Type (n bytes) and (length - n bytes) of data.
* See Core_V4.0.pdf -> Vol.3 -> Part C -> Section 8 for details
*/
for (int i = 0; i < data.length;) {
final int eirLength = data[i];
// check whether there is no more to read
if (eirLength == 0)
break;
final int eirDataType = data[++i];
switch (eirDataType) {
case FLAGS:
// do nothing
break;
case LOCAL_NAME:
/*
* Local name data structure contains length - 1 bytes of the device name (1 byte for the data type)
*/
final String name = decodeLocalName(data, i + 1, eirLength - 1);
td.setName(name);
break;
case SERVICE_DATA:
/*
* First 2 bytes of service data are the 16-bit Service UUID in reverse order. The rest is service specific data.
*/
final short serviceUUID = decodeServiceUUID(data, i + 1);
switch (serviceUUID) {
case BATTERY_SERVICE_UUID:
final int battery = decodeBatteryLevel(data, i + 3);
td.setBattery(battery);
break;
case TEMPERATURE_SERVICE_UUID:
final double temp = decodeTempLevel(data, i + 3);
td.setTemp(temp);
break;
case DEVICE_INFORMATION_SERVICE_UUID:
// do nothing
break;
}
break;
default:
break;
}
i += eirLength;
}
return td;
}
private static String decodeLocalName(final byte[] data, final int start, final int length) {
try {
return new String(data, start, length, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unable to convert the local name to UTF-8", e);
return null;
}
}
private static short decodeServiceUUID(final byte[] data, final int start) {
return (short) ((data[start + 1] << 8) | data[start]);
}
private static int decodeBatteryLevel(final byte[] data, final int start) {
/*
* Battery level is a 1 byte number 0-100 (0x64). Value 255 (0xFF) is used for illegal measurement values
*/
return data[start];
}
private static float decodeTempLevel(final byte[] data, final int start) {
return bytesToFloat(data[start], data[start + 1], data[start + 2], data[start + 3]);
}
/**
* Convert signed bytes to a 32-bit short float value.
*/
private static float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
int mantissa = unsignedToSigned(unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8) + (unsignedByteToInt(b2) << 16), 24);
return (float) (mantissa * Math.pow(10, b3));
}
/**
* Convert a signed byte to an unsigned int.
*/
private static int unsignedByteToInt(byte b) {
return b & 0xFF;
}
/**
* Convert an unsigned integer value to a two's-complement encoded signed value.
*/
private static int unsignedToSigned(int unsigned, int size) {
if ((unsigned & (1 << size - 1)) != 0) {
unsigned = -1 * ((1 << size - 1) - (unsigned & ((1 << size - 1) - 1)));
}
return unsigned;
}
}
答案 0 :(得分:0)
据我所知,代码正在扫描每个BLE设备,扫描mBluetoothAdapter.startLeScan(this)中没有服务uuid限制;
此代码的问题(与许多示例一样)是它假设每个设备都属于他们自己的类型(在这种情况下是温度传感器)。
假设在这里:
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
final TemperatureData td = TemperatureDataParser.parse(device, scanRecord);
通过连接设备来了解设备支持的服务的唯一方法是,进行服务发现并检查支持的服务。
问候,Rob。