ESP8266をWifiモデムとして使う

ライブラリを使ったSocket通信(クライアント編)


Wifiモデムを使ったRaspberryとのSocket通信を紹介します。
最初に、Raspberryがサーバー、Arduino+ESP-01がクライアントの動作を紹介します。

【Raspberry側】

以下のコード(server.c)をコンパイルして実行します。
クライアントから受信した文字列を大文字に変換して送り返す単純なものです。
コンパイルは単純に「cc server.c」で、実行は「./a.out」です。

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

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

int main(int argc, char **argv){
  int i;
  int srcSocket; //自分
  int dstSocket; //相手
  // sockaddr_in 構造体
  struct sockaddr_in srcAddr;
  struct sockaddr_in dstAddr;
  socklen_t dstAddrSize;
  // 各種パラメータ
  int numrcv;
  char buf[1024];
  int loopMax;
  int loopCnt;

  time_t start_time=0, end_time;
  double dtime;

  loopMax=INT_MAX;
  if (argc == 2) {
    loopMax=atoi(argv[1]);
  }

  // sockaddr_in 構造体のセット
  bzero((char *)&srcAddr, sizeof(srcAddr));
  srcAddr.sin_port = htons(PORT);
  srcAddr.sin_family = AF_INET;
  srcAddr.sin_addr.s_addr = INADDR_ANY;
   
  // ソケットの生成(ストリーム型)
  srcSocket = socket(AF_INET, SOCK_STREAM, 0);
  // ソケットのバインド
  bind(srcSocket, (struct sockaddr *)&srcAddr, sizeof(srcAddr));
  // 接続の許可
  listen(srcSocket, 5);
 
  for(loopCnt=0;loopCnt<loopMax;loopCnt++) {
//  while(1){
    // 接続の受付け
    printf("接続を待っています\nクライアントプログラムを動かして下さい\n");
    dstAddrSize = sizeof(dstAddr);
    dstSocket = accept(srcSocket, (struct sockaddr *)&dstAddr, &dstAddrSize);
    printf("%s から接続を受けました\n",inet_ntoa(dstAddr.sin_addr));
    if (start_time == 0) time( &start_time );
       
    while(1) { // クライアントがSocketをクローズしてからこちらもクローズする
      //パケットの受信
      memset(buf,0,sizeof(buf));
      numrcv = read(dstSocket, buf, 1024);
      printf("numrcv=%d\n",numrcv);
      if(numrcv ==0 || numrcv ==-1 ){ // client close socket
        close(dstSocket); break;
      }
      printf("Recv=[%s]",buf);
      for (i=0; i< numrcv; i++){ // bufの中の小文字を大文字に変換
        if(isalpha(buf[i])) buf[i] = toupper(buf[i]);
      }
      // パケットの送信
      write(dstSocket, buf, numrcv);
      printf("->Send=[%s]\n",buf);
    } // end while
  } // end for
  time( &end_time );
  dtime=difftime( end_time, start_time );
  printf("loop=%d difftime=%f[sec] %f[min]\n",loopMax,dtime,dtime/60);
  return(0);
}

プログラムを起動すると以下の表示となります。


【Arduino側】

Arduino側のスケッチは以下の通りです。
相手側(今回はRaspberry)とポート番号(今回は9876番を使用)とIPアドレスを合わせて下さい。
ここが合っていないと正しく通信できません。
SIDにはアクセスポイントのSSID、PASSにはそのパスワードを指定してください。
赤字の部分は自分の環境に合わせて変更してください。

/*
 * ESP8266 TCP Client Example with WeeESP8266 Library
 *
 * ESP8266----------ATmega
 * ESP8266_TX    -> RX(D2)
 * ESP8266_RX    -> TX(D3)
 */
#include "ESP8266.h"
#include <SoftwareSerial.h>

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

SoftwareSerial myESP8266(rxPin, txPin); /* RX:D2, TX:D3 */
ESP8266 wifi(myESP8266,baudRate); // https://github.com/itead/ITEADLIB_Arduino_WeeESP8266

#define SSID        "APのSSID"
#define PASSWORD    "APのパスワード"
#define HOST_NAME   "192.168.10.10"
#define HOST_PORT   (9876)

void setup(void)
{
    Serial.begin(9600);
    wifi.leaveAP();
     
    if (wifi.setOprToStation()) {
      Serial.print("to station ok\r\n");
    } else {
      Serial.print("to station err\r\n");
    }

    if (wifi.joinAP(SSID, PASSWORD)) {
      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.disableMUX()) {
      Serial.print("single ok\r\n");
    } else {
      Serial.print("single err\r\n");
    }

    Serial.print("setup end\r\n");
}

void loop(void)
{
    static int num = 0;
    uint8_t rmsg[128] = {0};
    char smsg[40];
    
    if (wifi.createTCP(HOST_NAME, HOST_PORT)) {
      Serial.print("create tcp ok\r\n");
    } else {
      Serial.print("create tcp err\r\n");
    }
    
    sprintf(smsg,"data from arduino %05d",num);
    num++;
    wifi.send((const uint8_t*)smsg, strlen(smsg));
    
    uint32_t len = wifi.recv(rmsg, sizeof(rmsg), 10000);
    if (len > 0) {
      Serial.print("[");
      Serial.print(smsg);
      Serial.write("]->[");
      for(uint32_t i = 0; i < len; i++) {
        Serial.print((char)rmsg[i]);
      }
      Serial.print("]\r\n");
    }
    
    if (wifi.releaseTCP()) {
      Serial.print("release tcp ok\r\n");
    } else {
      Serial.print("release tcp err\r\n");
    }
    if (Serial.available() > 0) {
      char inChar = Serial.read();
      Serial.print("KeyIn");
      wifi.leaveAP();
      Serial.println("client end");
      while(1) { }
    }
    delay(1000);
}

このスケッチを実行するとRaspberry側の表示は以下のようになります。


Arduino-IDEのシリアルモニターはこのように表示されます。



しばらく放置しましたが、順調に動いています。



次回はRaspberryがクライアント、Arduinoがサー バーの動作を紹介します。