diff --git a/M5StickCPlus_FactoryTest2022.ino b/M5StickCPlus_FactoryTest2022.ino index 13bbb94..f14917b 100644 --- a/M5StickCPlus_FactoryTest2022.ino +++ b/M5StickCPlus_FactoryTest2022.ino @@ -63,13 +63,19 @@ extern const unsigned char icon_ble_disconnect[1]; #endif -bool TestMode = true; // テストモード 常時ONにした (A/Bボタンを押しながら起動すれば、通常のFactoryTestでもテストモードになる) +bool TestMode = false; // テストモード 常時ONにした (A/Bボタンを押しながら起動すれば、通常のFactoryTestでもテストモードになる) bool startCoundDownShutdown = false; // 電源OFFのカウントダウンを開始するならtrue +bool startWebOTA = false; // WebOTA(from Remote Signal)を開始するならtrue #ifdef ENABLE_OTA bool startOTA = false; bool startOTAhandle = false; #endif +void start_WebOTA(); +bool wifi_setup(); +void ntp_setup(); +void wifi_down(); + TFT_eSprite Disbuff = TFT_eSprite(&M5.Lcd); // 画面ちらつき防止スプライト(画面のバッファリング) hw_timer_t *timer = NULL; @@ -102,6 +108,9 @@ if (startCoundDownShutdown) countDownShutdown(); + + if (startWebOTA) + countDownWebOTA(); #ifdef ENABLE_OTA if (startOTA) { @@ -116,17 +125,14 @@ void Displaybuff() // Disbuffスプライトを表示する。(テストモードだったらTest Modeと表示する) { - if (TestMode) - { - Disbuff.setTextSize(1); - Disbuff.setTextColor(TFT_CYAN); - Disbuff.drawString("FactoryTest 2024", 10, 0, 1); - Disbuff.setTextColor(TFT_WHITE); + Disbuff.setTextSize(1); + Disbuff.setTextColor(TFT_CYAN); + Disbuff.drawString("FactoryTest 2024", 10, 0, 1); + Disbuff.setTextColor(TFT_WHITE); - battery.batteryUpdate(); + battery.batteryUpdate(); - // battery.showBattery(); - } + // battery.showBattery(); Disbuff.pushSprite(0, 0); } @@ -295,7 +301,7 @@ rect_source[n].end_point.z = rect[n].end_point.z * 30; } - while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) + while ((!M5.BtnA.isPressed()) /*&& (!M5.BtnB.isPressed())*/) { M5.Imu.getAccelData(&accX, &accY, &accZ); @@ -583,7 +589,8 @@ { // RTC sync from NTP // Wifi → NTP → update RTC → WifiOff - if (wifi_setup()) ntp_setup(); + if (wifi_setup()) + ntp_setup(); wifi_down(); Init_ESPNOW(); // ESPNOWの初期化 @@ -603,6 +610,7 @@ Disbuff.setTextColor(TFT_WHITE); } +#ifdef ENABLE_IRSEND static esp_pm_lock_handle_t rmt_freq_lock; #define RMT_TX_CHANNEL RMT_CHANNEL_0 #define RMT_TX_GPIO_NUM GPIO_NUM_9 @@ -702,6 +710,7 @@ free(tx_buffer); return true; } +#endif #ifdef ENABLE_BLE #define SERVICE_UUID "1bc68b2a-f3e3-11e9-81b4-2a2ae2dbcce4" @@ -1075,6 +1084,7 @@ Disbuff.setTextColor(TFT_RED); } Disbuff.printf("b%.2f", M5.Axp.GetBatVoltage()); // バッテリー電圧を表示する + Disbuff.setCursor(12, 37); if (M5.Axp.GetVinVoltage() > 4.6) { @@ -1240,12 +1250,10 @@ { startCoundDownShutdown = true; // シャットダウンタイマースタート予約(発動はcheckAXPPress()のなかで) } -#ifdef ENABLE_OTA if (data[0] == 99 && data[1] == 254) // 99,254に深い意味はない。uint8_tは0〜255の数値 { - startOTA = true; + startWebOTA = true; } -#endif } void countDownShutdown() { @@ -1257,7 +1265,7 @@ Disbuff.setTextColor(TFT_BLACK); Disbuff.setTextSize(3); Disbuff.setCursor(12, 20); - Disbuff.printf("%d sec to shutdown. A/B press to cancel.", countsec); + Disbuff.printf("%d sec to shutdown. press A to cancel.", countsec); Disbuff.pushSprite(0, 0); M5.update(); @@ -1278,6 +1286,38 @@ M5.Beep.mute(); Disbuff.setTextColor(TFT_WHITE); } +void countDownWebOTA() +{ + int countsec = 10; + int subcount = 10; + while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) + { + Disbuff.fillRect(0, 0, 240, 135, TFT_PURPLE); + Disbuff.setTextColor(TFT_WHITE); + Disbuff.setTextSize(3); + Disbuff.setCursor(12, 20); + Disbuff.printf("%d sec to\n WebOTA.\n press A to cancel.", countsec); + + Disbuff.pushSprite(0, 0); + M5.update(); + delay(100); + subcount--; // subcountが10から0になると、約1秒 + if (subcount < 0) + { + countsec--; // カウントダウン秒数を減らす + subcount = 10; + } + if (countsec < 0) + { + start_WebOTA(); + } + } + startWebOTA = false; + delay(50); + M5.Beep.mute(); + Disbuff.setTextColor(TFT_WHITE); +} + void onESPNOWSent(const uint8_t *mac_addr, esp_now_send_status_t status) { char macStr[18]; @@ -1291,20 +1331,68 @@ void ESP_NOW_SendShutdown() // Bボタンを押したら、ESPNOWで周辺デバイスの電源OFF { - while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) + while ((!M5.BtnA.isPressed()) /*&& (!M5.BtnB.isPressed())*/) { - Disbuff.fillRect(0, 0, 240, 135, TFT_BLUE); - Disbuff.setTextColor(TFT_YELLOW); - Disbuff.setTextSize(3); - Disbuff.setCursor(12, 20); - Disbuff.printf("Press the B button to turn off nearby devices"); + if (TestMode) + { + Disbuff.fillRect(0, 0, 240, 135, TFT_PURPLE); + Disbuff.setTextColor(TFT_YELLOW); + Disbuff.setTextSize(3); + Disbuff.setCursor(12, 20); + Disbuff.printf("Press the B button to WebOTA nearby devices"); + } + else + { + Disbuff.fillRect(0, 0, 240, 135, TFT_BLUE); + Disbuff.setTextColor(TFT_YELLOW); + Disbuff.setTextSize(3); + Disbuff.setCursor(12, 20); + Disbuff.printf("Press the B button to turn off nearby devices"); + } Disbuff.pushSprite(0, 0); checkAXPPress(); M5.update(); - if (M5.BtnB.isPressed()) + if (M5.BtnB.wasReleasefor(3000)) { + Disbuff.fillRect(0, 0, 240, 135, TFT_ORANGE); + Disbuff.setCursor(12, 20); + Disbuff.setTextColor(TFT_BLACK); + Disbuff.printf("WebOTA\n start!!"); + Disbuff.pushSprite(0, 0); + for (int i = 4000; i > 1000; i -= 100) + { + M5.Beep.tone(i); + delay(30); + } + M5.Beep.mute(); + M5.update(); + start_WebOTA(); // WebOTA.ino + } + if (M5.BtnB.wasReleasefor(100)) + { + if (TestMode) + { + Disbuff.fillRect(0, 0, 240, 135, TFT_RED); + } + else + { + Disbuff.fillRect(0, 0, 240, 135, TFT_GREENYELLOW); + } + Disbuff.setCursor(12, 20); + Disbuff.setTextColor(TFT_BLACK); + Disbuff.printf("Send\n Shutdown\n Signal!!"); + Disbuff.pushSprite(0, 0); + for (int i = 2000; i < 4000; i += 100) + { + M5.Beep.tone(i); + delay(30); + } + M5.Beep.mute(); + uint8_t data[2] = {100, 254}; // 送信データ  100, 254に深い意味はない。uint8_tは0〜255の数値 + if (TestMode) + data[0] = 99; // TestModeのときは、RemoteからWebOTA信号をおくる esp_err_t result = esp_now_send(peerInfo.peer_addr, data, sizeof(data)); Serial.print("Send Status: "); if (result == ESP_OK) @@ -1335,12 +1423,13 @@ { Serial.println("Not sure what happened"); } + delay(500); } if (M5.BtnA.isPressed()) break; delay(100); } - while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed())) + while ((M5.BtnA.isPressed()) /*|| (M5.BtnB.isPressed())*/) { M5.update(); checkAXPPress(); @@ -1539,7 +1628,9 @@ M5.Imu.Init(); // 加速度・角速度(ジャイロ)初期化 InitI2SMicroPhone(); // マイク初期化 - InitIRTx(); // 赤外線通信 初期化 +#ifdef ENABLE_IRSEND + InitIRTx(); // 赤外線通信 初期化 +#endif #ifdef ENABLE_BLE InitBLEServer(); // Bluetooth Low Energyサーバ初期化 #endif @@ -1568,7 +1659,7 @@ void loop() { // それぞれのテスト中は、関数のなかのループがまわる - // AorBボタンを押したら、現在実行中の関数のループを抜け、次の関数を実行する + // A(orB)ボタンを押したら、現在実行中の関数のループを抜け、次の関数を実行する MPU6886Test(); // 加速度・ジャイロ DisplayRTC(); // リアルタイムクロック DisplayMicro(); // マイク @@ -1576,16 +1667,12 @@ DisIRSend(); // 赤外線通信 #endif - if (TestMode) - { - DisplayTestMode(); // バッテリー電圧 - } + // DisplayTestMode(); // バッテリー電圧 #ifdef ENABLE_BLE DisPlayBLESend(); -#else - ESP_NOW_SendShutdown(); // シャットダウン信号の送信 #endif + ESP_NOW_SendShutdown(); // シャットダウン信号の送信 M5.update(); delay(50); diff --git a/WebOTA.ino b/WebOTA.ino new file mode 100644 index 0000000..285f733 --- /dev/null +++ b/WebOTA.ino @@ -0,0 +1,171 @@ +// FactoryTestをWebからダウンロードして書き込む +// 参考:https://lang-ship.com/blog/work/m5stickc-web-update-ota/ + +#include +#include +#include + +const char *ssid0 = "ics-ap"; // 802.11b/g (2.4GHz)only. 5GHz is not supported. +const char *password0 = "jikkenics"; + +WiFiClient client; +void execOTA(String host, int port, String bin); +void lcdprintln(String mes, uint16_t color, int y) +{ + if (y == 0) + M5.Lcd.fillScreen(color); + if (y < 999) + M5.Lcd.setCursor(0, y, 4); + M5.Lcd.setTextColor(BLACK, color); + M5.Lcd.println(mes); +} +void start_WebOTA() +{ + // M5.begin(); + // M5.Lcd.setRotation(3); + lcdprintln(" -- WebOTA --\n\n wifi connecting...", ORANGE, 0); + + WiFi.begin(ssid0, password0); // 接続開始 + while (WiFi.status() != WL_CONNECTED) + { // 接続中... + M5.Beep.tone(2000); + delay(200); + M5.Beep.mute(); + delay(1000); + M5.Lcd.print("."); + } + // 接続完了!! + M5.Beep.tone(4000); + lcdprintln(" Wifi Connected!\n ", GREEN, 0); + String gotip = WiFi.localIP().toString(); // m5デバイスのIPアドレス + M5.Lcd.println(gotip); + delay(1500); + M5.Beep.mute(); + + String host = "cit.istlab.info"; + int port = 80; + String bin = "/f/M5StickCPlus_FactoryTest2022.ino.bin"; + execOTA(host, port, bin); +} + +// Utility to extract header value from headers +String getHeaderValue(String header, String headerName) +{ + return header.substring(strlen(headerName.c_str())); +} +// OTA Logic +void execOTA(String host, int port, String bin) +{ + // Connection Succeed + Serial.println(""); + Serial.println("Connected to Wi-Fi"); + long contentLength = 0; + bool isValidContentType = false; + lcdprintln(" Downloading...", YELLOW, 0); + if (client.connect(host.c_str(), port)) + { + Serial.println("Fetching Bin: " + String(bin)); + client.print(String("GET ") + bin + " HTTP/1.1\r\n" + + "Host: " + host + "\r\n" + + "Cache-Control: no-cache\r\n" + + "Connection: close\r\n\r\n"); + unsigned long timeout = millis(); + while (client.available() == 0) + { + if (millis() - timeout > 5000) + { + Serial.println("Client Timeout !"); + client.stop(); + return; + } + } + while (client.available()) + { + String line = client.readStringUntil('\n'); + line.trim(); + if (!line.length()) + { + break; + } + if (line.startsWith("HTTP/1.1")) + { + if (line.indexOf("200") < 0) + { + Serial.println("Got a non 200 status code from server. Exiting OTA Update."); + break; + } + } + if (line.startsWith("Content-Length: ")) + { + contentLength = atol((getHeaderValue(line, "Content-Length: ")).c_str()); + Serial.println("Got " + String(contentLength) + " bytes from server"); + } + if (line.startsWith("Content-Type: ")) + { + String contentType = getHeaderValue(line, "Content-Type: "); + Serial.println("Got " + contentType + " payload."); + if (contentType == "application/octet-stream") + { + isValidContentType = true; + } + } + } + } + else + { + Serial.println("Connection to " + String(host) + " failed. Please check your setup"); + } + Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType)); + if (contentLength && isValidContentType) + { + bool canBegin = Update.begin(contentLength); + if (canBegin) + { + lcdprintln(" Downloaded.\n Upgrading...(wait 2-3 min.)", GREENYELLOW, 999); + Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!"); + size_t written = Update.writeStream(client); + if (written == contentLength) + { + Serial.println("Written : " + String(written) + " successfully"); + } + else + { + Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?"); + } + if (Update.end()) + { + M5.Beep.tone(4000); + lcdprintln("\n\n OTA Done. \n shutdown now", GREENYELLOW, 0); + + delay(2000); + M5.Beep.mute(); + + Serial.println("OTA done!"); + if (Update.isFinished()) + { + Serial.println("Update successfully completed. Rebooting."); + // ESP.restart(); + M5.Axp.Write1Byte(0x32, M5.Axp.Read8bit(0x32) | 0x80); // 電源OFF + } + else + { + Serial.println("Update not finished? Something went wrong!"); + } + } + else + { + Serial.println("Error Occurred. Error #: " + String(Update.getError())); + } + } + else + { + Serial.println("Not enough space to begin OTA"); + client.flush(); + } + } + else + { + Serial.println("There was no content in the response"); + client.flush(); + } +} \ No newline at end of file