Le蓝牙接入记录

2 篇文章 0 订阅

什么是LE蓝牙?

在接入一个功能前肯定要对这个功能有多多少少的了解;
Q:什么是LE蓝牙?
A:LE蓝牙 = BLE(Bluetooh Low Energy) = 低功耗蓝牙,区别普通蓝牙的是它耗电极低。
Q:我接入它不能像接入普通蓝牙那样吗?
A:很抱歉并不能,Android官方中LE蓝牙的借口几乎完全不同于普通蓝牙的借口。
Q:那直接找Demo复制粘贴就好了,为啥要你要写这篇博客?
A:两个字 - “有坑”。

多说无益,先让我看看Demo吧

首页蓝牙动态权限搜索蓝牙选中蓝牙后点击“去通讯”蓝牙通讯页稍等会刷出蓝牙设备的特征码系统会提示配对选中特征码并写入数据侧滑查看设备返回的数据

github - https://github.com/Like151320/BleBluetoothDemoApplication – 建议使用nordicsemi蓝牙包

搜索LE蓝牙设备

	/**是否正在搜索中*/
	private var isSearching = false
	/**停止搜索计时器,若为null则意味着计时器不存在,及没在搜索中*/
	private var stopScanTimer: Timer? = null
	/**搜到的设备-不重复*/
	private val searchedDeviceList = mutableListOf<BluetoothDevice>()

	/**开始搜索。超时时间[outTime]、搜索结果不重复[searchCallback]*/
	private fun searchBle(outTime: Long, searchCallback: (BluetoothDevice) -> Unit) {
		if (isSearching) {
			Toast.makeText(this, "已在搜索…", Toast.LENGTH_LONG).show()
			return
		}
		isSearching = true
		searchedDeviceList.clear()

		val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()

		//开始搜索LE蓝牙 - PS:注意Android官方警告 - 执行设备发现对于蓝牙适配器而言是一个非常繁重的操作过程,并且会消耗大量资源。 在找到要连接的设备后,确保始终使用 cancelDiscovery() 停止发现,然后再尝试连接。 此外,如果您已经保持与某台设备的连接,那么执行发现操作可能会大幅减少可用于该连接的带宽,因此不应该在处于连接状态时执行发现操作。
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
			//AndroidAPI 21 更新的新搜索方式
			val scanCallback = object : ScanCallback() {
				/**搜索失败回调*/
				override fun onScanFailed(errorCode: Int) {
					isSearching = false
					clearStopScanTimer()
					Log.e(TAG, "onScanFailed: $errorCode")
				}

				/**搜到LE蓝牙后立即回调-[result]会重复*/
				override fun onScanResult(callbackType: Int, result: ScanResult?) {
					if (result?.device?.address != null) {
						//过滤重复
						val isContains = searchedDeviceList.any { device ->
							device.address == result.device?.address
						}
						//不重复时保存
						if (!isContains) {
							searchedDeviceList.add(result.device)
							searchCallback.invoke(result.device)
						}
					}
				}

				/**搜索结果列表回调,但[results]也有重复,在制定上报延时后使用,比[onScanResult]效果好*/
				override fun onBatchScanResults(results: MutableList<ScanResult>?) {
					Log.e(
						TAG, "onBatchScanResults: " +
								"${results?.map {
									"\n[${it.device?.address}]"
								}}"
					)

					val noContainsDevice = mutableListOf<BluetoothDevice>()
					results?.forEach { result ->
						if (result.device?.address != null) {
							//过滤重复
							val isContains = searchedDeviceList.any { device ->
								device.address == result.device?.address
							}
							//不重复时保存
							if (!isContains) {
								noContainsDevice.add(result.device)
							}
						}
					}

					if (noContainsDevice.isNotEmpty()) {
						searchedDeviceList.addAll(noContainsDevice)
						noContainsDevice.forEach { device ->
							searchCallback.invoke(device)
						}
					}
				}
			}
			val scanSetting = ScanSettings.Builder()
				.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)//扫描模式 - SCAN_MODE_LOW_LATENCY: 低延迟,高消耗,建议仅当前台搜索时使用此模式
				.setReportDelay(500)//扫描报告延时,若设置此项,则搜到设备后不会立即通知,而是加入队列一起通知,回调会走 onBatchScanResults 而非 onScanResult
				.build()
			//扫描设置scanSetting决不能null PS:建议手动设置scanSetting,并添加ReportDelay
			bluetoothAdapter.bluetoothLeScanner.startScan(null, scanSetting, scanCallback)
