إنترنت الأشياءلغة سي و متحكماتمقالات

كل ما يتعلق بـESP32 -الجزء الثالث

الـTCP والـHTTP عبر الـWiFi

لقد تم تغطية العديد من المفاهيم المتعلقة بالـESP32 عبر الأجزاء السابقة، مما يسمح للانتقال لقضايا أكثر تعمقاً لاحقاً. فلقد تعرفنا في الجزء السابق على العمليات الأساسيّة للواي فاي في ESP-IDF بما في ذلك إجراء مسح للشبكات المتاحة والاتصال بأحدها. سنوظّف في هذا الجزء الاتصال الذي قمنا به وذلك للقيام باتصال TCP و عمليات HTTP، وسنكتشف بأية حال أن جزء كبير من برمجة الواي فاي في ESP32 أنه متعلق ببرمجة الـSocket بلغة السي باستخدام LwIP stack. كما قامت شركة Espressif ولتسهيل الأمور بطرح مكتبة متخصصة بالعمليات اللازمة بعمليات الـHTTP كمستخدم Client في ESP-IDF.

 

LwIP Stack

 

يستخدم الـESP32 الـLwIP stack، ولذلك للقيام باتصال TCP و عمليات HTTP حيث سيتم استدعاء توابع من LwIP حيث تحوي طبقة الـLwIP ‘s application API layers توابع خاصة للتعامل مع الـSocket وهذه التوابع متوافقة مع شكل توابع نظام BSD أي compatible with standard BSD-sockets. هذا الموضوع socket programming in C واسع ، ولذلك سنقوم بتغطية الأساسيات فقط.

سأستلف في ما يلي أجزاء من شرح رائع لموضوع TCP/IP socket programming in C من مقالة من موقع BinaryTides. يعرّف المقال في الموقع الـSocket على أنها نقاط اتصال “افتراضية” من أجل أي نوع من أنواع الاتصالات الشبكية بين مستخدمين host على الشبكة. مثال: عندما نحدد موقع غوغل للنفاذ له في المتصفح، فإنه يتم فتح Socket مرتبطة بالموقع لجلب المعلومات وعرضها. إن الجزء الأول الذي سنقوم به إذا هو إنشاء Socket عبر استدعاء التابع socket:

  • يحدد الوسيط الأول عائلة بروتكول الاتصال (مثلاً: AF_INET6 من أجل بروتكولات IPv6 ).
  • يأخذ الوسيط الثاني قيمة SOCK_STREAM من أجل اتصال TCP أو SOCK_DGRAM من أجل اتصال UDP.
  • أما الوسيط الثالث فهو لتحديد بروتوكول معين ضمن عائلة الاتصال و يكون البروتوكول وحيد بالنسبة للـSocket ذات النوع المحدد بشكل طبيعي وبهذه الحالة تكون القيمة صفر.

يُعد استدعاء هذا التابع رقم، وهو رقم موصف لملف file descriptor خاص بالـSocket، ويستخدم هذا الرقم لاحقاً في توابع أخرى.

إذا إن الجزء الأول من برمجة الـSocket هو:

 

من طرف المُخدّم

 

يجب ربط الـSocket بعنوان address ورقم منفذ port محدّدين، أو يمكن أن يكون IP غير محدد عبر الخيار INADDR_ANY. يمكن تحديد العنوان والمنفذ من خلال متحول من نوع struct sockaddr_in.

إن sockaddr_in struct في LwIP هو:

الخطوة الأخيرة في التهيئة هي استدعاء التابع listen وذلك لبدء الاستماع على هذا الـSocket. يأخذ هذا التابع وسيطين: الأول هو رقم الموصف للـSocket ويحدد الثاني العدد الأعظمي للاتصالات المسموحة maximum number of queued connections.

لاحقاً يقوم التابع accept بالتحقق من طلبات الاتصال المنتظرة ويعيد رقم موصّف جديد يتم استخدامه مثلاً في عملية الكتابة والقراءة، وأما الوسطاء لهذا التابع: فالأول هو الرقم الموصّف للـSocket والثاني متحول من نوع struct sockaddr ويستخدم لتخزين عنوان الـSocket المقابل.

من الممكن لاحقاً تنفيذ القراءة والكتابة باستخدام التوابع read و write.

بوضع كل شيء معاً:

 

من طرف المستخدم

 

إذا كانت الـSocket المنشأة بغرض الاتصال بعنوان خارجي remote address كالنفاذ لموقع انترنت فإن التابع connect يستخدم عوضاً عن bind مع الوسطاء نفسها ومن دون حاجة لاستدعاء accept و listem. إن المخطط التالي المرفق في إجابة على Stackoverflow توضح ذلك.

ESP32 BSD Socket Creation

 

نقطة نفاذ أو ما يعرف بـ (SoftAP)

 

يلزمنا في تطبيق لاحق جعل الـESP32 بنمط العمل كنقطة نفاذ Access Point وهو النمط SoftAP. حيث يقوم التطبيق على اتصال مستخدم بشبكة الـESP32 ثم القيام باتصال TCP عبر telnet/PuTTY.

سنستخدم لتهيئة الـESP32 للعمل كنقطة نفاذ نفس التوابع المُستخدمة عندما تم ضبطها للاتصال بشبكة محددة في الدرس السابق، ولكن باستخدام متحول بقيم مختلفة من wifi_config_t.

حيث يحوي النوع wifi_config_t على جزئين وهما:

كنا قد استعملنا في المرة الأخيرة الجزء sta من المتحول ولكن هذه المرة سنستخدم الجزء ap. تبدو عملية تهيئة الـESP32 كنقطة نفاذ كالتالي:

ولنلقي نظرة الآن على التابع event_handler. يمكن للأحداث Events الخاصة بالـAP أن تكون واحدة من هذه:

