esp-open-rtosを使ってみる

TCP Client & Server(Socket-API)

こちらでlwIPを使ったTCP Clientを紹介しました。
また、こちらでlwIPを使ったTCP Serverを紹介しました。
そこで、ClientとServerを同時に動かしてみました。

以下のコードでは、3つのタスクを起動しています。

task1(WiFiタスク)
APの接続状況を監視し、接続が完了したらSemaphoreを使ってtask2とtask3に許可を与えます。

task2(Serverタスク)
外部のClientからの接続を待って、受信データーを変換してTCP Clientに送り返します。
受信用にポート番号=9877を使います。

task3(Clientタスク)
定期的に、外部のServer(192.168.10.10)に「test」の文字を送信し、サーバーからの応答を表示します。
送信用にポート番号=9876を使います。

/* The example of esp-free-rtos
 *
 * This sample code is in the public domain.
 */
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "esp8266.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"

#define SERVER_IP "192.168.10.10"
#define SEND_PORT 9876
#define RECEIVE_PORT 9877

int TaskIsAlive = 1;
SemaphoreHandle_t xSemaphore1;
SemaphoreHandle_t xSemaphore2;

void showNetworkInfo() {
  uint8_t hwaddr[6];
  if (sdk_wifi_get_macaddr(STATION_IF, hwaddr)) {
    printf("[%s] MAC address="MACSTR"\n",pcTaskGetName(0),MAC2STR(hwaddr));
  }
  struct ip_info info;
  if (sdk_wifi_get_ip_info(STATION_IF, &info)) {
    printf("[%s] IP address="IPSTR"\n",pcTaskGetName(0),IP2STR(&info.ip));
    printf("[%s] Netmask="IPSTR"\n",pcTaskGetName(0),IP2STR(&info.netmask));
    printf("[%s] Gateway="IPSTR"\n",pcTaskGetName(0),IP2STR(&info.gw));
  }
}

// Socket Server Task
void task2(void *pvParameters)
{
  TickType_t nowTick;
  nowTick = xTaskGetTickCount();
  printf("[%s:%d] Start\n",pcTaskGetName(0),nowTick);

  /* wait for Semaphore */
  xSemaphoreTake(xSemaphore1, portMAX_DELAY);
  nowTick = xTaskGetTickCount();
  printf("[%s:%d] Take\n",pcTaskGetName(0),nowTick);

  /* set up address to connect to */
  struct sockaddr_in srcAddr;
  struct sockaddr_in dstAddr;
  memset(&srcAddr, 0, sizeof(srcAddr));
  //srcAddr.sin_len = sizeof(srcAddr);
  srcAddr.sin_family = AF_INET;
  //srcAddr.sin_port = PP_HTONS(RECEIVE_PORT);
  srcAddr.sin_port = htons(RECEIVE_PORT);
  srcAddr.sin_addr.s_addr = INADDR_ANY;

  /* create the socket */
  int srcSocket;
  int dstSocket;
  socklen_t dstAddrSize;
  int ret;
  int numrcv;

  srcSocket = lwip_socket(AF_INET, SOCK_STREAM, 0);
  LWIP_ASSERT("srcSocket >= 0", srcSocket >= 0);

  /* bind socket */
  ret = lwip_bind(srcSocket, (struct sockaddr *)&srcAddr, sizeof(srcAddr));
  /* should succeed */
  LWIP_ASSERT("ret == 0", ret == 0);

  /* listen socket */
  ret = lwip_listen(srcSocket, 5);
  /* should succeed */
  LWIP_ASSERT("ret == 0", ret == 0);

  char buf[1024];
  while(1) {
    // 接続の受付け
    printf("[%s:%d] %d で接続を待っています クライアントプログラムを動かして下さい\n",pcTaskGetName(0),nowTick,RECEIVE_PORT);
    dstAddrSize = sizeof(dstAddr);
    dstSocket = lwip_accept(srcSocket, (struct sockaddr *)&dstAddr, &dstAddrSize);
    nowTick = xTaskGetTickCount();
    printf("[%s:%d] %s から接続を受けました\n",pcTaskGetName(0),nowTick,inet_ntoa(dstAddr.sin_addr));

    while(1) { // クライアントがSocketをクローズしてからこちらもクローズする
      /* read something */
      memset(buf,0,sizeof(buf));
      numrcv = lwip_read(dstSocket, buf, 1024);
      nowTick = xTaskGetTickCount();
      printf("[%s:%d] numrcv=%d\n",pcTaskGetName(0),nowTick,numrcv);
      if(numrcv ==0 || numrcv ==-1 ){ // client close socket
        lwip_close(dstSocket); break;
      }
      printf("Recv=[%s]",buf);
      for (int i=0; i< numrcv; i++){ // bufの中の小文字を大文字に変換
        if(isalpha((int)buf[i])) {
          if(islower((int)buf[i])) {
            buf[i] = toupper((int)buf[i]);
          } else {
            buf[i] = tolower((int)buf[i]);
          }
        }
      }
      /* write something */
      ret = lwip_write(dstSocket, buf, numrcv);
      LWIP_ASSERT("ret == numrcv", ret == numrcv);
      printf("->Send=[%s]\n",buf);
    } // end while
  } // end for


  /* close (never come here) */
  ret = lwip_close(srcSocket);
  LWIP_ASSERT("ret == 0", ret == 0);
  vTaskDelete( NULL );

}

