Arduinoと無線LANで通信する(ESP8266 4)


前回は、Raspberryがサーバー、 Arduino+ESP8266がクライアントの動作を試してみました。
そこで、今回はRaspberryがクライアント、Arduino+ESP8266がサーバーの動作を試してみます。

【Arduino側】

Arduino側のスケッチは以下の通りです。
クライアントから受信した文字列を大文字に変換して送り返す単純なものです。

/*
 * ESP8266 TCP Server Example with WeeESP8266 Library
 * https://github.com/itead/ITEADLIB_Arduino_WeeESP8266
 *
 * ESP8266----------ATmega
 * ESP8266_TX    -> RX(D3)
 */
#include "ESP8266.h"
#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3
#define baudRate 4800

SoftwareSerial myESP8266(rxPin, txPin); /* RX:D3, TX:D2 */
ESP8266 wifi(myESP8266,baudRate);
#define SID         "アクセスポイントのSSID"
#define PASS        "アクセスポイントのパスワード"

void setup(void)
{
    Serial.begin(9600);
    wifi.leaveAP();
    Serial.print("FW Version:");
    Serial.println(wifi.getVersion().c_str());
   
    if (wifi.setOprToStationSoftAP()) {
      Serial.print("to station ok\r\n");
    } else {
      Serial.print("to station err\r\n");
    }

    if (wifi.joinAP(SID, PASS)) {
      Serial.print("Join AP success\r\n");
      Serial.print("IP: ");      
      Serial.println(wifi.getLocalIP().c_str());
    } else {
      Serial.print("Join AP failure\r\n");
    }

    if (wifi.enableMUX()) {
      Serial.print("multiple ok\r\n");
    } else {
      Serial.print("multiple err\r\n");
    }
   
    if (wifi.startTCPServer(9876)) {
      Serial.print("start tcp server ok\r\n");
    } else {
      Serial.print("start tcp server err\r\n");
    }
   
    if (wifi.setTCPServerTimeout(10)) {
      Serial.print("set tcp server timout 10 seconds\r\n");
    } else {
      Serial.print("set tcp server timout err\r\n");
    }
    Serial.print("setup end\r\n");
}

void loop(void)
{
    static int num = 0;
    uint8_t rmsg[128] = {0};
    uint8_t smsg[128];
    uint8_t mux_id;
    uint32_t len;
   
    len = wifi.recv(&mux_id, rmsg, sizeof(rmsg), 100);
    if (len > 0) {
      Serial.print("Status:[");
      Serial.print(wifi.getIPStatus().c_str());
      Serial.println("]");
       
      Serial.print("Received from :");
      Serial.print(mux_id);
      Serial.print("[");
      for(uint32_t i = 0; i < len; i++) {
        Serial.print((char)rmsg[i]);
        if(isalpha(rmsg[i])) {
          smsg[i] = toupper(rmsg[i]);
        } else {
          smsg[i] = rmsg[i];
        } // end if
      } // end for
      Serial.print("]\r\n");
       
      if(wifi.send(mux_id, smsg, len)) {
        Serial.print("send back ok\r\n");
      } else {
        Serial.print("send back err\r\n");
      }

#if 0
        if (wifi.releaseTCP(mux_id)) {
          Serial.print("release tcp ");
          Serial.print(mux_id);
          Serial.println(" ok");
        } else {
          Serial.print("release tcp");
          Serial.print(mux_id);
          Serial.println(" err");
        }
#endif
       
      Serial.print("Status:[");
      Serial.print(wifi.getIPStatus().c_str());
      Serial.println("]");
    } // end if
}


このスケッチを実行するとArduinoのシリアルモニターに以下が表示されます。



サーバ動作をする場合、IPアドレスを固定した方が便利です。、
IPアドレスを固定する方法を色々調べましたが見つかりませんでした。

【Raspberry側】

以下のコード(client.c)をコンパイルして実行します。
サーバー側が止まっているなどで、Connectできないときはリトライします。
コンパイルは単純に「cc client.c」で、実行は「./a.out」です。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>
#include <limits.h>

int retryTotal=0;

#define PORT 9876 //サーバープログラムとポート番号を合わせてください

int connect2(struct sockaddr_in * dstAddr, int dstAddrLen) {
  int dstSocket;
  int retry = 0;
  int retryMax = 10;
  time_t start_time, end_time;
  double dtime;

  while (1) {
    //ソケットの生成
    dstSocket = socket(AF_INET, SOCK_STREAM, 0);
 
    //接続
    write(1,"Connecting...",13);
    time( &start_time );
    if (connect(dstSocket, (struct sockaddr *)dstAddr, dstAddrLen) == 0) return(dstSocket);
    time( &end_time );
    dtime=difftime( end_time, start_time );
    retry++;
    printf("接続できませんでした retry=%d difftime=%f\n",retry,dtime);
    retryTotal++;
    close(dstSocket);
    if (retry > retryMax) return(-1);
    sleep(10);
  }
}

int main(int argc, char **argv){
  // IP アドレス,ソケット,sockaddr_in 構造体
  char destination[32];
  int dstSocket;
  struct sockaddr_in dstAddr;

  //struct sockaddr_in addr;
  struct hostent *hp;
  char  buf[1024];
  int number = 0;
  int numrcv;
  int retry = 0;
  int loopMax;
  int loopCnt;

  time_t start_time=0, end_time;
  double dtime;

  loopMax=INT_MAX;
  if (argc == 2) {
    loopMax=atoi(argv[1]);
  }
  // 相手先アドレスの入力と送る文字の入力
  printf("サーバーマシンのIPは?:");
  scanf("%s", destination);
 
  //sockaddr_in 構造体のセット
  bzero((char *)&dstAddr, sizeof(dstAddr));
  dstAddr.sin_family = AF_INET;
  dstAddr.sin_port = htons(PORT);
 
  hp = gethostbyname(destination);
  bcopy(hp->h_addr, &dstAddr.sin_addr, hp->h_length);

  for(loopCnt=0;loopCnt<loopMax;loopCnt++) {
//  while (0) {
    dstSocket = connect2(&dstAddr, sizeof(dstAddr));
    printf("dstSocket=%d\n",dstSocket);
    if (dstSocket < 0) {
      printf("%s に接続できませんでした\n",destination);
      return(-1);
    }
    printf("%s に接続しました\n",destination);
    if (start_time == 0) time( &start_time );
 
    memset(buf,0,sizeof(buf));
    sprintf(buf,"data from raspberry %05d",number);
    number++;
    printf("Send=[%s]",buf);
    //パケットの送信
    write(dstSocket, buf, strlen(buf));
    //パケットの受信
    memset(buf,0,sizeof(buf));
    numrcv = read(dstSocket, buf, 1024);
    printf("→Recv=[%s]\n",buf);
    close(dstSocket);
    sleep(5);
  } // end for
  time( &end_time );
  dtime=difftime( end_time, start_time );
  printf("loop=%d difftime=%f[sec] %f[min] retry=%d\n",loopMax,dtime,dtime/60,retryTotal);
  return(0);
}

実行するとサーバーのIPアドレスを聞いてきますので、ArduinoのIPアドレスを入力します。



Raspberryから送った「data from raspberry」の文字が「DATA FROM RASPBERRY」となって返ってきます。



Raspberry側は以下の様に表示されます。




続く....