//			bluetoothAdapter.bluetoothLeScanner.startScan(scanCallback)//使用默认scanSetting

			if (stopScanTimer != null)//关闭上次计时
				clearStopScanTimer()
			//开启 停止搜索计时器
			stopScanTimer = Timer()
			stopScanTimer!!.schedule(object : TimerTask() {
				override fun run() {
					bluetoothAdapter.bluetoothLeScanner.stopScan(scanCallback)
					isSearching = false
				}
			}, outTime)
		} else {

			//AndroidAPI 21 前的旧搜索方式
			val scanCallback: (BluetoothDevice, Int, ByteArray) -> Unit =
				{ device: BluetoothDevice, rssi: Int, scanRecord: ByteArray ->
					if (device.address != null) {
						//过滤重复
						val isContains = searchedDeviceList.any { myDevice ->
							myDevice.address == device.address
						}
						//不重复时保存
						if (!isContains) {
							searchedDeviceList.add(device)
							searchCallback.invoke(device)
						}
						searchCallback.invoke(device)
					}
				}
			bluetoothAdapter.startLeScan(scanCallback)

			if (stopScanTimer != null)//关闭上次计时
				clearStopScanTimer()
			//开启 停止搜索计时器
			stopScanTimer = Timer()
			stopScanTimer!!.schedule(object : TimerTask() {
				override fun run() {
					bluetoothAdapter.stopLeScan(scanCallback)
					isSearching = false
				}
			}, outTime)
		}

	}

	/**清除停止搜索计时器*/
	private fun clearStopScanTimer() {
		stopScanTimer?.cancel()
		stopScanTimer?.purge()
		stopScanTimer = null
	}

连接蓝牙设备

private var selectedAddress = ""

	fun connection(address: String) {
		if (!BluetoothAdapter.checkBluetoothAddress(address))
			return

		val device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address)

		//连接蓝牙来获得蓝牙信息 PS:按照Android官方的说法,连接前会自动提示绑定 - 注:如果两台设备之前尚未配对,则在连接过程中,Android 框架会自动向用户显示配对请求通知或对话框(如图 3 所示)。因此,在尝试连接设备时,您的应用无需担心设备是否已配对。 您的 RFCOMM 连接尝试将被阻塞,直至用户成功完成配对或配对失败(包括用户拒绝配对、配对失败或超时)。
		device.connectGatt(this, false, object : BluetoothGattCallback() {
			/**连接状态改变,著名的 22、133 都出自这里
			 * 要注意 [status]和[newState]是两个数据,而不是一个数据的变化前与变化后的值*/
			override fun onConnectionStateChange(
				gatt: BluetoothGatt?, status: Int, newState: Int
			) {
				super.onConnectionStateChange(gatt, status, newState)

				Log.d(TAG, "onConnectionStateChange: status = $status; newState = $newState")

				if (status == BluetoothGatt.GATT_SUCCESS
					&& newState == BluetoothProfile.STATE_CONNECTED
				) {
					//连接只是连接,不能通讯,发现服务后才算是准备好通讯了
					Log.d(TAG, "连接成功")
					gatt?.discoverServices()
				}
			}

			/**发现了连接服务*/
			override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
				super.onServicesDiscovered(gatt, status)
				//这里才可以看到service

				Log.d(TAG, "发现连接通道")
				//保存特征码列表
				val characteristicMap = mutableMapOf<String, String>()
				for (service in gatt!!.services) {
					//characteristic(特征码)列表
					for (characteristic in service.characteristics) {
						characteristicMap[characteristic.uuid.toString()] =
								service.uuid.toString()
					}
				}
				val deviceInfo = DeviceInfo(address, device.name, characteristicMap)

				"连接了$address\n$deviceInfo".run {
					Log.d(TAG, this)
					runOnUiThread {
						Toast.makeText(baseContext, this, Toast.LENGTH_LONG).show()
					}
				}

				gatt.disconnect()//断开连接
			}
		})
	}

但是当然,仅仅连接没什么卵用

与BL蓝牙设备通讯

	/**开始连接*/
	fun connection(address: String) {
		if (!BluetoothAdapter.checkBluetoothAddress(address))
			return

		val device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address)

		//连接蓝牙来获得蓝牙信息 PS:按照Android官方的说法,连接前会自动提示绑定 - 注:如果两台设备之前尚未配对,则在连接过程中,Android 框架会自动向用户显示配对请求通知或对话框(如图 3 所示)。因此,在尝试连接设备时,您的应用无需担心设备是否已配对。 您的 RFCOMM 连接尝试将被阻塞,直至用户成功完成配对或配对失败(包括用户拒绝配对、配对失败或超时)。
		device.connectGatt(this, false, object : BluetoothGattCallback() {
			/**连接状态改变,著名的 22、133 都出自这里
			 * 要注意 [status]和[newState]是两个数据,而不是一个数据的变化前与变化后的值*/
			override fun onConnectionStateChange(
				gatt: BluetoothGatt?, status: Int, newState: Int
			) {
				super.onConnectionStateChange(gatt, status, newState)

				Log.d(TAG, "onConnectionStateChange: status = $status; newState = $newState")

				if (status == BluetoothGatt.GATT_SUCCESS
					&& newState == BluetoothProfile.STATE_CONNECTED
				) {
					//连接只是连接,不能通讯,发现服务后才算是准备好通讯了
					Log.d(TAG, "连接成功")
					gatt?.discoverServices()
				}
			}

			/**发现了连接服务*/
			override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
				super.onServicesDiscovered(gatt, status)
				//这里才可以看到service

				Log.d(TAG, "发现连接通道 status = $status")
				if (status == BluetoothGatt.GATT_SUCCESS) {
					//保存特征码列表
					val characteristicMap = mutableMapOf<String, String>()
					for (service in gatt!!.services) {
						//characteristic(特征码)列表
						for (characteristic in service.characteristics) {
							characteristicMap[characteristic.uuid.toString()] =
									service.uuid.toString()
						}
					}

					//保存特征码通道ID
					deviceInfo = MyBLEActivity.DeviceInfo(address, device.name, characteristicMap)


					"连接了$address\n$deviceInfo".run {
						Log.d(TAG, this)
						runOnUiThread {
							Toast.makeText(baseContext, this, Toast.LENGTH_LONG).show()
						}
					}

					onServicesDiscovered(gatt, deviceInfo!!)

					//监听通道发来的讯息
					registerNotification(gatt, deviceInfo!!)
				}
			}

			override fun onDescriptorWrite(
				gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int
			) {
				super.onDescriptorWrite(gatt, descriptor, status)
				if (status == BluetoothGatt.GATT_SUCCESS
					&& descriptor?.value?.contentEquals(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) == true
				)
				//正在注册特征码
					if (isRegisteringNotification)
						registerNotification(gatt!!, deviceInfo!!, descriptor.uuid.toString())

			}

			var isRegisteringNotification = false
			/**开始注册返回信息监听。 [deviceInfo]-所有需要写入注册的Descriptor;
			 * [registeredDescriptorID]-当前注册到哪个Descriptor了,会去注册下一个,null则从头开始注册。
			 * 配合 [isRegisteringNotification] 与 [onDescriptorWrite] 能注册全部的特征码。
			 * 为何不直接全部写入注册信息? 我也希望能一下子全部写入descriptor,但是有个大坑文档中都没有提到。
			 *
			 * 坑:底层与蓝牙的交互是一条通道,数据只能一条一条的处理,好比一个缆车连接两座山,当我 writeDescriptor 把数据丢进缆车后,
			 * 不等缆车运过去又 writeDescriptor 丢一条数据,但缆车中已经有数据了,所以我就会写入失败 writeDescriptor() 返回 false。
			 * 我必须得等缆车把数据运过去了,在等缆车运回来“成功”两个字,我才能写下一条数据,WTF。
			 */
			private fun registerNotification(
				gatt: BluetoothGatt,
				deviceInfo: MyBLEActivity.DeviceInfo,
				registeredDescriptorID: String? = null
			) {
				isRegisteringNotification = true

				//开启所有特征码的监听通知,开启一次即可,并且仅仅 setCharacteristicNotification 不能真的监听回调,还需要向设备写入监听注册
				if (registeredDescriptorID == null) {
					for (service in gatt.services) {
						val characteristics = service.characteristics
						for (characteristic in characteristics) {
							val notificationResult =
								gatt.setCharacteristicNotification(characteristic, true)//监听发来的通道数据
							Log.d(TAG, "注册数据监听否? - ${characteristic.uuid} $notificationResult")
						}
					}
				}

				//寻找下个要写入注册的 descriptor
				var nextDescriptor: BluetoothGattDescriptor? = null
				var findDescriptor = registeredDescriptorID == null//从头开始 = 注册第一个 else 查找下一个
				for (entry in deviceInfo.characteristicAndService) {
					for (descriptor in gatt.getService(UUID.fromString(entry.value))
						.getCharacteristic(UUID.fromString(entry.key))
						.descriptors) {
						//找到了已写入的 descriptor
						if (descriptor.uuid.toString() == registeredDescriptorID) {
							findDescriptor = true
							continue
						}
						//这是下一个要写入的 descriptor
						if (findDescriptor) {
							nextDescriptor = descriptor
						}
					}
				}
				//去写入注册 descriptor
				if (nextDescriptor != null) {
					nextDescriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
					val writeResult = gatt.writeDescriptor(nextDescriptor)
					Log.d(TAG, "注册监听数据写入否? - ${nextDescriptor.uuid} $writeResult")
				} else {
					//已经全部写入注册
					isRegisteringNotification = false
				}
			}

			override fun onCharacteristicChanged(
				gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?
			) {
				super.onCharacteristicChanged(gatt, characteristic)
				val value = characteristic?.value
				if (value != null) {
					Log.e(TAG, Arrays.toString(value))
					onReceiveData(gatt!!, characteristic, value)
				}
			}

			override fun onCharacteristicRead(
				gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int
			) {
				super.onCharacteristicRead(gatt, characteristic, status)
			}
		})
	}

	/**连接成功了*/
	@WorkerThread
	private fun onServicesDiscovered(gatt: BluetoothGatt, deviceInfo: MyBLEActivity.DeviceInfo) {
		mGatt = gatt
		mCharacteristicAndService = deviceInfo.characteristicAndService

		runOnUiThread {
			listAdapter.clear()
			listAdapter.addAll(deviceInfo.characteristicAndService.keys)
			listAdapter.notifyDataSetChanged()
		}
	}

