11.11. Saluran L2CAP¶
GATT adalah model kunci/nilai. Operasi yang ditawarkannya (baca, tulis, notifikasi, indikasi) memindahkan satu nilai pendek pada satu waktu, dan payload tunggal terbesar yang dapat dibawa adalah sebesar MTU yang dinegosiasikan -- paling banyak beberapa ratus byte. Ini bekerja dengan baik untuk pembacaan sensor, register perintah, dan tanda status. Namun pendekatan ini tidak cocok untuk data berukuran kilobyte atau megabyte: memecah blob yang panjang menjadi ratusan penulisan kecil membutuhkan banyak round trip yang jauh lebih lambat dibandingkan kecepatan radio.
Untuk aliran data massal -- bingkai yang ditangkap dan di-stream kamera ke ponsel, citra pembaruan over-the-air, ekspor pengukuran secara batch -- BLE menawarkan jalur alternatif: Logical Link Control and Adaptation Protocol, L2CAP. L2CAP berada di antara lapisan tautan dan GATT, dan memungkinkan aplikasi mengklaim saluran berorientasi koneksi miliknya sendiri di atas tautan radio yang sama. Saluran ini adalah jalur byte yang dikontrol aliran kredit dengan MTU per-paket yang jauh lebih besar dan tanpa framing GATT di tengahnya.
11.11.1. Kapan Menggunakan L2CAP¶
Saluran L2CAP adalah alat yang tepat ketika:
Transfer data lebih dari beberapa ratus byte.
Kedua ujung sudah mengetahui bahwa saluran L2CAP akan digunakan (tidak diekspos dalam payload periklanan; klien harus mengetahui nomor protocol/service multiplexer saluran, atau PSM, dari luar jalur komunikasi utama).
Aplikasi bersedia melepaskan kenyamanan GATT: tidak ada pengalamatan bawaan berdasarkan UUID, tidak ada kemampuan penemuan oleh klien melalui aplikasi standar, tidak ada notifikasi.
Kasus paling umum dalam aplikasi berbasis aioble adalah memindahkan binary blob antara dua perangkat lunak yang sama-sama mengetahui konvensi PSM -- protokol kamera-ke-ponsel khusus, sepasang kamera openmv yang saling berkomunikasi, atau jalur pembaruan firmware internal di bawah layanan GATT sebuah periferal.
Untuk semua hal lainnya, tetap gunakan GATT. Status pendek, register kontrol, pembacaan sensor -- semua itu tempatnya di dalam sebuah karakteristik.
11.11.2. Membangun Saluran¶
L2CAP berjalan di atas aioble.DeviceConnection yang sudah ada, sehingga alur penemuan / periklanan / koneksi di sisi GAP persis sama seperti untuk GATT. Setelah kedua sisi memegang koneksi, satu sisi mendengarkan pada PSM, sisi lainnya terhubung ke sana.
PSM hanyalah bilangan bulat kecil. Bluetooth SIG mereservasi bagian bawah rentang untuk penggunaan yang distandarisasi (0x0001-0x007F); untuk saluran yang spesifik pada aplikasi, gunakan angka dari rentang dinamis (0x0080-0x00FF untuk PSM tetap, mulai 0x0040 umumnya bebas untuk penggunaan khusus). Kedua sisi harus menyepakati nilainya terlebih dahulu.
MTU pada saluran L2CAP adalah SDU (Service Data Unit) tunggal terbesar yang akan dikirimkan oleh salah satu sisi dalam satu send() -- bukan MTU tautan BLE. Aioble secara otomatis memfragmentasi payload yang lebih besar. Host BLE kamera membatasi MTU L2CAP pada 1017 byte; 512 adalah default yang masuk akal yang memberikan ruang di kedua sisi tanpa menghabiskan RAM.
Di sisi pendengar (misalnya kamera sebagai periferal):
async def serve_l2cap(connection, image_bytes):
channel = await connection.l2cap_accept(psm=0x80, mtu=512)
async with channel:
# image_bytes is a bytearray -- e.g. csi0.snapshot().bytearray()
# or a compressed JPEG buffer. send() fragments into MTU-sized
# chunks automatically and awaits flow-control credits between.
await channel.send(image_bytes)
await channel.flush()
Di sisi penghubung (misalnya ponsel atau central):
async def open_l2cap(connection, total_bytes):
channel = await connection.l2cap_connect(psm=0x80, mtu=512)
async with channel:
image_bytes = bytearray(total_bytes)
view = memoryview(image_bytes)
received = 0
while received < total_bytes:
n = await channel.recvinto(view[received:])
if n == 0:
break
received += n
return image_bytes
l2cap_accept() memblokir hingga peer terhubung (atau timeout_ms terpicu); l2cap_connect() memblokir hingga pendengar menerima (atau gagal). Keduanya mengembalikan aioble.L2CAPChannel -- yang merupakan async context manager yang menutup saluran saat keluar.
11.11.3. Mengirim dan Menerima¶
Dua operasi utama pada saluran adalah send() (menulis byte ke peer) dan recvinto() (membaca ke dalam buffer yang telah dialokasikan sebelumnya). Keduanya adalah coroutine.
send()memfragmentasi buffer menjadi potongan berukuran MTU dan menunggu kredit flow-control lapisan tautan di antaranya. Pengiriman yang panjang adalah satuawaitdari perspektif aplikasi; secara internal mungkin mengantrekan banyak paket dan berhenti setiap kali kredit penerima peer habis.recvinto()mengisi buffer yang diteruskan dengan data yang tersedia (hingga MTU saluran) dan mengembalikan jumlah byte. Menunggu jika tidak ada data yang tersedia.available()mengembalikanTruesecara sinkron jika ada data yang telah di-buffer dan siap -- berguna untuk polling tanpa menangguhkan eksekusi.flush()menunggu hingga semua pengiriman yang tertunda telah sepenuhnya dikirimkan ke controller.
Saluran L2CAP mirip stream dalam artian byte tiba secara berurutan dan tanpa kehilangan, tetapi batas-batas dari satu send dipertahankan -- setiap SDU keluar dari satu recvinto. Ini berbeda dengan TCP, di mana batas-batas satu send() dapat tersebar di beberapa panggilan recv().
11.11.4. Penanganan Pemutusan Koneksi¶
Saluran akan hilang dalam tiga kondisi: salah satu sisi memanggil disconnect(), koneksi GAP yang mendasarinya terputus, atau pemutusan koneksi di tingkat L2CAP tiba. Operasi yang sedang aktif akan memunculkan aioble.L2CAPDisconnectedError. Seperti pada sisi GATT, ini muncul sebagai pengecualian dalam coroutine yang sedang menunggu, dan blok async with channel keluar dengan bersih.
Jika sebuah saluran menjadi tidak dapat dijangkau karena pemutusan koneksi di tingkat GAP, aplikasi kembali ke periklanan atau pemindaian dengan cara yang sama seperti ketika terjadi pemutusan koneksi GATT.
11.11.5. Biaya Memori¶
MTU yang lebih besar dan antrean yang lebih panjang menggunakan lebih banyak RAM di kedua sisi. MTU 512 byte ditambah buffer penerimaan per-saluran adalah sekitar 1 KB per saluran -- tidak gratis pada kamera kecil jika beberapa saluran terbuka sekaligus. Pertahankan satu saluran per koneksi dan pilih MTU yang sesuai dengan ukuran pesan yang diharapkan; default satu L2CAPChannel per DeviceConnection sudah cukup untuk sebagian besar aplikasi.
L2CAP adalah katup pengaman BLE. GATT adalah yang pertama dicari oleh hampir setiap aplikasi, dan contoh-contoh central / periferal di bagian lainnya tetap menggunakan GATT. API berbasis saluran adalah jawabannya ketika sebuah aplikasi telah melampaui model kunci/nilai.