آموزش سوکت با رابط کاربری Netconn و سیستم عامل FreeRTOS در STM32

0

آموزش سوکت با رابط کاربری Netconn و سیستم عامل FreeRTOS در STM32

در بخش های قبل راه اندازی گذرگاه Ethernet مفاهیم مقدماتی و موردنیاز مرتبط با شبکه ­های کامپیوتری و Ethernet بیان شد و در بخش دوم نحوه برنامه نویسی سوکت TCP و UDP با رابط کاربری Raw بطور مفصل بررسی شد. در این بخش  نحوه نوشتن برنامه سوکت TCP و UDP با رابط کاربری Netconn و با استفاده از سیستم عامل FreeRTOS شرح داده شده است.

در بحث شبکه­های کامپیوتری، یکی از بهترین روش­ها به منظور تشریح مفهومی نحوه کارکرد و پیاده­سازی شبکه، استفاده از مدل­های ارائه شده در این زمینه مانند OSI و TCP/IP است. این مدل­ها را می­توان در اکثر کتاب­ها و مقالات در زمینه شبکه­ های کامپیوتری مشاهده کرد. در ادامه این گزارش ابتدا با این دو مدل و لایه­های مختلف آن بصورت مختصر بیان شده است.

رابط کاربری Netconn

Netconn یک رابط کاربری سطح بالا است که نحوه اجرای آن بر مبنای open-read-write-close است. Netconn برای عملکرد صحیح به سیستم عامل و محیط مالتی تسک نیازمند است.

نحوه تنظیم سیستم عامل FreeRTOS

در بخش آموزش سیستم عامل FreeRTOS نحوه تنظیم آن بطور کامل بیان شده است. لذا از تکرار مجدد آن خودداری شده است. تنها نکته­ای که باید به آن توجه کرد آن است که مقدار حافظه heap در فیلد TOTAL_HEAP_SIZE را مقدار کافی قرار دهید. در اینجا مقدار آن 40000 بایت تنظیم شده است. در اینجا اینترفیس سیستم عامل CMSIS_V1 انتخاب شده است ولی می-توان از CMSIS_V2 نیز استفاده کرد. در شکل 1 نحوه تنظیم FreeRTOS نشان داده شده است.

نحوه تنظیم سیستم عامل FreeRTOS

نحوه تنظیم کتابخانه LwIP

در بخش­های قبل نحوه تنظیم کتابخانه LwIP در نرم افزار STM32CubeMX با رابط کاربری Raw شرح داده شد. در این بخش نحوه تنظیم آن با رابط کاربری Netconn بیان شده است.  در شکل 2 نحوه تنظیم کتابخانه LwIP نشان داده شده است.

نحوه تنظیم کتابخانه LwIP
نحوه تنظیم کتابخانه LwIP

پس از انجام تنظیمات مربوط به FreeRTOS، Ethernet و LwIP به سربرگ Project Manager بروید و مقدار حافظه Stack و Heap را به مقدار کافی بزرگ دهید. در اینجا اندازه حافظه Stack و Heap به ترتیب برابر 0x8000 و 0x4000 تنظیم شده­اند.  بعد از انجام تنظیمات فوق نامه و مسیر پروژه را انتخاب کرده و بر روی دکمه Project Manager کلیک کنید تا پروژه اولیه ایجاد شود.

برنامه نویسی سوکت با استفاده از کتابخانه LwIP با رابط کاربری Netconn

در بخش­های قبل پروتکل­های TCP و UDP معرفی شدند. همچنین نحوه برنامه نویسی سوکت شرح داده شد. لذا در این قسمت از تکرار آن خودداری کرده و فقط مسائل مربوط به رابط کاربری Netconn بیان شده است.

در جدول 1 توابعی که رابط کاربری Raw برای کار با سوکت  TCPدر اختیار برنامه نویس قرار داده است نشان داده شده است. همانطور که مشاهده­ می­کنید، رابط کاربری Netconn بسیار شبیه به کتابخانه Winsock و یا سایر کتابخانه­هایی که در محیط ویندوز یا لینوکس برای Socket Programming استفاده می­شود، است.

رابط کاربری Netconn
رابط کاربری Netconn

برای یادگیری نحوه استفاده از توابع فوق دو مثالی که در بخش قبل با استفاده از رابط کاربری Raw انجام شد، را با استفاده از رابط کاربری Raw انجام شده است.

مثال اول: TCP Server Socket

کد این برنامه بصورت زیر است.