发送数据

	/**实际发送数据操作*/
	fun writeData(
		gatt: BluetoothGatt, serviceID: String, characteristicID: String, data: ByteArray
	) {
		Log.d(TAG, "开始发送数据 ${Arrays.toString(data)} - s = $serviceID c = $characteristicID")
		//获取发送通道
		val service = gatt.getService(UUID.fromString(serviceID))
		val characteristic = service.getCharacteristic(UUID.fromString(characteristicID))
		//填入并发送数据
		characteristic.value = data
		val writeResult = gatt.writeCharacteristic(characteristic)
		Log.d(TAG, "数据成功否? $writeResult")
		logListAdapter.add(
			"发送信息:" +
					"cid:${characteristic.uuid}\n" +
					"value:${Arrays.toString(data)} - $writeResult"
		)
		logListAdapter.notifyDataSetChanged()
		Toast.makeText(this, if (writeResult) "发送成功" else "发送失败", Toast.LENGTH_LONG).show()
	}

接收数据

前提:在连接中完成 - 1、调用API开启设备数据通知。2、向设备发送开启通知

	/**接收数据*/
	@WorkerThread
	private fun onReceiveData(
		gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray
	) {
		runOnUiThread {
			logListAdapter.add(
				"收到信息:" +
						"cid:${characteristic.uuid}\n" +
						"value:${Arrays.toString(value)}"
			)
			logListAdapter.notifyDataSetChanged()
		}
	}

