#include "M5StickCPlus.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_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 = true; // テストモード 常時ONにした (A/Bボタンを押しながら起動すれば、通常のFactoryTestでもテストモードになる)
bool startCoundDownShutdown = false; // 電源OFFのカウントダウンを開始するならtrue
#ifdef ENABLE_OTA
bool startOTA = false;
bool startOTAhandle = false;
#endif
TFT_eSprite Disbuff = TFT_eSprite(&M5.Lcd); // 画面ちらつき防止スプライト(画面のバッファリング)
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(10, TimerCount % 100); // LEDの明るさ
TimerCount++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void checkAXPPress() // 電源ボタン押下チェック
{
if (M5.Axp.GetBtnPress()) // 電源ボタン押下したら
{
do
{
delay(20);
} while (M5.Axp.GetBtnPress());
M5.Beep.mute();
// ESP.restart();
M5.Axp.Write1Byte(0x32, M5.Axp.Read8bit(0x32) | 0x80); //電源OFF
}
if (startCoundDownShutdown)
countDownShutdown();
#ifdef ENABLE_OTA
if (startOTA)
{
startOTA = false;
OTA_Setup();
startOTAhandle = true;
}
if (startOTAhandle)
ArduinoOTA.handle();
#endif
}
void Displaybuff() // Disbuffスプライトを表示する。(テストモードだったらTest Modeと表示する)
{
if (TestMode)
{
Disbuff.setTextSize(1);
Disbuff.setTextColor(TFT_CYAN);
Disbuff.drawString("FactoryTest 2022", 10, 0, 1);
Disbuff.setTextColor(TFT_WHITE);
battery.batteryUpdate();
// battery.showBattery();
}
Disbuff.pushSprite(0, 0);
}
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();
delay(100);
}
while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed()))
{
M5.update();
checkAXPPress();
M5.Beep.tone(4000);
delay(10);
}
delay(50);
M5.Beep.mute();
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(TFT_eSprite *display, line_3d_t *line, uint32_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()))
{
M5.Imu.getAccelData(&accX, &accY, &accZ);
// M5.MPU6886.getAccelData(&accX, &accY, &accZ);
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.setCursor(10, 115);
Disbuff.printf("%.2f", theta);
Disbuff.setCursor(10, 125);
Disbuff.printf("%.2f", phi);
// Displaybuff();
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();
M5.Beep.tone(4000);
delay(10);
}
delay(50);
M5.Beep.mute();
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) // フーリエ変換
{
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);
}
}
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;
void DisplayMicro()
{
Disbuff.fillRect(0, 0, 160, 80, Disbuff.color565(0, 0, 0)); //黒(R=0,G=0,B=0)で塗りつぶす
Disbuff.pushSprite(0, 0);
xSemaphoreGive(start_dis); // 画面表示タスク スタート
xSemaphoreGive(start_fft); // フーリエ変換タスク スタート
while ((!M5.BtnA.isPressed()) && (!M5.BtnB.isPressed())) // ABボタン押していない間、くりかえす
{
xSemaphoreGive(start_dis);
xSemaphoreGive(start_fft);
M5.update();
xSemaphoreTake(start_dis, portMAX_DELAY); // 画面表示タスク 一時停止
xSemaphoreTake(start_fft, portMAX_DELAY); // フーリエ変換タスク 一時停止
checkAXPPress();
}
// xSemaphoreTake( start_dis , portMAX_DELAY );
// xSemaphoreTake( start_fft , portMAX_DELAY );
while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed())) // ABボタン押している間、くりかえす
{
M5.update();
checkAXPPress();
M5.Beep.tone(4000);
delay(10);
}
delay(50);
M5.Beep.mute();
}
#define PIN_CLK 0
#define PIN_DATA 34
bool InitI2SMicroPhone() // マイクの初期化
{
esp_err_t err = ESP_OK;
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
.channel_format = I2S_CHANNEL_FMT_ALL_RIGHT,
.communication_format = I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 2,
.dma_buf_len = 128,
};
i2s_pin_config_t pin_config;
pin_config.bck_io_num = I2S_PIN_NO_CHANGE;
pin_config.ws_io_num = PIN_CLK;
pin_config.data_out_num = I2S_PIN_NO_CHANGE;
pin_config.data_in_num = PIN_DATA;
err += i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
err += i2s_set_pin(I2S_NUM_0, &pin_config);
err += i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
// i2s_set_clk(0)
if (err != ESP_OK)
{
return false;
}
else
{
return true;
}
}
void DisplayRTC() // リアルタイムクロック(内蔵時計)
{
Disbuff.fillRect(0, 0, 240, 135, Disbuff.color565(0, 0, 0));
// Displaybuff();
M5.Rtc.GetBm8563Time();
RTC_TimeTypeDef time;
M5.Rtc.GetTime(&time);
Disbuff.setTextSize(4);
Disbuff.setCursor(6, 25);
Disbuff.setTextColor(TFT_WHITE);
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_WHITE);
Disbuff.setCursor(25, 50);
Disbuff.printf("%02d:%02d:%02d", time.Hours, time.Minutes, time.Seconds);
Disbuff.fillRect(0, 0, 240, 25, Disbuff.color565(20, 20, 20));
Disbuff.setTextSize(2);
Disbuff.drawString("BMP8563 RTC Time", 26, 5, 1);
Displaybuff();
M5.update();
checkAXPPress();
delay(100);
}
while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed()))
{
M5.update();
checkAXPPress();
M5.Beep.tone(4000);
delay(10);
}
delay(50);
M5.Beep.mute();
Disbuff.setTextColor(TFT_WHITE);
}
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;
}
#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.Axp.GetBatVoltage();
while (VBat < 3.2)
{
VBat = M5.Axp.GetBatVoltage();
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;
}
// ENV. II SENSORをつないだときに、温度と湿度がとれる
int getTempAndHum(float *temp, float *hum)
{
static float _tempSave, _HUmSave;
uint8_t databuff[6];
Wire.beginTransmission(0x44);
Wire.write(0x2c);
Wire.write(0x06);
Wire.endTransmission();
Wire.requestFrom(0x44, 6);
for (int i = 0; i < 6; i++)
{
databuff[i] = Wire.read();
Serial.printf("%02X ", databuff[i]);
}
Serial.println("--");
if (crc8(0x31, &databuff[0], 2) == databuff[2])
{
uint16_t tempraw = databuff[0] << 8 | databuff[1];
*temp = -45 + 175 * (float(tempraw) / 65535.0);
_tempSave = *temp;
Serial.printf("Temp:%.2f ", *temp);
}
else
{
*temp = _tempSave;
}
if (crc8(0x31, &databuff[3], 2) == databuff[5])
{
uint16_t Humraw = databuff[3] << 8 | databuff[4];
*hum = 100 * (float(Humraw) / 65535.0);
_HUmSave = *hum;
Serial.printf("Hum:%.2f \n", *hum);
}
else
{
*hum = _HUmSave;
}
return 0;
}
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();
delay(100);
}
while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed()))
{
M5.update();
checkAXPPress();
M5.Beep.tone(4000);
delay(10);
}
delay(50);
M5.Beep.mute();
Disbuff.setTextColor(TFT_WHITE);
}
#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();
delay(100);
checkAXPPress();
}
while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed()))
{
M5.update();
checkAXPPress();
M5.Beep.tone(4000);
delay(10);
}
delay(50);
M5.Beep.mute();
Disbuff.setTextColor(TFT_WHITE);
pService->stop();
pServer->getAdvertising()->stop();
}
#endif
void DisplayGroveSHT30() // SHT30=ENV. II SENSOR 温度と湿度
{
float tempdata, humdata;
uint8_t count = 0;
Wire.begin(32, 33);
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 ");
if (count >= 10)
{
count = 0;
getTempAndHum(&tempdata, &humdata); // ENV. II SENSORをつないだときに、温度と湿度がとれる
Disbuff.setCursor(12, 50);
Disbuff.printf("%.2f", tempdata);
Disbuff.setCursor(12, 80);
Disbuff.printf("%.2f", humdata);
Disbuff.pushSprite(0, 0);
}
checkAXPPress();
M5.update();
delay(100);
count++;
}
while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed()))
{
M5.update();
checkAXPPress();
M5.Beep.tone(4000);
delay(10);
}
delay(50);
M5.Beep.mute();
Disbuff.setTextColor(TFT_WHITE);
}
void DisplayTestMode() // テストモード:ピンの電圧とバッテリー電圧
{
float tempdata, humdata;
uint8_t count = 10, count_u = 0, count_t = 0;
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);
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.Axp.GetBatVoltage() > 3.2) //バッテリーの電圧(残量によって変化する)
{
Disbuff.setTextColor(TFT_GREEN);
}
else
{
Disbuff.setTextColor(TFT_RED);
}
Disbuff.printf("b%.2f", M5.Axp.GetBatVoltage()); // バッテリー電圧を表示する
Disbuff.setCursor(12, 37);
if (M5.Axp.GetVinVoltage() > 4.6)
{
Disbuff.setTextColor(TFT_GREEN);
}
else
{
Disbuff.setTextColor(TFT_RED);
}
Disbuff.printf("v%.2f", M5.Axp.GetVinVoltage()); //外部電源電圧(5V←の電圧)
digitalWrite(0, 0);
digitalWrite(26, 0);
count_u = 0;
count_t = 0;
for (int i = 0; i < 10; i++)
{
digitalWrite(0, i % 2);
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);
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();
delay(10);
count++;
}
while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed()))
{
M5.update();
checkAXPPress();
M5.Beep.tone(4000);
delay(10);
}
delay(50);
M5.Beep.mute();
Disbuff.setTextColor(TFT_WHITE);
InitI2SMicroPhone();
}
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 uint8_t *mac_addr, const uint8_t *data, int data_len)
{
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.println();
// Serial.printf("Last Packet Recv from: %s\n", macStr);
// Serial.printf("Last Packet Recv Data(%d): ", data_len);
if (data[0] == 100 && data[1] == 254) // 100,254に深い意味はない。uint8_tは0〜255の数値
{
startCoundDownShutdown = true; // シャットダウンタイマースタート予約(発動はcheckAXPPress()のなかで)
}
#ifdef ENABLE_OTA
if (data[0] == 99 && data[1] == 254) // 99,254に深い意味はない。uint8_tは0〜255の数値
{
startOTA = true;
}
#endif
}
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. A/B press 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)
{
M5.Axp.Write1Byte(0x32, M5.Axp.Read8bit(0x32) | 0x80); //電源OFF
}
}
startCoundDownShutdown = 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];
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()))
{
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())
{
uint8_t data[2] = {100, 254}; // 送信データ 100, 254に深い意味はない。uint8_tは0〜255の数値
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");
}
}
if (M5.BtnA.isPressed())
break;
delay(100);
}
while ((M5.BtnA.isPressed()) || (M5.BtnB.isPressed()))
{
M5.update();
checkAXPPress();
M5.Beep.tone(4000);
delay(10);
}
delay(50);
M5.Beep.mute();
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();
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();
delay(500);
}
uint8_t addrcheckbuff[3] = {
0x34, //
0x51, //
0x68 //
};
int checkI2CAddr() // I2C 通信のテスト
{
uint8_t faild_count = 0;
do
{
faild_count = 0;
for (int i = 0; i < sizeof(addrcheckbuff); i++)
{
Wire1.beginTransmission(addrcheckbuff[i]);
if (Wire1.endTransmission() == ESP_OK)
{
Serial.printf("find %02X addr successful\r\n", addrcheckbuff[i]);
}
else
{
Serial.printf("find %02X addr faild\r\n", addrcheckbuff[i]);
char strbuff[128];
sprintf(strbuff, "i2c %02X fail", addrcheckbuff[i]);
ErrorDialog(addrcheckbuff[i], (const char *)strbuff);
faild_count++;
}
}
} while (faild_count != 0);
return 0;
}
void setup()
{
M5.begin();
Wire.begin(32, 33); // GROOVE端子のI2C通信
M5.Lcd.setRotation(3); // 画面向きは横
Disbuff.createSprite(240, 135);
Disbuff.fillRect(0, 0, 240, 135, Disbuff.color565(10, 10, 10));
Disbuff.pushSprite(0, 0);
delay(500);
M5.update();
if (M5.BtnB.isPressed()) // Bボタンを押して起動したら、テストモード
{
M5.Beep.tone(4000);
delay(100);
M5.Beep.mute();
TestMode = true;
while (M5.BtnB.isPressed())
{
M5.update();
delay(10);
}
}
M5.Axp.ScreenBreath(12); // 画面明るさ調整 8〜15
battery.setSprite(&Disbuff); // バッテリー残量表示
battery.setPosAndSize(160, 1, 1);
battery.setCheckRate(300);
// // deleteBattery()時の塗りつぶし色を設定
// battery.setDeleteBgColor(TFT_BLACK);
// 電池図形と%表示の色を設定
// battery.setTextColor(TFT_WHITE);
Init_ESPNOW(); // ESPNOWの初期化
ColorBar(); //ディスプレイ発色チェック
checkI2CAddr();
checkAXP192(); // バッテリー電圧チェック。低下してたらエラーメッセージ表示
M5.Imu.Init(); // 加速度・角速度(ジャイロ)初期化
InitI2SMicroPhone(); // マイク初期化
InitIRTx(); // 赤外線通信 初期化
#ifdef ENABLE_BLE
InitBLEServer(); // Bluetooth Low Energyサーバ初期化
#endif
pinMode(10, 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()
{
// それぞれのテスト中は、関数のなかのループがまわる
// AorBボタンを押したら、現在実行中の関数のループを抜け、次の関数を実行する
MPU6886Test(); // 加速度・ジャイロ
DisplayRTC(); // リアルタイムクロック
DisplayMicro(); // マイク
DisIRSend(); // 赤外線通信
if (TestMode)
{
DisplayTestMode(); // バッテリー電圧
}
#ifdef ENABLE_BLE
DisPlayBLESend();
#else
ESP_NOW_SendShutdown(); // シャットダウン信号の送信
#endif
M5.update();
delay(50);
Serial.println("end of loop");
}
#ifdef ENABLE_OTA
const char *ssid = "miura2g";
const char *password = "jikken2022";
void OTA_Setup()
{
WiFi.softAPdisconnect(true);
delay(1000);
WiFi.mode(WIFI_STA);
delay(1000);
WiFi.begin(ssid, password);
int trycount = 0;
while ((WiFi.status() != WL_CONNECTED))
{
M5.Beep.tone(2000);
delay(200);
M5.Beep.mute();
delay(300);
M5.Lcd.print(".");
trycount++;
if (trycount == 100)
{
M5.Axp.Write1Byte(0x32, M5.Axp.Read8bit(0x32) | 0x80); //電源OFF
}
}
M5.Lcd.fillScreen(GREEN);
M5.Lcd.setCursor(10, 50);
M5.Lcd.setTextColor(BLACK, GREEN);
M5.Lcd.println(" CONNECTED! ");
M5.Beep.tone(4000);
delay(1000);
M5.Beep.mute();
// 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.Beep.tone(2000);
delay(150);
M5.Beep.tone(4000);
delay(150);
M5.Beep.tone(8000);
delay(300);
M5.Beep.mute(); })
.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.Lcd.setCursor(0, 30, 1);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.println(buf);
prev_progress = cur_progress;
}
}
#endif