12.7. คอลแบ็กของแชนเนล¶
ออบเจกต์ backend ที่ส่งให้กับ protocol.register() คือคลาส Python ไลบรารีโปรโตคอลไม่ถามคลาสว่ามีเมธอดใดบ้าง แต่จะตรวจสอบ instance และเชื่อมโยงเมธอดที่พบ การตรวจสอบแบบนี้ทำให้ interface ของ backend มีความยืดหยุ่น: backend ที่เล็กที่สุดที่ยังใช้งานได้ต้องการแค่สองเมธอด ส่วน backend ที่ซับซ้อนที่สุดมีถึงสิบสองเมธอด และแอปพลิเคชันสามารถเลือกใช้ความสามารถแต่ละอย่างทีละเมธอด
12.7.1. กฎการตรวจสอบ¶
เมื่อ protocol.register() ทำงาน ไลบรารีจะวนตรวจสอบรายชื่อ callable ที่กำหนดไว้ และเชื่อมโยงแต่ละชื่อที่พบบน instance ของ backend:
การเพิ่ม
readลงในคลาสจะเปิดCHANNEL_FLAG_READการเรียกchannel_read()จากฝั่ง host จะส่งถึง backend ก็ต่อเมื่อ flag นี้ถูกตั้งค่าเท่านั้นการเพิ่ม
writeจะเปิดCHANNEL_FLAG_WRITEเพื่อเปิดใช้งานchannel_write()การเพิ่ม
lockและunlockจะเปิดCHANNEL_FLAG_LOCKทำให้ host สามารถล็อกแชนเนลสำหรับการอ่านแบบ atomic หลายแพ็กเก็ตได้การเพิ่ม
pollทำให้ host สามารถถามว่า "มีข้อมูลพร้อมหรือยัง?" ได้อย่างรวดเร็ว โดยไม่ต้องอ่านข้อมูลเต็มรูปแบบ
เมธอดที่ขาดหายไปไม่ถือเป็นข้อผิดพลาด -- ไลบรารีโปรโตคอลจะปล่อยให้ความสามารถที่เกี่ยวข้องถูกปิดใช้งาน backend ที่มีแค่ size และ read ถือว่าใช้งานได้ถูกต้อง นั่นคือแชนเนลข้อมูลแบบอ่านอย่างเดียว
12.7.2. แชนเนล sensor แบบอ่านอย่างเดียว¶
แชนเนล sensor ที่เผยแพร่ค่าใหม่ทุกครั้งที่ host ร้องขอ โดยปฏิเสธการเขียนจาก host ใช้คอลแบ็กสี่ตัว:
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))
อธิบายสิ่งที่แต่ละเมธอดทำ:
pollคืนค่า flag ความสดใหม่ของข้อมูล host จะเรียกก่อนอ่านและข้ามการอ่านทั้งหมดเมื่อคืนค่าFalseซึ่งประหยัดต้นทุนการส่งข้อมูลกลับไปกลับมาสำหรับกรณี "ยังไม่มีข้อมูลใหม่"sizeสร้างบัฟเฟอร์ใหม่ตามต้องการและรายงานความยาวของมัน การเก็บข้อมูลที่นี่หมายความว่า backend ไม่จำเป็นต้องมี task ที่ทำงานเบื้องหลัง -- การเรียกจาก host ขับเคลื่อนการวัดทุกครั้งreadคืนค่า slice ของบัฟเฟอร์ ไลบรารีโปรโตคอลอาจเรียกมากกว่าหนึ่งครั้งเมื่อบัฟเฟอร์มีขนาดใหญ่กว่า payload สูงสุดที่ตกลงกันไว้ อาร์กิวเมนต์offsetจะเดินผ่านส่วนต่างๆ ของข้อมูลการไม่มี
writeหมายความว่าการเขียนจาก host จะถูกปฏิเสธที่ชั้น framing ก่อนที่จะถึง backend
12.7.3. ชุดคอลแบ็กครบถ้วน¶
สำหรับการอ้างอิง ทุกเมธอดที่ไลบรารีค้นหาบน backend:
เมธอด |
ค่าที่คืน |
วัตถุประสงค์ |
|---|---|---|
|
object |
การเริ่มต้นครั้งเดียวแบบ optional เมื่อแชนเนลผูกกับ host เป็นครั้งแรก คืนค่าที่ไม่ใช่ |
|
bool |
คืนค่า |
|
bool |
ครอบครองแชนเนลสำหรับการถ่ายโอนข้อมูลแบบ atomic หลายแพ็กเก็ต |
|
bool |
ปลดล็อก |
|
int |
จำนวนไบต์ที่อ่านได้จากแชนเนลในขณะนั้น |
|
tuple |
จำนวนเต็มสูงสุดสี่ค่าที่อธิบายโครงสร้างข้อมูล (เช่น ความสูง ความกว้าง จำนวนไบต์ของภาพ) ใช้โดย host เพื่อแกะบัฟเฟอร์ที่มีชนิดข้อมูลกำกับ |
|
bytes |
คืนค่าสูงสุด size ไบต์เริ่มต้นที่ offset เรียกหนึ่งครั้งต่อส่วนเมื่อ payload เกินขนาดสูงสุดที่ตกลงกันไว้ |
|
bytes |
ตัวแปรแบบ zero-copy ของ |
|
int |
host เขียน data ที่ offset -- |
|
int |
opcode ที่กำหนดโดยแอปพลิเคชันนอกเหนือจากโมเดลการอ่าน/เขียน ค่าที่คืนเป็นลบคือข้อผิดพลาด |
|
object |
ลบข้อมูลที่บัฟเฟอร์ไว้ เรียกเมื่อ host ต้องการรีเซ็ตแชนเนล |
|
bool |
มีความหมายเฉพาะกับ backend ที่แทน transport จริง (แชนเนล USB ที่ built-in) แชนเนลของแอปพลิเคชันไม่จำเป็นต้องมีเมธอดนี้ |
นั่นคือ interface ของ backend ทั้งหมด ชื่อเมธอดสิบสองชื่อ ทั้งหมด optional และไลบรารีโปรโตคอลจะตัดสินว่าแชนเนลแต่ละอันทำอะไรได้บ้าง โดยอิงจากเมธอดที่มีอยู่