踩过的坑

接收不到设备发来的信息

  1. 确认开启了信息通知
val notificationResult = gatt.setCharacteristicNotification(characteristic, true)//监听发来的通道数据
Log.d(TAG, "注册数据监听否? - ${characteristic.uuid} $notificationResult")
  1. 确认写入了通知
nextDescriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
val writeResult = gatt.writeDescriptor(nextDescriptor)
Log.d(TAG, "注册监听数据写入否? - ${nextDescriptor.uuid} $writeResult")
  1. 若通知写入失败,可能是没有一个个写入

坑:底层与蓝牙的交互是一条通道,数据只能一条一条的处理,好比一个缆车连接两座山,当我 writeDescriptor 把数据丢进缆车后,不等缆车运过去又 writeDescriptor 丢一条数据,但缆车中已经有数据了,所以我就会写入失败 writeDescriptor() 返回 false。我必须得等缆车把数据运过去了,在等缆车运回来“成功”两个字,我才能写下一条数据,WTF。

status = 22

这个错误码,搜索结果少的可怜:
表现效果为:
1、直接连接手环->连接成功->系统弹出配对提示->点击不配对-> status = 22
2、直接连接手环->连接成功->系统弹出配对提示->点击配对->从此正常。但是当第二次打开应用时,永远 status = 22

https://blog.csdn.net/shangming150/article/details/82251860 - 有说要重复连接的,但我这里不行
最终解决发现:是设备的问题,设备人员修复了绑定协议后,先解绑再绑定成功就不会再提示22了

设备人员说是要:手动解绑来清除绑定记录,之后绑定来创建绑定记录,绑定记录相同才能连接(感觉有毒)

22 = 设备端断开了连接

status = 133

1、我这里这个错误会固定在蓝牙同时连接的设备超过6个时出现,所以我限制了它最多不能同时连接6个设备
2、当不扫描就直接连接某蓝牙时,可能会出现133 (未验证)

绑定失败

同时绑定多个蓝牙时(无论是createBond还是自动弹出绑定提示)只有第一个调用蓝牙能绑定成功。
之后的蓝牙虽然发起了绑定,却不会受到任何绑定状态广播。
所以要绑定多个设备的蓝牙时需要一个一个去绑定。解除绑定是否有相同的坑没有测试

扫描不到设备

1、若设备刚刚被绑定,是会扫描不到的,除非重开蓝牙或解绑(我的小米6证实)
2、若长期的持续的进行扫描,有可能导致扫描失效,需要注意扫描频率(未验证)

其它错误码

这些错误码取自
//蓝牙连接包 —— https://github.com/NordicSemiconductor/Android-BLE-Library
implementation ‘no.nordicsemi.android:ble:2.0.3’
的类:GattError

/**
 * Parses the GATT and HCI errors to human readable strings.
 * <p>
 * See: <a href="https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/stack/include/gatt_api.h">gatt_api.h</a> for details.<br>
 * See also: <a href="https://android.googlesource.com/platform/external/libnfc-nci/+/master/src/include/hcidefs.h#447">hcidefs.h</a> for other possible HCI errors.
 */
public class GattError {
	public static final int GATT_SUCCESS = BluetoothGatt.GATT_SUCCESS;
	public static final int GATT_CONN_L2C_FAILURE = 0x01;
	public static final int GATT_CONN_TIMEOUT = 0x08;
	public static final int GATT_CONN_TERMINATE_PEER_USER = 0x13;
	public static final int GATT_CONN_TERMINATE_LOCAL_HOST = 0x16;
	public static final int GATT_CONN_FAIL_ESTABLISH = 0x3E;
	public static final int GATT_CONN_LMP_TIMEOUT = 0x22;
	public static final int GATT_CONN_CANCEL = 0x0100;
	public static final int GATT_ERROR = 0x0085; // Device not reachable