static void tcpecho_thread(void *arg)
{
  struct netconn *conn, *newconn;
  err_t err;
  LWIP_UNUSED_ARG(arg);

  /* Create a new connection identifier. */
  /* Bind connection to well known port number 7. */
  conn = netconn_new(NETCONN_TCP);
  netconn_bind(conn, IP_ADDR_ANY, 7);

  LWIP_ERROR("tcpecho: invalid conn", (conn != NULL), return;);

  /* Tell connection to go into listening mode. */
  netconn_listen(conn);

  while (1) {

    /* Grab new connection. */
    err = netconn_accept(conn, &newconn);
    /*printf("accepted new connection %p\n", newconn);*/
    /* Process the new connection. */
    if (err == ERR_OK) {
      struct netbuf *buf;
      void *data;
      u16_t len;
      
      while ((err = netconn_recv(newconn, &buf)) == ERR_OK) {
          if (*(uint8_t*)(buf->p->payload) == 'A')
          {
            HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_SET);
          }
          else if (*(uint8_t*)(buf->p->payload) == 'B')
          {
            HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET);
          }
          
        /*printf("Recved\n");*/
        do {
             netbuf_data(buf, &data, &len);
             err = netconn_write(newconn, data, len, NETCONN_COPY);
        } while (netbuf_next(buf) >= 0);
        netbuf_delete(buf);
      }
      /*printf("Got EOF, looping\n");*/ 
      /* Close connection and discard connection identifier. */
      netconn_close(newconn);
      netconn_delete(newconn);
    }
  }
}
 

در برنامه فوق ابتدا با فراخوانی تابع netconn_new یک سوکت از نوع TCP تعریف شده و با استفاده از تابع netconn_bind به پورت هفت متصل شده است. سپس با فراخوانی تابع netconn_listen به سوکت گوش می­دهد. تابع netconn_accept بصورت Blocking است. بطوریکه تا زمانی­که Request دریافت نکند در این تابع می­ماند. بعد از دریافت Request منتظر دریافت داده از Client می­ماند و بعد از دریافت آن با توجه به مقدار آن LED را روشن و یا خاموش می­کند. همچنین داده دریافتی را به Client ارسال می­کند.

برای بهینه سازی می­توان هنگامی­که یک Request دریافت کرد، Thread جدیدی تعریف کرد و در آن پردازش موردنظر را انجام داد.

مثال دوم: UDP Server Socket

کد مثال UDP Server Socket بصورت زیر است.

static void udpecho_thread(void *arg)
{
  struct netconn *conn;
  struct netbuf *buf, *tx_buf;
  err_t err;
  LWIP_UNUSED_ARG(arg);
  
  conn = netconn_new(NETCONN_UDP);
  netconn_bind(conn, IP_ADDR_ANY, 7);
  
  LWIP_ERROR("udpecho: invalid conn", (conn != NULL), return;);
  
  while (1) {
    err = netconn_recv(conn, &buf);
    if (err == ERR_OK) {
      if (*(uint8_t*)(buf->p->payload) == 'A')
      {
        HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_SET);
      }
      else if (*(uint8_t*)(buf->p->payload) == 'B')
      {
        HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET);
      }
      tx_buf = netbuf_new();
      netbuf_alloc(tx_buf, buf->p->tot_len);
      
      pbuf_take(tx_buf->p, (const void *)buf->p->payload, buf->p->tot_len);
      
      err = netconn_sendto(conn, tx_buf, (const ip_addr_t *)&(buf->addr), buf->port);
      if(err != ERR_OK) {
        LWIP_DEBUGF(LWIP_DBG_ON, ("netconn_send failed: %d\n", (int)err));
      } else {
        LWIP_DEBUGF(LWIP_DBG_ON, ("got %s\n", buffer));
      }
      netbuf_delete(tx_buf);
    }
    netbuf_delete(buf);
  }
}
 

در این برنامه ابتدا یک سوکت UDP تعریف شده و به پورت 7 متصل شده است. سپس منتظر دریافت داده از Client می­ماند و در صورت دریافت داده آن را بررسی کرده و در صورتی­که داده حرف اول آن “A” باشد LED را روشن و اگر “B” باشد آن را خاموش می­کند. در نهایت داده دریافت شده را به Client ارسال می­کند.

خروجی برنامه سوکت UDP Server

در شکل 4 فریم ­های جابجا شده بین میکروکنترلر و کامپییوتر نشان داده شده است.

فریم های جابجا شده بین کامپیوتر و میکروکنترلر در حالت UDP Server
فریم های جابجا شده بین کامپیوتر و میکروکنترلر در حالت UDP Server
Choose your Reaction!
دیدگاه خود را بنویسید

آدرس ایمیل شما منتشر نخواهد شد.

redronic.com