LoginSignup
3
2

More than 5 years have passed since last update.

Arduino M0 Pro でマルチタスクプログラミング : Wifi通信

Last updated at Posted at 2016-03-15

はじめに

この記事では,TOPPERS/R2CAによるWifi通信の方法について説明します.タスクは1個のみのシングルタスク版を説明します.

TOPPERS/R2CAの説明とサンプルの動作方法は次の記事を見て下さい.

変更履歴

  • 2016/10/23
    • ファイルの変更
  • 2016/5/05
    • アクセスポイントの設定を別ファイルとした.
  • 2016/3/31
    • ESP8266のドライバの見直しによりサンプルプログラムを変更.
    • シングルタスク版について説明

ハードウエア

この記事で説明しているハードウェア以外にESP8266が必要です.

ESP8266のボードは多くの種類が出ています.基本的にはどれでも良いですが,動作確認したものは次の通りです.

  • スイッチサイエンス ESP-WROOM-02

    • ブレッドボードを使って接続しました.
  • NCES WiFi ボード

    • ESP8266をXbee互換の基盤にしたものです.
    • Arduino ワイヤレスプロトシールドや,NCES CAN シールドを使うと,簡単にArduinoと接続可能です.
    • ロゴから分かるようにTOPPERS/R2CA用に作成しました.

nces_can.jpg

サンプルのビルド

R2CAのパッケージの\examples\WifiEchoにあるサンプルを実行します.このサンプルはポート80に入力された文字列をそのまま返すエコーサーバーです.

まずexamples_gdef.hを開き,アクセスポイントの情報をSSIDとPASSWORDに設定します.

\examples\examples_gdef.h
#define STA_SSID       ""
#define STA_PASSWORD   ""

次にr2ca_app.hを開き,シングルタスク版にするためマクロをコメントアウトします.

\examples\WifiEcho\r2ca_app.h
//#define MULTI_ECHO_SERVER

ビルドは同じフォルダにあるdo_make.bat をダブルクリックすると開始されます.ファイルが色々作成されますが,rca.elfが出来るとビルド成功です.

実行

実行はdo_run.batをダブルクリックするとダウンロードが開始され,実行されます.Teratermには次のように表示されます.アクセスポイントに接続して,IPアドレスをDHCPから取得します.取得したアドレスはコンソールに出力されます.下記の例では,192.168.1.27となっています.

WS000000.JPG

PCから上記のIPのポート80に接続して適当な文字を入力してエンターを押すと入力した文字がそのまま送られて来ます.終了するには,Ctrl-Q入力してエンターを押します.

WS000001.JPG

ボード側のコンソールにもは,受信した旨が表示されます.
WS000002.JPG

プログラム

初期化処理

初期化処理ではアクセスポイントに接続してIPを取得しています.また,ポート番号80番でTCPサーバーを実行します.#define WMODE_STATION の定義をコメントアウトすると,アクセスポイントとして動作します.

