11.7. Operasi GATT¶
Sebuah karakteristik hanya duduk di database GATT sebagai nilai bernama. Yang membuatnya berguna adalah sekumpulan kecil operasi yang terdefinisi dengan baik yang dapat dijalankan client padanya. Setiap karakteristik mendeklarasikan operasi mana yang didukungnya sebagai property bitmask -- server yang tidak memiliki apa pun untuk diekspos dapat mempublikasikan nilai hanya-baca, register kontrol mungkin hanya-tulis, sensor yang melakukan streaming pembaruan akan menyetel bit notify. Client menemukan bitmask ini selama proses penemuan dan menghormatinya.
Lima operasinya adalah read, write, write without response, notify, dan indicate. Mereka terbagi menjadi dua kelompok -- pull (client yang meminta) dan push (server yang mengirim).
11.7.1. Pull: read dan write¶
Keduanya adalah yang paling sederhana dan terlihat persis seperti pemanggilan fungsi.
Read. Client meminta nilai saat ini, server mengirimkannya kembali. Satu perjalanan pulang-pergi, client mendapatkan byte apa pun yang telah ditetapkan server untuk karakteristik tersebut, server tidak mendapatkan informasi tentang siapa yang membaca.
Write. Client mengirimkan byte baru, server menyimpannya (dan secara opsional menjalankan logika aplikasi pada nilai baru). Ada dua variasi:
Write with response -- server mengakui, memunculkan kesalahan aplikasi pada status non-nol. Andal, satu perjalanan pulang-pergi.
Write without response -- server menyimpan byte secara diam-diam; client tidak mendapat pengakuan sama sekali. Lebih cepat (tidak ada perjalanan pulang-pergi menunggu ack) dan berguna untuk streaming, dengan biaya mengetahui kesalahan hanya melalui readback saluran samping.
Dalam aioble, API di sisi client menyembunyikan pilihan ini di balik satu metode aioble.ClientCharacteristic.write() dengan kata kunci response (True / False / None untuk pemilihan otomatis berdasarkan apa yang diiklankan peer).
11.7.2. Push: notify dan indicate¶
Model pull tidak tepat untuk data sensor. Sebuah sabuk detak jantung yang harus di-polling oleh ponsel setiap detik akan menguras baterai pada ratusan peristiwa radio yang tidak perlu; satu yang mendorong nilai hanya ketika ada pembacaan baru adalah inti dari BLE.
GATT menyelesaikan ini dengan operasi yang diprakarsai server. Client berlangganan pada sebuah karakteristik; mulai saat itu, setiap kali server memperbarui nilai, nilai baru didorong melalui tautan ke client. Dua variasi:
Notify. Kirim dan lupakan. Server mengantri notifikasi, lapisan tautan mengirimkannya selama peristiwa koneksi berikutnya, client menerimanya. Tidak ada pengakuan di level GATT; retransmisi normal lapisan tautan menangani kehilangan di sisi radio, tetapi aplikasi tidak melihat konfirmasi bahwa nilai tersebut telah diproses.
Indicate. Server mengirimkan notifikasi dan menunggu konfirmasi level GATT dari client sebelum mengirim yang berikutnya. Satu indikasi pada satu waktu. Digunakan ketika server perlu mengetahui bahwa client benar-benar melihat nilai tersebut -- karakteristik alarm kritis, konfirmasi konfigurasi.
Pull (read) versus push (notify). Dengan notifikasi, client berlangganan sekali dan server mendorong nilai baru setiap kali berubah.¶
Berlangganan dilakukan dengan menulis ke descriptor yang dilampirkan pada karakteristik -- Client Characteristic Configuration Descriptor (CCCD, 0x2902). Menulis 0x0001 mengaktifkan notifikasi, 0x0002 mengaktifkan indikasi, 0x0000 menonaktifkan keduanya. Metode aioble.ClientCharacteristic.subscribe() melakukan penulisan untuk Anda, dengan flag kata kunci notify=True dan indicate=True.
Setelah berlangganan, client menunggu push masuk dengan notified() dan indicated() -- keduanya adalah coroutine async yang menangguhkan eksekusi hingga push berikutnya tiba.
11.7.3. MTU mengatur ukuran payload¶
Setiap operasi dibatasi oleh MTU yang dinegosiasikan yang disepakati koneksi pada saat link-up. MTU default adalah 23 byte, yang menyisakan 20 byte untuk byte nilai karakteristik setelah header GATT. Apa pun yang lebih besar dari itu harus masuk ke dalam MTU yang lebih besar (dinegosiasikan ke atas melalui aioble.DeviceConnection.exchange_mtu(), hingga 512 byte pada kamera) atau dipecah menjadi beberapa karakteristik atau beberapa notifikasi.
Read dan write yang diprakarsai client untuk nilai yang lebih besar dari MTU ditangani oleh prosedur long GATT di balik layar (Read Long / Prepare-Write + Execute-Write); aioble menjalankan ini secara transparan, sehingga memanggil read() / write() dengan nilai yang terlalu besar hanya membutuhkan lebih banyak perjalanan pulang-pergi. Notifikasi dan indikasi yang diprakarsai server tidak difragmentasi -- satu push dibatasi oleh MTU, dan aplikasi membagi apa pun yang lebih besar menjadi beberapa notifikasi atau keluar dari GATT sepenuhnya.
Untuk transfer yang benar-benar besar -- bingkai yang ditangkap, sekumpulan pengukuran, blob firmware -- jawaban yang tepat biasanya adalah keluar dari GATT sepenuhnya dan menggunakan saluran L2CAP sebagai gantinya (lihat Saluran L2CAP).
11.7.4. Kedua sisi secara sekilas¶
Lima operasi ini diekspos secara berbeda di setiap sisi koneksi:
Di server (peripheral, dalam tata letak umum):
aioble.Characteristic.read()-- membaca nilai lokal saat ini dari database GATT (sisi server dari "apa yang akan dilihat client").aioble.Characteristic.write()-- memperbarui nilai lokal, secara opsional mendorong pembaruan ke setiap client yang berlangganan.aioble.Characteristic.notify()/indicate()-- mengirim push ke satu client tertentu.aioble.Characteristic.written()-- menunggu tulisan masuk berikutnya dari client mana pun.aioble.Characteristic.on_read()-- callback yang dipanggil secara sinkron ketika client membaca, berguna untuk menghitung nilai sesuai permintaan.
Di client (central, dalam tata letak umum):
aioble.ClientCharacteristic.read()-- meminta nilai saat ini ke server.aioble.ClientCharacteristic.write()-- mengirim nilai baru, dengan atau tanpa respons.aioble.ClientCharacteristic.subscribe()-- mengaktifkan / menonaktifkan notifikasi dan indikasi.aioble.ClientCharacteristic.notified()/indicated()-- menunggu push berikutnya.