ESP8266をWifiモデムとして使う

ATコマンドによるSocketクライアント


ESP8266用のライブラリはいくつかありますが、所詮シリアル通信でATコマンドを投げているだけなので、
ライブラリを使わずにSocket通信してみることにしました。
一連のATコマンドについてはこ ちらを参考にさせていただきました。

最初に、ATコマンドだけのSocketクライアントを紹介します。
スケッチは以下の通りです。
SERVERにはSocketサーバーのIPアドレス、PORTにはサーバー側のポート番号を指定してください。
sendCommand() waitForString() errorDisplay() clearBuffer() はセットなので
1つにまとめてしまってもいいかもしれません。
相手側のSocketサーバーは次回紹介します。
/*
 * Socket Client with AT Command
 * 
 * ESP8266----------ATmega
 * TX     ----------RX(D4)
 * RX     ----------TX(D5)
 *
 */

#include <SoftwareSerial.h>

#define rxPin    4    // D4
#define txPin    5    // D5
#define _DEBUG_  0

#define SERVER      "192.168.10.190"
#define PORT        "9876"
#define INTERVAL    5000

char cmd[64];
unsigned long lastmillis;

SoftwareSerial mySerial(rxPin, txPin); // RX, TX

//Wait for specific input string until timeout runs out
bool waitForString(char* input, int length, unsigned int timeout) {

  unsigned long end_time = millis() + timeout;
  char current_byte = 0;
  int index = 0;

   while (end_time >= millis()) {
   
      if(mySerial.available()) {
       
        //Read one byte from serial port
        current_byte = mySerial.read();
        if (_DEBUG_) Serial.print(current_byte);
        if (current_byte != -1) {
          //Search one character at a time
          if (current_byte == input[index]) {
            index++;
           
            //Found the string
            if (index == length) {             
              return true;
            }
          //Restart position of character to look for
          } else {
            index = 0;
          }
        }
      }
  } 
  //Timed out
  return false;
}

//Remove all bytes from the receive buffer
void clearBuffer() {
  while (mySerial.available())
    mySerial.read();
  if (_DEBUG_) Serial.println("");
}

//Send AT Command
void sendCommand(char* buff) {
  if (_DEBUG_) {
    Serial.println("");
    Serial.print(buff);
    Serial.println("-->");
  }
  mySerial.println(buff);
  mySerial.flush();
}

//Print error
void errorDisplay(char* buff) {
  Serial.print("Error:");
  Serial.println(buff);
  while(1) {}
}

//Receive Message
int readResponse(int id, char * buf,int sz_buf, int timeout) {
  int len=0;
  int flag=0;
  int datalen;
  long int time = millis();

  // id < 0  +IPD,nn:ReceiveData
  // id = 0  +IPD,0,nn:ReceiveData
  // id > 0  +IPD,id,nn:ReceiveData
  while( (time+timeout) > millis()) {
    while(mySerial.available())  {
      char current_byte = mySerial.read(); // read the next character.
      if (_DEBUG_) Serial.print(current_byte);
      if (flag == 0) {
        if (current_byte != 0x2c) continue;
        flag++;
        if (id < 0) flag++;
      } else if (flag == 1) {
        if (current_byte != 0x2c) continue;
        flag++;
      } else if (flag == 2) {
        if (current_byte == 0x3a) { // :
          datalen=atoi(buf);
          flag++;
          len=0;
        } else {
          buf[len++]=current_byte;
          buf[len]=0;
        }
      } else {
        buf[len++]=current_byte;
        if (len == sz_buf) return -len;
        buf[len]=0;
        if (len == datalen) return len;
      }
    } // end while
  } // end while
  return -len;
}

void setup(void)
{
  Serial.begin(9600);

  //Make sure ESP8266 is set to 4800
  mySerial.begin(4800);
  delay(100);

  //Restarts the Module
  sendCommand("AT+RST");
  if (!waitForString("WIFI GOT IP", 11, 10000)) {
    errorDisplay("ATE+RST Fail");
  }
  clearBuffer();

  //Local echo off
  sendCommand("ATE0");
  if (!waitForString("OK", 2, 1000)) {
    errorDisplay("ATE0 Fail");
  }
  clearBuffer();

  //Get local IP address
  sendCommand("AT+CIPSTA?");
  if (!waitForString("OK", 2, 1000)) {
    errorDisplay("AT+CIPSTA? Fail");
  }
  clearBuffer();

  lastmillis = millis();
  Serial.println("Start Socket Client via ESP8266");
}

void loop(void) {
  static int num = 0;
  char smsg[64];
  char rmsg[64];
  short sz_smsg;

  if (Serial.available() > 0) {
    char inChar = Serial.read();
    Serial.print("KeyIn");
    sendCommand("AT+CWQAP");
    if (!waitForString("OK", 2, 1000)) {
      errorDisplay("AT+CWQAP Fail");
    }
    clearBuffer();
    Serial.println("client end");
    while(1) { }
  }

  if (((signed long)(millis() - lastmillis)) > 0) {
    lastmillis = millis() + INTERVAL;
    //Start connection
    //Send AT+CIPSTART="TCP","192.168.XXX.XXX",PORT
    sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%s", SERVER,PORT);
    sendCommand(cmd);
    if (!waitForString("OK", 2, 10000)) {
      errorDisplay("AT+CIPSTART Fail");
    }
    clearBuffer();
    sprintf(smsg,"data from arduino %05d",num);
    num++;
    sz_smsg=strlen(smsg);
    //Send AT+CIPSEND=nn
    sprintf(cmd,"AT+CIPSEND=%d",sz_smsg);
    sendCommand(cmd);
    if (!waitForString(">", 1, 1000)) {
      errorDisplay("AT+CIPSEND Fail");
    }
    clearBuffer();
    Serial.write(smsg,sz_smsg);
   
    //Send data
    sendCommand(smsg);
    if (!waitForString("SEND OK", 7, 1000)) {
       errorDisplay("AT+CIPSEND Fail");
    }
    clearBuffer();
    //Read data
    int readLen = readResponse(-1, rmsg, sizeof(rmsg), 5000);
    if (_DEBUG_) {
      Serial.println();
      Serial.print("readLen=");
      Serial.println(readLen);
    }
    Serial.print("---->");
    Serial.write(rmsg,readLen);
    Serial.println();
    if (readLen < 0) {
       errorDisplay("Server not response");
    }
    clearBuffer();
    //Close TCP connection
    sendCommand("AT+CIPCLOSE");
    if (!waitForString("OK", 2, 1000)) {
      errorDisplay("AT+CIPCLOSE Fail");
    }
    clearBuffer();
  }
}

小文字の文字列を送信すると、サーバーから大文字に変換された文字列を受け取ります。


次回はSocketサーバーを紹介します。