当前位置: 首页 > article >正文

Android 解析蓝牙广播数据

static String toString(Map<T, byte[]> map) {

if (map == null) {

return “null”;

}

if (map.isEmpty()) {

return “{}”;

}

StringBuilder buffer = new StringBuilder();

buffer.append(‘{’);

Iterator<Map.Entry<T, byte[]>> it = map.entrySet().iterator();

while (it.hasNext()) {

Map.Entry<T, byte[]> entry = it.next();

Object key = entry.getKey();

buffer.append(key).append(“=”).append(Arrays.toString(map.get(key)));

if (it.hasNext()) {

buffer.append(", ");

}

}

buffer.append(‘}’);

return buffer.toString();

}

private static final String TAG = “ScanRecordUtil”;

// The following data type values are assigned by Bluetooth SIG.

// For more details refer to Bluetooth 4.1 specification, Volume 3, Part C, Section 18.

private static final int DATA_TYPE_FLAGS = 0x01;

private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;

private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;

private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;

private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;

private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;

private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;

private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;

private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;

private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;

private static final int DATA_TYPE_SERVICE_DATA = 0x16;

private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;

// Flags of the advertising data.

private final int mAdvertiseFlags;

@Nullable

private final List mServiceUuids;

private final SparseArray<byte[]> mManufacturerSpecificData;

private final Map<ParcelUuid, byte[]> mServiceData;

// Transmission power level(in dB).

private final int mTxPowerLevel;

// Local name of the Bluetooth LE device.

private final String mDeviceName;

// Raw bytes of scan record.

private final byte[] mBytes;

/**

  • Returns the advertising flags indicating the discoverable mode and capability of the device.

  • Returns -1 if the flag field is not set.

*/

public int getAdvertiseFlags() {

return mAdvertiseFlags;

}

/**

  • Returns a list of service UUIDs within the advertisement that are used to identify the

  • bluetooth GATT services.

*/

public List getServiceUuids() {

return mServiceUuids;

}

/**

  • Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific

  • data.

*/

public SparseArray<byte[]> getManufacturerSpecificData() {

return mManufacturerSpecificData;

}

/**

  • Returns the manufacturer specific data associated with the manufacturer id. Returns

  • {@code null} if the {@code manufacturerId} is not found.

*/

@Nullable

public byte[] getManufacturerSpecificData(int manufacturerId) {

return mManufacturerSpecificData.get(manufacturerId);

}

/**

  • Returns a map of service UUID and its corresponding service data.

*/

public Map<ParcelUuid, byte[]> getServiceData() {

return mServiceData;

}

/**

  • Returns the service data byte array associated with the {@code serviceUuid}. Returns

  • {@code null} if the {@code serviceDataUuid} is not found.

*/

@Nullable

public byte[] getServiceData(ParcelUuid serviceDataUuid) {

if (serviceDataUuid == null) {

return null;

}

return mServiceData.get(serviceDataUuid);

}

/**

  • Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE}

  • if the field is not set. This value can be used to calculate the path loss of a received

  • packet using the following equation:

  • pathloss = txPowerLevel - rssi

*/

public int getTxPowerLevel() {

return mTxPowerLevel;

}

/**

  • Returns the local name of the BLE device. The is a UTF-8 encoded string.

*/

@Nullable

public String getDeviceName() {

return mDeviceName;

}

/**

  • Returns raw bytes of scan record.

*/

public byte[] getBytes() {

return mBytes;

}

private ScanRecordUtil(List serviceUuids,

SparseArray<byte[]> manufacturerData,

Map<ParcelUuid, byte[]> serviceData,

int advertiseFlags, int txPowerLevel,

String localName, byte[] bytes) {

mServiceUuids = serviceUuids;

mManufacturerSpecificData = manufacturerData;

mServiceData = serviceData;

mDeviceName = localName;

mAdvertiseFlags = advertiseFlags;

mTxPowerLevel = txPowerLevel;

mBytes = bytes;

}

/**

  • Parse scan record bytes to {@link ScanRecord}.

  • The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18.

  • All numerical multi-byte entities and values shall use little-endian byte

  • order.

  • @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response.

  • @hide

*/