\examples\WifiEcho\r2ca_app.cpp
void setup()
{
    int ret;

    Serial.println("Echo Server : Start!");

    ret = WiFi.begin(Serial5, 115200);

    if(ret == 1) {
        Serial.print("Cannot communicate with ESP8266.");
        while(1);        
    } else if(ret == 2) {
        Serial.println("FW Version mismatch.");
        Serial.print("FW Version:");
        Serial.println(WiFi.getVersion().c_str());
        Serial.print("Supported FW Version:");
        Serial.println(ESP8266_SUPPORT_VERSION);
        while(1);
    } else {
        Serial.print("begin ok\r\n");
    }

    Serial.print("FW Version:");
    Serial.println(WiFi.getVersion().c_str());

#ifdef  WMODE_STATION
    if (WiFi.setOprToStation()) {
        Serial.print("to station ok\r\n");
    } else {
        Serial.print("to station err\r\n");
    }

    if (wifi.joinAP(STA_SSID, STA_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");
    }
#else /* !WMODE_STATION */ 
    if (WiFi.setOprToSoftAP()) {
        Serial.print("to softap ok\r\n");
    } else {
        Serial.print("to softap err\r\n");
    }    
    if(WiFi.setSoftAPParam(AP_SSID, AP_PASSWORD, 7, 0)){
        Serial.print("Set SoftAP success\r\n");
        Serial.print("IP: ");
        Serial.println(WiFi.getLocalIP().c_str());            
    }
    else {
        Serial.print("Set SoftAP failure\r\n");
    }
#endif /* WMODE_STATION */

    if (WiFi.enableMUX()) {
        Serial.print("multiple ok\r\n");
    } else {
        Serial.print("multiple err\r\n");
    }

    if (WiFi.startTCPServer(80)) {
        Serial.print("start tcp server ok\r\n");
    } else {
        Serial.print("start tcp server err\r\n");
    }

    if (WiFi.setTCPServerTimeout(60)) { 
        Serial.print("set tcp server timout 60 seconds\r\n");
    } else {
        Serial.print("set tcp server timout err\r\n");
    }

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

    setup_done = true;
}

エコーサーバー処理

まず,コネクションが変化したかをチェックします.コネクションは最大5個あります.このプログラムではコネクション0に対してデータを受け取り,エコーバックを行います.コネクション0に接続があれば,mux_idに0を設定します.

次に,コネクションが確立しているかをチェックして,80番のポートからデータを受け取ります.有効なデータを受け取った場合は,コンソールに出力した後,データをエコーバックしています.また,受信したデータをチェックして,Crtl-Qを受け取った場合は,終了処理も行います.

\examples\WifiEcho\r2ca_app.cpp
uint8_t mux_id_ptn;

uint8_t mux_id = MUX_NULL;
uint8_t task1_mux_id = MUX_NULL;

void loop()
{
    uint8_t buffer[128] = {0};
    uint8_t pre_mux_id_ptn;    
    uint32_t len;
    uint32_t i;

    delay(1);    
    /* Check Connection Status */
    pre_mux_id_ptn = mux_id_ptn;

    if(!Wifi.getMuxCStatus(&mux_id_ptn)) {
        Serial.println("getMuxCStatus(&mux_id_ptn) : Error!");
    }
    else {        
        if (pre_mux_id_ptn != mux_id_ptn) {
            Serial.print("Connection Status changed! : 0x");
            Serial.println(mux_id_ptn, HEX);
            if (mux_id_ptn & 0x01) {
                mux_id = 0; 
            }
            if (mux_id_ptn & 0x02) {
                task1_mux_id = 1;
            }
        }
    }

    if (mux_id == MUX_NULL) {
        return;
    }

    if (!WiFi.isConnected(mux_id)) {
        Serial.print("Echo Server : Port is closed: ");
        Serial.println(mux_id);
        mux_id = MUX_NULL;
        return;
    }

    if((len = WiFi.recv(mux_id, buffer, sizeof(buffer))) == 0) {
        return;
    }

    /* Recived Data */

    for(i = 0; i < len; i++) {
        /* If Recive Ctrl-q(17) */
        if(buffer[i] == 17) {
            Serial.print("Echo Server : Close port : ");
            Serial.println(mux_id);            
            WiFi.releaseTCP(mux_id);
            mux_id = MUX_NULL;
            return;
        }
    }

    Serial.print("Echo Server : Recive Data from mux : ");
    Serial.println(mux_id);
    Serial.print("Echo Server : Recive len   : ");
    Serial.println(len);
    Serial.print("Echo Server : Recive Data  : ");
    Serial.println((char*)buffer);

    if(!WiFi.send(mux_id, buffer, len)) {
        Serial.println("Echo Server : send(mux_id, cmd) : Error!");
    }
}

API

ESP8266のライブラリはITEADLIB_Arduino_WeeESP8266をベースとしていますが,API幾つか増やしています.

    int begin(HardwareSerial &uart, uint32_t baud = 115200);
    bool kick(void);
    bool restart(void);
    String getVersion(void);
    bool setOprToStation(void);
    bool setOprToSoftAP(void);
    bool setOprToStationSoftAP(void);
    String getAPList(void);
    bool joinAP(String ssid, String pwd);
    bool leaveAP(void);
    bool setSoftAPParam(String ssid, String pwd, uint8_t chl = 7, uint8_t ecn = 4);
    String getJoinedDeviceIP(void);
    String getIPStatus(void);
    String getLocalIP(void);
    bool enableMUX(void);
    bool disableMUX(void);
    bool createTCP(String addr, uint32_t port);
    bool releaseTCP(void);
    bool registerUDP(String addr, uint32_t port);
    bool unregisterUDP(void);
    bool createTCP(uint8_t mux_id, String addr, uint32_t port);
    bool releaseTCP(uint8_t mux_id);
    bool registerUDP(uint8_t mux_id, String addr, uint32_t port);
    bool unregisterUDP(uint8_t mux_id);
    bool setTCPServerTimeout(uint32_t timeout = 180);
    bool startTCPServer(uint32_t port = 333);
    bool stopTCPServer(void);
    bool startServer(uint32_t port = 333);
    bool stopServer(void);
    bool send(const uint8_t *buffer, uint32_t len);
    bool send(uint8_t mux_id, const uint8_t *buffer, uint32_t len);
    bool send(String &str);
    bool send(uint8_t mux_id, String &str);
    uint32_t recv(uint8_t *buffer, uint32_t buffer_size, uint32_t timeout = 1000);
    uint32_t recv(uint8_t mux_id, uint8_t *buffer, uint32_t buffer_size, uint32_t timeout = 1000);
    uint32_t recv(uint8_t *coming_mux_id, uint8_t *buffer, uint32_t buffer_size, uint32_t timeout = 1000);
    bool isDataAvailable(uint8_t mux_id);
    bool isDataAvailable(void);
    bool isConnected(void);
    bool isConnected(uint8_t mux_id);
    bool getMuxCStatus(uint8_t *mux_id_ptn);

おわりに

ESP8266を使うと安価に簡単にネットに接続できます.TOPPERS/R2CAを使うと,マルチタスクが使えるので,サーバーで接続待ちになりながら,センサー等の処理を同時に実行出来ます.

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2