وهذا مثال على تابع، ولمراجعة كيفية عمل التابع يمكن الاطلاع على ذلك في الدرس الماضي.

يحوي المتحول system_event_t على معلومات متعلقة بالمستخدمين المتصلين/غير المتصلين بنقطة نفاذ الـESP32 وذلك باستخدام event_info.sta_disconnected.mac مثلاً.

شيء آخر يستحق الذكر وهو التابع tcpip_adapter_get_ip_info والذي يستخدم للحصول على IP الشبكة، ونهاية التابع الذي يستخدم لتحويل القيمة العددية للـIP إلى قيمة نصية بالشكل (x.x.x.x).

 

 

التطبيق الأول: HTTP Request

 

سنقوم في هذا المثال التطبيقي بتهيئة الـESP32 للاتصال بنقطة نفاذ معينة للوصول إلى الإنترنت وثم إنشاء Socket وباعتبار أننا سنكون في حالة مستخدم سيتصل بموقع فنحن client وبالتالي لن نستدعي accept أو listen.

سنقوم أيضاً باستدعاء خدمة الـDNS باعتبار أن رسائل الـHTTP ستكون لموقع ويب معين وذلك لتحويل اسم الموقع إلى IP. يتم ذلك باستدعاء getaddrinfo والذي سيخزّن النتيجة في متحول يتم تمريره له.

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

إعدادات خاصة من قائمة Menuconfig

 

إن الكود الذي يتعامل مع الواي فاي على سبيل المثال غالباً ما يحوي ضبط لكلمة السر واسم الشبكة المراد الاتصال بها وذلك بتعريف define في الملف المصدري. يمكن لتغير هذه القيمة من قائمة menuconfig أن يتم إنشاء ملف باسم Kconfig.projbuild يوضع في نفس مسار الكود المصدري ويحوي هذا الملف على المحتوى التالي المكتوب بلغة Kconfig:
Kconfig ESP32

Kconfig ESP32

يجب أن يحوي الكود التعريفات بنفس النمط التالي:

حيث يمكن لاسم الماكرو بحد ذاته أن يكون أي اسم، بينما القيمة يجب أن تكون من الشكل CONFIG_*** وذلك حسب الاسم المستخدم داخل الملف Kconfig.projbuild.

 

الكود

 

هذا الكود هو نسخة معدلّة ومبسّطة من المثال المرفق في ESP-IDF.

 

التطبيق الثاني: ESP HTTP Client

 

إن التعامل مع الـHTTP ليس بسهولة دوماً حيث قد تتضمن عملية authentication (على مستوى اسم مستخدم/كلمة مرور أو HTTPS) ،أو إعادة توجيه redirection ، أو عمليات GET/POST/DELETE/ .. إلخ. لهذا السبب قدمت ESP-IDF مجموعة توابع للقيام بـHTTP/S requests بأنواعها ولكن كـclient فقط. هناك 3 خطوات أساسية لاستخدام هذه المكتبة:

1- تعريف متحول من  esp_http_client_config_t وتعبئته بالمعلومات المطلوبة متضمّنةً رابط الموقع. مثال:

  • عملية GET/POST:
  • Authentication لاسم مستخدم وكلمة السر:
2- استدعاء esp_http_client_init التابع:
3- استدعاء esp_http_client_perform() حيث ينفذ هذا التابع كل العمليات المطلوبة من فتح للاتصال وارسال/استقبال المعطيات وتسكير الاتصال عند اللزوم.

يتم استدعاء توابع أخرى بناءً على العمليّة المطلوبة، مثلاً: من أجل عملية POST نستدعي

الكود كاملاً:

وهذا خرج البرنامج من أجل استدعاء GET من موقع خاص لإعطاء مقولات عشوائية في كل استدعاء للرابط API (http://random-quote-generator.herokuapp.com/api/quotes/random).

 

ESP32 Random qoute API

وهذا تجريب آخر لموقع خاص لرسم الكلمات باستخدام فن الآسكي (http://artii.herokuapp.com/make?text=ASCII+art).

ESP32 ASCII ART API

يرجى الاطلاع على المثال الكامل لمشاهدة حالات استعمال متعددة من مستودع  ESP-IDF.

 

التطبيق الثالث: TCP Server

 

سنقوم في التطبيق الثالث والأخير بإنشاء سيرفر TCP يستمع لطلبات الاتصال ويقوم بالرد عليها بعبارة ترحيبيّة. في هذا التطبيق سنطبع IP الأجهزة المتصلة حيث ستكون الـESP32 في نمط SoftAP وسنقوم باستخدام المنفذ 8888.

قمنا مسبقاً بشرح كيفية تهيئة الـESP32 بنمط الـSoftAP ومن أجل الاتصال كـtelnet بالشبكة يجب أن نعرف عنوان IP الشبكة عبر التابع tcpip_adapter_get_ip_info.

تذكير: تعمل الـESP32 كسيرفر وبالتالي يجب استدعاء التابعين bind و listen بعد إنشاء الـSocket.

أخيراً، يمكننا استخدام الكود التالي لطباعة عنوان المستخدمين المتصلين بالشبكة:

الكود كاملاً:

ESP32 TCP server response

Yahya Tawil

مهندس نظم مضمّنة مهتم بالعتاد مفتوح المصدر وولد في نفس العام الذي ولد فيه نظام تشغيل لينكس. يحيى هو مدير التحرير في عتاديات ويؤمن بأهمية المحتوى المكتوب المجاني والنوعي والعملي. خبرته في مجال النظم المضمّنة تتركز في كتابة البرامج المضمنة وتصميم الدارات المطبوعة والنظرية وإنشاء المحتوى.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

This site uses Akismet to reduce spam. Learn how your comment data is processed.