13.3.1.4. Kênh tùy chỉnh

Một kênh là một luồng byte hai chiều có tên giữa tập lệnh phía camera và máy chủ. Camera đăng ký một kênh và cung cấp các hàm gọi lại để tạo ra hoặc tiêu thụ dữ liệu; máy chủ đọc từ và ghi vào kênh đó theo tên. Cơ chế mà gói sử dụng nội bộ cho kênh stream mang khung hình, kênh stdout mang đầu ra tập lệnh, và kênh stdin mang tải lên tập lệnh được tiếp xúc với các tập lệnh người dùng, do đó bất kỳ dữ liệu dành riêng cho ứng dụng nào mà máy chủ cần đều có thể sử dụng cùng kết nối USB mà không cần phát minh một giao thức thứ hai.

Đây là tính năng hữu ích nhất của gói và là tính năng mà tài liệu tiêu chuẩn đề cập ít nhất, vì vậy trang này làm việc qua nó từ đầu đến cuối.

13.3.1.4.1. Hai nửa

Một kênh tùy chỉnh cần mã hợp tác trên cả hai phía. Tập lệnh phía camera nhập protocol, định nghĩa một lớp với ba phương thức (size(), read(), poll()) cùng một write() tùy chọn, và gọi protocol.register(name=..., backend=...) để xuất bản kênh dưới một tên được chọn:

import protocol
import time

class TicksChannel:
    def size(self):
        return 10

    def read(self, offset, size):
        return f'{time.ticks_ms():010d}'

    def poll(self):
        return True

protocol.register(name='ticks', backend=TicksChannel())

Phương thức size() trả về số byte mà kênh hiện có sẵn. read() là bộ sản xuất: cho một offsetsize được yêu cầu bởi máy chủ, nó trả về các byte (hoặc một chuỗi mà lớp giao thức mã hóa). poll() trả về True khi có gì đó để đọc -- lớp giao thức sử dụng điều này để đánh dấu kênh là sẵn sàng trong read_status().

Chương trình phía máy chủ sử dụng bốn phương thức openmv.Camera: has_channel() để kiểm tra kênh tồn tại, channel_size() để hỏi có bao nhiêu dữ liệu đang chờ, channel_read() để kéo byte ra, và channel_write() để đẩy byte vào. read_status() thăm dò mọi kênh cùng một lúc:

from openmv import Camera

with Camera('/dev/ttyACM0') as cam:
    cam.stop()
    cam.exec(open('ticks_cam.py').read())

    while True:
        status = cam.read_status()

        if status.get('ticks'):
            data = cam.channel_read('ticks')
            print(f"ticks: {data.decode()}")

Vòng lặp máy chủ thăm dò read_status(); khi kênh ticks sẵn sàng, nó gọi channel_read() không có size để kéo bất cứ thứ gì có sẵn. TicksChannel.poll() của camera trả về True trên mỗi lần kiểm tra, do đó kênh luôn "sẵn sàng" và máy chủ nhận được một giá trị tick mới mỗi lần thăm dò.

13.3.1.4.2. Kênh hai chiều

Đối với máy chủ cần đẩy dữ liệu trở lại, lớp phía camera thêm một phương thức write() chấp nhận các byte đến:

import protocol

class CommandChannel:
    def __init__(self):
        self.last_command = b''
        self.replied = False

    def size(self):
        return len(self.last_command)

    def read(self, offset, size):
        self.replied = True
        return self.last_command

    def write(self, offset, data):
        self.last_command = b'echo: ' + bytes(data)
        self.replied = False

    def poll(self):
        return not self.replied and len(self.last_command) > 0

protocol.register(name='echo', backend=CommandChannel())

Máy chủ ghi vào kênh bằng channel_write() và đọc phản hồi trở lại thông qua mẫu read_status() / channel_read() thông thường:

with Camera('/dev/ttyACM0') as cam:
    cam.stop()
    cam.exec(open('echo_cam.py').read())

    cam.channel_write('echo', b'hello')

    while True:
        if cam.read_status().get('echo'):
            print(cam.channel_read('echo').decode())
            break

13.3.1.4.3. Lợi ích cho ứng dụng

Kênh tùy chỉnh là công cụ phù hợp khi một ứng dụng muốn sử dụng kết nối USB hiện có cho dữ liệu không phải khung hình, không phải in: bộ đếm đo từ xa, núm cấu hình được truyền trực tiếp từ giao diện người dùng trên máy chủ, lệnh điều khiển được gửi theo chiều ngược lại, kết quả của một phép đo mà camera đã tính toán không phù hợp với khung "ảnh" mà kênh stream giả định. Lớp giao thức xử lý việc đóng khung, phân mảnh, xác nhận và thử lại; tập lệnh chỉ cần triển khai backend bốn phương thức, và máy chủ chỉ cần biết tên kênh và hình dạng dữ liệu.

Cờ --channel NAME của CLI là cách nhanh để xác minh một kênh tùy chỉnh từ terminal mà không cần viết chương trình phía máy chủ: CLI thăm dò kênh được đặt tên và in mười byte đầu tiên của mỗi lần cập nhật.

Giới hạn kích thước trên một lần gọi channel_read() hoặc channel_write()max_payload đã được đàm phán của giao thức -- mặc định là 4096 byte. Các phương thức phía máy chủ tự động chia nhỏ các lần ghi lớn hơn thành số lượng gói tin phù hợp, vì vậy ứng dụng có thể truyền các bộ đệm tùy ý lớn; việc phân mảnh là vô hình.