الفئة CAN -- بروتوكول شبكة منطقة التحكم (Controller Area Network)

CAN هو بروتوكول تسلسلي ثنائي الأسلاك يُستخدم لتوصيل الرسائل في الوقت الفعلي بشكل موثوق بين عقدة واحدة أو أكثر متصلة بناقل مشترك. تم توحيد CAN 2.0 في المعيار ISO-11898، وهو معروف الآن أيضًا باسم CAN Classic.

يوجد أيضًا بروتوكول أحدث ومتوافق مع الإصدارات السابقة يُسمى CAN FD (أي CAN بمعدل بيانات مرن). لا يدعم برنامج التشغيل machine.CAN حاليًا ميزات CAN FD؛ استخدم pyb.CAN على STM32 إذا كنت بحاجة إلى CAN FD.

يتطلب دعم CAN وحدة تحكم (غالبًا ما تكون طرفية داخلية للمتحكم الدقيق)، ومرسلًا مستقبلًا خارجيًا لمعايرة مستوى الإشارات على ناقل CAN.

متوفر على كاميرات OpenMV المعتمدة على STM32 (M4 / M7 / H7 / H7 Plus / Pure Thermal / N6، إضافة إلى المتغيرات التي تحمل علامة Arduino التجارية والتي تتضمن مرسلًا مستقبلًا). غير مدعوم بعد على OpenMV Cam RT1062 (منفذ mimxrt) أو OpenMV Cam AE3 (منفذ alif).

واجهة machine.CAN هي واجهة منخفضة المستوى وأساسية لتبادل رسائل CAN تجرّد وحدة تحكم CAN على هيئة طابور أولوية صادر لإرسال الرسائل، وطابور وارد لاستقبال الرسائل، وآليات للإبلاغ عن الأخطاء.

ملاحظة

ستكون وحدتا micropython-lib المخططتان can و aiocan هما الطريقة الموصى بها لاستخدام CAN مع MicroPython.

المُنشئ

class machine.CAN(id: int, *args, **kwargs)

إنشاء كائن وحدة تحكم CAN بالمعرّف المحدد:

  • يحدد id كائن وحدة تحكم CAN معيّنًا؛ وهو خاص باللوحة والمنفذ.

  • تُمرَّر جميع الوسائط الأخرى إلى CAN.init(). يجب توفير وسيطة واحدة على الأقل (bitrate).

قد تقبل الإصدارات المستقبلية من هذه الفئة أيضًا وسائط مفتاحية خاصة بالمنفذ هنا لتكوين العتاد. لم تُنفَّذ حاليًا أي وسائط مفتاحية من هذا القبيل.

مثال

إنشاء وتهيئة وحدة تحكم CAN رقم 1 بمعدل بت 500kbps:

from machine import CAN
can = CAN(1, 500_000)

الطرق

init(bitrate: int, mode: int = CAN.MODE_NORMAL, sample_point: int = 75, sjw: int = 1, tseg1: int | None = None, tseg2: int | None = None) None

تهيئة ناقل CAN بالمعطيات المحددة:

  • bitrate هو معدل بت الناقل المطلوب بالبت في الثانية.

  • mode هو إحدى القيم الموضحة تحت الأوضاع، ويشير إلى وضع التشغيل المطلوب. الوضع الافتراضي هو التشغيل "العادي" على الناقل.

المعطيات التالية اختيارية وتتعلق بتوقيتات بت CAN. في معظم الحالات يمكنك ترك هذه المعطيات على قيمها الافتراضية:

  • sample_point هو نسبة مئوية صحيحة من زمن بت البيانات. يحدد موضع عينة البت بالنسبة إلى زمن البت الاسمي الكامل. ستحسب وحدة تشغيل CAN المعطيات وفقًا لذلك. يُتجاهل هذا المعطى إذا تم ضبط tseg1 و tseg2.

  • sjw هو عرض قفزة إعادة المزامنة بوحدات كميات الزمن للبتات الاسمية؛ ويمكن أن يكون قيمة بين 1 و 4 شاملة في CAN الكلاسيكي.

  • tseg1 يحدد موضع نقطة العينة بوحدات كميات الزمن للبتات الاسمية؛ ويمكن أن يكون قيمة بين 1 و 16 شاملة في CAN الكلاسيكي. وهو مجموع المرحلتين Prop_Seg و Phase_Seg1 كما هو معرّف في معيار ISO-11898. إذا تم ضبط هذه القيمة فيجب ضبط tseg2 أيضًا ويُتجاهل sample_point.

  • tseg2 يحدد موضع نقطة الإرسال بوحدات كميات الزمن للبتات الاسمية؛ ويمكن أن يكون قيمة بين 1 و 8 شاملة في CAN الكلاسيكي. وهو يقابل Phase_Seg2 في معيار ISO-11898. إذا تم ضبط هذه القيمة فيجب ضبط tseg1 أيضًا.

إذا تم تحديد هذه الوسائط فستُهيَّأ وحدة تحكم CAN بشكل صحيح من أجل bitrate المطلوب والعدد الإجمالي المحدد لكميات الزمن لكل بت. تتجاوز قيمتا tseg1 و tseg2 الوسيطة sample_point إذا تم توفير كل هذه القيم.

ملاحظة

قد يكون لعتاد وحدة التحكم الفردي قيود إضافية على القيم الصالحة لهذه المعطيات، وسيُطلق ValueError إذا لم تكن قيمة معينة مدعومة.

ملاحظة

قد يقبل عتاد وحدة تحكم معين وسائط مفتاحية اختيارية إضافية لميزات خاصة بالعتاد مثل الإفراط في أخذ العينات.

set_filters(filters: list | tuple | None) None

ضبط مرشحات الاستقبال في وحدة تحكم CAN. يمكن أن تكون filters:

  • None لقبول جميع الرسائل الواردة، أو

  • [] أو () لتعطيل استقبال جميع الرسائل، أو

  • كائن قابل للتكرار يحتوي على عنصر واحد أو أكثر تحدد معايير المرشح. ينبغي أن يكون كل عنصر صفًا (tuple) أو قائمة بثلاثة عناصر:

    • identifier هو معرّف CAN (عدد صحيح).

    • bit_mask هو قناع بت للبتات في حقل معرّف CAN (عدد صحيح).

    • flags هو عدد صحيح يحتوي على صفر أو أكثر من البتات المعرّفة في أعلام الرسائل. يحدد هذا الخصائص التي تحتاج الرسالة الواردة إلى مطابقتها. لا تدعم جميع وحدات التحكم التصفية على جميع الأعلام، ويُطلق ValueError إذا طُلب علم غير مدعوم.

تُقبل الرسائل الواردة إذا تطابقت البتات المقنّعة في bit_mask بين معرّف الرسالة وقيمة identifier للمرشح، وتطابقت الأعلام المضبوطة في المرشح مع الرسالة الواردة.

إذا كان البت CAN.FLAG_EXT_ID مضبوطًا في الأعلام، فإن المرشح يطابق معرّفات CAN الموسّعة فقط. وإذا لم يكن البت CAN.FLAG_EXT_ID مضبوطًا، فإن المرشح يطابق معرّفات CAN القياسية فقط.

تُدمج جميع المرشحات معًا بعملية OR في وحدة التحكم. يعني تمرير قائمة أو صف فارغ لوسيطة المرشحات أنه لن يتم استقبال أي رسائل.

تتطلب بعض وحدات تحكم CAN أن يرتبط كل مرشح بطابور استقبال FIFO واحد فقط. في هذه الحالات، تُوزَّع عناصر المرشح في الوسيطة بالتناوب (round-robin) على طوابير FIFO المتاحة. لا يميّز برنامج التشغيل هذا بين طوابير FIFO في مقاطعة الاستقبال (IRQ).

ملاحظة

إذا مرّر المستدعي كائنًا قابلًا للتكرار يحتوي على عناصر أكثر من CAN.FILTERS_MAX، فسيُطلق ValueError.

ملاحظة

إذا كان أي من identifier أو bit_mask خارج النطاق لنوع المعرّف المحدد، فسيُطلق ValueError بالسبب "invalid id".

أمثلة

استقبال جميع الرسائل الواردة:

can.set_filters(None)

استقبال الرسائل ذات قيم المعرّف القياسي 0x301 و 0x700 فقط:

can.set_filters(((0x301, 0x7FF, 0),
                 (0x700, 0x7FF, 0)))

استقبال الرسائل ذات قيم المعرّف القياسي في النطاق 0x300-0x3FF، وقيمة المعرّف الموسّع 0x50700 فقط:

can.set_filters(((0x300, 0x700, 0),
                 (0x50700, 0x1FFF_FFFF, CAN.FLAG_EXT_ID)))
FILTERS_MAX: int

قيمة ثابتة تقرأ العدد الأقصى لمرشحات الاستقبال المدعومة لوحدة التحكم العتادية هذه.

لاحظ أن بعض وحدات التحكم قد يكون لها قيود عتادية أكثر تعقيدًا على عدد المرشحات قيد الاستخدام (على سبيل المثال، عدّ مرشحات المعرّف القياسي والموسّع بشكل مستقل.) في هذه الحالات قد يُطلق CAN.set_filters خطأ ValueError حتى عندما لا يتم تجاوز الحد FILTERS_MAX.

send(id: int, data: bytes, flags: int = 0) int | None

نسخ رسالة CAN جديدة إلى طابور الإرسال العتادي لوحدة التحكم ليتم إرسالها على الناقل. طابور الإرسال هو طابور أولوية مرتب وفق أولوية معرّف CAN (المعرّفات الرقمية الأدنى لها أولوية أعلى).

  • id هو قيمة معرّف CAN عددية صحيحة.

  • data هو كائن bytes (أو ما يشبهه) يحتوي على بيانات رسالة CAN، أو يصف طلب إرسال عن بُعد (Remote Transmission Request) (انظر أدناه).

  • flags هو عدد صحيح يحتوي على صفر أو أكثر من البتات المعرّفة في أعلام الرسائل، يحدد خصائص رسالة CAN الصادرة (معرّف موسّع، طلب إرسال عن بُعد، إلخ.)

إذا تمت إضافة الرسالة بنجاح إلى طابور الإرسال على الناقل، فإن الدالة تُرجع عددًا صحيحًا في النطاق من 0 إلى CAN.TX_QUEUE_LEN (غير شامل). هذه القيمة هي فهرس مخزن الإرسال المؤقت حيث أُضيفت الرسالة للإرسال، ويمكن استخدامها بواسطة دالة CAN.cancel_send وفي أحداث CAN.IRQ_TX.

إذا كان الطابور ممتلئًا فسيفشل الإرسال ويُرجَع None.

قد يفشل الإرسال أيضًا ويُرجِع None إذا كانت قيمة id المقدمة ذات أولوية مساوية لرسالة موجودة في طابور الإرسال ولم يستطع عتاد وحدة تحكم CAN ضمان إرسال الرسائل ذات المعرّف نفسه على الناقل بنفس الترتيب الذي أُضيفت به إلى الطابور. لإضافة الرسالة إلى الطابور على أي حال، مرّر العلم CAN.FLAG_UNORDERED في الوسيطة flags. يشير هذا العلم إلى أنه لا بأس بإرسال الرسائل ذات معرّف CAN نفسه على الناقل بأي ترتيب.

إذا كانت وحدة التحكم في حالة الخطأ "Bus Off" أو معطّلة فإن استدعاء هذه الدالة سيُطلق OSError.

ملاحظة

صُمِّم هذا التنفيذ منخفض المستوى عمدًا بحيث يستطيع المستدعي إنشاء طابور برمجي للرسائل الصادرة.

مهم

"طابور إرسال" CAN ليس طابور FIFO، بل هو مرتب وفق الأولوية، ورغم أنه يمكن أن يحمل حتى CAN.TX_QUEUE_LEN عنصرًا فقد توجد قيود عتادية أخرى على الرسائل التي يمكن إضافتها إلى الطابور في الوقت نفسه.

طلبات الإرسال عن بُعد (Remote Transmission Requests)

إذا كان البت CAN.FLAG_RTR مضبوطًا في الوسيطة flags فإن وحدة التحكم سترسل طلب إرسال عن بُعد بدلًا من رسالة. في هذه الحالة يُتجاهل محتوى الوسيطة data. سترسل وحدة التحكم طلبًا يكون فيه حقل الطول DLC مساويًا لطول الوسيطة data.

أمثلة

محاولة إرسال رسالة بحمولة من ثلاثة بايتات 0a0b0c ومعرّف قياسي 0x200:

can.send(0x200, b"\x0a\x0b\x0c", 0)

محاولة إرسال رسالة بحمولة فارغة ومعرّف موسّع 0x180008. الإشارة إلى أن وحدة التحكم يمكنها إرسال الرسائل بهذا المعرّف بأي ترتيب، في حال وجود رسائل أخرى مضافة للإرسال بنفس المعرّف:

can.send(0x180008, b"", can.FLAG_EXT_ID | can.FLAG_UNORDERED)

محاولة إرسال طلب إرسال عن بُعد بطول 8 بايتات ومعرّف قياسي 0x555:

can.send(0x555, b" " * 8, can.FLAG_RTR)
recv(arg: list | None = None) list | None

إرجاع رسالة CAN التي استقبلتها وحدة التحكم، وفقًا للمرشحات المضبوطة بواسطة CAN.set_filters().

تأخذ هذه الدالة وسيطة اختيارية واحدة، إذا قُدِّمت فيجب أن تكون قائمة من 4 عناصر على الأقل يكون فيها العنصر الثاني كائن memoryview يشير إلى bytearray أو كائن مشابه بسعة كافية لاحتواء أي رسالة CAN مستقبَلة (8 بايتات لـ CAN Classic، 64 بايتًا لـ CAN FD). ستُرجَع القائمة المقدمة كنتيجة ناجحة، وهو ما يتجنب تخصيص الذاكرة داخل الدالة.

إذا لم تستقبل وحدة تحكم CAN أي رسائل، فإن هذه الدالة تُرجع None.

ملاحظة

يجب استدعاء CAN.set_filters قبل أن تتمكن وحدة التحكم من استقبال أي رسائل. لاستقبال جميع الرسائل، استدعِ set_filters(None).

إذا استقبلت وحدة تحكم CAN رسالة، فإن هذه الدالة تُرجع قائمة من 4 عناصر:

  • الفهرس 0 هو معرّف CAN للرسالة المستقبَلة، كعدد صحيح.

  • الفهرس 1 هو memoryview يتيح الوصول إلى بيانات الرسالة المستقبَلة.

    • إذا لم يُقدَّم arg فهذا memoryview يحمل البايتات التي تم استقبالها. يستند هذا memoryview إلى bytearray مخصص حديثًا بحجم كافٍ لاحتواء أي رسالة CAN مستقبَلة. يتيح هذا إعادة استخدام النتيجة بأمان كـ arg مستقبلي، لتوفير عمليات تخصيص الذاكرة.

    • إذا قُدِّم arg فسيُعاد تحجيم memoryview المقدَّم ليحمل تمامًا البايتات التي تم استقبالها. يتحمل المستدعي مسؤولية التأكد من أن الكائن الداعم لـ memoryview يمكنه احتواء رسالة CAN بأي طول.

  • الفهرس 2 هو عدد صحيح يحتوي على صفر أو أكثر من البتات المعرّفة في أعلام الرسائل. ويشير إلى بيانات وصفية حول الرسالة المستقبَلة.

  • الفهرس 3 هو عدد صحيح يحتوي على صفر أو أكثر من البتات المعرّفة في أعلام أخطاء الاستقبال. أي قيمة غير صفرية تشير إلى مشكلات محتملة عند استقبال رسائل CAN. تُعاد هذه الأعلام إلى وضعها الأصلي داخل وحدة التحكم في كل مرة تُرجع فيها هذه الدالة.

طلبات الإرسال عن بُعد (Remote Transmission Requests)

إذا تم استقبال طلب إرسال عن بُعد فسيُضبط البت CAN.FLAG_RTR في الفهرس 2 وسيحتوي memoryview في الفهرس 1 على أصفار بالكامل، بطول مساوٍ لحقل DLC للطلب المستقبَل.

مثال
can.set_filters(None)   # receive all
while True:
    res = can.recv()
    if res:
        can_id, data, flags, errs = res
        print("Received", hex(can_id), data.hex(), hex(flags), hex(errs))
    else:
        time.sleep_ms(1)  # not a good pattern, use the irq instead!
irq(handler: Callable[[CAN], None] | None = None, trigger: int = 0, hard: bool = False) None

تضبط دالة معالج مقاطعة handler ليتم استدعاؤها عند وقوع واحد أو أكثر من الأحداث المعلَّمة في trigger.

  • handler هي دالة تُستدعى عند تحفيز حدث المقاطعة. يجب أن يأخذ المعالج وسيطة واحدة بالضبط هي مثيل CAN.

  • trigger يكوّن الحدث (أو الأحداث) الذي يمكن أن يولّد مقاطعة. القيم الممكنة هي قناع لواحد أو أكثر مما يلي:

    • يقع حدث CAN.IRQ_RX بعد أن تكون وحدة تحكم CAN قد استقبلت رسالة واحدة على الأقل في طابور RX FIFO الخاص بها (مما يعني أن CAN.recv() سيُرجِع بنجاح).

    • يقع حدث CAN.IRQ_TX بعد أن تكون وحدة تحكم CAN قد أرسلت رسالة بنجاح على ناقل CAN أو فشلت في إرسال رسالة. لهذا المُحفِّز متطلبات إضافية على المعالج، انظر أعلام IRQ للتفاصيل.

    • يقع حدث CAN.IRQ_STATE عندما تنتقل وحدة تحكم CAN إلى حالة خطأ أكثر خطورة. استدعِ CAN.state() للحصول على الحالة المحدّثة.

  • hard إذا كانت True، تُستخدم مقاطعة صلبة (hard). يقلل هذا التأخير بين حدث وحدة تحكم CAN واستدعاء المعالج. قد لا تخصص معالجات المقاطعة الصلبة ذاكرة؛ انظر كتابة معالجات المقاطعات.

يُرجِع كائن irq. إذا استُدعيت بدون وسائط فسيُرجَع كائن irq مكوّن مسبقًا.

انظر أعلام IRQ للحصول على مثال.

cancel_send(index: int) bool

طلب وحدة تحكم CAN إلغاء إرسال رسالة على الناقل.

تحدد الوسيطة index مخزن إرسال مؤقت واحدًا. ينبغي أن تكون عددًا صحيحًا في النطاق من 0 إلى CAN.TX_QUEUE_LEN (غير شامل). عمومًا ستكون هذه قيمة أرجعتها سابقًا CAN.send().

تكون النتيجة True إذا كانت هناك رسالة في انتظار الإرسال في هذا المخزن المؤقت وتم إلغاء الإرسال.

تكون النتيجة False خلاف ذلك (إما لم تكن هناك رسالة في انتظار الإرسال في هذا المخزن المؤقت، أو نجح الإرسال بالفعل).

ينبغي استخدام حدث المقاطعة CAN.IRQ_TX لتحديد ما إذا كانت الرسالة قد أُرسلت بالتأكيد أم لا، لكن لاحظ وجود حالات تسابق محتملة إذا أُلغي إرسال ثم استُخدم المخزن المؤقت نفسه لإرسال رسالة أخرى (خاصة إذا لم تكن مقاطعة وحدة تحكم CAN "صلبة").

state() int

يُرجِع قيمة عددية صحيحة تشير إلى الحالة الراهنة لوحدة التحكم. ستكون القيمة إحدى القيم المعرّفة في الحالات.

قد تُمسح حالات الخطأ الأقل خطورة تلقائيًا إذا تعافى الناقل، لكن الحالة CAN.STATE_BUS_OFF لا يمكن التعافي منها إلا باستدعاء CAN.restart().

get_counters(list: list | None = None, /) list

يُرجِع قيم عدّادات الأخطاء لوحدة التحكم. النتيجة هي قائمة من ثماني قيم. إذا حُدِّد المعطى الاختياري list فسيُحدَّث كائن القائمة المقدَّم ويُرجَع كنتيجة، لتجنب عملية تخصيص.

عناصر القائمة هي:

  • قيمة TEC (عدّاد أخطاء الإرسال)

  • قيمة REC (عدّاد أخطاء الاستقبال)

  • عدد المرات التي دخلت فيها وحدة التحكم في حالة التحذير من حالة النشاط.

  • عدد المرات التي دخلت فيها وحدة التحكم في حالة الخطأ السلبي من حالة التحذير.

  • عدد المرات التي دخلت فيها وحدة التحكم في حالة Bus Off من حالة الخطأ السلبي.

  • العدد الإجمالي لرسائل TX المعلّقة في الطابور العتادي.

  • العدد الإجمالي لرسائل RX المعلّقة في الطابور العتادي.

  • عدد المرات التي حدث فيها تجاوز سعة RX.

ملاحظة

حسب وحدة التحكم، قد تتجاوز هذه القيم السعة وتعود إلى 0 بعد قيمة معينة.

ملاحظة

إذا لم تدعم وحدة التحكم عدّادًا معينًا، فستُرجِع None لعنصر القائمة ذاك.

get_timings(list: list | None = None, /) list

يُرجِع قائمة من العناصر تشير إلى التوقيتات المكوّنة حاليًا في وحدة تحكم CAN. يمكن استخدام هذا للتحقق من التوقيتات لأغراض تصحيح الأخطاء. النتيجة هي قائمة من ست قيم. إذا حُدِّد المعطى الاختياري list فسيُحدَّث كائن القائمة المقدَّم ويُرجَع كنتيجة، لتجنب عملية تخصيص.

عناصر القائمة هي:

  • معدل البت الدقيق المستخدم من قبل وحدة التحكم. قد يختلف عن وسيطة bitrate الممرَّرة إلى CAN.init() بسبب التكميم لتلبية قيود العتاد.

  • عرض قفزة إعادة المزامنة (SJW) بوحدات كميات الزمن للبتات الاسمية. له المعنى نفسه للمعطى sjw في CAN.init().

  • موضع نقطة العينة بوحدات كميات الزمن للبتات الاسمية. له المعنى نفسه للمعطى tseg1 في CAN.init().

  • موضع نقطة الإرسال بوحدات كميات الزمن للبتات الاسمية. له المعنى نفسه للمعطى tseg2 في CAN.init().

  • معلومات توقيت CAN FD. تكون None لوحدات التحكم التي لا تدعم CAN FD، أو إذا لم تُهيَّأ CAN FD. وإلا فستكون قائمة متداخلة من أربعة عناصر مقابلة للعناصر أعلاه لكنها تنطبق على ميزة CAN FD BRS.

  • معلومات توقيت اختيارية خاصة بوحدة التحكم. حسب وحدة التحكم ستكون إما None إذا لم تُبلّغ وحدة التحكم عن أي منها، أو ستكون قائمة ثابتة الطول عناصرها خاصة بوحدة تحكم عتادية معينة.

ملاحظة

إذا لم يتم استدعاء CAN.init() فإن هذه الدالة لا تزال تُرجِع نتيجة، لكن النتيجة تعتمد على بنية وحدة التحكم الداخلية وقد لا تكون دقيقة.

restart() None

يجعل وحدة التحكم تخرج من STATE_BUS_OFF دون مسح أي حالة داخلية أخرى. يمسح أيضًا بعض عدّادات الأخطاء (دائمًا عدد المرات التي دُخلت فيها كل حالة خطأ، وربما TEC و REC حسب وحدة التحكم.)

يؤدي استدعاء هذه الدالة أيضًا إلى إلغاء أي رسائل في انتظار الإرسال. لا يتم تسليم أي مقاطعات IRQ_TX لهذه الرسائل.

لاحظ أن هذه الدالة قد تتسبب أو لا تتسبب في خروج وحدة التحكم من حالة "الخطأ السلبي"، حسب ما إذا كان عتاد وحدة التحكم يصفّر TEC و REC أم لا.

deinit() None

يلغي تهيئة مثيل CAN كان نشطًا سابقًا. تُسقَط جميع الرسائل المعلّقة (الإرسال والاستقبال) وتتوقف وحدة التحكم عن التفاعل على الناقل. لاستخدام هذا المثيل مرة أخرى، استدعِ CAN.init().

لا تُستدعى أي مقاطعات IRQ_TX أو IRQ_RX استجابةً لاستدعاء هذه الدالة.

انظر أيضًا CAN.restart().

الثوابت

TX_QUEUE_LEN: int

العدد الأقصى لرسائل CAN التي يمكن إضافتها إلى طابور الرسائل العتادي الصادر لوحدة التحكم. ستكون "فهارس مخزن الإرسال المؤقت" المستخدمة بواسطة CAN.send() و CAN.cancel_send() و أعلام IRQ في هذا النطاق.

الأوضاع

تمثل هذه القيم أوضاع تشغيل وحدة التحكم، كما تُمرَّر إلى CAN.init(). قد لا تدعم جميع وحدات التحكم جميع الأوضاع.

يتطلب تغيير وضع وحدة تحكم قيد التشغيل استدعاء CAN.deinit() ثم استدعاء CAN.init() مرة أخرى بالوضع الجديد.

MODE_NORMAL: int

وحدة التحكم نشطة كعقدة شبكة CAN قياسية (ستقرّ باستلام الرسائل الصالحة وقد ترسل أخطاء حسب حالتها الراهنة State).

MODE_SLEEP: int

وحدة تحكم CAN نائمة في وضع منخفض الطاقة. حسب وحدة التحكم، قد يدعم هذا إيقاظ وحدة التحكم والانتقال إلى CAN.MODE_NORMAL إذا تم استقبال حركة مرور CAN.

MODE_LOOPBACK: int

وضع اختباري. لا تزال وحدة تحكم CAN متصلة بالناقل الخارجي، لكنها ستستقبل أيضًا رسائلها المرسَلة وتتجاهل أي أخطاء ACK.

MODE_SILENT: int

تستقبل وحدة تحكم CAN الرسائل لكنها لا تتفاعل مع ناقل CAN (بما في ذلك إرسال إقرارات ACK والأخطاء وما إلى ذلك.)

MODE_SILENT_LOOPBACK: int

وضع اختباري لا يتطلب توصيل مرسل مستقبِل CAN على الإطلاق. تستقبل وحدة تحكم CAN رسائلها المرسَلة دون التفاعل مع ناقل CAN على الإطلاق. يظل دبوسا TX و RX لـ CAN خاملين.

الحالات

تُرجَع هذه القيم بواسطة CAN.state() وتعكس حالة الخطأ لوحدة تحكم CAN:

STATE_STOPPED: int

لم تتم تهيئة وحدة التحكم.

STATE_ACTIVE: int

وحدة التحكم نشطة وكلا عدّادي الأخطاء TEC و REC أدنى من عتبة التحذير البالغة 96. انظر CAN.get_counters().

STATE_WARNING: int

وحدة التحكم نشطة لكن واحدًا على الأقل من عدّادي الأخطاء TEC و REC بين 96 و 127. انظر CAN.get_counters().

STATE_PASSIVE: int

وحدة التحكم في حالة "الخطأ السلبي" مما يعني أنها لم تعد ترسل أخطاء نشطة إلى الناقل، لكنها بخلاف ذلك تعمل. تُدخَل هذه الحالة عندما يكون واحد على الأقل من عدّادي الأخطاء TEC و REC يساوي 128 أو أكثر، لكن TEC أقل من 255. انظر CAN.get_counters().

STATE_BUS_OFF: int

وحدة التحكم في حالة Bus-Off، مما يعني أن عدّاد الأخطاء TEC أكبر من 255. لن تتفاعل وحدة تحكم CAN مع الناقل في هذه الحالة، وتحتاج إلى إعادة تشغيل عبر CAN.restart() للمتابعة.

أعلام الرسائل

تمثل هذه القيم بيانات وصفية حول رسالة CAN. تقبل الدوال CAN.send() و CAN.recv() و CAN.set_filters() أو تُرجِع قيمة عددية صحيحة مكوّنة من صفر أو أكثر من هذه الأعلام مدموجة معًا بعملية OR بتية.

FLAG_RTR: int

يشير إلى أن الرسالة طلب إرسال عن بُعد.

FLAG_EXT_ID: int

إذا ضُبط، يشير إلى أن معرّف الرسالة موسّع (29 بت). وإذا لم يُضبط، يشير إلى أن معرّف الرسالة قياسي (11 بت).

FLAG_UNORDERED: int

إذا ضُبط في وسيطة flags لـ CAN.send()، يشير إلى أنه لا بأس بإرسال الرسائل ذات معرّف CAN نفسه بأي ترتيب على الناقل.

وإلا فإن محاولة إضافة رسائل متعددة بالمعرّف نفسه إلى الطابور قد تؤدي إلى فشل CAN.send() إذا لم يستطع عتاد وحدة التحكم فرض الترتيب.

لا يُضبط هذا العلم أبدًا على الرسائل المستقبَلة، ويُتجاهل من قبل CAN.set_filters().

أعلام أخطاء الاستقبال

تتضمن نتيجة CAN.recv() قيمة عددية صحيحة مكوّنة من صفر أو أكثر من هذه الأعلام مدموجة معًا بعملية OR بتية. إذا ضُبطت، تشير هذه الأعلام إلى مشكلات عامة محتملة في استقبال رسائل CAN.

RECV_ERR_FULL: int

طابور FIFO العتادي الذي استُقبلت فيه هذه الرسالة ممتلئ، وقد تُفقد رسائل واردة إضافية.

RECV_ERR_OVERRUN: int

طابور FIFO العتادي الذي استُقبلت فيه هذه الرسالة ممتلئ، وقد فُقدت رسالة واردة واحدة أو أكثر.

قيم IRQ

IRQ_RX: int

مرّرها إلى وسيطة trigger لـ irq() لتحفيز المعالج في كل مرة تستقبل فيها وحدة تحكم CAN رسالة كاملة في طابور RX FIFO. داخل المعالج، اقرأ الرسالة باستخدام recv().

IRQ_TX: int

مرّرها إلى وسيطة trigger لـ irq() لتحفيز المعالج في كل مرة تنهي فيها وحدة تحكم CAN محاولة إرسال (نجاحًا أو فشلًا). داخل المعالج، استخدم البتات الإضافية أدناه لمعرفة أي صندوق بريد (mailbox) اكتمل وما إذا كان قد فشل -- انظر أعلام IRQ.

IRQ_STATE: int

مرّرها إلى وسيطة trigger لـ irq() لتحفيز المعالج في كل مرة تنتقل فيها وحدة التحكم بين قيم STATE_* (نشط / تحذير / سلبي / bus-off). استخدم state() داخل المعالج لقراءة الحالة الجديدة.

IRQ_TX_FAILED: int

علم حالة قد يُضبط في irq().flags() عند تحفيز حدث IRQ_TX. يشير إلى أن محاولة الإرسال فشلت (عادةً لأن cancel_send() قد استُدعي، أو لأن وحدة التحكم دخلت في حالة خطأ).

IRQ_TX_IDX_SHIFT: int

موضع البت لحقل فهرس صندوق بريد الإرسال ضمن قيمة irq().flags() أثناء حدث IRQ_TX. يُستخرَج فهرس صندوق البريد على هيئة (flags >> IRQ_TX_IDX_SHIFT) & IRQ_TX_IDX_MASK.

IRQ_TX_IDX_MASK: int

قناع البت لحقل فهرس صندوق بريد الإرسال ضمن قيمة irq().flags() أثناء حدث IRQ_TX. يطابق الفهرس المستخرَج العدد الصحيح الذي أرجعه استدعاء send() المقابل (عدد صحيح في النطاق من 0 إلى TX_QUEUE_LEN).

أعلام IRQ

يسجّل استدعاء CAN.irq() معالج مقاطعة بواحد أو أكثر من المُحفِّزات CAN.IRQ_RX و CAN.IRQ_TX و CAN.IRQ_STATE.

تُرجِع الدالة كائن IRQ، ويُرجِع استدعاء دالة flags() على هذا الكائن عددًا صحيحًا يشير إلى حدث (أو أحداث) المُحفِّز الذي حفّز المقاطعة. ينبغي لمعالج IRQ الخاص بـ CAN استدعاء دالة flags() بشكل متكرر حتى تُرجِع 0.

عندما تُرجِع دالة flags() والبت CAN.IRQ_TX مضبوط، يمكن للمعالج أيضًا فحص بتات الأعلام التالية في النتيجة للحصول على معلومات إضافية حول حدث TX:

  • يُضبط البت CAN.IRQ_TX_FAILED إذا فشل الإرسال. عادةً لن يحدث هذا إلا إذا استُدعي CAN.cancel_send()، رغم أنه قد يحدث أيضًا إذا دخلت وحدة التحكم في حالة خطأ.

  • CAN.IRQ_TX_IDX_MASK << CAN.IRQ_TX_IDX_SHIFT هو منطقة مقنّعة بتيًا من قيمة الأعلام تحمل فهرس مخزن الإرسال المؤقت الذي ولّد الحدث. سيكون هذا عددًا صحيحًا في النطاق من 0 إلى CAN.TX_QUEUE_LEN (غير شامل)، وسيطابق نتيجة استدعاء سابق لـ CAN.send().

مثال IRQ_TX

from machine import CAN

def irq_send(can):
    while flags := can.irq().flags():
        if flags & can.IRQ_TX:
            idx = (flags >> can.IRQ_TX_IDX_SHIFT) & can.IRQ_TX_IDX_MASK
            success = not (flags & can.IRQ_TX_FAILED)
            print("irq_send", idx, success)

can = CAN(1, 500_000)
can.irq(irq_send, trigger=can.IRQ_TX, hard=True)

مهم

إذا كان مُحفِّز CAN.IRQ_TX مضبوطًا فإن المعالج يجب أن يستدعي flags() بشكل متكرر حتى تُرجِع 0، كما هو موضح في هذا المثال. وإلا فقد لا يُعاد تمكين مقاطعات CAN بشكل صحيح.