// WiFi Task
void task1(void *pvParameters)
{
  TickType_t nowTick;
  nowTick = xTaskGetTickCount();
  printf("[%s:%d] Start\n",pcTaskGetName(0),nowTick);

  /* Wait until we have joined AP and are assigned an IP */
  int wifiStatus;
  while (1) {
    wifiStatus = sdk_wifi_station_get_connect_status();
    nowTick = xTaskGetTickCount();
    printf("[%s:%d] wifiStatus=%d\n",pcTaskGetName(0),nowTick,wifiStatus);
    //if (sdk_wifi_station_get_connect_status() == STATION_GOT_IP) break;
    if (wifiStatus == STATION_GOT_IP) break;
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
  nowTick = xTaskGetTickCount();
  printf("[%s:%d] Connected to AP\n",pcTaskGetName(0),nowTick);
  showNetworkInfo();

  /* Now start task2 */
  xSemaphoreGive(xSemaphore1);
  nowTick = xTaskGetTickCount();
  printf("[%s:%d] Give to task2\n",pcTaskGetName(0),nowTick);

  /* Now start task3 */
  xSemaphoreGive(xSemaphore2);
  nowTick = xTaskGetTickCount();
  printf("[%s:%d] Give to task3\n",pcTaskGetName(0),nowTick);

  while(1) {
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}

// Socket Client Task
void task3(void *pvParameters)
{
  TickType_t nowTick;
  nowTick = xTaskGetTickCount();
  printf("[%s:%d] Start\n",pcTaskGetName(0),nowTick);

  /* wait for Semaphore */
  xSemaphoreTake(xSemaphore2, portMAX_DELAY);
  nowTick = xTaskGetTickCount();
  printf("[%s:%d] Take\n",pcTaskGetName(0),nowTick);

  /* set up address to connect to */
  struct sockaddr_in addr;
  memset(&addr, 0, sizeof(addr));
  //addr.sin_len = sizeof(addr);
  addr.sin_family = AF_INET;
  addr.sin_port = htons(SEND_PORT);
  addr.sin_addr.s_addr = inet_addr(SERVER_IP);

  /* create the socket */
  int fd;
  int ret;
  fd = lwip_socket(AF_INET, SOCK_STREAM, 0);
  LWIP_ASSERT("fd >= 0", fd >= 0);

  /* connect */
  ret = lwip_connect(fd, (struct sockaddr*)&addr, sizeof(addr));
  /* should succeed */
  LWIP_ASSERT("ret == 0", ret == 0);

  char buf[256];
  for(int i=0;i<10;i++) {

    /* write something */
    sprintf(buf,"test");
    ret = lwip_write(fd, buf, strlen(buf));
    _printf("lwip_write ret=%d\n",ret);
    LWIP_ASSERT("ret == strlen(buf)", ret == strlen(buf));

    /* read something */
    memset(buf,0,sizeof(buf));
    ret = lwip_read(fd, buf, sizeof(buf));
    LWIP_ASSERT("ret > 0", ret > 0);
    nowTick = xTaskGetTickCount();
    printf("[%s:%d] lwip_read ret=%d\n",pcTaskGetName(0),nowTick,ret);
    if (ret > 0) {
      nowTick = xTaskGetTickCount();
      printf("[%s:%d] ret=%d buf=%s\n",pcTaskGetName(0),nowTick,ret,buf);
    }

    vTaskDelay(10000 / portTICK_PERIOD_MS);

  } // end while

  /* close */
  ret = lwip_close(fd);
  LWIP_ASSERT("ret == 0", ret == 0);
  TaskIsAlive = 0;
  vTaskDelete( NULL );
}

void user_init(void)
{
  uart_set_baud(0, 115200);
  printf("SDK version:%s\n", sdk_system_get_sdk_version());
  printf("pcTaskGetName=%s\n",pcTaskGetName(0));

  /* Create Semaphore */
  xSemaphore1 = xSemaphoreCreateBinary();
  xSemaphore2 = xSemaphoreCreateBinary();
  /* Check everything was created. */
  configASSERT( xSemaphore1 );
  configASSERT( xSemaphore2 );

  xTaskCreate(task1, "WiFi", 256, NULL, 2, NULL);
  xTaskCreate(task2, "Server", 1024, NULL, 2, NULL);
  xTaskCreate(task3, "Client", 512, NULL, 2, NULL);
}

結果は以下のようになります。
438tick目でWiFi接続が完了したので、ServerタスクとClientタスクが動き始めます。
これ以降、ServerタスクとClientタスクが並行して動作します。
SDK version:0.9.9
pcTaskGetName=uiT
mode : sta(18:fe:34:d4:2f:77)
add if0
[WiFi:1] Start
[WiFi:1] wifiStatus=1
[Server:1] Start
[Client:1] Start
scandone
[WiFi:138] wifiStatus=1
add 0
aid 7
cnt

connected with aterm-e625c0-g, channel 11
dhcp client start...
[WiFi:238] wifiStatus=1
[WiFi:338] wifiStatus=1
ip:192.168.10.154,mask:255.255.255.0,gw:192.168.10.1
[WiFi:438] wifiStatus=5
[WiFi:438] Connected to AP
[WiFi] MAC address=18:fe:34:d4:2f:77
[WiFi] IP address=192.168.10.154
[WiFi] Netmask=255.255.255.0
[WiFi] Gateway=192.168.10.1
[WiFi:438] Give to task2
[WiFi:438] Give to task3
[Server:438] Take
[Server:438] 9877 で接続を待っています クライアントプログラムを動かして下さい
[Client:440] Take
[Client:442] lwip_write ret=4
[Client:442] lwip_read ret=4
[Client:442] ret=4 buf=TEST
[Server:705] 192.168.10.10 から接続を受けました
[Server:705] numrcv=25
Recv=[data from raspberry 00000]->Send=[DATA FROM RASPBERRY 00000]
[Server:705] numrcv=0
[Server:705] 9877 で接続を待っています クライアントプログラムを動かして下さい
[Server:1208] 192.168.10.10 から接続を受けました
[Server:1208] numrcv=25
Recv=[data from raspberry 00001]->Send=[DATA FROM RASPBERRY 00001]
[Server:1209] numrcv=0
[Server:1209] 9877 で接続を待っています クライアントプログラムを動かして下さい
[Client:1442] lwip_write ret=4
[Client:1442] lwip_read ret=4
[Client:1442] ret=4 buf=TEST
[Server:1713] 192.168.10.10 から接続を受けました
[Server:1713] numrcv=25
Recv=[data from raspberry 00002]->Send=[DATA FROM RASPBERRY 00002]
[Server:1715] numrcv=0
[Server:1715] 9877 で接続を待っています クライアントプログラムを動かして下さい
[Server:2217] 192.168.10.10 から接続を受けました
[Server:2217] numrcv=25
Recv=[data from raspberry 00003]->Send=[DATA FROM RASPBERRY 00003]
[Server:2218] numrcv=0
[Server:2218] 9877 で接続を待っています クライアントプログラムを動かして下さい

Arduino-IDEではクラスを使わないとできない処理が、とても簡単に作れてしまいます。

続く....