#include <M5Unified.h> #include "fft.h" // #include "esp_pm.h" #include <esp_now.h> #include <WiFi.h> // #include <rom/crc.h> // #include <driver/i2s.h> // #include <driver/rmt.h> #define ENABLE_I2S 1 // #define ENABLE_BLE 1 #ifdef ENABLE_BLE #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> #endif // #define ENABLE_OTA 1 #ifdef ENABLE_OTA #include <ArduinoOTA.h> #endif #include "Battery.h" typedef struct { double x; double y; double z; } point_3d_t; typedef struct { point_3d_t start_point; point_3d_t end_point; } line_3d_t; typedef struct { double x; double y; } point_2d_t; double r_rand = PI / 180; double r_alpha = 19.47 * PI / 180; double r_gamma = 20.7 * PI / 180; double sin_alpha = sin(19.47 * PI / 180); double cos_alpha = cos(19.47 * PI / 180); double sin_gamma = sin(20.7 * PI / 180); double cos_gamma = cos(20.7 * PI / 180); extern const unsigned char ImageData[768]; extern const unsigned char error_48[4608]; extern const unsigned char icon_ir[4608]; extern const unsigned char icon_wifi[4608]; #ifdef ENABLE_BLE extern const unsigned char icon_ble[4608]; extern const unsigned char icon_ble_disconnect[4608]; #else extern const unsigned char icon_ble[1]; extern const unsigned char icon_ble_disconnect[1]; #endif 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(); LGFX_Sprite Disbuff(&M5.Display); // 画面ちらつき防止スプライト(画面のバッファリング) hw_timer_t *timer = NULL; volatile SemaphoreHandle_t timerSemaphore; portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; volatile uint8_t TimerCount = 0; Battery battery = Battery(); void IRAM_ATTR onTimer() // タイマー処理(LEDをチカチカさせている) { portENTER_CRITICAL_ISR(&timerMux); digitalWrite(19, TimerCount % 100); // LEDの明るさ TimerCount++; portEXIT_CRITICAL_ISR(&timerMux); } void checkAXPPress() // 電源ボタン押下チェック { if (M5.BtnPWR.wasPressed()) // 電源ボタン押下したら { powerOffOrDeepSleep(); // do // { // M5.delay(20); // } while (M5.BtnPWR.wasPressed()); // ESP.restart(); } if (startCoundDownShutdown) countDownShutdown(); if (startWebOTA) countDownWebOTA(); #ifdef ENABLE_OTA if (startOTA) { startOTA = false; OTA_Setup(); startOTAhandle = true; } if (startOTAhandle) ArduinoOTA.handle(); #endif } void powerOffOrDeepSleep() { // M5.Power.isCharging() if (true) { Disbuff.fillRect(0, 0, 240, 135, TFT_RED); Disbuff.setCursor(12, 20, 4); Disbuff.setTextColor(TFT_WHITE); Disbuff.printf("Enter Deep Sleep"); Disbuff.pushSprite(0, 0); M5.delay(3000); esp_sleep_enable_timer_wakeup(7 * 86400 * 1000000ULL); // 1週間後に復帰 esp_deep_sleep_start(); } else { Disbuff.fillRect(0, 0, 240, 135, TFT_GREEN); Disbuff.setCursor(12, 20); Disbuff.setTextColor(TFT_BLACK); Disbuff.printf("Power Off"); Disbuff.pushSprite(0, 0); M5.delay(3000); M5.Power.powerOff(); // 電源OFF } } void Displaybuff() // Disbuffスプライトを表示する。(テストモードだったらTest Modeと表示する) { Disbuff.setTextSize(1); Disbuff.setTextColor(TFT_GREENYELLOW); Disbuff.drawString("FactoryTest 2025", 10, 2, 1); Disbuff.setTextColor(TFT_WHITE); battery.batteryUpdate(); // battery.showBattery(); Disbuff.pushSprite(0, 0); } void mytone_switch(int freq, int duration) { M5.Speaker.tone(freq, duration); // tone(GPIO_NUM_2, freq, duration); // M5.Display.setBrightness(255); } void ErrorDialog(uint8_t code, const char *str) // エラー表示(主にバッテリー切れ警告) { Disbuff.fillRect(28, 20, 184, 95, Disbuff.color565(45, 45, 45)); Disbuff.fillRect(30, 22, 180, 91, TFT_BLACK); // Disbuff.drawRect(30,22,180,91,Disbuff.color565(45,45,45)); // Disbuff.setSwapBytes(true); Disbuff.pushImage(40, 43, 48, 48, (uint16_t *)error_48); Disbuff.setCursor(145, 37); Disbuff.setTextFont(2); Disbuff.printf("%02X", code); Disbuff.drawString("ERROR", 55 + 45, 10 + 27, 2); Disbuff.drawString("-----------------", 55 + 45, 30 + 27, 1); Disbuff.drawString(str, 55 + 45, 45 + 27, 1); Disbuff.drawString("check Hardware ", 55 + 45, 60 + 27, 1); Disbuff.pushSprite(0, 0); while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) { M5.update(); checkAXPPress(); M5.delay(100); } while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed())) { M5.update(); checkAXPPress(); mytone_switch(1000, 200); } Disbuff.setTextColor(TFT_WHITE); Disbuff.setTextFont(1); } bool point3Dto2D(point_3d_t *source, point_2d_t *point) { point->x = (source->x * cos_gamma) - (source->y * sin_gamma); point->y = -(source->x * sin_gamma * sin_alpha) - (source->y * cos_gamma * sin_alpha) + (source->z * cos_alpha); return true; } bool point2DToDisPoint(point_2d_t *point, uint8_t *x, uint8_t *y) { *x = point->x + 120; *y = 67 - point->y; return true; } bool printLine3D(LGFX_Sprite *display, line_3d_t *line, uint16_t color) { uint8_t start_x, start_y, end_x, end_y; point_2d_t point; point3Dto2D(&line->start_point, &point); point2DToDisPoint(&point, &start_x, &start_y); point3Dto2D(&line->end_point, &point); point2DToDisPoint(&point, &end_x, &end_y); display->drawLine(start_x, start_y, end_x, end_y, color); return true; } void RotatePoint(point_3d_t *point, double x, double y, double z) { if (x != 0) { point->y = point->y * cos(x * r_rand) - point->z * sin(x * r_rand); point->z = point->y * sin(x * r_rand) + point->z * cos(x * r_rand); } if (y != 0) { point->x = point->z * sin(y * r_rand) + point->x * cos(y * r_rand); point->z = point->z * cos(y * r_rand) - point->x * sin(y * r_rand); } if (z != 0) { point->x = point->x * cos(z * r_rand) - point->y * sin(z * r_rand); point->y = point->x * sin(z * r_rand) + point->y * cos(z * r_rand); } } void RotatePoint(point_3d_t *point, point_3d_t *point_new, double x, double y, double z) { if (x != 0) { point_new->y = point->y * cos(x * r_rand) - point->z * sin(x * r_rand); point_new->z = point->y * sin(x * r_rand) + point->z * cos(x * r_rand); } if (y != 0) { point_new->x = point->z * sin(y * r_rand) + point->x * cos(y * r_rand); point_new->z = point->z * cos(y * r_rand) - point->x * sin(y * r_rand); } if (z != 0) { point_new->x = point->x * cos(z * r_rand) - point->y * sin(z * r_rand); point_new->y = point->x * sin(z * r_rand) + point->y * cos(z * r_rand); } } line_3d_t rect[12] = { {.start_point = {-1, -1, 1}, .end_point = {1, -1, 1}}, {.start_point = {1, -1, 1}, .end_point = {1, 1, 1}}, {.start_point = {1, 1, 1}, .end_point = {-1, 1, 1}}, {.start_point = {-1, 1, 1}, .end_point = {-1, -1, 1}}, { .start_point = {-1, -1, 1}, .end_point = {-1, -1, -1}, }, { .start_point = {1, -1, 1}, .end_point = {1, -1, -1}, }, { .start_point = {1, 1, 1}, .end_point = {1, 1, -1}, }, { .start_point = {-1, 1, 1}, .end_point = {-1, 1, -1}, }, {.start_point = {-1, -1, -1}, .end_point = {1, -1, -1}}, {.start_point = {1, -1, -1}, .end_point = {1, 1, -1}}, {.start_point = {1, 1, -1}, .end_point = {-1, 1, -1}}, {.start_point = {-1, 1, -1}, .end_point = {-1, -1, -1}}, }; void MPU6886Test() // 加速度テスト { float accX = 0; float accY = 0; float accZ = 0; double theta = 0, last_theta = 0; double phi = 0, last_phi = 0; double alpha = 0.2; line_3d_t x = { .start_point = {0, 0, 0}, .end_point = {0, 0, 0}}; line_3d_t y = { .start_point = {0, 0, 0}, .end_point = {0, 0, 0}}; line_3d_t z = { .start_point = {0, 0, 0}, .end_point = {0, 0, 30}}; line_3d_t rect_source[12]; line_3d_t rect_dis; for (int n = 0; n < 12; n++) { rect_source[n].start_point.x = rect[n].start_point.x * 30; rect_source[n].start_point.y = rect[n].start_point.y * 30; rect_source[n].start_point.z = rect[n].start_point.z * 30; rect_source[n].end_point.x = rect[n].end_point.x * 30; rect_source[n].end_point.y = rect[n].end_point.y * 30; rect_source[n].end_point.z = rect[n].end_point.z * 30; } while ((!M5.BtnA.isPressed()) /*&& (!M5.BtnB.isPressed())*/) { auto imu_update = M5.Imu.update(); if (imu_update) { m5::IMU_Class::imu_data_t d = M5.Imu.getImuData(); // M5.Imu.getAccelData(&accX, &accY, &accZ); // M5.MPU6886.getAccelData(&accX, &accY, &accZ); accX = d.accel.x; accY = d.accel.y; accZ = d.accel.z; } if ((accX < 1) && (accX > -1)) { theta = asin(-accX) * 57.295; } if (accZ != 0) { phi = atan(accY / accZ) * 57.295; } theta = alpha * theta + (1 - alpha) * last_theta; phi = alpha * phi + (1 - alpha) * last_phi; Disbuff.fillRect(0, 0, 240, 135, TFT_BLACK); Disbuff.setTextSize(1); Disbuff.setTextColor(TFT_WHITE); Disbuff.setCursor(10, 115); Disbuff.printf("%.2f", theta); Disbuff.setCursor(10, 125); Disbuff.printf("%.2f", phi); // Displaybuff(); M5.delay(20); z.end_point.x = 0; z.end_point.y = 0; z.end_point.z = 60; RotatePoint(&z.end_point, theta, phi, 0); RotatePoint(&z.end_point, &x.end_point, -90, 0, 0); RotatePoint(&z.end_point, &y.end_point, 0, 90, 0); for (int n = 0; n < 12; n++) { RotatePoint(&rect_source[n].start_point, &rect_dis.start_point, theta, phi, (double)0); RotatePoint(&rect_source[n].end_point, &rect_dis.end_point, theta, phi, (double)0); printLine3D(&Disbuff, &rect_dis, TFT_WHITE); } // Disbuff.fillRect(0,0,160,80,BLACK); printLine3D(&Disbuff, &x, TFT_RED); printLine3D(&Disbuff, &y, TFT_GREEN); printLine3D(&Disbuff, &z, TFT_BLUE); /* Disbuff.setTextColor(TFT_WHITE); Disbuff.setTextSize(1); Disbuff.fillRect(0,0,52,18,Disbuff.color565(20,20,20)); Disbuff.drawString("MPU6886",5,5,1); */ Displaybuff(); last_theta = theta; last_phi = phi; M5.update(); checkAXPPress(); } while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed())) { M5.update(); checkAXPPress(); mytone_switch(1000, 200); } Disbuff.setTextColor(TFT_WHITE); } SemaphoreHandle_t xSemaphore = NULL; SemaphoreHandle_t start_dis = NULL; SemaphoreHandle_t start_fft = NULL; int8_t i2s_readraw_buff[2048]; uint8_t fft_dis_buff[241][128] = {0}; uint16_t posData = 160; char fftmes[30]; int fftmax, fftmaxidx; void MicRecordfft(void *arg) // フーリエ変換 { #ifdef ENABLE_I2S // int16_t *buffptr; // size_t bytesread; // uint16_t count_n = 0; // float adc_data; // double data = 0; // uint16_t ydata; // uint16_t count_offset = 1; // while (1) // { // xSemaphoreTake(start_fft, portMAX_DELAY); // xSemaphoreGive(start_fft); // fft_config_t *real_fft_plan = fft_init(1024, FFT_REAL, FFT_FORWARD, NULL, NULL); // i2s_read(I2S_NUM_0, (char *)i2s_readraw_buff, 2048, &bytesread, (100 / portTICK_RATE_MS)); // portTICK_RATE_MS は 1 // buffptr = (int16_t *)i2s_readraw_buff; // // fftmax, fftmaxidx = real_fft_plan->size; // for (count_n = 0; count_n < real_fft_plan->size; count_n++) // eal_fft_plan->sizeは1024 // { // adc_data = (float)map(buffptr[count_n], INT16_MIN, INT16_MAX, -2000, 2000); // long map(long x, long in_min, long in_max, long out_min, long out_max) // real_fft_plan->input[count_n] = adc_data; // } // fft_execute(real_fft_plan); // xSemaphoreTake(xSemaphore, 100 / portTICK_RATE_MS); // for (count_n = 1; count_n < real_fft_plan->size / 4; count_n++) // 1024/4=>256 // { // data = sqrt(real_fft_plan->output[2 * count_n] * real_fft_plan->output[2 * count_n] + real_fft_plan->output[2 * count_n + 1] * real_fft_plan->output[2 * count_n + 1]); // if ((count_n - 1) < 254) // { // data = (data > 3000) ? 3000 : data; // ydata = map(data, 0, 3000, 0, 255); // if (128 - count_n > 0) // fft_dis_buff[posData][128 - count_n] = ydata; // if (ydata > 40 && fftmax < ydata) // { // fftmax = ydata; // fftmaxidx = count_n; // } // } // } // posData++; // if (posData >= 241) // { // posData = 0; // } // xSemaphoreGive(xSemaphore); // fft_destroy(real_fft_plan); // } #endif } void Drawdisplay(void *arg) // フーリエ変換のときの画面表示 { uint16_t count_x = 0, count_y = 0; uint16_t colorPos; while (1) { xSemaphoreTake(start_dis, portMAX_DELAY); xSemaphoreGive(start_dis); xSemaphoreTake(xSemaphore, 500 / portTICK_RATE_MS); for (count_y = 0; count_y < 128; count_y++) { for (count_x = 0; count_x < 240; count_x++) { if ((count_x + (posData % 240)) > 240) { colorPos = fft_dis_buff[count_x + (posData % 240) - 240][count_y]; } else { colorPos = fft_dis_buff[count_x + (posData % 240)][count_y]; } Disbuff.drawPixel(count_x, count_y, Disbuff.color565(ImageData[colorPos * 3 + 0], ImageData[colorPos * 3 + 1], ImageData[colorPos * 3 + 2])); /* disbuff[ count_y * 160 + count_x ].r = ImageData[ colorPos * 3 + 0 ]; disbuff[ count_y * 160 + count_x ].g = ImageData[ colorPos * 3 + 1 ]; disbuff[ count_y * 160 + count_x ].b = ImageData[ colorPos * 3 + 2 ]; */ } } xSemaphoreGive(xSemaphore); Disbuff.setTextColor(WHITE); Disbuff.setTextSize(1); Disbuff.fillRect(0, 0, 235, 20, Disbuff.color565(20, 20, 20)); if (fftmaxidx > 200) { Disbuff.fillRect(0, 0, 235, 20, Disbuff.color565(fftmax, 20, 20)); } sprintf(fftmes, "max %3d idx %3d %5.0f Hz", fftmax, fftmaxidx, fftmaxidx * 41.67); Disbuff.drawString(fftmes, 5, 5, 2); fftmax = 0; fftmaxidx = 0; Disbuff.pushSprite(0, 0); } } TaskHandle_t xhandle_display = NULL; TaskHandle_t xhandle_fft = NULL; static constexpr const size_t record_number = 256; static constexpr const size_t record_length = 200; static constexpr const size_t record_size = record_number * record_length; static constexpr const size_t record_samplerate = 16000; static int16_t prev_y[record_length]; static int16_t prev_h[record_length]; static size_t rec_record_idx = 2; static size_t draw_record_idx = 0; static int16_t *rec_data; void DisplayMicro() { Disbuff.fillRect(0, 0, 160, 80, Disbuff.color565(0, 0, 0)); // 黒(R=0,G=0,B=0)で塗りつぶす Disbuff.pushSprite(0, 0); #ifdef ENABLE_I2S prepareMic(); #endif // xSemaphoreGive(start_dis); // 画面表示タスク スタート // xSemaphoreGive(start_fft); // フーリエ変換タスク スタート M5.Display.setFont(&fonts::lgfxJapanGothic_16); M5.Display.startWrite(); M5.Display.clear(); M5.Display.setTextColor( WHITE, TFT_BLACK ); rec_data = (typeof(rec_data))heap_caps_malloc(record_size * sizeof(int16_t), MALLOC_CAP_8BIT); memset(rec_data, 0, record_size * sizeof(int16_t)); M5.Speaker.setVolume(132); // 0-255だが、あまり大きいと音が割れる while ((!M5.BtnA.isPressed())) // ABボタン押していない間、くりかえす { M5.update(); if (M5.Mic.isEnabled()) { static constexpr int shift = 6; auto data = &rec_data[rec_record_idx * record_length]; if (M5.Mic.record(data, record_length, record_samplerate)) { data = &rec_data[draw_record_idx * record_length]; int32_t w = M5.Display.width(); if (w > record_length - 1) { w = record_length - 1; } for (int32_t x = 0; x < w; ++x) { M5.Display.writeFastVLine(x, prev_y[x], prev_h[x], TFT_BLACK); // 以前の線を消す int32_t y1 = (data[x] >> shift); int32_t y2 = (data[x + 1] >> shift); if (y1 > y2) { int32_t tmp = y1; y1 = y2; y2 = tmp; } int32_t y = (M5.Display.height() >> 1) + y1; int32_t h = (M5.Display.height() >> 1) + y2 + 1 - y; prev_y[x] = y; prev_h[x] = h; M5.Display.writeFastVLine(x, y, h, TFT_WHITE); } M5.Display.setCursor(0, 0); M5.Display.print("●マイク録音モード:\nBボタンで最新の3秒間を再生"); M5.Display.display(); if (++draw_record_idx >= record_number) { draw_record_idx = 0; } if (++rec_record_idx >= record_number) { rec_record_idx = 0; } } } // if (M5.BtnA.wasHold() || M5.BtnB.wasClicked()) // { // auto cfg = M5.Mic.config(); // cfg.noise_filter_level = (cfg.noise_filter_level + 8) & 255; // M5.Mic.config(cfg); // M5.Display.setCursor(32,0); // M5.Display.printf("nf:%03d", cfg.noise_filter_level); // } // else { if (M5.BtnB.wasPressed()) { if (M5.Speaker.isEnabled()) { M5.Display.clear(); while (M5.Mic.isRecording()) { M5.delay(1); } /// Since the microphone and speaker cannot be used at the same time, turn off the microphone here. M5.Mic.end(); M5.delay(20); M5.Speaker.begin(); // M5.Display.setCursor(0,0); // M5.Display.print("再生中"); int start_pos = rec_record_idx * record_length; if (start_pos < record_size) { M5.Speaker.playRaw(&rec_data[start_pos], record_size - start_pos, record_samplerate, false, 1, 0); } if (start_pos > 0) { M5.Speaker.playRaw(rec_data, start_pos, record_samplerate, false, 1, 0); } Serial.println("Playing..."); for (int sec = 3; sec > 0; sec--) { M5.Display.setCursor(0, 0); M5.Display.printf("再生モード:\n 再生中 %d", sec); M5.delay(1000); } // ここを実行しているあいだに、playRawの内容が再生されている。 do { M5.delay(10); M5.update(); // Serial.println("waiting end of play"); } while (M5.Speaker.isPlaying()); // まだ再生中だったら待つ // Reset I2S and reinitialize microphone prepareMic(); M5.Display.clear(); // M5.Display.setCursor(0,0); // M5.Display.print("録音モード"); // } } } checkAXPPress(); } while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed())) // ABボタン押している間、くりかえす { M5.update(); checkAXPPress(); M5.Display.endWrite(); M5.Speaker.setVolume(45); mytone_switch(1000, 200); } } #define PIN_CLK 0 #define PIN_DATA 34 #ifdef ENABLE_I2S void prepareMic() { // This function will reset the I2S peripheral to clear any existing issues with channel allocation. M5.Speaker.end(); delay(10); // Add a small delay to allow hardware reset M5.Mic.begin(); // Reinitialize the microphone auto cfg = M5.Mic.config(); cfg.noise_filter_level = 128; M5.Mic.config(cfg); // Serial.println("resetI2S_end"); } #endif void DisplayRTC() // リアルタイムクロック(内蔵時計) { Disbuff.fillRect(0, 0, 240, 135, Disbuff.color565(0, 0, 0)); // Displaybuff(); m5::rtc_time_t time; M5.Rtc.getTime(&time); while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) { Disbuff.fillRect(0, 0, 240, 135, Disbuff.color565(0, 0, 0)); M5.Rtc.getTime(&time); Disbuff.setTextSize(4); Disbuff.setTextColor(TFT_GREENYELLOW); Disbuff.setCursor(25, 50); Disbuff.printf("%02d:%02d:%02d", time.hours, time.minutes, time.seconds); Disbuff.fillRect(0, 0, 240, 37, Disbuff.color565(20, 20, 20)); Disbuff.setTextSize(2); Disbuff.setTextColor(TFT_WHITE); Disbuff.drawString("BM8563 RTC Time", 26, 19, 1); Disbuff.setTextSize(2); Disbuff.setCursor(6, 90); Disbuff.setTextColor(TFT_YELLOW); Disbuff.println("Press B to sync RTC from NTP"); Displaybuff(); M5.update(); checkAXPPress(); M5.delay(100); } if (M5.BtnB.isPressed()) { // RTC sync from NTP // Wifi → NTP → update RTC → WifiOff if (wifi_setup()) ntp_setup(); wifi_down(); Init_ESPNOW(); // ESPNOWの初期化 M5.update(); DisplayRTC(); // あまりよろしくないが、やっぱり時刻同期を確認したいので } while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed())) { M5.update(); checkAXPPress(); mytone_switch(1000, 200); } 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 #define RMT_CLK_DIV (1) // 80000000 / 1(HZ) rmt_item32_t *tx_buffer = NULL; void ir_tx_callback(rmt_channel_t channel, void *arg) { // static BaseType_t xHigherPriorityTaskWoken = false; if (channel == RMT_TX_CHANNEL) { esp_pm_lock_release(rmt_freq_lock); // xHigherPriorityTaskWoken = pdFALSE; // xSemaphoreGiveFromISR( irTxSem, &xHigherPriorityTaskWoken ); free(tx_buffer); } } bool InitIRTx() // 赤外線通信 初期化 { rmt_config_t rmt_tx; rmt_tx.rmt_mode = RMT_MODE_TX; rmt_tx.channel = RMT_TX_CHANNEL; rmt_tx.gpio_num = RMT_TX_GPIO_NUM; rmt_tx.mem_block_num = 1; rmt_tx.clk_div = RMT_CLK_DIV; rmt_tx.tx_config.loop_en = false; rmt_tx.tx_config.carrier_duty_percent = 50; rmt_tx.tx_config.carrier_freq_hz = 38000; rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; rmt_tx.tx_config.carrier_en = true; rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH; rmt_tx.tx_config.idle_output_en = true; rmt_config(&rmt_tx); rmt_driver_install(rmt_tx.channel, 0, 0); return true; } bool ir_uart_tx(const uint8_t *src, uint8_t len, bool wait_tx_done) { /* if(src == NULL || recvFlag == true) { return false; } */ if (src == NULL) { return false; } #if BAUD == 4800 const rmt_item32_t bit0 = {{{8421, 1, 8421, 1}}}; // Logical 0 const rmt_item32_t bit1 = {{{8421, 0, 8421, 0}}}; // Logical 1 #else const rmt_item32_t bit0 = {{{16842, 1, 16842, 1}}}; // Logical 0 const rmt_item32_t bit1 = {{{16842, 0, 16842, 0}}}; // Logical 1 #endif uint8_t *psrc = (uint8_t *)src; // xSemaphoreTake(irTxSem, portMAX_DELAY); tx_buffer = (rmt_item32_t *)malloc(sizeof(rmt_item32_t) * 10 * len); if (tx_buffer == NULL) { return false; } rmt_item32_t *pdest = tx_buffer; for (uint8_t ptr = 0; ptr < len; ptr++) { pdest->val = bit0.val; pdest++; for (int i = 0; i < 8; i++) { if (*psrc & (0x1 << i)) { pdest->val = bit1.val; } else { pdest->val = bit0.val; } pdest++; } pdest->val = bit1.val; pdest++; psrc++; } esp_pm_lock_acquire(rmt_freq_lock); rmt_write_items(RMT_TX_CHANNEL, tx_buffer, 10 * len, true); free(tx_buffer); return true; } #endif #ifdef ENABLE_BLE #define SERVICE_UUID "1bc68b2a-f3e3-11e9-81b4-2a2ae2dbcce4" #define CHARACTERISTIC_RX_UUID "1bc68da0-f3e3-11e9-81b4-2a2ae2dbcce4" #define CHARACTERISTIC_TX_UUID "1bc68efe-f3e3-11e9-81b4-2a2ae2dbcce4" BLEServer *pServer = NULL; BLEService *pService = NULL; BLECharacteristic *pTxCharacteristic; bool deviceConnected = false; bool oldDeviceConnected = false; class MyServerCallbacks : public BLEServerCallbacks { void onConnect(BLEServer *pServer) { deviceConnected = true; }; void onDisconnect(BLEServer *pServer) { deviceConnected = false; } }; uint8_t *data = new uint8_t[128]; class MyCallbacks : public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { data = pCharacteristic->getData(); } }; bool InitBLEServer() // Bluetooth Low Energyサーバ初期化 { uint64_t chipid = ESP.getEfuseMac(); String blename = "M5-" + String((uint32_t)(chipid >> 32), HEX); BLEDevice::init(blename.c_str()); // BLEDevice::setPower(ESP_PWR_LVL_N12); pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); pService = pServer->createService(SERVICE_UUID); pTxCharacteristic = pService->createCharacteristic( CHARACTERISTIC_RX_UUID, BLECharacteristic::PROPERTY_NOTIFY); pTxCharacteristic->addDescriptor(new BLE2902()); BLECharacteristic *pRxCharacteristic = pService->createCharacteristic( CHARACTERISTIC_TX_UUID, BLECharacteristic::PROPERTY_WRITE); pRxCharacteristic->setCallbacks(new MyCallbacks()); return true; } #endif bool checkAXP192() // 電源・バッテリー管理モジュール { float VBat = M5.Power.getBatteryVoltage(); while (VBat < 3.2) { VBat = M5.Power.getBatteryVoltage(); ErrorDialog(0x22, "Bat Vol error"); } return true; } uint8_t crc8(uint8_t data, uint8_t *buff, uint32_t length) // 巡回冗長検査 { uint8_t bit; // bit mask uint8_t crc = 0xFF; // calculated checksum uint8_t byteCtr; // byte counter for (byteCtr = 0; byteCtr < length; byteCtr++) { crc ^= (buff[byteCtr]); for (bit = 8; bit > 0; --bit) { if (crc & 0x80) { crc = (crc << 1) ^ data; } else { crc = (crc << 1); } } } return crc; } #ifdef ENABLE_IRSEND void DisIRSend() // 赤外線通信 画面表示 { uint8_t senddata[20] = {0}; memset(senddata, 0x00, sizeof(uint8_t) * 20); while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) { Disbuff.fillRect(0, 0, 240, 135, TFT_BLACK); // Disbuff.setSwapBytes(true); Disbuff.pushImage(180, 16, 48, 48, (uint16_t *)icon_ir); Disbuff.setTextColor(Disbuff.color565(180, 180, 180)); Disbuff.setTextSize(3); Disbuff.setCursor(12, 20); Disbuff.printf("IR Send "); Disbuff.setTextSize(5); Disbuff.setCursor(12, 75); if (senddata[0] % 4 == 0) { Disbuff.printf("0x%02X> ", senddata[0]); } else if (senddata[0] % 4 == 1) { Disbuff.printf("0x%02X>>", senddata[0]); } else if (senddata[0] % 4 == 2) { Disbuff.printf("0x%02X >>", senddata[0]); } else if (senddata[0] % 4 == 3) { Disbuff.printf("0x%02X >", senddata[0]); } Displaybuff(); senddata[1]++; if (senddata[1] > 3) { senddata[1] = 0; senddata[0]++; ir_uart_tx(senddata, 20, true); } checkAXPPress(); M5.update(); M5.delay(100); } while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed())) { M5.update(); checkAXPPress(); } M5.delay(50); Disbuff.setTextColor(TFT_WHITE); } #endif #ifdef ENABLE_BLE void DisPlayBLESend() // Bluetooth Low Energy 画面表示 { uint8_t senddata[2] = {0}; pService->start(); pServer->getAdvertising()->start(); uint64_t chipid = ESP.getEfuseMac(); String blename = "M5-" + String((uint32_t)(chipid >> 32), HEX); while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) { Disbuff.fillRect(0, 0, 240, 135, TFT_BLACK); if (deviceConnected) { Disbuff.pushImage(180, 16, 48, 48, (uint16_t *)icon_ble); Disbuff.setTextColor(Disbuff.color565(180, 180, 180)); Disbuff.setTextSize(3); Disbuff.setCursor(12, 20); // Disbuff.printf("BLE connect!\n"); Disbuff.printf("BLE Send\n"); Disbuff.setTextSize(5); Disbuff.setCursor(12, 75); if (senddata[0] % 4 == 0) { Disbuff.printf("0x%02X> ", senddata[0]); } else if (senddata[0] % 4 == 1) { Disbuff.printf("0x%02X>>", senddata[0]); } else if (senddata[0] % 4 == 2) { Disbuff.printf("0x%02X >>", senddata[0]); } else if (senddata[0] % 4 == 3) { Disbuff.printf("0x%02X >", senddata[0]); } senddata[1]++; if (senddata[1] > 3) { senddata[1] = 0; senddata[0]++; pTxCharacteristic->setValue(senddata, 1); pTxCharacteristic->notify(); } } else { Disbuff.setTextSize(2); Disbuff.setCursor(12, 20); Disbuff.setTextColor(TFT_RED); Disbuff.printf("BLE disconnect\n"); Disbuff.setCursor(12, 45); Disbuff.setTextColor(Disbuff.color565(18, 150, 219)); Disbuff.printf(String("Name:" + blename + "\n").c_str()); Disbuff.setCursor(12, 70); Disbuff.printf("UUID:1bc68b2a\n"); Disbuff.pushImage(180, 16, 48, 48, (uint16_t *)icon_ble_disconnect); } Displaybuff(); M5.update(); M5.delay(100); checkAXPPress(); } while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed())) { M5.update(); checkAXPPress(); M5.delay(10); } M5.delay(50); Disbuff.setTextColor(TFT_WHITE); pService->stop(); pServer->getAdvertising()->stop(); } #endif void DisplayTestMode() // テストモード:ピンの電圧とバッテリー電圧 { float tempdata, humdata; uint8_t count_u = 0, count_t = 0; // #ifdef ENABLE_I2S // i2s_pin_config_t pin_config; // pin_config.bck_io_num = I2S_PIN_NO_CHANGE; // pin_config.ws_io_num = 33; // pin_config.data_out_num = I2S_PIN_NO_CHANGE; // pin_config.data_in_num = PIN_DATA; // i2s_set_pin(I2S_NUM_0, &pin_config); // i2s_driver_uninstall(I2S_NUM_0); // #endif gpio_reset_pin(GPIO_NUM_0); gpio_reset_pin(GPIO_NUM_26); pinMode(26, OUTPUT); pinMode(25, INPUT_PULLDOWN); pinMode(36, INPUT_PULLDOWN); pinMode(0, OUTPUT); digitalWrite(0, 0); digitalWrite(26, 0); while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) { Disbuff.fillRect(0, 0, 240, 135, TFT_BLACK); // Disbuff.setSwapBytes(true); Disbuff.setTextColor(Disbuff.color565(180, 180, 180)); Disbuff.setTextSize(3); Disbuff.setCursor(12, 7); if (M5.Power.getBatteryVoltage() > 3.2) // バッテリーの電圧(残量によって変化する) { Disbuff.setTextColor(TFT_GREEN); } else { Disbuff.setTextColor(TFT_RED); } Disbuff.printf("b%4.2f", M5.Power.getBatteryLevel()); // バッテリー電圧を表示する Disbuff.setCursor(12, 37); if (M5.Power.getBatteryLevel() > 40) { Disbuff.setTextColor(TFT_GREEN); } else { Disbuff.setTextColor(TFT_RED); } Disbuff.printf("v%4.2f", M5.Power.getBatteryLevel()); // 外部電源電圧(5V←の電圧) digitalWrite(0, 0); digitalWrite(26, 0); count_u = 0; count_t = 0; for (int i = 0; i < 10; i++) { digitalWrite(0, i % 2); M5.delay(10); // pin36_adc = analogRead(36); if ((digitalRead(36) == HIGH) && (i % 2 == 1)) { count_u++; } if ((digitalRead(25) == HIGH) && (i % 2 == 1)) { count_t++; } } Disbuff.setCursor(110, 7); if (count_u >= 5) { Disbuff.setTextColor(TFT_GREEN); Disbuff.printf(" %d G0", count_u); } else { Disbuff.setTextColor(TFT_RED); Disbuff.printf(" %d G0", count_u); } Disbuff.setTextColor(TFT_WHITE); Disbuff.setCursor(110, 37); if (count_t >= 5) { Disbuff.setTextColor(TFT_GREEN); Disbuff.printf(" %d G25", count_t); } else { Disbuff.setTextColor(TFT_RED); Disbuff.printf(" %d G25", count_t); } Disbuff.setTextColor(TFT_WHITE); digitalWrite(0, 0); digitalWrite(26, 0); count_u = 0; for (int i = 0; i < 10; i++) { digitalWrite(26, i % 2); M5.delay(10); // pin36_adc = analogRead(36); if ((digitalRead(36) == HIGH) && (i % 2 == 1)) { count_u++; } } Disbuff.setCursor(110, 67); if (count_u >= 5) { Disbuff.setTextColor(TFT_GREEN); Disbuff.printf(" %d G26", count_u); } else { Disbuff.setTextColor(TFT_RED); Disbuff.printf(" %d G26", count_u); } Disbuff.setTextColor(TFT_WHITE); digitalWrite(0, 0); digitalWrite(26, 0); // Serial.printf("G36 Vol:%d\n",analogRead(36)); // if (count >= 10) // { // count = 0; // getTempAndHum(&tempdata, &humdata); // ENV. II SENSORをつないだときに、温度と湿度がとれる // } // Disbuff.setTextColor(TFT_WHITE); // 白色で // Disbuff.setCursor(12, 67); // Disbuff.printf(" %.1f", tempdata); // 温度? // Disbuff.setCursor(12, 97); // Disbuff.printf(" %.1f", humdata); // 湿度? Disbuff.pushSprite(0, 0); checkAXPPress(); M5.update(); M5.delay(10); // count++; } while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed())) { M5.update(); checkAXPPress(); mytone_switch(1000, 200); } Disbuff.setTextColor(TFT_WHITE); } esp_now_peer_info_t peerInfo; void Init_ESPNOW() { // ESPNowの初期化 // 引用: https://101010.fun/iot/esp32-m5stickc-plus-esp-now.html WiFi.mode(WIFI_STA); WiFi.disconnect(); if (esp_now_init() == ESP_OK) { Serial.println("ESP-Now Init Success"); } else { Serial.println("ESP-Now Init failed"); ESP.restart(); } // マルチキャスト用Slave登録 memset(&peerInfo, 0, sizeof(peerInfo)); for (int i = 0; i < 6; ++i) { peerInfo.peer_addr[i] = (uint8_t)0xff; } esp_err_t addStatus = esp_now_add_peer(&peerInfo); if (addStatus == ESP_OK) { // Pair success Serial.println("Pair success"); esp_now_register_send_cb(onESPNOWSent); // 送信後のコールバック関数を指定する esp_now_register_recv_cb(onESPNOWReceive); /// 受信時のコールバック関数を指定する } } // 引用: https://101010.fun/iot/esp32-m5stickc-plus-esp-now.html void onESPNOWReceive(const esp_now_recv_info_t *recv_info, const uint8_t *data, int data_len) { // char macStr[18]; // snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", // recv_info->src_addr[0], recv_info->src_addr[1], recv_info->src_addr[2], // recv_info->src_addr[3], recv_info->src_addr[4], recv_info->src_addr[5]); if (strcmp((char *)data, "ESPNOW__SHUTDOWN") == 0) // 100,254に深い意味はない。uint8_tは0〜255の数値 { startCoundDownShutdown = true; // シャットダウンタイマースタート予約(発動はcheckAXPPress()のなかで) } if (strcmp((char *)data, "ESPNOW__WEBOTA") == 0) // 99,254に深い意味はない。uint8_tは0〜255の数値 { startWebOTA = true; } } void countDownShutdown() { int countsec = 10; int subcount = 10; while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) { Disbuff.fillRect(0, 0, 240, 135, TFT_ORANGE); Disbuff.setTextColor(TFT_BLACK); Disbuff.setTextSize(3); Disbuff.setCursor(12, 20); Disbuff.printf("%d sec to shutdown. press A to cancel.", countsec); Disbuff.pushSprite(0, 0); M5.update(); M5.delay(100); subcount--; // subcountが10から0になると、約1秒 if (subcount < 0) { countsec--; // カウントダウン秒数を減らす subcount = 10; } if (countsec < 0) { powerOffOrDeepSleep(); } } startCoundDownShutdown = false; M5.delay(50); 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(); M5.delay(100); subcount--; // subcountが10から0になると、約1秒 if (subcount < 0) { countsec--; // カウントダウン秒数を減らす subcount = 10; } if (countsec < 0) { start_WebOTA(); } } startWebOTA = false; M5.delay(50); Disbuff.setTextColor(TFT_WHITE); } void onESPNOWSent(const uint8_t *mac_addr, esp_now_send_status_t status) { char macStr[18]; snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); // Serial.print("Last Packet Sent to: "); // Serial.println(macStr); // Serial.print("Last Packet Send Status: "); // Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); } void ESP_NOW_SendShutdown() // Bボタンを押したら、ESPNOWで周辺デバイスの電源OFF { while ((!M5.BtnA.isPressed()) /*&& (!M5.BtnB.isPressed())*/) { 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.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) { tone(GPIO_NUM_2, i, 20); } M5.Display.setBrightness(255); 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) { tone(GPIO_NUM_2, i, 20); } M5.Display.setBrightness(255); uint8_t data[50]; if (TestMode) { sprintf((char *)data, "ESPNOW__WEBOTA"); // 送信する文字列 } else { sprintf((char *)data, "ESPNOW__SHUTDOWN"); } esp_err_t result = esp_now_send(peerInfo.peer_addr, data, sizeof(data)); Serial.print("Send Status: "); if (result == ESP_OK) { Serial.println("Success"); } else if (result == ESP_ERR_ESPNOW_NOT_INIT) { Serial.println("ESPNOW not Init."); } else if (result == ESP_ERR_ESPNOW_ARG) { Serial.println("Invalid Argument"); } else if (result == ESP_ERR_ESPNOW_INTERNAL) { Serial.println("Internal Error"); } else if (result == ESP_ERR_ESPNOW_NO_MEM) { Serial.println("ESP_ERR_ESPNOW_NO_MEM"); } else if (result == ESP_ERR_ESPNOW_NOT_FOUND) { Serial.println("Peer not found."); } else { Serial.println("Not sure what happened"); } M5.delay(500); } if (M5.BtnA.isPressed()) break; M5.delay(100); } while ((M5.BtnA.isPressed()) /*|| (M5.BtnB.isPressed())*/) { M5.update(); checkAXPPress(); M5.Speaker.tone(3000, 200); } M5.delay(50); Disbuff.setTextColor(TFT_WHITE); } void ColorBar() // 起動直後のカラーバー表示 { float color_r, color_g, color_b; color_r = 0; color_g = 0; color_b = 255; for (int i = 0; i < 384; i = i + 4) { if (i < 128) { color_r = i * 2; color_g = 0; color_b = 255 - (i * 2); } else if ((i >= 128) && (i < 256)) { color_r = 255 - ((i - 128) * 2); color_g = (i - 128) * 2; color_b = 0; } else if ((i >= 256) && (i < 384)) { color_r = 0; color_g = 255 - ((i - 256) * 2); ; color_b = (i - 256) * 2; ; } Disbuff.fillRect(0, 0, 240, 135, Disbuff.color565(color_r, color_g, color_b)); Displaybuff(); } for (int i = 0; i < 4; i++) { switch (i) { case 0: color_r = 0; color_g = 0; color_b = 0; break; case 1: color_r = 255; color_g = 0; color_b = 0; break; case 2: color_r = 0; color_g = 255; color_b = 0; break; case 3: color_r = 0; color_g = 0; color_b = 255; break; } for (int n = 0; n < 240; n++) { color_r = (color_r < 255) ? color_r + 1.0625 : 255U; color_g = (color_g < 255) ? color_g + 1.0625 : 255U; color_b = (color_b < 255) ? color_b + 1.0625 : 255U; Disbuff.drawLine(n, i * 33.75, n, (i + 1) * 33.75, Disbuff.color565(color_r, color_g, color_b)); } } Displaybuff(); M5.delay(500); for (int i = 0; i < 4; i++) { switch (i) { case 0: color_r = 255; color_g = 255; color_b = 255; break; case 1: color_r = 255; color_g = 0; color_b = 0; break; case 2: color_r = 0; color_g = 255; color_b = 0; break; case 3: color_r = 0; color_g = 0; color_b = 255; break; } for (int n = 0; n < 240; n++) { color_r = (color_r > 2) ? color_r - 1.0625 : 0U; color_g = (color_g > 2) ? color_g - 1.0625 : 0U; color_b = (color_b > 2) ? color_b - 1.0625 : 0U; Disbuff.drawLine(239 - n, i * 33.75, 239 - n, (i + 1) * 33.75, Disbuff.color565(color_r, color_g, color_b)); } } Displaybuff(); M5.delay(500); } uint8_t addrcheckbuff[3] = { 0x34, // 0x51, // 0x68 // }; void setup() { auto cfg = M5.config(); cfg.serial_baudrate = 115200; M5.begin(cfg); M5.Display.setRotation(3); // 画面向きは横 M5.Speaker.setVolume(45); M5.Speaker.tone(2000, 500); M5.Display.setBrightness(255); // M5.Display.setFont(&fonts::lgfxJapanGothic_16); // M5.Display.setTextScroll(true); // Disbuff.setSwapBytes(true); Disbuff.setColorDepth(16); Disbuff.createSprite(240, 135); Disbuff.fillRect(0, 0, 240, 135, Disbuff.color565(200, 50, 50)); Disbuff.pushSprite(0, 0); M5.delay(500); M5.update(); if (M5.BtnB.isPressed()) // Bボタンを押して起動したら、テストモード { M5.Speaker.tone(4000, 200); M5.delay(100); TestMode = true; while (M5.BtnB.isPressed()) { M5.update(); M5.delay(10); } } M5.Display.setBrightness(200); battery.setSprite(&Disbuff); // バッテリー残量表示 battery.setPosAndSize(160, 1, 1); battery.setCheckRate(300); // // deleteBattery()時の塗りつぶし色を設定 // battery.setDeleteBgColor(TFT_BLACK); // 電池図形と%表示の色を設定 // battery.setTextColor(TFT_WHITE); Init_ESPNOW(); // ESPNOWの初期化 if (!TestMode) ColorBar(); // ディスプレイ発色チェック checkAXP192(); // バッテリー電圧チェック。低下してたらエラーメッセージ表示 // M5.Imu.init(); // 加速度・角速度(ジャイロ)初期化 // InitI2SMicroPhone(); // マイク初期化 #ifdef ENABLE_IRSEND InitIRTx(); // 赤外線通信 初期化 #endif #ifdef ENABLE_BLE InitBLEServer(); // Bluetooth Low Energyサーバ初期化 #endif pinMode(19, OUTPUT); // LEDのポートを出力に設定 // timerSemaphore = xSemaphoreCreateBinary(); // バイナリセマフォ作成 // timer = timerBegin(0, 80, true); // タイマーID=0, 80クロックで1カウントする, カウントアップならtrue // timerAttachInterrupt(timer, &onTimer, true); // 割り込み関数onTimer()を登録 // timerAlarmWrite(timer, 30000, true); // トリガー条件。50000カウントで発動。trueは繰り返し実行(falseにすると1回のみ) // timerAlarmEnable(timer); // xSemaphore = xSemaphoreCreateMutex(); // ミューテックス排他制御 // start_dis = xSemaphoreCreateMutex(); // start_fft = xSemaphoreCreateMutex(); // xSemaphoreTake(start_dis, portMAX_DELAY); // フーリエ変換のときの画面表示タスクを「待ち」状態にする // xSemaphoreTake(start_fft, portMAX_DELAY); // FFTタスクを「待ち」状態にする // xTaskCreate(Drawdisplay, "Drawdisplay", 1024 * 2, (void *)0, 4, &xhandle_display); // xTaskCreate(MicRecordfft, "MicRecordfft", 1024 * 2, (void *)0, 5, &xhandle_fft); Disbuff.pushSprite(0, 0); } bool beepstate = false; void loop() { // それぞれのテスト中は、関数のなかのループがまわる // A(orB)ボタンを押したら、現在実行中の関数のループを抜け、次の関数を実行する MPU6886Test(); // 加速度・ジャイロ DisplayRTC(); // リアルタイムクロック DisplayMicro(); // マイク #ifdef ENABLE_IRSEND DisIRSend(); // 赤外線通信 #endif // DisplayTestMode(); // バッテリー電圧 #ifdef ENABLE_BLE DisPlayBLESend(); #endif ESP_NOW_SendShutdown(); // シャットダウン信号の送信 M5.update(); M5.delay(50); } #ifdef ENABLE_OTA const char *ssid = "ics-ap"; const char *password = "jikkenics"; void OTA_Setup() { WiFi.softAPdisconnect(true); M5.delay(1000); WiFi.mode(WIFI_STA); M5.delay(1000); WiFi.begin(ssid, password); int trycount = 0; while ((WiFi.status() != WL_CONNECTED)) { M5.Speaker.tone(2000, 500); M5.delay(200); M5.Display.print("."); trycount++; if (trycount == 100) { M5.Power.powerOff(); } } M5.Display.fillScreen(GREEN); M5.Display.setCursor(10, 50); M5.Display.setTextColor(BLACK, GREEN); M5.Display.println(" CONNECTED! "); M5.Speaker.tone(4000, 500); M5.delay(1000); // Port defaults to 3232 ArduinoOTA.setPort(3232); // Hostname defaults to esp3232-[MAC] ArduinoOTA.setHostname("m5"); // No authentication by default // ArduinoOTA.setPassword(""); // Password can be set with it's md5 value as well // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // ArduinoOTA.setPasswordHash("2bf9b9f1272b09206f050251343dcfcc"); // ArduinoOTA .onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else // U_SPIFFS type = "filesystem"; }) .onEnd([]() { M5.Speaker.tone(2000,500); M5.delay(150); M5.Speaker.tone(4000,500); M5.delay(150); M5.Speaker.tone(8000,500); M5.delay(300); M5.Speaker.tone(0,1); }) .onProgress([](unsigned int progress, unsigned int total) { ota_progress(progress, total); }) .onError([](ota_error_t error) {}); // Serial.printf("Error[%u]: ", error); // if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); // else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); // else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); // else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); // else if (error == OTA_END_ERROR) Serial.println("End Failed"); ArduinoOTA.begin(); } int prev_progress = -1; char buf[30]; void ota_progress(unsigned int progress, unsigned int total) { int cur_progress = (progress / (total / 100)); sprintf(buf, "OTA %d%% done", cur_progress); if (prev_progress < cur_progress) { M5.Display.setCursor(0, 30, 1); M5.Display.fillScreen(BLACK); M5.Display.setTextColor(WHITE, BLACK); M5.Display.println(buf); prev_progress = cur_progress; } } #endif