rpc --- مكتبة rpc¶
تتيح لك وحدة rpc على OpenMV Cam ربط جهاز OpenMV Cam الخاص بك بمتحكم دقيق أو حاسوب آخر وتنفيذ استدعاءات بايثون (أو إجرائية) عن بُعد على OpenMV Cam. كما تتيح وحدة rpc العكس أيضًا إذا أردت أن يتمكن OpenMV Cam من تنفيذ استدعاءات إجرائية (أو بايثون) عن بُعد على متحكم دقيق أو حاسوب آخر.
كيفية استخدام المكتبة¶
جهاز تابع بسيط يكشف دالة رد نداء واحدة عبر UART:
import rpc
import csi
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
interface = rpc.rpc_uart_slave(baudrate=115200)
def snapshot(_):
return csi0.snapshot().compress().bytearray()
interface.register_callback(snapshot)
interface.loop() # Does not return.
جهاز رئيسي مطابق يطلب من التابع إطار JPEG:
import rpc
interface = rpc.rpc_uart_master(baudrate=115200)
result = interface.call("snapshot")
if result is None:
print("communication failed")
elif len(result) == 0:
print("remote function not registered on the slave")
else:
# result is a memoryview of the JPEG bytes returned by the slave.
print("received", len(result), "bytes")
استبدل rpc_uart_master / rpc_uart_slave بالزوج المطابق can أو i2c أو spi لاستخدام وسيلة نقل مختلفة.
بشكل عام، لكي يستخدم جهاز التحكم مكتبة rpc ستقوم بإنشاء كائن واجهة باستخدام مكتبة rpc. على سبيل المثال:
interface = rpc.rpc_uart_master(baudrate=115200)
ينشئ هذا واجهة UART للتواصل مع تابع rpc.
بمجرد إنشاء الواجهة، كل ما تحتاجه هو تنفيذ:
memory_view_object_result = interface.call("remote_function_or_method_name", bytes_object_argument)
وستحاول مكتبة rpc تنفيذ "remote_function_or_method_name" على التابع. ستتلقى الدالة أو الطريقة البعيدة الوسيط bytes_object_argument الذي يمكن أن يصل حجمه إلى 2^32-1 بايت. بمجرد انتهاء الطريقة البعيدة من التنفيذ، ستعيد memory_view_object_result الذي يمكن أن يصل حجمه أيضًا إلى 2^32-1 بايت. ولأن كلًا من الوسيط والاستجابة عبارة عن حاويات بايت عامة، يمكنك تمرير أي شيء عبر مكتبة rpc وتلقي أي نوع من الاستجابات. إحدى الطرق البسيطة لتمرير الوسائط هي استخدام struct.pack() لإنشاء الوسيط و struct.unpack() لاستقبال الوسيط على الجانب الآخر. أما بالنسبة للاستجابة، فقد يرسل الجانب الآخر كائن سلسلة نصية أو سلسلة json كنتيجة يمكن للجهاز الرئيسي تفسيرها بعد ذلك.
أما بالنسبة للأخطاء، فإذا حاولت تنفيذ اسم دالة أو طريقة غير موجود، فستعيد الطريقة rpc_master.call() كائن bytes() فارغًا. وإذا فشلت مكتبة rpc في التواصل مع التابع، فستعيد مكتبة rpc القيمة None.
لإبقاء الأمور بسيطة، لا تحتفظ مكتبة rpc باتصال بين الجهازين الرئيسي والتابع. تغلّف الطريقة rpc_master.call() محاولة الاتصال بالتابع، وبدء تنفيذ الدالة أو الطريقة البعيدة، والحصول على النتيجة.
الآن، على جانب التابع، يجب عليك إنشاء واجهة rpc للتواصل مع الجهاز الرئيسي. يبدو هذا كالتالي:
interface = rpc.rpc_uart_slave(baudrate=115200)
سينشئ هذا طبقة واجهة UART للتواصل مع جهاز rpc رئيسي.
بمجرد إنشاء واجهة التابع، تحتاج بعد ذلك إلى تسجيل دوال رد النداء التي يمكن للجهاز الرئيسي استدعاؤها باستخدام كائن الواجهة:
def remote_function_or_method_name(memoryview_object_argument):
<lots of code>
return bytes_object_result
interface.register_callback(remote_function_or_method_name)
يمكنك تسجيل أي عدد تريده من دوال رد النداء على التابع. أخيرًا، بمجرد الانتهاء من تسجيل دوال رد النداء، كل ما تحتاجه هو تنفيذ:
interface.loop()
على التابع لبدء تشغيل مكتبة rpc والبدء في الاستماع للجهاز الرئيسي. لاحظ أن الطريقة rpc_slave.loop() لا تعود.
class rpc -- الفئة الأساسية rpc¶
يُعاد تنفيذ الفئة الأساسية rpc بواسطة الفئتين rpc_master و rpc_slave لإنشاء الواجهتين الرئيسية والتابعة. وهي ليست مخصصة للاستخدام المباشر.
- class rpc.rpc¶
ينشئ كائن
rpc. ليس مخصصًا للاستخدام المباشر.- get_bytes(buff: bytearray | memoryview, timeout_ms: int) bytes | None¶
يُعاد تنفيذها بواسطة الفئات الفرعية الخاصة بوسيلة النقل. تملأ
buffببايتات من الواجهة الأساسية خلالtimeout_msمللي ثانية. تعيدNoneعند انتهاء المهلة.
- put_bytes(data: bytes | memoryview, timeout_ms: int) None¶
يُعاد تنفيذها بواسطة الفئات الفرعية الخاصة بوسيلة النقل. ترسل
dataعبر الواجهة الأساسية خلالtimeout_msمللي ثانية.
- stream_reader(call_back: Callable[[memoryview], None], queue_depth: int = 1, read_timeout_ms: int = 5000) None¶
يستقبل تدفقًا من الحمولات من كاتب
rpc.stream_writerبعيد. ينبغي استدعاؤه من داخل دالة رد نداءrpc_slave(أو مباشرة بعد استدعاءrpc_master.callناجح) بمجرد تزامن الجانبين.call_back-- كائن قابل للاستدعاء يُستدعى مرة واحدة لكل حمولة مستلمة بالصيغةcall_back(data)حيثdataهوmemoryview. تُتجاهل القيمة المعادة.queue_depth-- عدد الإطارات قيد النقل التي يُسمح للكاتب بإرسالها قبل الانتظار على القارئ. القيم الأعلى تزيد الإنتاجية على حساب الذاكرة.read_timeout_ms-- عدد المللي ثوانٍ للانتظار لكل حمولة.
يعود عند أي خطأ. للإلغاء، أطلق استثناءً داخل
call_back؛ وستنتهي مهلة الجانب البعيد.
- stream_writer(call_back: Callable[[], bytes | memoryview], write_timeout_ms: int = 5000) None¶
يرسل تدفقًا من الحمولات إلى قارئ
rpc.stream_readerبعيد. ينبغي استدعاؤه من داخل دالة رد نداءrpc_slave(أو مباشرة بعد استدعاءrpc_master.callناجح) بمجرد تزامن الجانبين.call_back-- كائن قابل للاستدعاء يُستدعى بدون وسائط ويعيد حمولةbytesأوmemoryviewالتالية لإرسالها.write_timeout_ms-- عدد المللي ثوانٍ للانتظار عند إرسال كل حمولة.
يعود عند أي خطأ. للإلغاء، أطلق استثناءً داخل
call_back؛ وستنتهي مهلة الجانب البعيد.
class rpc_master -- الفئة الأساسية rpc_master¶
إن rpc_master فئة أساسية. استخدم إحدى الفئات الفرعية الخاصة بوسيلة النقل (rpc_can_master أو rpc_i2c_master أو rpc_spi_master أو rpc_uart_master).
- class rpc.rpc_master¶
ينشئ كائن
rpc_master. ليس مخصصًا للاستخدام المباشر.- call(name: str, data: bytes = bytes(), send_timeout: int = 1000, recv_timeout: int = 1000) memoryview | None¶
ينفذ استدعاءً بعيدًا على الجهاز التابع.
name-- الاسم النصي للدالة أو الطريقة البعيدة المراد تنفيذها.data-- كائن من نوعbytesيُمرَّر كوسيط للدالة البعيدة.send_timeout-- عدد المللي ثوانٍ للانتظار أثناء الاتصال بالتابع وبدء تنفيذ الدالة البعيدة. بمجرد بدء الجهاز الرئيسي في إرسال الوسيط، لا ينطبق هذا بعد الآن؛ إذ تسمح المكتبة بما يصل إلى 5 ثوانٍ لنقل الوسيط.recv_timeout-- عدد المللي ثوانٍ للانتظار حتى يبدأ التابع في إعادة استجابة. بمجرد بدء الجهاز الرئيسي في استقبال الاستجابة، لا ينطبق هذا بعد الآن؛ إذ تسمح المكتبة بما يصل إلى 5 ثوانٍ لنقل الاستجابة.
تعيد
memoryviewللاستجابة عند النجاح، أوbytes()فارغًا إذا كان الاسم البعيد غير موجود على التابع، أوNoneعند فشل الاتصال.
class rpc_slave -- الفئة الأساسية rpc_slave¶
إن rpc_slave فئة أساسية. استخدم إحدى الفئات الفرعية الخاصة بوسيلة النقل (rpc_can_slave أو rpc_i2c_slave أو rpc_spi_slave أو rpc_uart_slave).
- class rpc.rpc_slave¶
ينشئ كائن
rpc_slave. ليس مخصصًا للاستخدام المباشر.- register_callback(cb: Callable[[memoryview], bytes | memoryview]) None¶
يسجل دالة رد نداء يمكن للجهاز الرئيسي استدعاؤها بالاسم.
cbكائن قابل للاستدعاء يأخذ وسيطmemoryviewواحدًا ويعيد كائنًا من نوعbytes. يُستخدم__name__الخاص بدالة رد النداء كمفتاح للبحث.
- schedule_callback(cb: Callable[[], None]) None¶
يجدول
cb(كائن قابل للاستدعاء لا يأخذ وسائط) لتنفيذه مرة واحدة، مباشرة بعد أن تعيد دالة رد نداء rpc قيد التشغيل حاليًا استجابتها بنجاح إلى الجهاز الرئيسي. يجب استدعاؤه من داخل دالة رد نداء rpc. يتيح تشغيل عمل طويل الأمد أو عمليات نقل العبورrpc.get_bytes/rpc.put_bytesبين معاملات rpc. أعد التسجيل عند كل استدعاء إذا كان التنفيذ المتكرر مطلوبًا.
- setup_loop_callback(cb: Callable[[], None]) None¶
يسجل
cb(كائن قابل للاستدعاء لا يأخذ وسائط) ليُستدعى في كل تكرار منrpc_slave.loop. على عكسrpc_slave.schedule_callback، تبقى دالة رد النداء هذه مسجلة. يجب أن تكون غير حاجبة؛ إذ يكون معدل الاستدعاء متغيرًا.
- loop(recv_timeout: int = 1000, send_timeout: int = 1000) None¶
يشغّل حلقة توزيع التابع rpc. لا يعود إلا عبر استثناء يُطلق من دالة رد نداء.
recv_timeout-- عدد المللي ثوانٍ للانتظار للحصول على أمر من الجهاز الرئيسي قبل إعادة المحاولة.send_timeout-- عدد المللي ثوانٍ للانتظار حتى يؤكد الجهاز الرئيسي استلام الاستجابة قبل العودة للاستقبال.
class rpc_can_master -- واجهة CAN الرئيسية¶
التحكم في جهاز rpc آخر عبر CAN.
- class rpc.rpc_can_master(message_id: int = 0x7FF, bit_rate: int = 250000, sample_point: float = 75, can_bus: int = 2)¶
message_id-- معرّف رسالة CAN بطول 11 بت يُستخدم لنقل البيانات.bit_rate-- معدل بت CAN بالبت في الثانية.sample_point-- نسبة نقطة أخذ العينة Tseg1/Tseg2 المئوية (مثل 50.0 أو 62.5 أو 75 أو 87.5).can_bus-- رقم طرفية CAN.
يجب أن يتطابق
message_idوbit_rateلدى الجهاز الرئيسي والتابع. ويجب إنهاء الناقل بمقاومة 120 أوم.
class rpc_can_slave -- واجهة CAN التابعة¶
التحكم به بواسطة جهاز rpc آخر عبر CAN.
class rpc_i2c_master -- واجهة I2C الرئيسية¶
التحكم في جهاز rpc آخر عبر I2C.
- class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)¶
slave_addr-- عنوان I2C بطول 7 بت للجهاز التابع.rate-- تردد ساعة ناقل I2C بوحدة Hz.i2c_bus-- رقم طرفية I2C.
يجب أن يتطابق عنوانا الجهاز الرئيسي والتابع. يلزم وجود مقاومات سحب علوية خارجية على SCL و SDA، ويجب أن يشترك الجهازان في أرضي مشترك.
class rpc_i2c_slave -- واجهة I2C التابعة¶
التحكم به بواسطة جهاز rpc آخر عبر I2C.
class rpc_spi_master -- واجهة SPI الرئيسية¶
التحكم في جهاز rpc آخر عبر SPI.
- class rpc.rpc_spi_master(cs_pin: str = 'P3', freq: int = 1000000, clk_polarity: int = 1, clk_phase: int = 0, spi_bus: int = 2)¶
cs_pin-- اسم دبوس تحديد الشريحة.freq-- تردد ساعة ناقل SPI بوحدة Hz.clk_polarity-- مستوى الساعة في وضع الخمول (0 أو 1).clk_phase-- أخذ عينة البيانات عند حافة الساعة الأولى (0) أو الثانية (1).spi_bus-- رقم طرفية SPI.
يجب أن تتطابق إعدادات الجهاز الرئيسي والتابع. وصّل CS و SCLK و MOSI و MISO مباشرة. ويجب أن يشترك الجهازان في أرضي مشترك.
class rpc_spi_slave -- واجهة SPI التابعة¶
التحكم به بواسطة جهاز rpc آخر عبر SPI.
class rpc_uart_master -- واجهة UART الرئيسية¶
التحكم في جهاز rpc آخر عبر التسلسلي غير المتزامن (UART).
- class rpc.rpc_uart_master(baudrate: int = 9600, uart_port: int = 3)¶
baudrate-- معدل الباود التسلسلي.uart_port-- رقم طرفية UART.
يجب أن يتطابق معدلا الباود لدى الجهاز الرئيسي والتابع. وصّل TX الخاص بالجهاز الرئيسي بـ RX الخاص بالتابع و RX الخاص بالجهاز الرئيسي بـ TX الخاص بالتابع. ويجب أن يشترك الجهازان في أرضي مشترك.
class rpc_uart_slave -- واجهة UART التابعة¶
التحكم به بواسطة جهاز rpc آخر عبر التسلسلي غير المتزامن (UART).