ESP8266 32文字のSSID局に繋がらない
ESP8266 を使ったリモートコンセント製作、前回のハード編 に引き続きソフト編をただいま準備しています。
だいたいの骨格は出来ました。
最初は自力でソケット通信しようと思っていたのですが、「こんな機能もあると便利だな・・・」的に想像を膨らませていったら、「それ何て言う MQTT?」って風になってしまいましたので、独自仕様は捨ててオープンな MQTT 3.1 に準拠した仕様にしてしまうぞぉ〜と頑張っております。
細かい話は次回以降にするとして、その過程で見つけた個人的に重大と思うバグがひとつ
SSID が32文字の無線親機に繋がらない
31文字なら大丈夫で32文字だと確実にNGという風なのです。
libraries\ESP8266WiFi\src\ESP8266WiFi.cpp
前略 int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid) { _useClientMode = true; if(_useApMode) { // turn on AP+STA mode _mode(WIFI_AP_STA); } else { // turn on STA mode _mode(WIFI_STA); } if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) { // fail SSID too long or missing! return WL_CONNECT_FAILED; } 後略
なんと、strlen(ssid) が 31 を越えてる場合はエラー処理にしてしまってるじゃないですか。
これじゃ繋がらないわけです。
じゃあと「strlen(ssid) > 31」を「strlen(ssid) > 32」に書き換えたら動く気がするじゃないですか。
しかしながら動きません。
tools\sdk\include\user_interface.h
前略 struct station_config { uint8 ssid[32]; uint8 password[64]; uint8 bssid_set; // Note: If bssid_set is 1, station will just connect to the router // with both ssid[] and bssid[] matched. Please check about this. uint8 bssid[6]; }; 後略
ssid が入る配列が 32バイト(31文字分)しか取ってないじゃないですか。
strlen(ssid) の判定を誤魔化したら、今度は構造体の中でバッファオーバーランですよ。
ヘッダーファイルだけ弄ってもダメです。
これを使ってコンパイルされたライブラリも一緒に再コンパイルしないといけませんが、あいにくソースは見つからず。。。
「無線LANの親機のSSIDを31文字に変更してしまえばいいじゃん」と仰られるかもしれませんが、WiFi.scanNetworks() で近所の局を検索かけてみると一部の局が文字化けして出てくるんですよ。
つまり32文字の SSID を弾いていないので、中でバッファオーバーランを起こしているぽい感じです。
きっと WPS が使えない原因もコレですね。
ほとんどのルーターでは WPS で最大長の SSID を払い出しますから。
とりあえず、つたない英語で Expressif へバグレポート 出してみましたが、果たして対策してもらえるのでしょうか。
当面は WiFi.scanNetworks() も使わないで、31文字以内の SSID を固定で記述してやりすごすしかなさそうです。
(追記)2015/12/09
「とりあえず、こうすれば繋がるよ。このリンク見て」的な英語の返事が返ってきました。
Station mode: Connect to router
カタコトの英語が通じたみたいで喜ばしい限り。
EspressIf が出してる SDK のバグでなくて、Arduino 側の ESP8266WiFi のバグということですか。
了解しました!
とりあえず ESP8266WiFi.cpp に手を加えて 32文字 に対応させましたが、本家は直す気ないのかなぁ