	public static final int GATT_INVALID_HANDLE = 0x0001;
	public static final int GATT_READ_NOT_PERMIT = 0x0002;
	public static final int GATT_WRITE_NOT_PERMIT = 0x0003;
	public static final int GATT_INVALID_PDU = 0x0004;
	public static final int GATT_INSUF_AUTHENTICATION = 0x0005;
	public static final int GATT_REQ_NOT_SUPPORTED = 0x0006;
	public static final int GATT_INVALID_OFFSET = 0x0007;
	public static final int GATT_INSUF_AUTHORIZATION = 0x0008;
	public static final int GATT_PREPARE_Q_FULL = 0x0009;
	public static final int GATT_NOT_FOUND = 0x000a;
	public static final int GATT_NOT_LONG = 0x000b;
	public static final int GATT_INSUF_KEY_SIZE = 0x000c;
	public static final int GATT_INVALID_ATTR_LEN = 0x000d;
	public static final int GATT_ERR_UNLIKELY = 0x000e;
	public static final int GATT_INSUF_ENCRYPTION = 0x000f;
	public static final int GATT_UNSUPPORT_GRP_TYPE = 0x0010;
	public static final int GATT_INSUF_RESOURCE = 0x0011;
	public static final int GATT_CONTROLLER_BUSY = 0x003A;
	public static final int GATT_UNACCEPT_CONN_INTERVAL = 0x003B;
	public static final int GATT_ILLEGAL_PARAMETER = 0x0087;
	public static final int GATT_NO_RESOURCES = 0x0080;
	public static final int GATT_INTERNAL_ERROR = 0x0081;
	public static final int GATT_WRONG_STATE = 0x0082;
	public static final int GATT_DB_FULL = 0x0083;
	public static final int GATT_BUSY = 0x0084;
	public static final int GATT_CMD_STARTED = 0x0086;
	public static final int GATT_PENDING = 0x0088;
	public static final int GATT_AUTH_FAIL = 0x0089;
	public static final int GATT_MORE = 0x008a;
	public static final int GATT_INVALID_CFG = 0x008b;
	public static final int GATT_SERVICE_STARTED = 0x008c;
	public static final int GATT_ENCRYPTED_NO_MITM = 0x008d;
	public static final int GATT_NOT_ENCRYPTED = 0x008e;
	public static final int GATT_CONGESTED = 0x008f;
	public static final int GATT_CCCD_CFG_ERROR = 0x00FD;
	public static final int GATT_PROCEDURE_IN_PROGRESS = 0x00FE;
	public static final int GATT_VALUE_OUT_OF_RANGE = 0x00FF;
	public static final int TOO_MANY_OPEN_CONNECTIONS = 0x0101;

	/**
	 * Converts the connection status given by the
	 * {@link android.bluetooth.BluetoothGattCallback#onConnectionStateChange(BluetoothGatt, int, int)}
	 * to error name.
	 *
	 * @param error the status number.
	 * @return The error name as stated in the links in {@link GattError} documentation.
	 */
	public static String parseConnectionError(final int error) {
		switch (error) {
			case GATT_SUCCESS:
				return "SUCCESS";
			case GATT_CONN_L2C_FAILURE:
				return "GATT CONN L2C FAILURE";
			case GATT_CONN_TIMEOUT:
				return "GATT CONN TIMEOUT";
			case GATT_CONN_TERMINATE_PEER_USER:
				return "GATT CONN TERMINATE PEER USER";
			case GATT_CONN_TERMINATE_LOCAL_HOST:
				return "GATT CONN TERMINATE LOCAL HOST";
			case GATT_CONN_FAIL_ESTABLISH:
				return "GATT CONN FAIL ESTABLISH";
			case GATT_CONN_LMP_TIMEOUT:
				return "GATT CONN LMP TIMEOUT";
			case GATT_CONN_CANCEL:
				return "GATT CONN CANCEL ";
			case GATT_ERROR:
				return "GATT ERROR"; // Device not reachable
			default:
				return "UNKNOWN (" + error + ")";
		}
	}

