Как использовать onCharacteristicWrite () для BLE в Kotlin? - PullRequest
0 голосов
/ 17 марта 2020

Я реализую небольшое приложение BLE и у меня есть список устройств, и я хочу отключить их, когда я нажимаю на них в представлении списка.

UUID моего сервиса: 0xFFB0

Мои характеристики c UUID: 0xFFB7 Запись с ответом / Чтение с ответом

Характеристики c Формат:

Порядок байтов; 0; 1 ~ 19

R / W ON / OFF; -

0x01 -> ON и 0x00 -> OFF

class MainActivity : AppCompatActivity() {

private var macList: ArrayList<String> = ArrayList()
private var deviceList: ArrayList<BluetoothDevice> = ArrayList()
private lateinit var adapter: ArrayAdapter<String>
private var mBtAdapter: BluetoothAdapter? = null
private var mConnectedGatt: BluetoothGatt? = null
private var mCharacteristic: BluetoothGattCharacteristic? = null
private var on = true
private lateinit var currentDevice: BluetoothDevice

/**
 * CHECK IF BT AND LOCATION IS ON!
 */
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    if (!isBLESupported(this)) {
        Toast.makeText(this, "This device doesn't support bluetooth", Toast.LENGTH_SHORT).show()
        finish()
    } else {
        if (!mBtAdapter!!.isEnabled) {
            val enableBluetoothIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
            startActivityForResult(enableBluetoothIntent, REQUEST_ENABLE_BLUETOOTH)
        }
    }

    adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, macList)
    list_view.adapter = adapter

    list_view.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
        currentDevice = deviceList[position]
        mConnectedGatt = currentDevice.connectGatt(applicationContext, false, gattCallback)
    }

    scan_button.setOnClickListener {
        scanForDeviceWithFilter(LIGHT_SERVICE)
    }

    power_button.setOnClickListener {
        mConnectedGatt = currentDevice.connectGatt(applicationContext, true, powerCallback)
        on = !on
    }

}

override fun onStop() {
    super.onStop()
    //Disconnect from any active tag connection
    if (mConnectedGatt != null) {
        mConnectedGatt!!.disconnect()
        mConnectedGatt = null
    }
}

private fun scanForDeviceWithFilter(serviceUUID: Int) {

    val uuid = ParcelUuid(convertFromInteger(serviceUUID))
    val filter = ScanFilter.Builder().setServiceUuid(uuid).build()
    val filters = listOf(filter)
    val settings = ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build()
    checkBTPermissions()
    mBtAdapter!!.bluetoothLeScanner.startScan(filters, settings, scanDevicesCallback)
    Thread.sleep(3000)
    mBtAdapter!!.bluetoothLeScanner.stopScan(scanDevicesCallback)

}

private val scanDevicesCallback = object : ScanCallback() {
    override fun onBatchScanResults(results: MutableList<ScanResult>?) {
        results?.forEach { result ->
            macList.add(result.device.toString())
            Log.d(TAG, "device name:${result.device}")
        }
    }

    override fun onScanResult(callbackType: Int, result: ScanResult?) {
        result?.let {
            if (!macList.contains(result.device.name.toString())) {
                deviceList.add(result.device)
                macList.add(result.device.name.toString())
                adapter.notifyDataSetChanged()
            }
            Log.d(TAG, "device found:${result.device}")
        }

    }

    override fun onScanFailed(errorCode: Int) {
        Log.d(TAG, "Scan failed $errorCode")
    }
}


private val gattCallback = object : BluetoothGattCallback() {

    /* OK */
    override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
        Log.d(TAG, "Connection State Change: " + status + " -> " + connectionState(newState))
        if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
            /**
             * Once successfully connected, we must next discover all the services on the
             * device before we can read and write their characteristics.
             */
            gatt.discoverServices()
            Thread.sleep(500)
        } else if (status != BluetoothGatt.GATT_SUCCESS) {
            /**
             * If there is a failure at any stage, simply disconnect
             */
            gatt.disconnect()
        }
    }

    private fun connectionState(status: Int): String {
        return when (status) {
            BluetoothProfile.STATE_CONNECTED -> "Connected"
            BluetoothProfile.STATE_DISCONNECTED -> "Disconnected"
            BluetoothProfile.STATE_CONNECTING -> "Connecting"
            BluetoothProfile.STATE_DISCONNECTING -> "Disconnecting"
            else -> status.toString()
        }
    }

    override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {

        mCharacteristic = gatt?.getService(convertFromInteger(LIGHT_SERVICE))?.getCharacteristic(convertFromInteger(PASSWORD_CHARACTERISTIC))
        mCharacteristic!!.setValue("0123")
        if (gatt!!.writeCharacteristic(mCharacteristic)) {
            Log.d(TAG, "Login success")
            Thread.sleep(500)
        } else
            Log.d(TAG, "Login failed")
    }

    override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) {
        if (status != BluetoothGatt.GATT_SUCCESS) {
            Log.d("onCharacteristicWrite", "Failed write, retrying: $status")
            gatt!!.writeCharacteristic(characteristic)
        }
        super.onCharacteristicWrite(gatt, characteristic, status)
    }
}


