11.7. Các thao tác GATT¶
Một đặc trưng (characteristic) chỉ nằm trong cơ sở dữ liệu GATT như một giá trị được đặt tên. Điều làm cho nó hữu ích là tập hợp nhỏ các thao tác được định nghĩa rõ ràng mà một máy khách có thể thực hiện trên nó. Mỗi đặc trưng khai báo các thao tác nó hỗ trợ dưới dạng bitmask thuộc tính -- một máy chủ không có gì để công bố có thể xuất bản một giá trị chỉ đọc, một thanh ghi điều khiển có thể chỉ ghi, một cảm biến phát trực tuyến các cập nhật sẽ đặt bit thông báo. Máy khách khám phá bitmask trong quá trình phát hiện và tuân theo nó.
Năm thao tác là đọc, ghi, ghi không có phản hồi, thông báo và chỉ định. Chúng chia thành hai nhóm -- kéo (máy khách hỏi) và đẩy (máy chủ gửi).
11.7.1. Kéo: đọc và ghi¶
Hai thao tác này đơn giản nhất và trông giống như các lời gọi hàm.
Đọc. Máy khách yêu cầu giá trị hiện tại, máy chủ gửi lại. Một vòng đi về, máy khách nhận được các byte mà máy chủ đã đặt cho đặc trưng đó, máy chủ không nhận được gì về người đã đọc.
Ghi. Máy khách gửi các byte mới, máy chủ lưu trữ chúng (và tùy chọn chạy logic ứng dụng trên giá trị mới). Có hai biến thể:
Ghi có phản hồi -- máy chủ xác nhận, phát sinh bất kỳ lỗi ứng dụng nào trên trạng thái khác không. Đáng tin cậy, một vòng đi về.
Ghi không có phản hồi -- máy chủ lưu trữ các byte một cách im lặng; máy khách không nhận được xác nhận nào cả. Nhanh hơn (không có vòng đi về chờ xác nhận) và hữu ích cho việc phát trực tuyến, với chi phí chỉ phát hiện lỗi thông qua kênh phụ đọc lại.
Trong aioble, API phía máy khách ẩn sự lựa chọn sau một phương thức aioble.ClientCharacteristic.write() duy nhất với từ khóa response (True / False / None để tự chọn dựa trên những gì thiết bị đồng nghiệp quảng cáo).
11.7.2. Đẩy: thông báo và chỉ định¶
Mô hình kéo không phù hợp với dữ liệu cảm biến. Một dải đo nhịp tim mà điện thoại phải thăm dò mỗi giây sẽ tiêu tốn pin cho hàng trăm sự kiện radio không cần thiết; một dải đẩy giá trị chỉ khi có một lần đọc mới mới chính là điểm mấu chốt của BLE.
GATT giải quyết vấn đề này bằng các thao tác do máy chủ khởi tạo. Máy khách đăng ký một đặc trưng; từ thời điểm đó trở đi, mỗi khi máy chủ cập nhật giá trị, giá trị mới sẽ được đẩy qua liên kết đến máy khách. Hai biến thể:
Thông báo. Gửi và quên. Máy chủ xếp hàng một thông báo, tầng liên kết truyền nó trong sự kiện kết nối tiếp theo, máy khách nhận được. Không có xác nhận ở tầng GATT; việc truyền lại thông thường của tầng liên kết xử lý mất mát ở phía radio, nhưng ứng dụng không thấy xác nhận rằng giá trị đã được xử lý.
Chỉ định. Máy chủ gửi một thông báo và chờ xác nhận ở tầng GATT của máy khách trước khi gửi cái tiếp theo. Mỗi lần chỉ một chỉ định. Được sử dụng khi máy chủ cần biết máy khách đã thực sự thấy giá trị -- một đặc trưng cảnh báo quan trọng, một xác nhận cấu hình.
Kéo (đọc) so với đẩy (thông báo). Với thông báo, máy khách đăng ký một lần và máy chủ đẩy giá trị mới bất cứ khi nào chúng thay đổi.¶
Việc đăng ký được thực hiện bằng cách ghi vào một bộ mô tả được gắn với đặc trưng -- Bộ mô tả cấu hình đặc trưng máy khách (CCCD, 0x2902). Ghi 0x0001 kích hoạt thông báo, 0x0002 kích hoạt chỉ định, 0x0000 vô hiệu hóa cả hai. Phương thức aioble.ClientCharacteristic.subscribe() thực hiện việc ghi cho bạn, với các cờ từ khóa notify=True và indicate=True.
Sau khi đăng ký, máy khách chờ các lần đẩy đến bằng notified() và indicated() -- cả hai đều là coroutine async tạm dừng cho đến khi lần đẩy tiếp theo đến.
11.7.3. MTU điều chỉnh kích thước tải trọng¶
Mọi thao tác đều bị giới hạn bởi MTU đã thỏa thuận mà kết nối đã chốt vào lúc liên kết. MTU mặc định là 23 byte, để lại 20 byte cho các byte giá trị đặc trưng sau tiêu đề GATT. Bất kỳ thứ gì lớn hơn đó phải vừa vào một MTU lớn hơn (được thỏa thuận tăng qua aioble.DeviceConnection.exchange_mtu(), lên đến 512 byte trên camera) hoặc được chia thành nhiều đặc trưng hoặc nhiều thông báo.
Các lần đọc và ghi do máy khách khởi tạo với các giá trị lớn hơn MTU được xử lý bởi các thủ tục dài của GATT phía sau (Read Long / Prepare-Write + Execute-Write); aioble thực hiện các thủ tục này một cách trong suốt, vì vậy việc gọi read() / write() với một giá trị quá lớn chỉ tốn thêm vòng đi về. Các thông báo và chỉ định do máy chủ khởi tạo không bị phân mảnh -- một lần đẩy bị giới hạn bởi MTU, và ứng dụng chia bất kỳ thứ gì lớn hơn thành nhiều thông báo hoặc thoát khỏi GATT hoàn toàn.
Đối với các truyền tải thực sự lớn -- một khung hình đã chụp, một loạt phép đo, một blob firmware -- câu trả lời đúng thường là thoát khỏi GATT hoàn toàn và sử dụng kênh L2CAP thay thế (xem Các kênh L2CAP).
11.7.4. Tổng quan hai phía¶
Năm thao tác hiển thị khác nhau ở mỗi phía của kết nối:
Ở phía máy chủ (thiết bị ngoại vi, trong bố cục thông thường):
aioble.Characteristic.read()-- đọc giá trị cục bộ hiện tại ra khỏi cơ sở dữ liệu GATT (phía máy chủ của "những gì máy khách sẽ thấy").aioble.Characteristic.write()-- cập nhật giá trị cục bộ, tùy chọn đẩy bản cập nhật đến mọi máy khách đã đăng ký.aioble.Characteristic.notify()/indicate()-- gửi một lần đẩy đến một máy khách cụ thể.aioble.Characteristic.written()-- chờ lần ghi đến tiếp theo từ bất kỳ máy khách nào.aioble.Characteristic.on_read()-- hàm gọi lại được gọi đồng bộ khi máy khách đọc, hữu ích để tính toán một giá trị theo yêu cầu.
Ở phía máy khách (thiết bị trung tâm, trong bố cục thông thường):
aioble.ClientCharacteristic.read()-- yêu cầu máy chủ cung cấp giá trị hiện tại.aioble.ClientCharacteristic.write()-- gửi giá trị mới, có hoặc không có phản hồi.aioble.ClientCharacteristic.subscribe()-- bật / tắt thông báo và chỉ định.aioble.ClientCharacteristic.notified()/indicated()-- chờ lần đẩy tiếp theo.