12.7. Hàm gọi lại kênh

Đối tượng backend được truyền vào protocol.register() là một lớp Python. Thư viện protocol không kiểm tra lớp đó triển khai những phương thức nào; nó kiểm tra instance và kết nối những phương thức tìm thấy. Cơ chế introspection đó chính là điều làm cho giao diện backend trở nên linh hoạt: backend nhỏ nhất chỉ cần hai phương thức, backend phức tạp nhất có mười hai, và ứng dụng có thể chọn từng khả năng một.

12.7.1. Các quy tắc introspection

Khi protocol.register() chạy, thư viện duyệt qua một danh sách cố định các tên callable và liên kết từng tên tìm thấy trên instance backend:

  • Thêm read vào lớp sẽ bật CHANNEL_FLAG_READ. Một lệnh gọi từ host tới channel_read() chỉ đến backend nếu cờ này được đặt.

  • Thêm write sẽ bật CHANNEL_FLAG_WRITE, kích hoạt channel_write().

  • Thêm lockunlock sẽ bật CHANNEL_FLAG_LOCK, cho phép host khóa kênh để thực hiện đọc nguyên tử nhiều gói.

  • Thêm poll cho phép host hỏi "có dữ liệu sẵn sàng không?" một cách nhẹ nhàng, không cần thực hiện đọc đầy đủ.

Các phương thức bị thiếu không phải là lỗi -- thư viện protocol chỉ để khả năng tương ứng bị vô hiệu hóa. Một backend chỉ có sizeread là hoàn toàn hợp lệ; đó là kênh dữ liệu chỉ đọc.

12.7.2. Kênh cảm biến chỉ đọc

Một kênh cảm biến công bố dữ liệu mới mỗi khi host yêu cầu, từ chối ghi từ host, sử dụng bốn hàm gọi lại:

import protocol
import struct

class TempChannel:
    def __init__(self, read_sensor):
        self._read_sensor = read_sensor
        self._buf = b''
        self._fresh = False

    def poll(self):
        # Tell the host whether a reading is waiting.
        return self._fresh

    def size(self):
        # Sample fresh data on every host-side size query.
        value = self._read_sensor()
        self._buf = struct.pack('<f', value)
        self._fresh = True
        return len(self._buf)

    def read(self, offset, size):
        end = offset + size
        if end >= len(self._buf):
            self._fresh = False
        return self._buf[offset:end]

protocol.register(name='temp', backend=TempChannel(read_temperature))

Giải thích từng phương thức làm gì:

  • poll trả về cờ freshness. Host gọi nó trước khi đọc và bỏ qua việc đọc hoàn toàn khi nó trả về False. Điều đó tiết kiệm chi phí round-trip cho trường hợp "chưa có dữ liệu mới".

  • size tái tạo bộ đệm theo yêu cầu và báo cáo độ dài của nó. Việc lấy mẫu tại đây có nghĩa là backend không cần tác vụ nền -- mỗi lệnh gọi từ host điều khiển một phép đo.

  • read trả về một đoạn của bộ đệm. Thư viện protocol có thể gọi nó nhiều hơn một lần khi bộ đệm lớn hơn payload tối đa đã thỏa thuận; tham số offset duyệt qua các đoạn.

  • Không có write nghĩa là ghi từ host bị từ chối ở tầng đóng khung, trước khi backend tham gia.

12.7.3. Tập hàm gọi lại đầy đủ

Để tham khảo, mọi phương thức mà thư viện tìm kiếm trên một backend:

Phương thức

Trả về

Mục đích

init(self)

object

Khởi tạo một lần tùy chọn khi kênh lần đầu liên kết với host. Trả về bất kỳ giá trị nào khác None khi thành công.

poll(self)

bool

Trả về True khi có dữ liệu sẵn sàng.

lock(self)

bool

Giữ kênh để thực hiện truyền nguyên tử nhiều gói.

unlock(self)

bool

Giải phóng lock trước đó.

size(self)

int

Số byte hiện có thể đọc từ kênh.

shape(self)

tuple

Tối đa bốn số nguyên mô tả cấu trúc dữ liệu (ví dụ: chiều cao ảnh, chiều rộng, số byte). Được host sử dụng để giải mã bộ đệm có kiểu.

read(self, offset, size)

bytes

Trả về tối đa size byte bắt đầu từ offset. Được gọi một lần cho mỗi đoạn khi payload vượt quá giới hạn tối đa đã thỏa thuận.

readp(self, offset, size)

bytes

Biến thể zero-copy của read: bộ nhớ của bộ đệm phải tiếp tục hợp lệ trong suốt quá trình truyền.

write(self, offset, data)

int

Host đã ghi data tại offset. data là một view bytearray vào bộ đệm nhận của tầng protocol -- hãy sao chép ra những gì bạn muốn giữ trước khi trả về.

ioctl(self, cmd, length, arg)

int

Opcode do ứng dụng định nghĩa nằm ngoài mô hình đọc/ghi. Giá trị trả về âm là lỗi.

flush(self)

object

Xóa dữ liệu đang được đệm. Được gọi khi host muốn đặt lại kênh.

is_active(self)

bool

Chỉ có nghĩa với các backend đại diện cho transport vật lý (các kênh USB tích hợp). Các kênh ứng dụng không cần điều này.

Đó là toàn bộ giao diện backend. Mười hai tên phương thức, tất cả đều tùy chọn, và thư viện protocol quyết định mỗi kênh có thể làm gì dựa trên những phương thức nào có mặt.