12.7. Callback channel

Objek backend yang diberikan ke protocol.register() adalah kelas Python. Pustaka protokol tidak menanyakan kelas metode mana yang diimplementasikannya; pustaka memeriksa instance dan menghubungkan yang ditemukannya. Introspeksi itulah yang membuat antarmuka backend fleksibel: backend paling kecil yang berguna terdiri dari dua metode, yang paling lengkap terdiri dari dua belas, dan aplikasi memilih setiap kemampuan satu metode sekaligus.

12.7.1. Aturan introspeksi

Ketika protocol.register() dijalankan, pustaka menelusuri daftar tetap nama-nama yang dapat dipanggil dan mengikat setiap yang ditemukan pada instance backend:

  • Menambahkan read ke kelas mengaktifkan CHANNEL_FLAG_READ. Panggilan host ke channel_read() hanya mencapai backend jika flag ini diset.

  • Menambahkan write mengaktifkan CHANNEL_FLAG_WRITE, memungkinkan channel_write().

  • Menambahkan lock dan unlock mengaktifkan CHANNEL_FLAG_LOCK, memungkinkan host mengunci channel untuk pembacaan atomik multi-paket.

  • Menambahkan poll memungkinkan host bertanya "apakah ada yang siap?" dengan murah, tanpa memaksakan pembacaan penuh.

Metode yang hilang bukan merupakan kesalahan -- pustaka protokol hanya menonaktifkan kemampuan yang sesuai. Backend dengan hanya size dan read adalah valid sepenuhnya; itu adalah channel data hanya-baca.

12.7.2. Channel sensor hanya-baca

Channel sensor yang menerbitkan pembacaan baru setiap kali host bertanya, menolak penulisan host, melatih empat dari callback:

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))

Menelusuri apa yang dilakukan setiap metode:

  • poll mengembalikan flag kesegaran. Host memanggilnya sebelum membaca dan melewati pembacaan sepenuhnya ketika mengembalikan False. Ini menghemat biaya round-trip untuk "belum ada data baru."

  • size meregenerasi buffer sesuai permintaan dan melaporkan panjangnya. Melakukan pengambilan sampel di sini berarti backend tidak memerlukan tugas latar belakang -- panggilan host mendorong setiap pengukuran.

  • read mengembalikan irisan buffer. Pustaka protokol mungkin memanggilnya lebih dari sekali ketika buffer lebih besar dari payload maks yang dinegosiasikan; argumen offset menelusuri fragmen-fragmen tersebut.

  • Tidak adanya write berarti penulisan host ditolak di lapisan framing, sebelum backend terlibat.

12.7.3. Set callback lengkap

Sebagai referensi, setiap metode yang dicari pustaka pada backend:

Metode

Mengembalikan

Tujuan

init(self)

object

Inisialisasi satu kali opsional ketika channel pertama kali terikat ke host. Kembalikan nilai non-None apa pun saat berhasil.

poll(self)

bool

Kembalikan True ketika data tersedia.

lock(self)

bool

Ambil channel untuk transfer multi-paket atomik.

unlock(self)

bool

Lepaskan lock sebelumnya.

size(self)

int

Jumlah byte yang saat ini dapat dibaca dari channel.

shape(self)

tuple

Hingga empat bilangan bulat yang mendeskripsikan struktur data (misalnya tinggi citra, lebar, jumlah byte). Digunakan oleh host untuk membongkar buffer bertipe.

read(self, offset, size)

bytes

Kembalikan hingga size byte mulai dari offset. Dipanggil sekali per fragmen ketika payload melebihi maks yang dinegosiasikan.

readp(self, offset, size)

bytes

Varian tanpa-salinan dari read: memori buffer harus tetap valid selama durasi transfer.

write(self, offset, data)

int

Host menulis data pada offset. data adalah tampilan bytearray ke dalam buffer penerimaan lapisan protokol -- salin apa yang ingin Anda simpan sebelum kembali.

ioctl(self, cmd, length, arg)

int

Opcode yang didefinisikan aplikasi di luar model baca/tulis. Nilai kembalian negatif adalah kesalahan.

flush(self)

object

Buang semua data yang di-buffer. Dipanggil ketika host ingin mereset channel.

is_active(self)

bool

Hanya bermakna pada backend yang merepresentasikan transport fisik (channel USB bawaan). Channel aplikasi tidak memerlukan ini.

Itulah seluruh antarmuka backend. Dua belas nama metode, semua opsional, dan pustaka protokol memutuskan apa yang dapat dilakukan setiap channel berdasarkan metode mana yang ada.