目的:
WEBブラウザからの文字列受信にタイムアウト処理を追加する。問題点:
「SPIFFSのテキストファイルをダウンロードする 」等 WEBサーバー動作で、クライアント接続後 に client.connected() のまま何も文字列を受信しなかった場合に while 文のループを抜けなくなってしまう。文字列受信開始後に 最終行(空行) を受信せずに client.available() == 0 となった場合も同様。( clientclient.connected() のまま で )
対策:
一定時間 client.available() == 0 の状態が続いた場合、タイムアウトとして、ループを抜けて client.stop() を行う。タイムアウト時間は状況に応じて設定。start_time = millis() ; // 開始前の時刻を取得
while (client.connected()) {
if (client.available()) {
start_time = millis() ; // 文字列受信時の時刻に更新
|
} else {
if ( (millis() - start_time) > 3000 ) {
break ; // 3000 mS 受信がなければループを抜ける
}
}
例:
「SPIFFSのテキストファイルをダウンロードする 」の メインスケッチにタイムアウト処理を追加した例を示す。(メインスケッチ以外のファイルは 「SPIFFSのテキストファイルをダウンロードする 」を参照 )
#include <WiFi.h> // WiFi 使用の為
#include "FS.h" // SPIFFS 使用の為
#include "SPIFFS.h" // SPIFFS 使用の為
#define DEBUG_HTML // Debug用 Serial 表示制御用
#define DEBUG // Debug用 Serial 表示制御用
// AP モード用 WIFI 設定 ---------------------------------------------
const char ssid[] = "ESP32_AP"; // SSID for softAP
const char pass[] = "password"; // password for softAP
const IPAddress ip(192, 168, 4, 1); // IPアドレス for softAP
const IPAddress subnet(255, 255, 255, 0); // サブネットマスク for softAP
// 動作モードフラグ ---------------------------------------------------
bool stamode = true ; // WiFi STA 接続モード : true
bool sta_exec = false ; // WiFi STA接続モード実行中フラグ
bool config_mode = false ; // 初期設定モード ; true
bool config_exec = false ; // 初期設定実行中フラグ
// 設定ファイル用 -----------------------------------------------------
String s_config ; // 設定ファイル用 String
char wifi_ssid[128] = "" ; // SSID for WiFi STA
char wifi_pass[128] = "" ; // password for WiFi STA
IPAddress wifi_ip(192,168,1,66) ; // IP Address for WiFi STA
IPAddress wifi_gw(192,168,1,1) ; // gate way for WiFi STA
IPAddress wifi_sm(255,255,255,0) ; // subnet mask for WiFi STA
IPAddress wifi_dns(192,168,1,1) ; // dns address for WiFi STA
char wifi_mode[16] = "" ; // wifi mode
String foot_msg ="" ; // リブートメッセージ用
#define CLIENT_TIMEOUT 3000 // クライアントタイムアウト (mS)
WiFiServer server(80);
String html_CONF ; // 設定用 HTML
String html_MAIN ; // メイン HTML
String html_resp ;
// LED 調光処理用 ----------------------------------------------------------------
// -- for ledc
byte brightness = 0 ; // LED 明るさ設定 (0-255)
// -----------------------------------------------------------------------------
// arduino 初期化処理 --
// -----------------------------------------------------------------------------
void setup() {
int res = 0 ; // 結果格納用 (ワーク)
Serial.begin(115200); // シリアル 開始
SPIFFS.begin(true) ; // SPIFFS 開始
// 初期設定用 HTML ファイルの読み込み ---------------------------------------
res = rd_SPIFFS("/WiFi_Config.html",html_CONF) ; // html_CONF に Config.html を格納
// 本体 HTML ファイルの読み込み ----------------------------------------------
res = rd_SPIFFS("/main.html",html_MAIN) ; // html_MAIN に main.html を格納
// レスポンス用HTML ファイルの読み込み ----------------------------------------
res = rd_SPIFFS("/resp_cnfld.html",html_resp) ; // html_resp に resp_confld.html を格納
// 初期設定ファイルを読み込み、グローバル変数に設定し、wifi,画面モードを決定 ---
res = rd_config() ; //
// wifiモード(stamode) に応じて AP か STA かを選択してサーバー起動 -------------
if (stamode == false) { // APモードの場合 softAP WiFi 開始
start_AP_server() ; // APモードでサーバー起動
sta_exec = false ; //
} else { // STAモードの場合 Wifi 開始
start_STA_server() ; // APモードでサーバー起動
sta_exec = true ; //
} //
// 実行中のモード (設定かメインか) を設定 -------------------------------------
if (config_mode) config_exec = true ; // config_mode なら config_exec を '1'
else config_exec = false ; //
Serial.println("Server start!");
// メイン処理用 初期化 ------------------------------------------------------
ledcSetup(0, 5000, 8); // channel 0 周波数 5000 Hz, 8 bit
ledcAttachPin(2,0); // attach pin 2 to channel 0
ledcWrite(0, 0); // initialize channel 0 to off
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// arduino メインループ処理 --
// -----------------------------------------------------------------------------
void loop() {
WiFiClient client = server.available();
String htmlwk = "" ; // html 用 ワーク変数
String line = "" ; // クライアントからの入力用
int xhr = 0 ; // xhr 要求フラグ
unsigned long start_time = 0 ; // タイムアウト監視開始時間
unsigned long wait_time = 0 ; // 開始/前回受信からの経過時間
// HTML クライアント処理 ------------------------------------------------------
if (client) {
start_time = millis() ; // タイムアウト監視開始時間を更新
Serial.println(" +++++++++++++++++ new client! +++++++++++++++++ ");
while (client.connected()) { // クライアントから接続されたとき
if (client.available()) { // 受信文字列がある事
start_time = millis() ; // タイムアウト監視開始時間を更新
line = client.readStringUntil('\n'); // 1行分取得
# ifdef DEBUG_HTML //
Serial.println(line) ; //
# endif //
if (line.indexOf("GET /?") != -1) { // GET 処理
if (config_mode) // 初期設定用 フォームデータ処理
set_form2param(line) ; // フォームデータを変数に格納
else { // メイン用 処理
xhr = proc_main(line) ; // フォームデータのメイン処理
} //
} //
// 最終行(空行)を受信した時 -------------------------------------------
if (line.length() == 1 && line[0] == '\r'){ // 最終行判定
if (stamode != sta_exec) { // sta_mode が変わった場合
if (strcmp(wifi_mode,"ap") == 0){ // リブートメッセージを設定
foot_msg = "アクセスポイントモードに移行します。<br> " ;
foot_msg += "この画面を閉じてアクセスポイントに接続して下さい。" ;
}else{
foot_msg = "ステーションモードに移行します。<br>";
foot_msg += "この画面を閉じて 設定したアドレスに接続して下さい。" ;
}
if (config_exec) { // 初期設定中なら
send_CONF_html(client) ; // 初期設定 HTML 送信
} else { // メイン画面なら
send_MAIN_html(client) ; // メイン HTML 送信
} // ( その後 リブート)
} else { // sta_mode が変わらない場合
if (config_mode) { // 次に初期設定を表示するなら
send_CONF_html(client) ; // 初期設定 HTML 送信
config_exec = true ; //
} else { // 次にメイン画面なら
if (xhr) { // XHR 応答の場合
send_resp_html(client) ; // XHR 応答 送信
} else { // HTML 送信なら
send_MAIN_html(client) ; // メイン HTML 送信
config_exec = false ; //
} //
} //
} //
# ifdef DEBUG_HTML //
Serial.println("Send HTML") ; //
# endif //
break ; // ループ終了
} //
//-------------------------------------------------------------------
} else { // 文字列受信していない時
wait_time = millis() - start_time ; // 前回受信からの時間を取得
if ((wait_time) > CLIENT_TIMEOUT) { // 文字列受信タイムアウト判定
Serial.print("タイムアウト :") ; //
Serial.print(wait_time) ; //
Serial.println(" mS") ; //
break ; // ループ終了
} //
} //
}
// 接続が切れた場合 ------------------------------------------------------
client.stop();
Serial.println("client disonnected");
Serial.println("----------------------------------------------------");
}
if (stamode != sta_exec) { // sta_mode が変わった場合
Serial.println("------------------- リブートします------------------- ");
delay(500); //
ESP.restart() ; // リブート
} else {
}
// --------------------------------------------------------------------------
}
(行#31)
タイムアウト時間 の define 文
(行#96,97)
タイムアウト処理用ローカル変数
(行#101,105)
開始時、文字列受信時の 監視開始時間を取得
(行#151~158)
client.available() == 0 時の処理。
タイムアウト時間を超えていたら break ;を実行
0 件のコメント:
コメントを投稿