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.

Two side-by-side diagrams of a server and a client. On the left, the client sends "read", the server replies with the value. Three reads in a row, each pair of arrows. On the right, the client sends a single "subscribe", then the server pushes three "notify" packets at the times it chooses, without any client request in between.

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: