
برنامج ثابت لـ Raspberry Pi Pico W ينشئ محول USB Wi-Fi بدون برامج تشغيل مع جسر شفاف من الطبقة 2، ومصادقة WPA2/WPA3، ووحدة تحكم إدارة خارج النطاق.
= pico-usb-wifi :toc: macro :toclevels: 3 :idprefix: :idseparator: -
pico-usb-wifi هو برنامج ثابت (فيرموير) لـ Raspberry Pi Pico W يحوّله إلى محوّل USB Wi-Fi بدون برامج تشغيل، حيث يتعرّف عليه النظام كجهاز USB CDC-NCM.
:figure-caption: محتوى الذكاء الاصطناعي الرديء
.مخطط pico-usb-wifi image::images/openrouter-banana2-rpi-pico.png[]
يعمل البرنامج الثابت كجسر شفاف للطبقة 2 يمرّر الإطارات بين الواجهة اللاسلكية لـ Pico W وواجهة USB الخاصة بها. تتبنّى واجهة USB على المضيف عنوان MAC الخاص بمحطة Wi-Fi في Pico W، مما يوفر هوية MAC وعنوان IP واحدة من الطرف إلى الطرف.
لا يلزم أي برنامج تشغيل على جانب المضيف، أو وحدة نواة، أو مكدس لاسلكي؛ انظر <<no-host-side-wi-fi-stack,لا حاجة لمكدس Wi-Fi على جانب المضيف>>.
يحتاج المضيف فقط إلى برنامجي التشغيل المدمجين cdc_ncm وcdc_acm اللذين يأتيان مع كل نظام Linux وmacOS وWindows ونظام تشغيل هواتف حديث.
== الميزات
يوفر pico-usb-wifi هذه الميزات:
.سيناريو من الواقع الفعلي image::images/slop_2.png[]
== لماذا وُجد هذا المشروع
كنت بحاجة إلى محوّل USB Wi-Fi لاستخدامه في مشروع Linux مضمّن قادم. لم يكن لديّ دونجل USB Wi-Fi رخيص، فبدلًا من الذهاب وشراء واحد من متجر فعلي بخمسة دولارات أمريكية، أمضيت يومين من عطلة نهاية أسبوع طويلة وحوالي مليون رمز (token) من Claude Code في بناء هذا البرنامج الثابت.
白一百، مؤلف pico-usb-wifi
قالت Google إن الأمر غير ممكن:
.pico-usb-wifi «غير ممكن» image::images/gemini_says_not_possible.png[]
toc::[]
== لا حاجة لمكدس Wi-Fi على جانب المضيف
بخلاف دونجل USB Wi-Fi، يعرض هذا المحوّل للمضيف واجهة شبيهة بإيثرنت فقط. يحتوي Pico W على الجانب اللاسلكي بأكمله: الراديو، والاقتران (association)، وعميل WPA2/WPA3 (supplicant)، والنطاق التنظيمي.
يتيح ذلك للأنظمة تجنّب تثبيت wpa_supplicant، ومكدس cfg80211/mac80211 اللاسلكي، وقاعدة بيانات تنظيمية، وبرنامج تشغيل خاص بالرقاقة أو من البائع.
يتم توفير بيانات اعتماد Wi-Fi على الجهاز نفسه، عبر وحدة التحكم الإدارية خارج النطاق، وليس من خلال أي أداة لاسلكية على جانب المضيف.
بهذا يظل المضيف محدود الموارد، أو الجهاز المخصّص (appliance)، أو المضيف الذي لا يملك برامج تشغيل لاسلكية أو الذي تفتقر نواة البائع لديه إليها، قادرًا على الاتصال بالشبكات اللاسلكية باستخدام برامج تشغيل CDC العامة فقط.
== كيف يعمل
[#fig-topology] .مخطط الطوبولوجيا image::images/topology.svg[طوبولوجيا جسر الطبقة 2 الشفاف,820]
تُمنح واجهة USB على المضيف عنوان MAC الخاص بمحطة Wi-Fi في Pico W، بحيث توجد هوية MAC واحدة من الطرف إلى الطرف ويستطيع Pico W تمرير إطارات إيثرنت كما هي بين USB وWi-Fi. لا يمكن لمحطة Wi-Fi أن تجسر عدة عناوين MAC، لذا فإن دمج المضيف والمحطة في عنوان MAC واحد هو ما يجعل الجسر الشفاف ممكنًا أصلًا. المنطق الكامل، ومسار البيانات، ومعالجة IPv6/البث المتعدد موصوفة في <<architecture,البنية>>.
== متطلبات المضيف
يتطلب المضيف برنامجي التشغيل المدمجين في الشجرة cdc_ncm وcdc_acm.
كلاهما جزء من نواة Linux الرئيسية منذ أكثر من عقد من الزمن، لذا فإن أي نواة مدعومة حاليًا تشملهما.
لا حاجة لأي وحدة خارج الشجرة، أو blob برنامج ثابت، أو برنامج تشغيل من البائع.
توجد برامج التشغيل نفسها على macOS وWindows 10 والإصدارات الأحدث وAndroid وiOS.
[NOTE] لم تُختبر أي أنظمة تشغيل أخرى.
== البناء
المشروع هو مشروع CMake قياسي يعتمد على pico-sdk. يتطلب سلسلة أدوات ARM المضمّنة، وCMake، ومحرك بناء (Ninja أو Make)، وPython 3، ونسخة مستنسخة من pico-sdk مع وحداته الفرعية. يُستخدم TinyUSB وlwIP المرفقان مع pico-sdk كما هما دون تعديل.
=== التبعيات
على الأنظمة المبنية على Arch (Arch وCachyOS وManjaro)، تأتي السلسلة من المستودعات الرسمية:
يوفر arm-none-eabi-newlib مكتبة C المضمّنة والملفات الرأسية؛ وبدونه لا يستطيع المترجم المتقاطع العثور على stdint.h والملفات الرأسية المشابهة.
libusb مطلوب فقط من أجل picotool، الذي يبنيه pico-sdk من المصدر أثناء أول إعداد (configure) لتوليد ملف UF2؛ ولا يلزم أي حزمة picotool منفصلة.
=== خطوات البناء
git clone -b 2.2.0 --recurse-submodules https://github.com/raspberrypi/pico-sdk export PICO_SDK_PATH="$PWD/pico-sdk"
cp src/wifi_config.h.example src/wifi_config.h # then edit SSID/password, or leave blank cmake -S . -B build -G Ninja -DPICO_BOARD=pico_w -DCMAKE_BUILD_TYPE=Release cmake --build build
العلامة -G Ninja اختيارية؛ احذفها لاستخدام مولد Make الافتراضي (ثم نفّذ cmake --build build -j).
يحتفظ wifi_config.h ببيانات الاعتماد الافتراضية وقت البناء، وهو مستثنى من Git (gitignored).
تركه فارغًا ينتج صورة بدون بيانات اعتماد مدمجة (baked)، تُزوَّد لاحقًا في زمن التشغيل عبر وحدة التحكم الإدارية (<<management-console,وحدة التحكم الإدارية>>)؛ وملؤه يدمج شبكة افتراضية في الصورة.
== كتابة البرنامج الثابت
الخطوات هنا تحمّل البرنامج الثابت على اللوحة.
. اضغط مع الاستمرار على زر BOOTSEL أثناء توصيل اللوحة عبر USB.
تظهر كوحدة تخزين USB كتلي باسم RPI-RP2، عادةً تحت /run/media/<user>/RPI-RP2 أو /media/<user>/RPI-RP2.
. انسخ pico-usb-wifi.uf2 إلى تلك الوحدة.
تعيد اللوحة تشغيل نفسها تلقائيًا لتعمل بالبرنامج الثابت.
. وصّل اللوحة بالمضيف الذي سيستقبل الاتصال اللاسلكي.
== الاستخدام على مضيف Linux
وصّل الجهاز بالمضيف وزوّده ببيانات اعتماد Wi-Fi مرة واحدة عبر وحدة التحكم الإدارية (<<management-console,وحدة التحكم الإدارية>>). بعدها تتصرف واجهة المضيف مثل أي اتصال سلكي على شبكة نقطة الوصول.
المضيف الذي يدير واجهاته تلقائيًا (NetworkManager، أو systemd-networkd، أو dhcpcd) لا يحتاج إلى أي إعداد: فهو يشغّل DHCP وSLAAC عبر الجسر ويستلم عنوان IPv4 واحدًا وعنوان IPv6 وبوابة نقطة الوصول وخوادم DNS، تمامًا كما يفعل أي عميل سلكي.
لا يوجد عنوان أو بوابة على جانب الجهاز لتكوينها، لأن Pico لا يحمل أيًّا منها.
عنوان MAC للواجهة هو عنوان MAC الخاص بمحطة Wi-Fi، وبهذه الطريقة تُقدَّم هوية واحدة للشبكة.
يُظهر مخرج أمر ip هنا الواجهة الناتجة: عميل DHCP/SLAAC عادي على الشبكة الفرعية الخاصة بنقطة الوصول، بعنوان MAC الخاص بالمحطة ودون أي أثر لـ Pico.
== وحدة التحكم الإدارية
وحدة التحكم الإدارية هي الواجهة الأمامية للتكوين، وتعمل على أول وظيفة تسلسلية CDC-ACM (عادةً /dev/ttyACM0).
يمكن الوصول إليها فور أن يتعرّف النظام على الجهاز، قبل اقتران Wi-Fi، لذا لا يتطلب تزويد البيانات أي شبكة.
افتحها باستخدام طرفية تسلسلية مثل picocom أو screen؛ لا يهم معدل الباود مع USB CDC.
تعيد وحدة التحكم عرض ما تكتبه وتظهر صيغة انتظار أوامر (prompt)، ويطبع كل أمر حالة الجهاز الكاملة.
مصادقة Wi-Fi تكون إما WPA2-PSK أو WPA3-SAE (AES).
كلمة المرور هي عبارة مرور الشبكة، أو تظل الشبكة مفتوحة عند تركها فارغة.
يستخدم الملف المحمي بكلمة مرور وضع الانتقال WPA2/WPA3، لذا ينضم إلى أيٍّ من نوعي نقاط الوصول.
تخزّن وحدة التحكم حتى ثمانية ملفات تعريف لبيانات الاعتماد؛ أحدها هو الملف النشط ويقترن به الجهاز.
يعدّل set ssid/set pass الملف النشط، وتدير list/use/del مجموعة الملفات، ويكتشف scan الشبكات القريبة وينضم إلى إحداها من قائمة مرقّمة — وهو أمر مفيد عندما تحتوي SSID على أحرف يصعب كتابتها.
كلمات الأوامر غير حساسة لحالة الأحرف؛ وتعرضها وحدة التحكم بأحرف صغيرة.
في الجلسة هنا، تُزوَّد الشبكة بالبيانات عبر مسحها.
$ picocom /dev/ttyACM0
يسري التغيير فورًا مع إعادة الاقتران بالملف النشط؛ ولا يلزم إعادة تشغيل.
كرر الأمر لحفظ المزيد من الشبكات؛ يعرض list هذه الشبكات ويبدّل use <n> الملف النشط:
يحفظ save كل ملف تعريف في ذاكرة الفلاش؛ ويتجاهل restore التعديلات غير المحفوظة بإعادة تحميل السجل المحفوظ.
يسرد الجدول هنا مجموعة الأوامر.
[#tbl-config-commands] .أوامر وحدة التحكم الإدارية [cols="2,3", options="header"] |=== |الأمر |التأثير
|set ssid <text>
|تعيين SSID للملف النشط (قد تحتوي القيمة على مسافات) وإعادة الاقتران؛ ينشئ الملف الأول إذا لم يوجد أي ملف.
|set pass <text>
|تعيين عبارة مرور WPA2/WPA3 للملف النشط (اتركها فارغة لشبكة مفتوحة) وإعادة الاقتران.
|set country <CC\|WORLDWIDE>
|تعيين الدولة التنظيمية (يُطبَّق بالكامل عند الإقلاع التالي).
|set debug <on\|off>
|بث التشخيصات على وحدة تحكم التصحيح؛ انظر <<debug-console,وحدة تحكم التصحيح>>.
|list
|عرض ملفات التعريف المحفوظة مع تمييز النشط منها.
|use <n>
|جعل الملف n نشطًا وإعادة الاقتران.
|del <n>
|حذف الملف n.
|scan
|مسح الشبكات القريبة والدخول إلى القائمة الفرعية للمسح (back للرجوع، وjoin <n> للانضمام، وscan للتكرار، أو live لتدفق مستمر دون اقتران). يجهّز join الشبكة المختارة كملف نشط، جاهزًا لأمر set pass.
|save
|حفظ جميع ملفات التعريف والإعدادات في ذاكرة الفلاش.
|restore
|تجاهل التغييرات غير المحفوظة بإعادة تحميل الإعدادات المحفوظة.
|===
يظهر العنوان المعيّن للمضيف في تفريغ الحالة كـ host IPv4 وhost IPv6، ويُلتقط بشكل سلبي من حركة المرور المُجسَّرة، لأن Pico لا يحمل عنوانًا يبلّغ عنه.
يقع قطاع الإعدادات في نهاية ذاكرة الفلاش، منفصلًا عن صورة البرنامج في بدايتها، لذا فإن إعادة وميض عادية لملف pico-usb-wifi.uf2 تُبقي ملفات التعريف المحفوظة سليمة (بينما يمسحها مسح الشريحة بالكامل).
الاستثناء هو الترقية إلى v1.1.0: فقد تغيّر تخطيط السجل ليحمل ملفات تعريف متعددة، لذا يُتجاهل السجل الأقدم من 1.1.0 ويجب إدخال الشبكات مرة واحدة (انظر سجل التغييرات).
== وحدة تحكم التصحيح
وحدة تحكم التصحيح هي تدفق تشخيصي للكتابة فقط على ثاني وظيفة تسلسلية CDC-ACM (عادةً /dev/ttyACM1).
تظل صامتة حتى يصدر أمر set debug on من وحدة التحكم الإدارية، لذا لا تكلف شيئًا عند إيقافها ولا تتعارض أبدًا مع الإدارة.
عند تفعيلها، تُبلغ عن تغييرات الاقتران وسطر إحصاءات الجسر الدوري، كما في الجلسة هنا.
يضيف بناء مع -DTRACE_FRAMES=1 سطرًا ملخصًا واحدًا لكل إطار مُجسَّر، لكنه يُغرق وحدة التحكم تحت الحمل، لذا فهو معطل افتراضيًا.
تُوصف حقول الإحصائيات في الجدول هنا.
[#tbl-debug-stats] .حقول إحصائيات التصحيح [cols="1,3", options="header"] |=== |الحقل |الدلالة
|->wifi
|الإطارات المُمرَّرة من المضيف إلى Wi-Fi.
|->host
|الإطارات المُمرَّرة من Wi-Fi إلى المضيف.
|txdrop
|إطارات من المضيف إلى Wi-Fi أُسقطت لأن المحطة لم تكن قد اقترنت بعد (يعيد المضيف المحاولة).
|rxdrop
|إطارات من Wi-Fi إلى المضيف أُسقطت لأن جانب USB لم يستطع التفريغ بالسرعة الكافية.
|refl
|إطارات من Wi-Fi إلى المضيف أُسقطت لأنها كانت إرسال المضيف نفسه، أعادتها نقطة الوصول (انعكاس).
|poolfail
|إطارات من المضيف إلى Wi-Fi أُسقطت لأن مجموعة pbuf في lwIP نضبت مؤقتًا.
|ringpk
|ذروة عمق قائمة انتظار USB-TX من Wi-Fi إلى المضيف (من أصل 32) منذ سطر الإحصائيات السابق، ثم تُصفَّر — وهو مؤشر لحظي، حيث تعني القيمة القريبة من 32 أن USB لا يستطيع التفريغ بسرعة وصول Wi-Fi. (على عكس الحد الأقصى المطلق، يعود للانخفاض بمجرد أن تمرّ الاندفاعة.)
|link
|حالة رابط Wi-Fi للمحطة: up (مقترنة)، أو join/down (قيد الاقتران)، أو سبب فشل — badauth (عبارة مرور خاطئة)، أو nonet (لم يُعثر على SSID)، أو fail.
|hangs
|عدد المرات التي أنقذ فيها الحارس (watchdog) البرنامج الثابت من التعليق منذ آخر تشغيل بارد؛ انظر <<automatic-recovery,الاسترداد التلقائي>>.
|faults
|الأخطاء الصلبة (hard faults) التي تعافى منها البرنامج الثابت منذ آخر تشغيل بارد.
|faultpc
|عنوان آخر خطأ صلب (0x00000000 إن لم يوجد)، لربطه بالكود باستخدام addr2line.
|freeram
|الذاكرة الحرة بالبايت، لقياس الهامش المتاح عند ضبط أحجام المخازن المؤقتة.
|===
يتشارك التتبع لكل إطار رابط USB Full-Speed مع حركة المرور المُجسَّرة، لذا فهو يقلل الإنتاجية ويُغرق وحدة التحكم معًا؛ وهو خيار زمن البناء (-DTRACE_FRAMES=1) مخصص فقط للتصحيح العميق.
== الاسترداد التلقائي
يعيد حارس عتادي (hardware watchdog) تشغيل الجهاز إذا توقف البرنامج الثابت عن خدمة حلقته الرئيسية — بسبب تعليق أو جمود برنامج تشغيل — فيعيد الجهاز تعرّف النظام عليه من تلقاء نفسه خلال ثوانٍ بدلًا من الحاجة إلى فصله. معالج خطأ صلب منفصل يلتقط خطأ المعالج فورًا ويسجّل عنوان الخطأ.
تبقى عدادات الجسر من اللحظات التي سبقت الانهيار سليمة بعد إعادة التشغيل في ذاكرة RAM غير مهيأة.
عند الاسترداد، يطبع الجهاز تقريرًا من سطر واحد بصيغة RECOVERED from ... على وحدة تحكم التصحيح يتضمن تلك العدادات (وعنوان الخطأ في حالة الخطأ الصلب)، ويحمل سطر stats: الجاري إجماليات hangs وfaults وfaultpc، لذا يترك أي انهيار أثرًا تشخيصيًا حتى وإن زال من تلقاء نفسه.
== حالات LED المدمجة على اللوحة
يسرد الجدول هنا أنماط LED المدمجة ومعناها.
[#tbl-led] .أنماط LED المدمجة [cols="1,3", options="header"] |=== |النمط |الدلالة
|مضاء باستمرار |مقترنة بنقطة وصول — حالة التشغيل العادية.
|وميض بطيء - 1 هرتز |Wi-Fi مُهيأة، قيد الاقتران أو لم تقترن بعد.
|وميض سريع - 5 هرتز |لا توجد Wi-Fi مُهيأة؛ زوّدها عبر وحدة التحكم الإدارية.
|وميض مزدوج - نبضتان سريعتان ثم توقف |مسح حي (مستمر) قيد التشغيل؛ الجهاز غير مقترن ويبث نقاط الوصول القريبة إلى وحدة التحكم الإدارية حتى يُضغط أي مفتاح.
|مطفأ |USB غير جاهز. |===
== أعمال مستقبلية
يعمل الجسر عبر منفذ USB Full-Speed الأصلي في RP2040 (12 ميجابت/ثانية)، لذا تبلغ الإنتاجية حدها الأقصى عند نحو 4-5 ميجابت/ثانية من حمولة TCP — وهو ما يكفي للوحة معلومات أو سطح تحكم، لكنه سقف صلب. عنق الزجاجة هو رابط USB، وليس راديو Wi-Fi. بعض الاتجاهات التي قد ترفع هذا الحد، بترتيب تقريبي حسب الجهد المطلوب:
لا شيء من هذه الإجراءات مطلوب للاستخدام المقصود من البرنامج الثابت؛ إنها نقاط انطلاق لمن يرغب في إنتاجية أعلى.
== المكتبات العلوية والاعتمادات
هذا البرنامج الثابت مُجمَّع من عدة مشاريع علوية، موثقة في الجدول هنا.
[#tbl-upstream] .المكونات العلوية [cols="1,2,1,4", options="header"] |=== |المكوّن (الملفات داخل الشجرة) |المشروع الأصلي |الرخصة |الدور
|USBNet |https://github.com/mattmyne/usbnet[mattmyne/usbnet] |MIT a|وحدة شبكة USB الأساسية، وواصفات USB، والهيكل الرئيسي، ممدَّدة هنا إلى جسر Wi-Fi.
usb_network.c وusb_network.h - أُعيدت كتابتهما كجسر الطبقة 2usb_descriptors.c - عُدّل ليشمل CDC-NCM مركّبًا + CDC-ACM مزدوجةtusb_config.h - عُدّل|TinyUSB |https://github.com/hathach/tinyusb[hathach/tinyusb] |MIT a|مكدس أجهزة USB CDC-NCM وCDC-ACM، مستخدم كما هو مرفق في pico-sdk. +
|pico-sdk 2.2.0 |https://github.com/raspberrypi/pico-sdk[raspberrypi/pico-sdk] |BSD-3-Clause a|دعم اللوحة، ونظام البناء، وTinyUSB وlwIP وcyw43-driver المرفقة.
pico_sdk_import.cmake - نسخة مطابقةlwipopts.h - مثال pico_w مقتطع|مثال TinyUSB net_lwip_webserver
|Peter Lawrence وHa Thach، عبر https://github.com/hathach/tinyusb[hathach/tinyusb]
|MIT
a|الأساس الأصلي لطبقة الربط الخاصة بشبكة USB؛ مقلَّصة إلى مسار CDC-NCM. +
|lrndis |https://github.com/fetisov/lrndis[fetisov/lrndis] |MIT a|أثر تصميمي على نهج شبكة USB +
أما المصادر المتبقية فهي أصلية من هذا المشروع:
main.cconfig.cconfig.hconfig_proto.cconfig_proto.hserial_console.cserial_console.hwifi_scan.cwifi_scan.hdebug_console.cdebug_console.h== الترخيص
هذا المشروع مرخّص بموجب MIT؛ انظر link:LICENSE[LICENSE]. تحتفظ المكونات العلوية بتراخيصها الخاصة كما هو موثق في <<upstream-libraries-and-credits,المكتبات العلوية والاعتمادات>>.
== البنية
=== نظرة عامة
الجهاز هو واجهة طرفية USB CDC-NCM تجسر المضيف مع Wi-Fi.
يشغّل Pico W محطة Wi-Fi وينقل إطارات إيثرنت بين رابط USB والراديو.
يشغّل المضيف مكدس IP الخاص به ويحمل هوية الشبكة الوحيدة؛ ولا يحمل Pico أي عنوان IP خاص به.
لا يحتاج المضيف إلى أي شيء يتجاوز برنامجي التشغيل المدمجين cdc_ncm وcdc_acm.
=== لماذا جسر الطبقة 2 عبر تبنّي عنوان MAC
الهدف هو أن يظهر المضيف على شبكة Wi-Fi كجهاز عادي بعنوان واحد، بينما يبقى Pico غير مرئي. قيد مادي صارم واحد في الطبقة المادية يشكّل طريقة تحقيق ذلك.
لا يمكن لمحطة Wi-Fi أن تجسر عدة عناوين MAC بشفافية. عندما يقترن Infineon CYW43 بنقطة وصول في وضع المحطة، يمنح الاقتران عنوان MAC واحدًا بالضبط، وإطارات بيانات 802.11 التي يرسلها مرتبطة بعنوان MAC الخاص بتلك المحطة. بدون إطارات رباعية العناوين (WDS)، التي يجب أن تدعمها نقطة الوصول وتسمح بها أيضًا، لا يمكن للراديو حمل إطارات نيابة عن عناوين MAC أخرى خلفه. هذا هو القيد المعروف بأن عميل Wi-Fi لا يمكن تجسيره.هذا البرنامج الثابت لا يحارب هذا القيد؛ بل يزيله. يُطلب من واجهة USB الخاصة بالمضيف أن تتبنّى عنوان MAC الخاص بمحطة Wi-Fi، بحيث يوجد عنوان MAC واحد بالضبط من طرف إلى طرف. ومع تقاسم المضيف والمحطة لهوية واحدة، يكون Pico جسرًا بسيطًا من الطبقة 2: فهو يمرر إطارات Ethernet كما هي بين USB وWi-Fi، دون أن يمسّ أي شيء فوق الطبقة 2. ترى نقطة الوصول محطة واحدة عادية؛ والمضيف يشغّل DHCP وSLAAC وNeighbor Discovery بنفسه ويحتفظ بالعناوين الناتجة.
النتائج مذكورة في الجدول هنا.
[#tbl-bridge-effects] .خصائص جسر تبنّي MAC [cols="1,3", options="header"] |=== |الخاصية |لماذا تنطبق
|عنوان IP واحد، يحمله المضيف |لا يخصص Pico لنفسه أي عنوان، لذا توجد هوية واحدة على الشبكة الفرعية الخاصة بنقطة الوصول نفسها - وليست شبكة فرعية خاصة للتوصيل.
|IPv4 و IPv6 معًا |الترحيل يتم عند الطبقة 2، لذا تمر SLAAC وDHCPv6 وإعلانات الموجّهات وNeighbor Discovery دون تغيير، دون أي كود خاص بإصدار معيّن.
|لا NAT ولا إعادة توجيه منافذ |لا يُعاد كتابة أي شيء، لذا تصل الاتصالات الواردة إلى المضيف مباشرة؛ لا يوجد ما يُخفى أو يُوجَّه.
|لا حزمة Wi-Fi على جانب المضيف
|يمتلك Pico الارتباط وعميل المصادقة، لذا لا يحتاج المضيف إلى wpa_supplicant أو قاعدة بيانات تنظيمية أو برنامج تشغيل لاسلكي - فقط برامج تشغيل فئة CDC.
|===
=== مسار البيانات
على جانب USB، يوفّر TinyUSB جهاز CDC-NCM، ويُضبط MAC لواجهة المضيف على MAC المحطة عند بدء التشغيل (usb_network_set_host_mac، قبل التعداد).
من المضيف إلى Wi-Fi: يصل إطار عبر tud_network_recv_cb، ويُرحَّل، وفي الحلقة الرئيسية يُرسَل عبر الراديو باستخدام cyw43_send_ethernet.
من Wi-Fi إلى المضيف: يُستبدل معالج input الخاص بـ netif المحطة، لذا يُسلَّم كل إطار يستقبله برنامج تشغيل cyw43 إلى الجسر بدلاً من lwIP، ويوضع في قائمة انتظار، ثم يُرسَل إلى المضيف عبر tud_network_xmit.
لا توجد واجهة IP تابعة لـ lwIP على جانب USB، ولا يحمل netif المحطة أي عنوان IP؛ يخدم lwIP فقط حالة الارتباط الخاصة بـ netif cyw43 وتجمّع pbuf.
=== نموذج التزامن
يستخدم البرنامج الثابت pico_cyw43_arch_lwip_threadsafe_background.
تُخدَم Wi-Fi في سياق IRQ خلفي وسياق غير متزامن بحيث لا تجوّع USB أبدًا، حيث يعمل tud_task() في الحلقة الرئيسية.
لهذا الترتيب نتيجة صارمة واحدة بالنسبة للجسر.
يجب عدم لمس TinyUSB إلا من الحلقة الرئيسية، ومع ذلك تُستقبل إطارات Wi-Fi في السياق الخلفي.
لذلك لا يقوم معالج استقبال Wi-Fi إلا بإدراج كل إطار في مخزن حلقي (ring buffer)، وتفرّغ الحلقة الرئيسية هذا المخزن إلى tud_network_xmit.
تجلّى انتهاك هذه القاعدة على جانب المضيف كرسالة NETDEV WATCHDOG: transmit queue timed out مع انقطاع USB.
إرسال إطارات المضيف إلى Wi-Fi يحدث في الحلقة الرئيسية ويحمل cyw43_arch_lwip_begin()/cyw43_arch_lwip_end() حول استدعاء cyw43.
=== البث المتعدد و IPv6
تستقبل المحطة، افتراضيًا، مجموعات البث المتعدد التي انضمّت إليها فقط. لا يشغّل الجسر أي حزمة IP خاصة به ولا ينضم إلى أي شيء، لذا بدون تدخل سيسقط الراديو البث المتعدد الذي يعتمد عليه IPv6، ولن يعمل IPv6 الخاص بالمضيف عبر الجسر. إعلانات الموجّهات، واكتشاف العناوين المكررة، وحل العناوين — كلها تعتمد على البث المتعدد.
عند كل ارتباط، يضبط البرنامج الثابت iovar allmulti الخاص بـ CYW43، لذا تسلّم المحطة جميع إطارات البث المتعدد بغض النظر عن عامل التصفية.
يتم ذلك عبر cyw43_ioctl العام ضد WLC_SET_VAR، وليس بإدخال وضع المراقبة (monitor mode)، لذا يبقى تنسيق إطار Ethernet دون تغيير.
قد تستبعد شبكة خلف مبدّل يدعم IGMP أو MLD snooping بعض البث المتعدد الذي لم يطلبه المضيف؛ أما نقطة الوصول المنزلية العادية فتُغرق الشبكة به.
=== فلتر الانعكاس الذاتي
بما أن المضيف يشارك المحطة في عنوان MAC، فإن أي بث متعدد أو بث عام يرسله المضيف يُغمر به نقطة الوصول عائدة إلى المحطة، التي تستقبل الآن كل البث المتعدد، وسيُسلَّم إلى المضيف كإطار خاص به.
يُسقط معالج الاستقبال أي إطار من Wi-Fi إلى المضيف يكون عنوان MAC المصدر فيه هو MAC المحطة، لأن هذا الإطار لا يمكن إلا أن يكون إرسال المضيف نفسه المنعكس عبر نقطة الوصول.
يجب ألا يعيد الجسر إرسال إطارات المحطة إليها مرة أخرى؛ يُحتسب الإسقاط كـ refl في إحصاءات التصحيح.
=== وحدتا التحكم التسلسليتان
الإدارة والتشخيص تتم خارج النطاق، عبر وظيفتين من نوع CDC-ACM لنفس جهاز USB المركّب، وليس عبر الشبكة. هذه نتيجة مقصودة للشفافية: يحمل جانب الشبكة حركة مرور المضيف فقط، ولا يوجد عنوان يمكن لـ Pico الرد عليه.
وحدة التحكم الإدارية (/dev/ttyACM0) تشغّل بروتوكول خط الإعداد وتكون قابلة للوصول فور تعداد USB، قبل تشغيل Wi-Fi، لذا يمكن دائمًا تجهيز الجهاز دون أي IP.
وحدة التحكم التشخيصية (/dev/ttyACM1) هي تدفق تشخيص للكتابة فقط — أحداث الارتباط، وعدادات الجسر الدورية، وملخصات حزم اختيارية لكل إطار — ولا تُرسَل إلا عند تفعيلها، لذا لا تكلف شيئًا عند إيقافها ولا تزاحم وحدة التحكم الإدارية أبدًا.
لا تلمس أي من الوحدتين الشبكة، فلا تولّد أي حركة مرور يسجّلها جدار حماية المضيف.
=== تخزين الإعدادات
إعدادات وقت التشغيل — حتى ثمانية ملفات تعريف لبيانات اعتماد Wi-Fi، ومؤشر الملف النشط، والدولة التنظيمية، وعلامة التصحيح — موجودة في سجل واحد في آخر قطاع من الفلاش، بعيدًا عن صورة البرنامج في بداية الفلاش.
يمتد السجل على عدة صفحات فلاش، لذا فإن save يبرمج القطاع بأكمله دفعة واحدة (المسح يشمل القطاع كاملًا على أي حال).
عند الإقلاع، يُقبل السجل فقط عند تطابق تام لرقمه السحري وCRC-32 على بقية البنية؛ أي عدم تطابق يحمّل الإعدادات الافتراضية المترجمة في وقت البناء بدلاً من ذلك.
لا يوجد ترحيل بإصدارات: أي تغيير في تخطيط السجل يفشل ببساطة في فحص magic/CRC ويعود إلى الافتراضيات، وهو أمر مقبول لأن الإعداد الافتراضي المدمج في وقت البناء ما زال يهيّئ الملف الأول. (لهذا السبب، الترقية إلى v1.1.0 التي وسّعت السجل إلى قائمة ملفات تعريف تتجاهل سجل ما قبل v1.1.0).
يكتب save السجل مرة أخرى عبر flash_safe_execute، الذي ينسّق المسح والبرمجة مع النواة الأخرى ويعطّل المقاطعات لعدة ميلي ثانية يستغرقها ذلك.
يُشغَّل هذا الكتابة من معالج وحدة التحكم بينما قفل lwIP ممسوك؛ نافذة تعطيل المقاطعات القصيرة توقف خدمة Wi-Fi الخلفية مؤقتًا، وهو أمر مقبول لعملية حفظ نادرة يبادر بها المضيف.
=== خصوصيات العتاد وسلسلة الأدوات
هذه السلوكيات الخاصة بـ RP2040 وInfineon CYW43 وpico-sdk تكلّف وقت تصحيح حقيقيًا، ومن السهل إعادة إدخالها.
==== الخدمة الخلفية تتطلب TinyUSB في الحلقة الرئيسية فقط
هذه هي قاعدة التزامن المذكورة في <<concurrency-model,نموذج التزامن>>. مع الخدمة الخلفية، يعمل استقبال Wi-Fi في سياق قد لا يستدعي TinyUSB، ولهذا يوجد مخزن الإرسال المؤجل.
==== الارتباط ليس عنوان IP
يُبلغ مساعد cyw43 cyw43_tcpip_link_status عن CYW43_LINK_UP فقط بمجرد امتلاك المحطة عنوان IP، وهذه المحطة تتعمّد ألا تحصل على أي عنوان.
لذلك تُقرأ حالة الارتباط من علم حالة الارتباط netif (netif_is_link_up)، والذي يستخدمه الجسر أيضًا لتحديد ما إذا كان سيرحّل.
==== الهوية المتغيرة تتطلب معرّف منتج جديد
قد يقدّم المضيف واصفًا مخزّنًا مؤقتًا لجهاز مركّب يغيّر مجموعة واجهاته مع الاحتفاظ بنفس مُصنّع USB ومعرّف المنتج.
يُشتق معرّف المنتج من الفئات المفعّلة، لذا إضافة كل وظيفة CDC-ACM تُزيحه (cafe:4020 إلى cafe:4022) ويعيد المضيف قراءة التخطيط الجديد.
==== بنيات الإصدار تحوّل assert إلى عملية دون تأثير
CMAKE_BUILD_TYPE=Release يعرّف NDEBUG، الذي يترجم assert() إلى لا شيء، لذا فإن أي تخصيص ذاكرة محروس فقط بتأكيد (assertion) يتجاوز الفشل وينفّذ إلغاء مرجعية NULL.
يظهر تعطل البرنامج الثابت قبل تشغيل tud_task على جانب المضيف كخطأ تعداد USB -110، وهو انتهاء مهلة قراءة واصف الجهاز.
تُستخدم حراسات NULL حقيقية بدلاً من التأكيدات في مسار بدء التشغيل.
=== البيئة المُتحقَّق منها
الإعداد المؤكَّد أنه يعمل يستخدم pico-sdk 2.2.0، وسلسلة أدوات GCC arm-none-eabi، وTinyUSB وlwIP المضمّنين في pico-sdk دون تعديل.
اللوحة المرجعية هي Pico W (RP2040).
من المتوقع أن يعمل Pico 2 W (RP2350).
ينتج عن البناء ملف build/pico-usb-wifi.uf2 بحوالي 670 كيلوبايت.