	/**
	 * Converts the Bluetooth communication status given by other BluetoothGattCallbacks to error
	 * name. It also parses the DFU errors.
	 *
	 * @param error the status number.
	 * @return The error name as stated in the links in {@link GattError} documentation.
	 */
	public static String parse(final int error) {
		switch (error) {
			case GATT_INVALID_HANDLE:
				return "GATT INVALID HANDLE";
			case GATT_READ_NOT_PERMIT:
				return "GATT READ NOT PERMIT";
			case GATT_WRITE_NOT_PERMIT:
				return "GATT WRITE NOT PERMIT";
			case GATT_INVALID_PDU:
				return "GATT INVALID PDU";
			case GATT_INSUF_AUTHENTICATION:
				return "GATT INSUF AUTHENTICATION";
			case GATT_REQ_NOT_SUPPORTED:
				return "GATT REQ NOT SUPPORTED";
			case GATT_INVALID_OFFSET:
				return "GATT INVALID OFFSET";
			case GATT_INSUF_AUTHORIZATION:
				return "GATT INSUF AUTHORIZATION";
			case GATT_PREPARE_Q_FULL:
				return "GATT PREPARE Q FULL";
			case GATT_NOT_FOUND:
				return "GATT NOT FOUND";
			case GATT_NOT_LONG:
				return "GATT NOT LONG";
			case GATT_INSUF_KEY_SIZE:
				return "GATT INSUF KEY SIZE";
			case GATT_INVALID_ATTR_LEN:
				return "GATT INVALID ATTR LEN";
			case GATT_ERR_UNLIKELY:
				return "GATT ERR UNLIKELY";
			case GATT_INSUF_ENCRYPTION:
				return "GATT INSUF ENCRYPTION";
			case GATT_UNSUPPORT_GRP_TYPE:
				return "GATT UNSUPPORT GRP TYPE";
			case GATT_INSUF_RESOURCE:
				return "GATT INSUF RESOURCE";
			case GATT_CONN_LMP_TIMEOUT:
				return "GATT CONN LMP TIMEOUT";
			case GATT_CONTROLLER_BUSY:
				return "GATT CONTROLLER BUSY";
			case GATT_UNACCEPT_CONN_INTERVAL:
				return "GATT UNACCEPT CONN INTERVAL";
			case GATT_ILLEGAL_PARAMETER:
				return "GATT ILLEGAL PARAMETER";
			case GATT_NO_RESOURCES:
				return "GATT NO RESOURCES";
			case GATT_INTERNAL_ERROR:
				return "GATT INTERNAL ERROR";
			case GATT_WRONG_STATE:
				return "GATT WRONG STATE";
			case GATT_DB_FULL:
				return "GATT DB FULL";
			case GATT_BUSY:
				return "GATT BUSY";
			case GATT_ERROR:
				return "GATT ERROR";
			case GATT_CMD_STARTED:
				return "GATT CMD STARTED";
			case GATT_PENDING:
				return "GATT PENDING";
			case GATT_AUTH_FAIL:
				return "GATT AUTH FAIL";
			case GATT_MORE:
				return "GATT MORE";
			case GATT_INVALID_CFG:
				return "GATT INVALID CFG";
			case GATT_SERVICE_STARTED:
				return "GATT SERVICE STARTED";
			case GATT_ENCRYPTED_NO_MITM:
				return "GATT ENCRYPTED NO MITM";
			case GATT_NOT_ENCRYPTED:
				return "GATT NOT ENCRYPTED";
			case GATT_CONGESTED:
				return "GATT CONGESTED";
			case GATT_CCCD_CFG_ERROR:
				return "GATT CCCD CFG ERROR";
			case GATT_PROCEDURE_IN_PROGRESS:
				return "GATT PROCEDURE IN PROGRESS";
			case GATT_VALUE_OUT_OF_RANGE:
				return "GATT VALUE OUT OF RANGE";
			case TOO_MANY_OPEN_CONNECTIONS:
				return "TOO MANY OPEN CONNECTIONS";
			default:
				return "UNKNOWN (" + error + ")";
		}
	}
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值