public static ScanRecordUtil parseFromBytes(byte[] scanRecord) {

if (scanRecord == null) {

return null;

}

Log.e(TAG + “MYX23P”, “进入parseFromBytes”);

int currentPos = 0;

int advertiseFlag = -1;

List serviceUuids = new ArrayList();

String localName = null;

int txPowerLevel = Integer.MIN_VALUE;

SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();

Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();

try {

while (currentPos < scanRecord.length) {

// length is unsigned int.

int length = scanRecord[currentPos++] & 0xFF;

if (length == 0) {

break;

}

// Note the length includes the length of the field type itself.

int dataLength = length - 1;

// fieldType is unsigned int.

int fieldType = scanRecord[currentPos++] & 0xFF;

switch (fieldType) {

case DATA_TYPE_FLAGS:

advertiseFlag = scanRecord[currentPos] & 0xFF;

break;

case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:

case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:

parseServiceUuid(scanRecord, currentPos,

dataLength,16, serviceUuids);

break;

case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:

case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:

parseServiceUuid(scanRecord, currentPos, dataLength,

32, serviceUuids);

break;

case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:

case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:

parseServiceUuid(scanRecord, currentPos, dataLength,

128, serviceUuids);

break;

case DATA_TYPE_LOCAL_NAME_SHORT:

case DATA_TYPE_LOCAL_NAME_COMPLETE:

localName = new String(

extractBytes(scanRecord, currentPos, dataLength));

break;

case DATA_TYPE_TX_POWER_LEVEL:

txPowerLevel = scanRecord[currentPos];

break;

case DATA_TYPE_SERVICE_DATA:

// The first two bytes of the service data are service data UUID in little

// endian. The rest bytes are service data.

int serviceUuidLength = 16;

byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,

serviceUuidLength);

ParcelUuid serviceDataUuid = parseUuidFrom(

serviceDataUuidBytes);

byte[] serviceDataArray = extractBytes(scanRecord,

currentPos + serviceUuidLength, dataLength - serviceUuidLength);

serviceData.put(serviceDataUuid, serviceDataArray);

break;

case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:

// The first two bytes of the manufacturer specific data are

// manufacturer ids in little endian.

int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +

(scanRecord[currentPos] & 0xFF);

byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2,

dataLength - 2);

manufacturerData.put(manufacturerId, manufacturerDataBytes);

break;

default:

// Just ignore, we don’t handle such data type.

break;

}

currentPos += dataLength;

}

if (serviceUuids.isEmpty()) {

serviceUuids = null;

}

return new ScanRecordUtil(serviceUuids, manufacturerData, serviceData,

advertiseFlag, txPowerLevel, localName, scanRecord);

} catch (Exception e) {

Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));

// As the record is invalid, ignore all the parsed results for this packet

// and return an empty record with raw scanRecord bytes in results

return new ScanRecordUtil(null, null, null, -1, Integer.MIN_VALUE, null, scanRecord);

}

}

@Override

public String toString() {

return “ScanRecord [mAdvertiseFlags=” + mAdvertiseFlags + “, mServiceUuids=” + mServiceUuids

  • “, mManufacturerSpecificData=” + ScanRecordUtil.toString(mManufacturerSpecificData)

  • “, mServiceData=” + ScanRecordUtil.toString(mServiceData)

  • “, mTxPowerLevel=” + mTxPowerLevel + “, mDeviceName=” + mDeviceName + “]”;

}

/**

  • byte数组转化为string

*/

static final char[] hexArray = “0123456789ABCDEF”.toCharArray();

public static String bytesToHex(byte[] bytes) {

char[] hexChars = new char[bytes.length * 2];

for (int j = 0; j < bytes.length; j++) {

int v = bytes[j] & 0xFF;

hexChars[j * 2] = hexArray[v >>> 4];

hexChars[j * 2 + 1] = hexArray[v & 0x0F];

}

return new String(hexChars);

}

// Parse service UUIDs.

private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength,

int uuidLength, List serviceUuids) {

while (dataLength > 0) {

byte[] uuidBytes = extractBytes(scanRecord, currentPos,

uuidLength);

serviceUuids.add(parseUuidFrom(uuidBytes));

dataLength -= uuidLength;

currentPos += uuidLength;

}

return currentPos;

}

// Helper method to extract bytes from byte array.

private static byte[] extractBytes(byte[] scanRecord, int start, int length) {

byte[] bytes = new byte[length];

System.arraycopy(scanRecord, start, bytes, 0, length);

return bytes;

}

/**

  • 转化方法

  • @param uuidBytes

  • @return

*/

public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {

if (uuidBytes == null) {

throw new IllegalArgumentException(“uuidBytes cannot be null”);

}

int length = uuidBytes.length;

if (length != 16 && length != 32 &&

length != 128) {

throw new IllegalArgumentException("uuidBytes length invalid - " + length);


http://www.kler.cn/a/512920.html

相关文章:

  • Git处理冲突详解
  • MIAOYUN信创云原生项目亮相西部“中试”生态对接活动
  • STM32-串口-UART-Asynchronous
  • 小白爬虫——selenium入门超详细教程
  • C语言内存之旅:从静态到动态的跨越
  • Low-Level 大一统:如何使用Diffusion Models完成视频超分、去雨、去雾、降噪等所有Low-Level 任务?
  • Redis 数据存储类型
  • swin transformer中相对位置编码解析
  • PHP CRM售后系统小程序
  • 1. 基于图像的三维重建
  • 华为EC6110T-海思Hi3798MV310_安卓9.0_通刷-强刷固件包
  • Nginx正向代理配置
  • 微服务与docker
  • Three.js实现动态水泡效果逐步解析GLSL着色器
  • JavaScript网页设计案例-JavaScript实现数据脱敏的几种解决方式
  • Mac 刷题环境配置
  • C#语言的计算机基础
  • 80篇数据库大数据精华内容
  • 使用 Flask 构建视频转 GIF 工具
  • WinHttp API接口辅助类实现GET POST网络通讯
  • PostgreSQL的学习心得和知识总结(一百六十六)|深入理解PostgreSQL数据库之\watch元命令的实现原理
  • RabbitMq原生接口详解
  • C++编译时间可视化
  • 合并两个img栅格影像——arcgis
  • 解决GB28181对接RTSP倍速播放导致FFmpeg缓冲区满导致花屏问题
  • LangGraph:基于图结构的智能系统开发与实践