private val powerCallback = object : BluetoothGattCallback() {

    /* OK */
    override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
        Log.d(TAG, "Connection State Change: " + status + " -> " + connectionState(newState))
        if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
            gatt.discoverServices()
            Thread.sleep(500)
        } else if (status != BluetoothGatt.GATT_SUCCESS) {
            gatt.disconnect()
        }
    }

    private fun connectionState(status: Int): String {
        return when (status) {
            BluetoothProfile.STATE_CONNECTED -> "Connected"
            BluetoothProfile.STATE_DISCONNECTED -> "Disconnected"
            BluetoothProfile.STATE_CONNECTING -> "Connecting"
            BluetoothProfile.STATE_DISCONNECTING -> "Disconnecting"
            else -> status.toString()
        }
    }

    override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {

        if (on) {
            mCharacteristic = gatt!!.getService(convertFromInteger(LIGHT_SERVICE))?.getCharacteristic(convertFromInteger(LIGHT_CHARACTERISTIC))
            mCharacteristic!!.setValue("0")

            gatt.setCharacteristicNotification(mCharacteristic, true)
            if (gatt.writeCharacteristic(mCharacteristic)) {
                Log.d(TAG, "Power off success")
                Thread.sleep(500)
            } else Log.d(TAG, "Power off failed")
        } else {
            mCharacteristic = gatt!!.getService(convertFromInteger(LIGHT_SERVICE))?.getCharacteristic(convertFromInteger(LIGHT_CHARACTERISTIC))
            mCharacteristic!!.setValue("1")
            if (gatt.writeCharacteristic(mCharacteristic)) {
                Log.d(TAG, "Power on success")
                Thread.sleep(500)
            } else Log.d(TAG, "Power on failed")
        }

    }


    override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) {
        if (status != BluetoothGatt.GATT_SUCCESS) {
            Log.d("onCharacteristicWrite", "Failed write, retrying: $status")
            gatt!!.writeCharacteristic(characteristic)
        }
        super.onCharacteristicWrite(gatt, characteristic, status);
    }

}

private fun isBLESupported(context: Context): Boolean {
    return BluetoothAdapter.getDefaultAdapter() != null && context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
}


init {
    mBtAdapter = BluetoothAdapter.getDefaultAdapter()
}

private fun checkBTPermissions() {
    val permissionCheck = checkSelfPermission("Manifest.permission.ACCESS_FINE_LOCATION")
    if (permissionCheck != 0) {
        requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1001)
    }
}

fun convertFromInteger(i: Int): UUID? {
    val msb = 0x0000000000001000L
    val lsb = -0x7fffff7fa064cb05L
    val value = (i and ((-0x1).toLong()).toInt()).toLong()
    return UUID(msb or (value shl 32), lsb)
}

companion object {
    private const val TAG = "Main Activity"
    private const val LIGHT_SERVICE = 0xffb0
    private const val LIGHT_CHARACTERISTIC = 0xffb7
    private const val PASSWORD_CHARACTERISTIC = 0xffba
    private const val REQUEST_ENABLE_BLUETOOTH = 1
}
}

Я изменил свой код, но теперь, когда я пытаюсь писать, я получаю status = 128; GATT_NO_RESOURCES и я понятия не имею, что делать.

Ответы [ 2 ]

1 голос
/ 17 марта 2020

Я не уверен, правильно ли вы поняли поток.

onCharacteristicWrite - это , а не , называемое "для отправки данных на устройство BLE". Он вызывается после того, как вы позвонили writeCharacteristic, после ответа удаленного устройства.

Этот обратный вызов вызывается, когда вы пытаетесь отправить данные с использованием writeCharacteristi c (характеристики) и устройство BLE отвечает некоторым значением.

Это не совсем верно в отношении onCharacteristicChanged. Этот метод вызывается всякий раз, когда локальное устройство получает уведомление от удаленного устройства. Чтобы включить это, вы должны сначала указать локальному стеку Bluetooth пересылать вам уведомления, сначала позвонив по номеру setCharacteristicNotification, и написать дескриптор конфигурации *1010* c на удаленное устройство, чтобы оно отправляло уведомления.

После того, как вы вызвали writeDescriptor, при ответе удаленного устройства будет вызван обратный вызов onDescriptorWrite.

Что вам нужно сделать, это реализовать метод onServicesDiscovered, который будет вызываться в результате discoverServices, когда обнаружение службы завершено. В этом обратном вызове вы можете позвонить writeCharacteristic на ВКЛ / ВЫКЛ характеристики c.

Из вашего описания не кажется, что вам нужно получать уведомления.

0 голосов
/ 23 марта 2020

Я решил свою проблему. Я отправлял на устройство строку, а не значение байта.

mCharacteristi c !!. Value = byteArrayOf (0x00) исправил мою проблему.

...