first commit
This commit is contained in:
commit
5893b00dd2
1669 changed files with 1982740 additions and 0 deletions
2122
libraries/M5Unified/src/M5Unified.cpp
Normal file
2122
libraries/M5Unified/src/M5Unified.cpp
Normal file
File diff suppressed because it is too large
Load diff
11
libraries/M5Unified/src/M5Unified.h
Normal file
11
libraries/M5Unified/src/M5Unified.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "M5Unified.hpp"
|
||||
|
||||
#else
|
||||
|
||||
#error M5Unified requires a C++ compiler, please change file extension to .cc or .cpp
|
||||
|
||||
#endif
|
||||
588
libraries/M5Unified/src/M5Unified.hpp
Normal file
588
libraries/M5Unified/src/M5Unified.hpp
Normal file
|
|
@ -0,0 +1,588 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5UNIFIED_HPP__
|
||||
#define __M5UNIFIED_HPP__
|
||||
|
||||
#include "utility/m5unified_common.h"
|
||||
|
||||
#if __has_include(<sdkconfig.h>)
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
// If you want to use a set of functions to handle SD/SPIFFS/HTTP,
|
||||
// please include <SD.h>,<SPIFFS.h>,<HTTPClient.h> before <M5GFX.h>
|
||||
// #include <SD.h>
|
||||
// #include <SPIFFS.h>
|
||||
// #include <HTTPClient.h>
|
||||
|
||||
#include <M5GFX.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
using board_t = m5gfx::board_t;
|
||||
using touch_point_t = m5gfx::touch_point_t;
|
||||
|
||||
enum pin_name_t
|
||||
{
|
||||
in_i2c_scl,
|
||||
in_i2c_sda,
|
||||
port_a_pin1, port_a_scl = port_a_pin1, ex_i2c_scl = port_a_pin1,
|
||||
port_a_pin2, port_a_sda = port_a_pin2, ex_i2c_sda = port_a_pin2,
|
||||
port_b_pin1, port_b_in = port_b_pin1,
|
||||
port_b_pin2, port_b_out = port_b_pin2,
|
||||
port_c_pin1, port_c_rxd = port_c_pin1,
|
||||
port_c_pin2, port_c_txd = port_c_pin2,
|
||||
port_d_pin1, port_d_rxd = port_d_pin1, port_b2_pin1 = port_d_pin1, // b2,c2 for M5Station
|
||||
port_d_pin2, port_d_txd = port_d_pin2, port_b2_pin2 = port_d_pin2,
|
||||
port_e_pin1, port_e_rxd = port_e_pin1, port_c2_pin1 = port_e_pin1,
|
||||
port_e_pin2, port_e_txd = port_e_pin2, port_c2_pin2 = port_e_pin2,
|
||||
sd_spi_sclk,
|
||||
sd_spi_copi, sd_spi_mosi = sd_spi_copi,
|
||||
sd_spi_cipo, sd_spi_miso = sd_spi_cipo,
|
||||
sd_spi_cs, sd_spi_ss = sd_spi_cs,
|
||||
rgb_led,
|
||||
power_hold,
|
||||
mbus_pin1, mbus_pin2, mbus_pin3, mbus_pin4, mbus_pin5,
|
||||
mbus_pin6, mbus_pin7, mbus_pin8, mbus_pin9, mbus_pin10,
|
||||
mbus_pin11, mbus_pin12, mbus_pin13, mbus_pin14, mbus_pin15,
|
||||
mbus_pin16, mbus_pin17, mbus_pin18, mbus_pin19, mbus_pin20,
|
||||
mbus_pin21, mbus_pin22, mbus_pin23, mbus_pin24, mbus_pin25,
|
||||
mbus_pin26, mbus_pin27, mbus_pin28, mbus_pin29, mbus_pin30,
|
||||
pin_name_max,
|
||||
};
|
||||
};
|
||||
|
||||
#include "gitTagVersion.h"
|
||||
#include "utility/RTC8563_Class.hpp"
|
||||
#include "utility/AXP192_Class.hpp"
|
||||
#include "utility/IP5306_Class.hpp"
|
||||
#include "utility/Button_Class.hpp"
|
||||
#include "utility/Power_Class.hpp"
|
||||
#include "utility/Speaker_Class.hpp"
|
||||
#include "utility/Mic_Class.hpp"
|
||||
#include "utility/Touch_Class.hpp"
|
||||
#include "utility/Log_Class.hpp"
|
||||
#include "utility/IMU_Class.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
using touch_detail_t = Touch_Class::touch_detail_t;
|
||||
|
||||
class M5Unified
|
||||
{
|
||||
public:
|
||||
struct config_t
|
||||
{
|
||||
#if defined ( ARDUINO )
|
||||
|
||||
/// use "Serial" begin. (0=disabled / Usually 115200 is used.)
|
||||
/// When this value is not 0, Serial.begin is executed.
|
||||
uint32_t serial_baudrate = 0;
|
||||
|
||||
#endif
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t module_display : 1;
|
||||
uint8_t module_rca : 1;
|
||||
uint8_t hat_spk : 1;
|
||||
uint8_t atomic_spk : 1;
|
||||
uint8_t hat_spk2 : 1;
|
||||
uint8_t atomic_echo : 1;
|
||||
uint8_t reserve : 2;
|
||||
} external_speaker;
|
||||
uint8_t external_speaker_value = 0x00;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16_t module_display : 1;
|
||||
uint16_t atom_display : 1;
|
||||
uint16_t unit_oled : 1;
|
||||
uint16_t unit_mini_oled : 1;
|
||||
uint16_t unit_lcd : 1;
|
||||
uint16_t unit_glass : 1;
|
||||
uint16_t unit_glass2 : 1;
|
||||
uint16_t unit_rca : 1;
|
||||
uint16_t module_rca : 1;
|
||||
uint16_t reserve : 7;
|
||||
} external_display;
|
||||
uint16_t external_display_value = 0xFFFF;
|
||||
};
|
||||
|
||||
/// Clear the screen when startup.
|
||||
bool clear_display = true;
|
||||
|
||||
/// 5V output to external port.
|
||||
bool output_power = true;
|
||||
|
||||
/// use PMIC(AXP192) pek for M5.BtnPWR.
|
||||
bool pmic_button = true;
|
||||
|
||||
/// use internal IMU.
|
||||
bool internal_imu = true;
|
||||
|
||||
/// use internal RTC.
|
||||
bool internal_rtc = true;
|
||||
|
||||
/// use the microphone.
|
||||
bool internal_mic = true;
|
||||
|
||||
/// use the speaker.
|
||||
bool internal_spk = true;
|
||||
|
||||
/// use Unit Accel & Gyro.
|
||||
bool external_imu = false;
|
||||
|
||||
/// use Unit RTC.
|
||||
bool external_rtc = false;
|
||||
|
||||
/// Turn off the IRQ bit of the RTC at startup.
|
||||
bool disable_rtc_irq = true;
|
||||
|
||||
/// system LED brightness (0=off / 255=max) (※ not RGBcolorLED)
|
||||
uint8_t led_brightness = 0;
|
||||
|
||||
/// If auto-detection fails, the board will operate as the board configured here.
|
||||
board_t fallback_board
|
||||
#if defined (CONFIG_IDF_TARGET_ESP32S3)
|
||||
= board_t::board_M5AtomS3Lite;
|
||||
#elif defined (CONFIG_IDF_TARGET_ESP32C3)
|
||||
= board_t::board_M5StampC3;
|
||||
#elif defined (CONFIG_IDF_TARGET_ESP32P4)
|
||||
= board_t::board_M5Tab5;
|
||||
#elif defined (CONFIG_IDF_TARGET_ESP32) || !defined (CONFIG_IDF_TARGET)
|
||||
= board_t::board_M5AtomLite;
|
||||
#else
|
||||
= board_t::board_unknown;
|
||||
#endif
|
||||
|
||||
union
|
||||
{
|
||||
uint8_t external_spk = 0;
|
||||
[[deprecated("Change to external_speaker")]]
|
||||
struct
|
||||
{
|
||||
uint8_t enabled : 1;
|
||||
uint8_t omit_atomic_spk : 1;
|
||||
uint8_t omit_spk_hat : 1;
|
||||
uint8_t reserve : 5;
|
||||
} external_spk_detail;
|
||||
};
|
||||
|
||||
#if defined ( __M5GFX_M5ATOMDISPLAY__ )
|
||||
M5AtomDisplay::config_t atom_display;
|
||||
#endif
|
||||
#if defined ( __M5GFX_M5MODULEDISPLAY__ )
|
||||
M5ModuleDisplay::config_t module_display;
|
||||
#endif
|
||||
#if defined ( __M5GFX_M5MODULERCA__ )
|
||||
M5ModuleRCA::config_t module_rca;
|
||||
#endif
|
||||
#if defined ( __M5GFX_M5UNITGLASS__ )
|
||||
M5UnitGLASS::config_t unit_glass;
|
||||
#endif
|
||||
#if defined ( __M5GFX_M5UNITGLASS2__ )
|
||||
M5UnitGLASS2::config_t unit_glass2;
|
||||
#endif
|
||||
#if defined ( __M5GFX_M5UNITOLED__ )
|
||||
M5UnitOLED::config_t unit_oled;
|
||||
#endif
|
||||
#if defined ( __M5GFX_M5UNITMINIOLED__ )
|
||||
M5UnitMiniOLED::config_t unit_mini_oled;
|
||||
#endif
|
||||
#if defined ( __M5GFX_M5UNITLCD__ )
|
||||
M5UnitLCD::config_t unit_lcd;
|
||||
#endif
|
||||
#if defined ( __M5GFX_M5UNITRCA__ )
|
||||
M5UnitRCA::config_t unit_rca;
|
||||
#endif
|
||||
};
|
||||
|
||||
M5GFX Display; // setPrimaryされたディスプレイのインスタンス
|
||||
M5GFX &Lcd = Display;
|
||||
|
||||
IMU_Class Imu;
|
||||
Log_Class Log;
|
||||
Power_Class Power;
|
||||
RTC8563_Class Rtc;
|
||||
Touch_Class Touch;
|
||||
|
||||
/*
|
||||
/// List of available buttons:
|
||||
M5Stack BASIC/GRAY/GO/FIRE: BtnA,BtnB,BtnC
|
||||
M5Stack Core2: BtnA,BtnB,BtnC,BtnPWR
|
||||
M5Stick C/CPlus: BtnA,BtnB, BtnPWR
|
||||
M5Stick CoreInk: BtnA,BtnB,BtnC,BtnPWR,BtnEXT
|
||||
M5Paper: BtnA,BtnB,BtnC
|
||||
M5Station: BtnA,BtnB,BtnC,BtnPWR
|
||||
M5Tough: BtnPWR
|
||||
M5ATOM: BtnA
|
||||
*/
|
||||
Button_Class &BtnA = _buttons[0];
|
||||
Button_Class &BtnB = _buttons[1];
|
||||
Button_Class &BtnC = _buttons[2];
|
||||
Button_Class &BtnEXT = _buttons[3]; // CoreInk top button
|
||||
Button_Class &BtnPWR = _buttons[4]; // CoreInk power button / AXP192 power button
|
||||
|
||||
/// for internal I2C device
|
||||
I2C_Class& In_I2C = m5::In_I2C;
|
||||
|
||||
/// for external I2C device (Port.A)
|
||||
I2C_Class& Ex_I2C = m5::Ex_I2C;
|
||||
|
||||
Speaker_Class Speaker;
|
||||
|
||||
Mic_Class Mic;
|
||||
|
||||
static int8_t getPin(pin_name_t name) { return _get_pin_table[name]; }
|
||||
|
||||
Button_Class& getButton(size_t index) { return _buttons[index]; }
|
||||
|
||||
Button_Class& Buttons(size_t index) { return getButton(index); }
|
||||
|
||||
M5GFX& getDisplay(size_t index);
|
||||
|
||||
M5GFX& Displays(size_t index) { return getDisplay(index); }
|
||||
|
||||
std::size_t getDisplayCount(void) const { return this->_displays.size(); }
|
||||
|
||||
std::size_t addDisplay(M5GFX& dsp);
|
||||
|
||||
// Get the display index of the type matching the argument.
|
||||
// Returns -1 if not found.
|
||||
int32_t getDisplayIndex(m5gfx::board_t board);
|
||||
|
||||
int32_t getDisplayIndex(std::initializer_list<m5gfx::board_t> board_list);
|
||||
|
||||
// Designates the display of the specified index as PrimaryDisplay.
|
||||
bool setPrimaryDisplay(std::size_t index);
|
||||
|
||||
// Find a display that matches the specified display type and designate it as PrimaryDisplay.
|
||||
// Multiple display types can be specified in the initializer list.
|
||||
bool setPrimaryDisplayType(std::initializer_list<m5gfx::board_t> board_list);
|
||||
|
||||
// Find a display that matches the specified display type and designate it as PrimaryDisplay.
|
||||
bool setPrimaryDisplayType(m5gfx::board_t board) { return setPrimaryDisplayType( { board } ); };
|
||||
|
||||
/// Set the display to show logs.
|
||||
void setLogDisplayIndex(size_t index);
|
||||
|
||||
void setLogDisplayType(std::initializer_list<m5gfx::board_t> board_list);
|
||||
|
||||
void setLogDisplayType(m5gfx::board_t board) { setLogDisplayType( { board } ); };
|
||||
|
||||
/// milli seconds at the time the update was called
|
||||
std::uint32_t getUpdateMsec(void) const { return _updateMsec; }
|
||||
|
||||
static inline config_t config(void)
|
||||
{
|
||||
return config_t();
|
||||
}
|
||||
|
||||
static inline void delay(uint32_t msec)
|
||||
{
|
||||
#if defined (ESP_PLATFORM)
|
||||
vTaskDelay( msec / portTICK_PERIOD_MS );
|
||||
#else
|
||||
SDL_Delay(msec);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t millis(void)
|
||||
{
|
||||
return m5gfx::millis();
|
||||
}
|
||||
|
||||
static inline uint32_t micros(void)
|
||||
{
|
||||
return m5gfx::micros();
|
||||
}
|
||||
|
||||
/// get the board type of the runtime environment.
|
||||
/// @return board type
|
||||
board_t getBoard(void) const { return _board; }
|
||||
|
||||
/// To call this function in a loop function.
|
||||
virtual void update(void);
|
||||
|
||||
/// Perform initialization process at startup.
|
||||
void begin(void)
|
||||
{
|
||||
config_t cfg;
|
||||
begin(cfg);
|
||||
}
|
||||
|
||||
/// Perform initialization process at startup.
|
||||
virtual void begin(config_t cfg)
|
||||
{
|
||||
// Allow begin execution only once.
|
||||
if (_board != m5gfx::board_t::board_unknown) { return; }
|
||||
|
||||
#if defined ( CONFIG_IDF_TARGET_ESP32S3 )
|
||||
// Power Hold pin for Capsule/Dial/DinMeter
|
||||
m5gfx::gpio_hi(GPIO_NUM_46);
|
||||
m5gfx::pinMode(GPIO_NUM_46, m5gfx::pin_mode_t::output);
|
||||
#endif
|
||||
|
||||
auto brightness = Display.getBrightness();
|
||||
Display.setBrightness(0);
|
||||
bool res = Display.init_without_reset(cfg.clear_display);
|
||||
auto board = _check_boardtype(Display.getBoard());
|
||||
if (board == board_t::board_unknown) { board = cfg.fallback_board; }
|
||||
_board = board;
|
||||
_setup_pinmap(board);
|
||||
_setup_i2c(board);
|
||||
if (res && getDisplayCount() == 0) {
|
||||
addDisplay(Display);
|
||||
}
|
||||
|
||||
#if defined ( __M5GFX_M5ATOMDISPLAY__ )
|
||||
if (cfg.external_display.atom_display) {
|
||||
#if defined (CONFIG_IDF_TARGET_ESP32S3)
|
||||
if (_board == board_t::board_M5AtomS3 || _board == board_t::board_M5AtomS3Lite || _board == board_t::board_M5AtomS3R || _board == board_t::board_M5AtomS3RCam || _board == board_t::board_M5AtomS3RExt)
|
||||
#elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
|
||||
if (_board == board_t::board_M5AtomLite || _board == board_t::board_M5AtomMatrix || _board == board_t::board_M5AtomEcho || _board == board_t::board_M5AtomPsram)
|
||||
#else
|
||||
if (false)
|
||||
#endif
|
||||
{
|
||||
M5AtomDisplay dsp(cfg.atom_display);
|
||||
if (dsp.init_without_reset()) {
|
||||
addDisplay(dsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
_begin(cfg);
|
||||
|
||||
|
||||
// Module Display / Unit OLED / Unit LCD is determined after _begin (because it must be after external power supply)
|
||||
#if defined ( __M5GFX_M5MODULEDISPLAY__ )
|
||||
if (cfg.external_display.module_display) {
|
||||
#if defined (CONFIG_IDF_TARGET_ESP32P4)
|
||||
if (_board == board_t::board_M5Tab5)
|
||||
#elif defined (CONFIG_IDF_TARGET_ESP32S3)
|
||||
if (_board == board_t::board_M5StackCoreS3 || _board == board_t::board_M5StackCoreS3SE)
|
||||
#elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
|
||||
if (_board == board_t::board_M5Stack || _board == board_t::board_M5StackCore2 || _board == board_t::board_M5Tough)
|
||||
#else
|
||||
if (false)
|
||||
#endif
|
||||
{
|
||||
M5ModuleDisplay dsp(cfg.module_display);
|
||||
if (dsp.init()) {
|
||||
addDisplay(dsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Speaker selection is performed after the Module Display has been determined.
|
||||
_begin_spk(cfg);
|
||||
|
||||
update();
|
||||
|
||||
bool port_a_used = _begin_rtc_imu(cfg);
|
||||
(void)port_a_used;
|
||||
|
||||
if (cfg.external_display_value)
|
||||
{
|
||||
#if defined ( __M5GFX_M5UNITOLED__ )
|
||||
if (cfg.external_display.unit_oled)
|
||||
{
|
||||
#if defined (ESP_PLATFORM)
|
||||
if (cfg.unit_oled.pin_sda >= GPIO_NUM_MAX) { cfg.unit_oled.pin_sda = (uint8_t)Ex_I2C.getSDA(); }
|
||||
if (cfg.unit_oled.pin_scl >= GPIO_NUM_MAX) { cfg.unit_oled.pin_scl = (uint8_t)Ex_I2C.getSCL(); }
|
||||
if (cfg.unit_oled.i2c_port < 0) { cfg.unit_oled.i2c_port = (int8_t)Ex_I2C.getPort(); }
|
||||
#endif
|
||||
|
||||
M5UnitOLED dsp(cfg.unit_oled);
|
||||
if (dsp.init()) {
|
||||
addDisplay(dsp);
|
||||
port_a_used = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined ( __M5GFX_M5UNITMINIOLED__ )
|
||||
if (cfg.external_display.unit_mini_oled)
|
||||
{
|
||||
#if defined (ESP_PLATFORM)
|
||||
if (cfg.unit_mini_oled.pin_sda >= GPIO_NUM_MAX) { cfg.unit_mini_oled.pin_sda = (uint8_t)Ex_I2C.getSDA(); }
|
||||
if (cfg.unit_mini_oled.pin_scl >= GPIO_NUM_MAX) { cfg.unit_mini_oled.pin_scl = (uint8_t)Ex_I2C.getSCL(); }
|
||||
if (cfg.unit_mini_oled.i2c_port < 0) { cfg.unit_mini_oled.i2c_port = (int8_t)Ex_I2C.getPort(); }
|
||||
#endif
|
||||
|
||||
M5UnitMiniOLED dsp(cfg.unit_mini_oled);
|
||||
if (dsp.init()) {
|
||||
addDisplay(dsp);
|
||||
port_a_used = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined ( __M5GFX_M5UNITGLASS__ )
|
||||
if (cfg.external_display.unit_glass)
|
||||
{
|
||||
#if defined (ESP_PLATFORM)
|
||||
if (cfg.unit_glass.pin_sda >= GPIO_NUM_MAX) { cfg.unit_glass.pin_sda = (uint8_t)Ex_I2C.getSDA(); }
|
||||
if (cfg.unit_glass.pin_scl >= GPIO_NUM_MAX) { cfg.unit_glass.pin_scl = (uint8_t)Ex_I2C.getSCL(); }
|
||||
if (cfg.unit_glass.i2c_port < 0) { cfg.unit_glass.i2c_port = (int8_t)Ex_I2C.getPort(); }
|
||||
#endif
|
||||
|
||||
M5UnitGLASS dsp(cfg.unit_glass);
|
||||
if (dsp.init()) {
|
||||
addDisplay(dsp);
|
||||
port_a_used = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined ( __M5GFX_M5UNITGLASS2__ )
|
||||
if (cfg.external_display.unit_glass2)
|
||||
{
|
||||
#if defined (ESP_PLATFORM)
|
||||
if (cfg.unit_glass2.pin_sda >= GPIO_NUM_MAX) { cfg.unit_glass2.pin_sda = (uint8_t)Ex_I2C.getSDA(); }
|
||||
if (cfg.unit_glass2.pin_scl >= GPIO_NUM_MAX) { cfg.unit_glass2.pin_scl = (uint8_t)Ex_I2C.getSCL(); }
|
||||
if (cfg.unit_glass2.i2c_port < 0) { cfg.unit_glass2.i2c_port = (int8_t)Ex_I2C.getPort(); }
|
||||
#endif
|
||||
|
||||
M5UnitGLASS2 dsp(cfg.unit_glass2);
|
||||
if (dsp.init()) {
|
||||
addDisplay(dsp);
|
||||
port_a_used = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined ( __M5GFX_M5UNITLCD__ )
|
||||
if (cfg.external_display.unit_lcd)
|
||||
{
|
||||
#if defined (ESP_PLATFORM)
|
||||
if (cfg.unit_lcd.pin_sda >= GPIO_NUM_MAX) { cfg.unit_lcd.pin_sda = (uint8_t)Ex_I2C.getSDA(); }
|
||||
if (cfg.unit_lcd.pin_scl >= GPIO_NUM_MAX) { cfg.unit_lcd.pin_scl = (uint8_t)Ex_I2C.getSCL(); }
|
||||
if (cfg.unit_lcd.i2c_port < 0) { cfg.unit_lcd.i2c_port = (int8_t)Ex_I2C.getPort(); }
|
||||
#endif
|
||||
|
||||
M5UnitLCD dsp(cfg.unit_lcd);
|
||||
int retry = 8;
|
||||
do {
|
||||
m5gfx::delay(32);
|
||||
if (dsp.init()) {
|
||||
addDisplay(dsp);
|
||||
port_a_used = true;
|
||||
break;
|
||||
}
|
||||
} while (--retry);
|
||||
}
|
||||
#endif
|
||||
|
||||
// RCA is not available on ESP32S3
|
||||
#if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
|
||||
#if defined ( __M5GFX_M5MODULERCA__ ) || defined ( __M5GFX_M5UNITRCA__ )
|
||||
{
|
||||
bool unit_rca = cfg.external_display.unit_rca;
|
||||
(void)unit_rca;
|
||||
#if defined ( __M5GFX_M5MODULERCA__ )
|
||||
if (cfg.external_display.module_rca)
|
||||
{
|
||||
if (board == board_t::board_M5Stack
|
||||
|| board == board_t::board_M5StackCore2
|
||||
|| board == board_t::board_M5Tough
|
||||
) {
|
||||
// When ModuleRCA is used, UnitRCA is not used.
|
||||
unit_rca = false;
|
||||
M5ModuleRCA dsp(cfg.module_rca);
|
||||
if (dsp.init()) {
|
||||
addDisplay(dsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined ( __M5GFX_M5UNITRCA__ )
|
||||
if (unit_rca)
|
||||
{
|
||||
if ( board == board_t::board_M5Stack
|
||||
|| board == board_t::board_M5StackCore2
|
||||
|| board == board_t::board_M5Paper
|
||||
|| board == board_t::board_M5Tough
|
||||
|| board == board_t::board_M5Station
|
||||
|| (!port_a_used && ( // ATOM does not allow video output via UnitRCA when PortA is used.
|
||||
board == board_t::board_M5AtomLite
|
||||
|| board == board_t::board_M5AtomMatrix
|
||||
|| board == board_t::board_M5AtomEcho
|
||||
|| board == board_t::board_M5AtomPsram
|
||||
|| board == board_t::board_M5AtomU
|
||||
)))
|
||||
{
|
||||
M5UnitRCA dsp(cfg.unit_rca);
|
||||
if (dsp.init()) {
|
||||
addDisplay(dsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Display.getBoard() != board_t::board_unknown)
|
||||
{
|
||||
Display.setBrightness(brightness);
|
||||
}
|
||||
}
|
||||
|
||||
void setTouchButtonHeightByRatio(uint8_t ratio);
|
||||
void setTouchButtonHeight(uint16_t pixel) { _touch_button_height = pixel; }
|
||||
uint16_t getTouchButtonHeight(void) const { return _touch_button_height; }
|
||||
|
||||
private:
|
||||
static constexpr std::size_t BTNPWR_MIN_UPDATE_MSEC = 4;
|
||||
|
||||
Button_Class _buttons[5];
|
||||
|
||||
std::vector<M5GFX> _displays; // 登録された全ディスプレイのインスタンス
|
||||
std::uint32_t _updateMsec = 0;
|
||||
std::uint16_t _touch_button_height = 0;
|
||||
m5gfx::board_t _board = m5gfx::board_t::board_unknown;
|
||||
|
||||
std::uint8_t _primary_display_index = -1;
|
||||
bool use_pmic_button = false;
|
||||
bool use_hat_spk = false;
|
||||
|
||||
void _begin(const config_t& cfg);
|
||||
void _begin_spk(config_t& cfg);
|
||||
bool _begin_rtc_imu(const config_t& cfg);
|
||||
|
||||
board_t _check_boardtype(board_t);
|
||||
void _setup_i2c(board_t);
|
||||
|
||||
static void _setup_pinmap(board_t);
|
||||
static bool _speaker_enabled_cb_core2(void* args, bool enabled);
|
||||
static bool _speaker_enabled_cb_cores3(void* args, bool enabled);
|
||||
static bool _speaker_enabled_cb_hat_spk(void* args, bool enabled);
|
||||
static bool _speaker_enabled_cb_atomic_echo(void* args, bool enabled);
|
||||
static bool _speaker_enabled_cb_tab5(void* args, bool enabled);
|
||||
static bool _microphone_enabled_cb_stickc(void* args, bool enabled);
|
||||
static bool _microphone_enabled_cb_cores3(void* args, bool enabled);
|
||||
static bool _microphone_enabled_cb_atomic_echo(void* args, bool enabled);
|
||||
static bool _microphone_enabled_cb_tab5(void* args, bool enabled);
|
||||
|
||||
static int8_t _get_pin_table[pin_name_max];
|
||||
};
|
||||
}
|
||||
|
||||
extern m5::M5Unified M5;
|
||||
|
||||
#endif
|
||||
4
libraries/M5Unified/src/gitTagVersion.h
Normal file
4
libraries/M5Unified/src/gitTagVersion.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#define M5UNIFIED_VERSION_MAJOR 0
|
||||
#define M5UNIFIED_VERSION_MINOR 2
|
||||
#define M5UNIFIED_VERSION_PATCH 7
|
||||
#define M5UNIFIED_VERSION F( M5UNIFIED_VERSION_MAJOR "." M5UNIFIED_VERSION_MINOR "." M5UNIFIED_VERSION_PATCH )
|
||||
363
libraries/M5Unified/src/utility/AXP192_Class.cpp
Normal file
363
libraries/M5Unified/src/utility/AXP192_Class.cpp
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "AXP192_Class.hpp"
|
||||
|
||||
#if __has_include(<esp_log.h>)
|
||||
#include <esp_log.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
/*
|
||||
DCDC1 : 0.7-3.5V, 25mV/step 1200mA
|
||||
DCDC2 : 0.7-2.275V,25mV/step 1600mA
|
||||
DCDC3 : 0.7-3.5V, 25mV/step 700mA
|
||||
|
||||
LDOio0: 1.8-3.3V, 100mV/step 50mA
|
||||
LDO1 : 30mA always on
|
||||
LDO2 : 1.8-3.3V, 100mV/step 200mA
|
||||
LDO3 : 1.8-3.3V, 100mV/step 200mA
|
||||
*/
|
||||
bool AXP192_Class::begin(void)
|
||||
{
|
||||
std::uint8_t val;
|
||||
_init = readRegister(0x03, &val, 1);
|
||||
if (_init)
|
||||
{
|
||||
_init = (val == 0x03);
|
||||
#if defined (ESP_LOGV)
|
||||
// ESP_LOGV("AXP192", "reg03h:%02x : init:%d", val, _init);
|
||||
#endif
|
||||
}
|
||||
return _init;
|
||||
}
|
||||
|
||||
/// @param num 0=DCDC1 / 1=DCDC2 / 2=DCDC3
|
||||
void AXP192_Class::_set_DCDC(std::uint8_t num, int voltage)
|
||||
{
|
||||
static constexpr uint8_t reg12bit_tbl[] = { 0x01, 0x10, 0x02 };
|
||||
static constexpr uint8_t volt_reg_tbl[] = { 0x26, 0x23, 0x27 };
|
||||
static constexpr uint8_t volt_max_tbl[] = { 0x7F, 0x3F, 0x7F };
|
||||
|
||||
voltage -= 700;
|
||||
std::uint_fast8_t val = (voltage < 0) ? 0 : std::min(voltage / 25, (int)volt_max_tbl[num]);
|
||||
writeRegister8(volt_reg_tbl[num], val);
|
||||
if (voltage < 0)
|
||||
{
|
||||
bitOff(0x12, reg12bit_tbl[num]);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitOn(0x12, reg12bit_tbl[num]);
|
||||
}
|
||||
}
|
||||
|
||||
/// @param num 0:LDOio0 ; 2:LDO2 ; 3=LDO3
|
||||
void AXP192_Class::_set_LDO(std::uint8_t num, int voltage)
|
||||
{
|
||||
if (num > 3 || num == 1) return;
|
||||
std::uint8_t reg_volt = (num == 0) ? 0x91 : 0x28;
|
||||
voltage -= 1800;
|
||||
/// convert voltage to value
|
||||
std::uint_fast8_t val = (voltage < 0) ? 0 : std::min(voltage / 100, 0x0F);
|
||||
std::uint_fast8_t now = readRegister8(reg_volt);
|
||||
if (num == 3)
|
||||
{ /// LDO3
|
||||
now = (now & 0xF0) + val;
|
||||
}
|
||||
else
|
||||
{ /// LDOio0 , LDO2
|
||||
now = (now & 0x0F) | (val << 4);
|
||||
}
|
||||
writeRegister8(reg_volt, now);
|
||||
|
||||
if (num)
|
||||
{ // LDO2 , LDO3
|
||||
std::uint_fast8_t reg12bit = 1 << num;
|
||||
if (voltage < 0)
|
||||
{
|
||||
bitOff(0x12, reg12bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitOn(0x12, reg12bit);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // LDOio0
|
||||
writeRegister8(0x90, (voltage < 0) ? 0x07 : 0x02 ); /// floating or LDO
|
||||
}
|
||||
}
|
||||
|
||||
/// @param num 0=LDO2 / 1=LDO3
|
||||
void AXP192_Class::_set_LDO2_LDO3(std::uint8_t num, int voltage)
|
||||
{
|
||||
voltage -= 1800;
|
||||
std::uint_fast8_t val = (voltage < 0) ? 0 : std::min(voltage / 100, 0x0F);
|
||||
std::uint_fast8_t now = readRegister8(0x28);
|
||||
if (num == 1)
|
||||
{ /// LDO3
|
||||
now = (now & 0xF0) + val;
|
||||
}
|
||||
else
|
||||
{ /// LDO2
|
||||
now = (now & 0x0F) | (val << 4);
|
||||
}
|
||||
writeRegister8(0x28, now);
|
||||
|
||||
std::uint_fast8_t reg12bit = 1 << (num + 2);
|
||||
if (voltage < 0)
|
||||
{
|
||||
bitOff(0x12, reg12bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitOn(0x12, reg12bit);
|
||||
}
|
||||
}
|
||||
|
||||
/// @param num 0=GPIO0 / 1=GPIO1 / 2=GPIO2
|
||||
void AXP192_Class::_set_GPIO0_2(std::uint8_t num, bool state)
|
||||
{
|
||||
static constexpr uint8_t reg[] = { 0x90, 0x92, 0x93 };
|
||||
writeRegister8(reg[num], state ? 0x06 : 0x05); // floating or LOW
|
||||
}
|
||||
|
||||
/// @param num 0=GPIO3 / 1=GPIO4
|
||||
void AXP192_Class::_set_GPIO3_4(std::uint8_t num, bool state)
|
||||
{
|
||||
uint32_t bit = num ? 2 : 1;
|
||||
if (state)
|
||||
{
|
||||
bitOn(0x96, bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitOff(0x96, bit);
|
||||
}
|
||||
uint_fast8_t mask = num ? ~0x0C : ~0x03;
|
||||
uint_fast8_t reg0x95 = readRegister8(0x95) & mask;
|
||||
writeRegister8(0x95, reg0x95 | (num ? 0x84 : 0x81)); // set GPIO mode
|
||||
}
|
||||
|
||||
void AXP192_Class::setBatteryCharge(bool enable)
|
||||
{
|
||||
std::uint8_t val = 0;
|
||||
if (readRegister(0x33, &val, 1))
|
||||
{
|
||||
writeRegister8(0x33, (val & 0x7F) + (enable ? 0x80 : 0x00));
|
||||
}
|
||||
}
|
||||
|
||||
void AXP192_Class::setChargeCurrent(std::uint16_t max_mA)
|
||||
{
|
||||
max_mA /= 10;
|
||||
if (max_mA > 132) { max_mA = 132; }
|
||||
static constexpr std::uint8_t table[] = { 19, 28, 36, 45, 55, 63, 70, 78, 88, 96, 100, 108, 116, 124, 132, 255 };
|
||||
|
||||
size_t i = 0;
|
||||
while (table[i] <= max_mA) { ++i; }
|
||||
|
||||
std::uint8_t val = 0;
|
||||
if (readRegister(0x33, &val, 1))
|
||||
{
|
||||
writeRegister8(0x33, (val & 0xF0) + i);
|
||||
}
|
||||
}
|
||||
|
||||
void AXP192_Class::setChargeVoltage(std::uint16_t max_mV)
|
||||
{
|
||||
max_mV = (max_mV / 10) - 410;
|
||||
if (max_mV > 436 - 410) { max_mV = 436 - 410; }
|
||||
static constexpr std::uint8_t table[] =
|
||||
{ 415 - 410 /// 4150mV
|
||||
, 420 - 410 /// 4200mV
|
||||
, 436 - 410 /// 4360mV
|
||||
, 255
|
||||
};
|
||||
size_t i = 0;
|
||||
while (table[i] <= max_mV) { ++i; }
|
||||
|
||||
std::uint8_t val = 0;
|
||||
if (readRegister(0x33, &val, 1))
|
||||
{
|
||||
writeRegister8(0x33, (val & 0x9F) + (i << 5));
|
||||
}
|
||||
}
|
||||
|
||||
std::int8_t AXP192_Class::getBatteryLevel(void)
|
||||
{
|
||||
std::uint8_t buf[4];
|
||||
if (!readRegister(0x78, buf, 4)) { return -1; }
|
||||
|
||||
std::uint_fast16_t voltage = (buf[0] << 4) + buf[1];
|
||||
std::uint_fast16_t current = (buf[2] << 5) + buf[3];
|
||||
|
||||
std::int_fast16_t res = (voltage > 3150) ? (( voltage - 3075 ) * 0.16f )
|
||||
: (voltage > 2690) ? (( voltage - 2690 ) * 0.027f )
|
||||
: 0;
|
||||
if (current > 16) { res -= 16; }
|
||||
|
||||
return (res < 100) ? res : 100;
|
||||
}
|
||||
|
||||
bool AXP192_Class::isCharging(void)
|
||||
{
|
||||
return readRegister8(0x00) & 0x04;
|
||||
}
|
||||
|
||||
void AXP192_Class::powerOff(void)
|
||||
{
|
||||
bitOn(0x32, 0x80);
|
||||
}
|
||||
|
||||
void AXP192_Class::setAdcState(bool enable)
|
||||
{
|
||||
writeRegister8(0x82, enable ? 0xff : 0x00);
|
||||
}
|
||||
|
||||
void AXP192_Class::setAdcRate( std::uint8_t rate )
|
||||
{
|
||||
std::uint_fast8_t buf = readRegister8(0x84);
|
||||
writeRegister8(0x84, (buf & ~(0xc0)) | (rate & 0xc0));
|
||||
}
|
||||
|
||||
void AXP192_Class::setEXTEN(bool enable)
|
||||
{
|
||||
static constexpr std::uint8_t add = 0x12;
|
||||
static constexpr std::uint8_t bit = 1 << 6;
|
||||
if (enable)
|
||||
{
|
||||
bitOn(add, bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitOff(add, bit);
|
||||
}
|
||||
}
|
||||
|
||||
bool AXP192_Class::getEXTEN(void)
|
||||
{
|
||||
return readRegister8(0x12) & (1 << 6);
|
||||
}
|
||||
|
||||
void AXP192_Class::setBACKUP(bool enable)
|
||||
{
|
||||
static constexpr std::uint8_t add = 0x35;
|
||||
static constexpr std::uint8_t bit = 1 << 7;
|
||||
if (enable)
|
||||
{ // Enable
|
||||
bitOn(add, bit);
|
||||
}
|
||||
else
|
||||
{ // Disable
|
||||
bitOff(add, bit);
|
||||
}
|
||||
}
|
||||
|
||||
bool AXP192_Class::isACIN(void)
|
||||
{
|
||||
return readRegister8(0x00) & 0x80;
|
||||
}
|
||||
bool AXP192_Class::isVBUS(void)
|
||||
{
|
||||
return readRegister8(0x00) & 0x20;
|
||||
}
|
||||
|
||||
bool AXP192_Class::getBatState(void)
|
||||
{
|
||||
return readRegister8(0x01) & 0x20;
|
||||
}
|
||||
|
||||
std::uint8_t AXP192_Class::getPekPress(void)
|
||||
{
|
||||
std::uint8_t val = readRegister8(0x46) & 0x03;
|
||||
if (val) { writeRegister8(0x46, val); }
|
||||
return val;
|
||||
}
|
||||
|
||||
float AXP192_Class::getACINVoltage(void)
|
||||
{
|
||||
return readRegister12(0x56) * (1.7f / 1000.0f);
|
||||
}
|
||||
|
||||
float AXP192_Class::getACINCurrent(void)
|
||||
{
|
||||
return readRegister12(0x58) * 0.625f;
|
||||
}
|
||||
|
||||
float AXP192_Class::getVBUSVoltage(void)
|
||||
{
|
||||
return readRegister12(0x5a) * (1.7f / 1000.0f);
|
||||
}
|
||||
|
||||
float AXP192_Class::getVBUSCurrent(void)
|
||||
{
|
||||
return readRegister12(0x5c) * 0.375f;
|
||||
}
|
||||
|
||||
float AXP192_Class::getInternalTemperature(void)
|
||||
{
|
||||
return readRegister12(0x5e) * 0.1f -144.7f;
|
||||
}
|
||||
|
||||
float AXP192_Class::getBatteryPower(void)
|
||||
{
|
||||
return readRegister24(0x70) * (1.1f * 0.5f / 1000.0f);
|
||||
}
|
||||
|
||||
float AXP192_Class::getBatteryVoltage(void)
|
||||
{
|
||||
return readRegister12(0x78) * (1.1f / 1000.0f);
|
||||
}
|
||||
|
||||
float AXP192_Class::getBatteryChargeCurrent(void)
|
||||
{
|
||||
return readRegister13(0x7a) * 0.5f;
|
||||
}
|
||||
|
||||
float AXP192_Class::getBatteryDischargeCurrent(void)
|
||||
{
|
||||
return readRegister13(0x7c) * 0.5f;
|
||||
}
|
||||
|
||||
float AXP192_Class::getAPSVoltage(void)
|
||||
{
|
||||
return readRegister12(0x7e) * (1.4f / 1000.0f);
|
||||
}
|
||||
|
||||
|
||||
std::size_t AXP192_Class::readRegister12(std::uint8_t addr)
|
||||
{
|
||||
std::uint8_t buf[2] = {0};
|
||||
readRegister(addr, buf, 2);
|
||||
return buf[0] << 4 | buf[1];
|
||||
}
|
||||
std::size_t AXP192_Class::readRegister13(std::uint8_t addr)
|
||||
{
|
||||
std::uint8_t buf[2] = {0};
|
||||
readRegister(addr, buf, 2);
|
||||
return buf[0] << 5 | buf[1];
|
||||
}
|
||||
std::size_t AXP192_Class::readRegister16(std::uint8_t addr)
|
||||
{
|
||||
std::uint8_t buf[2] = {0};
|
||||
readRegister(addr, buf, 2);
|
||||
return buf[0] << 8 | buf[1];
|
||||
}
|
||||
std::size_t AXP192_Class::readRegister24(std::uint8_t addr)
|
||||
{
|
||||
std::uint8_t buf[3] = {0};
|
||||
readRegister(addr, buf, 3);
|
||||
return buf[0] << 16 | buf[1] << 8 | buf[2];
|
||||
}
|
||||
std::size_t AXP192_Class::readRegister32(std::uint8_t addr)
|
||||
{
|
||||
std::uint8_t buf[4] = {0};
|
||||
readRegister(addr, buf, 4);
|
||||
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
|
||||
}
|
||||
}
|
||||
109
libraries/M5Unified/src/utility/AXP192_Class.hpp
Normal file
109
libraries/M5Unified/src/utility/AXP192_Class.hpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_AXP192_CLASS_H__
|
||||
#define __M5_AXP192_CLASS_H__
|
||||
|
||||
#include "I2C_Class.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class AXP192_Class : public I2C_Device
|
||||
{
|
||||
public:
|
||||
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x34;
|
||||
|
||||
AXP192_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C)
|
||||
: I2C_Device ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
|
||||
bool begin(void);
|
||||
|
||||
/// Get the remaining battery power.
|
||||
/// @return 0-100 level
|
||||
std::int8_t getBatteryLevel(void);
|
||||
|
||||
/// set battery charge enable.
|
||||
/// @param enable true=enable / false=disable
|
||||
void setBatteryCharge(bool enable);
|
||||
|
||||
/// set battery charge current
|
||||
/// @param max_mA milli ampere. (100 - 1320).
|
||||
void setChargeCurrent(std::uint16_t max_mA);
|
||||
|
||||
/// set battery charge voltage
|
||||
/// @param max_mV milli volt. (4100 - 4360).
|
||||
void setChargeVoltage(std::uint16_t max_mV);
|
||||
|
||||
/// Get whether the battery is currently charging or not.
|
||||
bool isCharging(void);
|
||||
|
||||
inline void setDCDC1(int voltage) { _set_DCDC(0, voltage); }
|
||||
inline void setDCDC2(int voltage) { _set_DCDC(1, voltage); }
|
||||
inline void setDCDC3(int voltage) { _set_DCDC(2, voltage); }
|
||||
|
||||
/// set LDOio0 voltage
|
||||
/// @param voltage milli volt. (0 - 3300).
|
||||
inline void setLDO0(int voltage) { _set_LDO(0, voltage); }
|
||||
|
||||
/// set LDO2 voltage
|
||||
/// @param voltage milli volt. (0 - 3300).
|
||||
inline void setLDO2(int voltage) { _set_LDO(2, voltage); }
|
||||
|
||||
/// set LDO3 voltage
|
||||
/// @param voltage milli volt. (0 - 3300).
|
||||
inline void setLDO3(int voltage) { _set_LDO(3, voltage); }
|
||||
|
||||
inline void setGPIO(uint8_t gpio_num, bool state) { if (gpio_num < 3) { _set_GPIO0_2(gpio_num, state); } else { _set_GPIO3_4(gpio_num - 3, state); } }
|
||||
inline void setGPIO0(bool state) { _set_GPIO0_2(0, state); }
|
||||
inline void setGPIO1(bool state) { _set_GPIO0_2(1, state); }
|
||||
inline void setGPIO2(bool state) { _set_GPIO0_2(2, state); }
|
||||
inline void setGPIO3(bool state) { _set_GPIO3_4(0, state); }
|
||||
inline void setGPIO4(bool state) { _set_GPIO3_4(1, state); }
|
||||
|
||||
void powerOff(void);
|
||||
|
||||
void setAdcState(bool enable);
|
||||
void setAdcRate( std::uint8_t rate );
|
||||
|
||||
void setEXTEN(bool enable);
|
||||
void setBACKUP(bool enable);
|
||||
|
||||
bool isACIN(void);
|
||||
bool isVBUS(void);
|
||||
bool getBatState(void);
|
||||
bool getEXTEN(void);
|
||||
|
||||
float getBatteryVoltage(void);
|
||||
float getBatteryDischargeCurrent(void);
|
||||
float getBatteryChargeCurrent(void);
|
||||
float getBatteryPower(void);
|
||||
float getACINVoltage(void);
|
||||
float getACINCurrent(void);
|
||||
float getVBUSVoltage(void);
|
||||
float getVBUSCurrent(void);
|
||||
float getAPSVoltage(void);
|
||||
float getInternalTemperature(void);
|
||||
|
||||
std::uint8_t getPekPress(void);
|
||||
|
||||
[[deprecated("use getACINVoltage()")]]
|
||||
inline float getACINVolatge(void) { return getACINVoltage(); }
|
||||
|
||||
private:
|
||||
std::size_t readRegister12(std::uint8_t addr);
|
||||
std::size_t readRegister13(std::uint8_t addr);
|
||||
std::size_t readRegister16(std::uint8_t addr);
|
||||
std::size_t readRegister24(std::uint8_t addr);
|
||||
std::size_t readRegister32(std::uint8_t addr);
|
||||
|
||||
void _set_DCDC(std::uint8_t num, int voltage);
|
||||
void _set_LDO(std::uint8_t num, int voltage);
|
||||
void _set_LDO2_LDO3(std::uint8_t num, int voltage);
|
||||
void _set_GPIO0_2(std::uint8_t num, bool state);
|
||||
void _set_GPIO3_4(std::uint8_t num, bool state);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
584
libraries/M5Unified/src/utility/AXP2101_Class.cpp
Normal file
584
libraries/M5Unified/src/utility/AXP2101_Class.cpp
Normal file
|
|
@ -0,0 +1,584 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "AXP2101_Class.hpp"
|
||||
|
||||
#if __has_include(<esp_log.h>)
|
||||
#include <esp_log.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define IS_BIT_SET(val,mask) (((val)&(mask)) == (mask))
|
||||
|
||||
namespace m5
|
||||
{
|
||||
/*
|
||||
DCDC1 : 1.5-3.4V, 2000mA
|
||||
DCDC2 : 0.5-1.2V,1.22-1.54V, 2000mA
|
||||
DCDC3 : 0.5-1.2V,1.22-1.54V, 1.6-3.4V, 2000mA
|
||||
DCDC4 : 0.5-1.2V, 1.22-1.84V, 1500mA
|
||||
DCDC5 : 1.2V , 1.4-3.7V, 1000mA
|
||||
|
||||
RTCLDO1/2 : 1.8V/2.5V/3V/3.3V, 30mA
|
||||
|
||||
ALDO1~4 : 0.5-3.5V, 100mV/step 300mA
|
||||
*/
|
||||
bool AXP2101_Class::begin(void)
|
||||
{
|
||||
std::uint8_t val;
|
||||
_init = readRegister(0x03, &val, 1);
|
||||
if (_init)
|
||||
{
|
||||
_init = (val == 0x4A);
|
||||
#if defined (ESP_LOGV)
|
||||
// ESP_LOGV("AXP2101", "reg03h:%02x : init:%d", val, _init);
|
||||
#endif
|
||||
}
|
||||
return _init;
|
||||
}
|
||||
|
||||
// 0=ALDO1 ~ 3=ALDO4 / 4=BLDO1 / 5=BLDO2
|
||||
void AXP2101_Class::_set_LDO(std::uint8_t num, int voltage)
|
||||
{
|
||||
if (num > 5) return;
|
||||
std::uint8_t reg_volt = num + 0x92;
|
||||
voltage -= 500;
|
||||
/// convert voltage to value
|
||||
std::uint_fast8_t val = (voltage < 0) ? 0 : std::min(voltage / 100, 0x1E);
|
||||
writeRegister8(reg_volt, val);
|
||||
|
||||
std::uint_fast8_t reg90bit = 1 << num;
|
||||
if (voltage < 0)
|
||||
{
|
||||
bitOff(0x90, reg90bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitOn(0x90, reg90bit);
|
||||
}
|
||||
}
|
||||
|
||||
void AXP2101_Class::_set_DLDO(std::uint8_t num, int voltage)
|
||||
{
|
||||
if (num > 1) return;
|
||||
|
||||
std::uint8_t reg_volt = num + 0x99;
|
||||
voltage -= 500;
|
||||
/// convert voltage to value
|
||||
std::uint_fast8_t val = (voltage < 0) ? 0 : std::min(voltage / (num ? 50 : 100), num ? 0x13 : 0x1C);
|
||||
writeRegister8(reg_volt, val);
|
||||
|
||||
uint8_t reg = 0x90 + num;
|
||||
uint8_t bit = num ? 0x01 : 0x80;
|
||||
if (voltage < 0)
|
||||
{
|
||||
bitOff(reg, bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitOn(reg, bit);
|
||||
}
|
||||
}
|
||||
|
||||
bool AXP2101_Class::_get_LDOEn(std::uint8_t num)
|
||||
{
|
||||
bool res = false;
|
||||
if (num <= 5) {
|
||||
std::uint_fast8_t reg90bit = 1 << num;
|
||||
res = readRegister8(0x90) & reg90bit;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void AXP2101_Class::setBatteryCharge(bool enable)
|
||||
{
|
||||
std::uint8_t val = 0;
|
||||
if (readRegister(0x18, &val, 1))
|
||||
{
|
||||
writeRegister8(0x18, (val & 0xFD) | (enable << 1));
|
||||
}
|
||||
}
|
||||
|
||||
void AXP2101_Class::setPreChargeCurrent(std::uint16_t max_mA)
|
||||
{
|
||||
static constexpr std::uint8_t table[] = { 0, 25, 50, 75, 100, 125, 150, 175, 200, 255 };
|
||||
if (max_mA > 200) { max_mA = 200; }
|
||||
|
||||
size_t i = 0;
|
||||
while (table[i] <= max_mA) { ++i; }
|
||||
i -= 1;
|
||||
writeRegister8(0x61, i);
|
||||
}
|
||||
|
||||
void AXP2101_Class::setChargeCurrent(std::uint16_t max_mA)
|
||||
{
|
||||
max_mA /= 5;
|
||||
if (max_mA > 1000/5) { max_mA = 1000/5; }
|
||||
static constexpr std::uint8_t table[] = { 125 / 5, 150 / 5, 175 / 5, 200 / 5, 300 / 5, 400 / 5, 500 / 5, 600 / 5, 700 / 5, 800 / 5, 900 / 5, 1000 / 5, 255 };
|
||||
|
||||
size_t i = 0;
|
||||
while (table[i] <= max_mA) { ++i; }
|
||||
i += 4;
|
||||
writeRegister8(0x62, i);
|
||||
}
|
||||
|
||||
void AXP2101_Class::setChargeVoltage(std::uint16_t max_mV)
|
||||
{
|
||||
max_mV = (max_mV / 10) - 400;
|
||||
if (max_mV > 460 - 400) { max_mV = 460 - 400; }
|
||||
static constexpr std::uint8_t table[] =
|
||||
{ 410 - 400 /// 4100mV
|
||||
, 420 - 400 /// 4200mV
|
||||
, 435 - 400 /// 4350mV
|
||||
, 440 - 400 /// 4400mV
|
||||
, 460 - 400 /// 4600mV
|
||||
, 255
|
||||
};
|
||||
size_t i = 0;
|
||||
while (table[i] <= max_mV) { ++i; }
|
||||
|
||||
if (++i >= 0b110) { i = 0; }
|
||||
writeRegister8(0x64, i);
|
||||
}
|
||||
|
||||
std::int8_t AXP2101_Class::getBatteryLevel(void)
|
||||
{
|
||||
std::int8_t res = readRegister8(0xA4);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// @return -1:discharge / 0:standby / 1:charge
|
||||
int AXP2101_Class::getChargeStatus(void)
|
||||
{
|
||||
uint32_t val = (readRegister8(0x01) >> 5) & 0b11;
|
||||
// 0b01:charge / 0b10:dischage / 0b00:stanby
|
||||
return (val == 1) ? 1 : ((val == 2) ? -1 : 0);
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isCharging(void)
|
||||
{
|
||||
return (readRegister8(0x01) & 0b01100000) == 0b00100000;
|
||||
}
|
||||
|
||||
void AXP2101_Class::powerOff(void)
|
||||
{
|
||||
bitOn(0x10, 0x01);
|
||||
}
|
||||
|
||||
//enable all ADC channel control or set default values
|
||||
void AXP2101_Class::setAdcState(bool enable)
|
||||
{
|
||||
writeRegister8(0x30, enable == true ? 0b111111 : 0b11);
|
||||
}
|
||||
|
||||
void AXP2101_Class::setAdcRate( std::uint8_t rate )
|
||||
{
|
||||
}
|
||||
|
||||
void AXP2101_Class::setBACKUP(bool enable)
|
||||
{
|
||||
/*
|
||||
static constexpr std::uint8_t add = 0x35;
|
||||
static constexpr std::uint8_t bit = 1 << 7;
|
||||
if (enable)
|
||||
{ // Enable
|
||||
bitOn(add, bit);
|
||||
}
|
||||
else
|
||||
{ // Disable
|
||||
bitOff(add, bit);
|
||||
}
|
||||
//*/
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isACIN(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool AXP2101_Class::isVBUS(void)
|
||||
{ // VBUS good indication
|
||||
return readRegister8(0x00) & 0x20;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::getBatState(void)
|
||||
{ // Battery present state
|
||||
return readRegister8(0x00) & 0x08;
|
||||
}
|
||||
|
||||
std::uint8_t AXP2101_Class::getPekPress(void)
|
||||
{
|
||||
std::uint8_t val = readRegister8(0x49) & 0x0C;
|
||||
if (val) { writeRegister8(0x49, val); }
|
||||
return val >> 2;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getACINVoltage(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getACINCurrent(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getVBUSVoltage(void)
|
||||
{
|
||||
if (isVBUS() == false) { return 0.0f; }
|
||||
|
||||
float vBus = readRegister14(0x38);
|
||||
if (vBus >= 16375) { return 0.0f; }
|
||||
|
||||
return vBus / 1000.0f;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getVBUSCurrent(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getTSVoltage(void)
|
||||
{
|
||||
float volt = readRegister14(0x36);
|
||||
if (volt >= 16375) { return 0.0f; }
|
||||
|
||||
return volt / 2000.0f;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getInternalTemperature(void)
|
||||
{
|
||||
return 22 + ((7274 - readRegister16(0x3C)) / 20);
|
||||
}
|
||||
|
||||
float AXP2101_Class::getBatteryPower(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getBatteryVoltage(void)
|
||||
{
|
||||
return readRegister14(0x34) / 1000.0f;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getBatteryChargeCurrent(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getBatteryDischargeCurrent(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float AXP2101_Class::getAPSVoltage(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::enableIRQ(std::uint64_t registerEn)
|
||||
{
|
||||
return setIRQEnRegister(registerEn, true);
|
||||
}
|
||||
|
||||
bool AXP2101_Class::disableIRQ(std::uint64_t registerEn)
|
||||
{
|
||||
return setIRQEnRegister(registerEn, false);
|
||||
}
|
||||
|
||||
bool AXP2101_Class::setIRQEnRegister(std::uint64_t registerEn, bool enable)
|
||||
{
|
||||
int res = 0;
|
||||
uint8_t data = 0, value = 0;
|
||||
if (registerEn & 0x0000FF)
|
||||
{
|
||||
value = registerEn & 0xFF;
|
||||
data = readRegister8(AXP2101_IRQEN0);
|
||||
intRegister[0] = enable ? (data | value) : (data & (~value));
|
||||
res |= writeRegister8(AXP2101_IRQEN0, intRegister[0]);
|
||||
}
|
||||
if (registerEn & 0x00FF00)
|
||||
{
|
||||
value = registerEn >> 8;
|
||||
data = readRegister8(AXP2101_IRQEN1);
|
||||
intRegister[1] = enable ? (data | value) : (data & (~value));
|
||||
res |= writeRegister8(AXP2101_IRQEN1, intRegister[1]);
|
||||
}
|
||||
if (registerEn & 0xFF0000)
|
||||
{
|
||||
value = registerEn >> 16;
|
||||
data = readRegister8(AXP2101_IRQEN2);
|
||||
intRegister[2] = enable ? (data | value) : (data & (~value));
|
||||
res |= writeRegister8(AXP2101_IRQEN2, intRegister[2]);
|
||||
}
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
std::uint64_t AXP2101_Class::getIRQStatuses(void)
|
||||
{
|
||||
statusRegister[0] = readRegister8(AXP2101_IRQSTAT0);
|
||||
statusRegister[1] = readRegister8(AXP2101_IRQSTAT1);
|
||||
statusRegister[2] = readRegister8(AXP2101_IRQSTAT2);
|
||||
return (uint32_t)(statusRegister[0] << 16) | (uint32_t)(statusRegister[1] << 8) | (uint32_t)(statusRegister[2]);
|
||||
}
|
||||
|
||||
void AXP2101_Class::clearIRQStatuses()
|
||||
{
|
||||
for (int i = 0; i < AXP2101_IRQSTAT_CNT; i++)
|
||||
{
|
||||
writeRegister8(AXP2101_IRQSTAT0 + i, 0xFF);
|
||||
statusRegister[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isDropWarningLevel2Irq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_WARNING_LEVEL2;
|
||||
if (intRegister[0] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[0], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isDropWarningLevel1Irq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_WARNING_LEVEL1;
|
||||
if (intRegister[0] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[0], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isGaugeWdtTimeoutIrq()
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_GAUGE_WDT_TIMEOUT;
|
||||
if (intRegister[0] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[0], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatChargerOverTemperatureIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BAT_CHG_OVER_TEMP;
|
||||
if (intRegister[0] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[0], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatChargerUnderTemperatureIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BAT_CHG_UNDER_TEMP;
|
||||
if (intRegister[0] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[0], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatWorkOverTemperatureIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BAT_OVER_TEMP;
|
||||
if (intRegister[0] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[0], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatWorkUnderTemperatureIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BAT_UNDER_TEMP;
|
||||
if (intRegister[0] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[0], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isVbusInsertIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_VBUS_INSERT >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[1], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isVbusRemoveIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_VBUS_REMOVE >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[1], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatInsertIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BAT_INSERT >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[1], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatRemoveIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BAT_REMOVE >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[1], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isPekeyShortPressIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_PKEY_SHORT_PRESS >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[1], mask);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isPekeyLongPressIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_PKEY_LONG_PRESS >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[1], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isPekeyNegativeIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_PKEY_NEGATIVE_EDGE >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[1], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isPekeyPositiveIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_PKEY_POSITIVE_EDGE >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[1], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isWdtExpireIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_WDT_EXPIRE >> 16;
|
||||
if (intRegister[2] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[2], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isLdoOverCurrentIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_LDO_OVER_CURR >> 16;
|
||||
if (intRegister[2] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[2], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatfetOverCurrentIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BATFET_OVER_CURR >> 16;
|
||||
if (intRegister[2] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[2], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatChagerDoneIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BAT_CHG_DONE >> 16;
|
||||
if (intRegister[2] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[2], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatChagerStartIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BAT_CHG_START >> 16;
|
||||
if (intRegister[2] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[2], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatDieOverTemperatureIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_DIE_OVER_TEMP >> 16;
|
||||
if (intRegister[2] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[2], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isChagerOverTimeoutIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_CHAGER_TIMER >> 16;
|
||||
if (intRegister[2] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[2], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AXP2101_Class::isBatOverVoltageIrq(void)
|
||||
{
|
||||
uint8_t mask = AXP2101_IRQ_BAT_OVER_VOLTAGE >> 16;
|
||||
if (intRegister[2] & mask)
|
||||
{
|
||||
return IS_BIT_SET(statusRegister[2], mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t AXP2101_Class::readRegister12(std::uint8_t addr)
|
||||
{
|
||||
std::uint8_t buf[2] = {0};
|
||||
readRegister(addr, buf, 2);
|
||||
return (buf[0] & 0x0F) << 8 | buf[1];
|
||||
}
|
||||
std::size_t AXP2101_Class::readRegister14(std::uint8_t addr)
|
||||
{
|
||||
std::uint8_t buf[2] = {0};
|
||||
readRegister(addr, buf, 2);
|
||||
return (buf[0] & 0x3F) << 8 | buf[1];
|
||||
}
|
||||
std::size_t AXP2101_Class::readRegister16(std::uint8_t addr)
|
||||
{
|
||||
std::uint8_t buf[2] = {0};
|
||||
readRegister(addr, buf, 2);
|
||||
return buf[0] << 8 | buf[1];
|
||||
}
|
||||
|
||||
}
|
||||
188
libraries/M5Unified/src/utility/AXP2101_Class.hpp
Normal file
188
libraries/M5Unified/src/utility/AXP2101_Class.hpp
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_AXP2101_CLASS_H__
|
||||
#define __M5_AXP2101_CLASS_H__
|
||||
|
||||
#include "I2C_Class.hpp"
|
||||
|
||||
//IRQ ENABLE REGISTER
|
||||
#define AXP2101_IRQEN0 0x40
|
||||
#define AXP2101_IRQEN1 0x41
|
||||
#define AXP2101_IRQEN2 0x42
|
||||
|
||||
//IRQ STATUS REGISTER
|
||||
#define AXP2101_IRQSTAT0 0x48
|
||||
#define AXP2101_IRQSTAT1 0x49
|
||||
#define AXP2101_IRQSTAT2 0x4A
|
||||
#define AXP2101_IRQSTAT_CNT 3
|
||||
|
||||
|
||||
namespace m5
|
||||
{
|
||||
typedef enum {
|
||||
AXP2101_IRQ_BAT_UNDER_TEMP = 1 << 0, // Battery Under Temperature in Work mode IRQ(bwut_irq)
|
||||
AXP2101_IRQ_BAT_OVER_TEMP = 1 << 1, // Battery Over Temperature in Work mode IRQ(bwot_irq)
|
||||
AXP2101_IRQ_BAT_CHG_UNDER_TEMP = 1 << 2, // Battery Under Temperature in Charge mode IRQ(bcut_irq)
|
||||
AXP2101_IRQ_BAT_CHG_OVER_TEMP = 1 << 3, // Battery Over Temperature in Charge mode IRQ(bcot_irq)
|
||||
AXP2101_IRQ_GAUGE_NEW_SOC = 1 << 4, // Gauge New SOC IRQ(lowsoc_irq)
|
||||
AXP2101_IRQ_GAUGE_WDT_TIMEOUT = 1 << 5, // Gauge Watchdog Timeout IRQ(gwdt_irq)
|
||||
AXP2101_IRQ_WARNING_LEVEL1 = 1 << 6, // SOC drop to Warning Level1 IRQ(socwl1_irq)
|
||||
AXP2101_IRQ_WARNING_LEVEL2 = 1 << 7, // SOC drop to Warning Level2 IRQ(socwl2_irq)
|
||||
|
||||
// IRQ2 REG 41H
|
||||
AXP2101_IRQ_PKEY_POSITIVE_EDGE = 1 << 8, // POWERON Positive Edge IRQ(ponpe_irq_en)
|
||||
AXP2101_IRQ_PKEY_NEGATIVE_EDGE = 1 << 9, // POWERON Negative Edge IRQ(ponne_irq_en)
|
||||
AXP2101_IRQ_PKEY_LONG_PRESS = 1 << 10, // POWERON Long PRESS IRQ(ponlp_irq)
|
||||
AXP2101_IRQ_PKEY_SHORT_PRESS = 1 << 11, // POWERON Short PRESS IRQ(ponsp_irq_en)
|
||||
AXP2101_IRQ_BAT_REMOVE = 1 << 12, // Battery Remove IRQ(bremove_irq)
|
||||
AXP2101_IRQ_BAT_INSERT = 1 << 13, // Battery Insert IRQ(binsert_irq)
|
||||
AXP2101_IRQ_VBUS_REMOVE = 1 << 14, // VBUS Remove IRQ(vremove_irq)
|
||||
AXP2101_IRQ_VBUS_INSERT = 1 << 15, // VBUS Insert IRQ(vinsert_irq)
|
||||
|
||||
// IRQ3 REG 42H
|
||||
AXP2101_IRQ_BAT_OVER_VOLTAGE = 1 << 16, // Battery Over Voltage Protection IRQ(bovp_irq)
|
||||
AXP2101_IRQ_CHAGER_TIMER = 1 << 17, // Charger Safety Timer1/2 expire IRQ(chgte_irq)
|
||||
AXP2101_IRQ_DIE_OVER_TEMP = 1 << 18, // DIE Over Temperature level1 IRQ(dotl1_irq)
|
||||
AXP2101_IRQ_BAT_CHG_START = 1 << 19, // Charger start IRQ(chgst_irq)
|
||||
AXP2101_IRQ_BAT_CHG_DONE = 1 << 20, // Battery charge done IRQ(chgdn_irq)
|
||||
AXP2101_IRQ_BATFET_OVER_CURR = 1 << 21, // BATFET Over Current Protection IRQ(bocp_irq)
|
||||
AXP2101_IRQ_LDO_OVER_CURR = 1 << 22, // LDO Over Current IRQ(ldooc_irq)
|
||||
AXP2101_IRQ_WDT_EXPIRE = 1 << 23, // Watchdog Expire IRQ(wdexp_irq)
|
||||
|
||||
// ALL IRQ
|
||||
AXP2101_IRQ_ALL = (0xFFFFFFFFUL)
|
||||
} axp2101_irq_t;
|
||||
class AXP2101_Class : public I2C_Device
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t AXP2101_EFUS_OP_CFG = 0xF0;
|
||||
static constexpr uint8_t AXP2101_EFREQ_CTRL = 0xF1;
|
||||
static constexpr uint8_t AXP2101_TWI_ADDR_EXT = 0xFF;
|
||||
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x34;
|
||||
|
||||
AXP2101_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C)
|
||||
: I2C_Device ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
|
||||
bool begin(void);
|
||||
|
||||
/// Get the remaining battery power.
|
||||
/// @return 0-100 level
|
||||
std::int8_t getBatteryLevel(void);
|
||||
|
||||
/// set battery charge enable.
|
||||
/// @param enable true=enable / false=disable
|
||||
void setBatteryCharge(bool enable);
|
||||
|
||||
/// set battery precharge current
|
||||
/// @param max_mA milli ampere. (0 - 200).
|
||||
void setPreChargeCurrent(std::uint16_t max_mA);
|
||||
|
||||
/// set battery charge current
|
||||
/// @param max_mA milli ampere. (100 - 1320).
|
||||
void setChargeCurrent(std::uint16_t max_mA);
|
||||
|
||||
/// set battery charge voltage
|
||||
/// @param max_mV milli volt. (4100 - 4360).
|
||||
void setChargeVoltage(std::uint16_t max_mV);
|
||||
|
||||
/// @return -1:discharge / 0:standby / 1:charge
|
||||
int getChargeStatus(void);
|
||||
|
||||
/// Get whether the battery is currently charging or not.
|
||||
bool isCharging(void);
|
||||
|
||||
|
||||
inline void setALDO1(int voltage) { _set_LDO(0, voltage); }
|
||||
inline void setALDO2(int voltage) { _set_LDO(1, voltage); }
|
||||
inline void setALDO3(int voltage) { _set_LDO(2, voltage); }
|
||||
inline void setALDO4(int voltage) { _set_LDO(3, voltage); }
|
||||
inline void setBLDO1(int voltage) { _set_LDO(4, voltage); }
|
||||
inline void setBLDO2(int voltage) { _set_LDO(5, voltage); }
|
||||
inline void setDLDO1(int voltage) { _set_DLDO(0, voltage); }
|
||||
inline void setDLDO2(int voltage) { _set_DLDO(1, voltage); }
|
||||
|
||||
inline bool getALDO1Enabled(void) { return _get_LDOEn(0); }
|
||||
inline bool getALDO2Enabled(void) { return _get_LDOEn(1); }
|
||||
inline bool getALDO3Enabled(void) { return _get_LDOEn(2); }
|
||||
inline bool getALDO4Enabled(void) { return _get_LDOEn(3); }
|
||||
inline bool getBLDO1Enabled(void) { return _get_LDOEn(4); }
|
||||
inline bool getBLDO2Enabled(void) { return _get_LDOEn(5); }
|
||||
|
||||
void powerOff(void);
|
||||
|
||||
void setAdcState(bool enable);
|
||||
void setAdcRate( std::uint8_t rate );
|
||||
|
||||
void setBACKUP(bool enable);
|
||||
|
||||
bool isACIN(void);
|
||||
bool isVBUS(void);
|
||||
bool getBatState(void);
|
||||
|
||||
float getBatteryVoltage(void);
|
||||
float getBatteryDischargeCurrent(void);
|
||||
float getBatteryChargeCurrent(void);
|
||||
float getBatteryPower(void);
|
||||
float getACINVoltage(void);
|
||||
float getACINCurrent(void);
|
||||
float getVBUSVoltage(void);
|
||||
float getVBUSCurrent(void);
|
||||
float getTSVoltage(void);
|
||||
float getAPSVoltage(void);
|
||||
float getInternalTemperature(void);
|
||||
|
||||
/// @return 0:none / 1:Long press / 2:Short press / 3:both
|
||||
std::uint8_t getPekPress(void);
|
||||
|
||||
bool enableIRQ(std::uint64_t registerEn);
|
||||
bool disableIRQ(std::uint64_t registerEn);
|
||||
std::uint64_t getIRQStatuses(void);
|
||||
void clearIRQStatuses();
|
||||
//IRQ STATUS 0
|
||||
bool isDropWarningLevel2Irq(void);
|
||||
bool isDropWarningLevel1Irq(void);
|
||||
bool isGaugeWdtTimeoutIrq();
|
||||
bool isBatChargerUnderTemperatureIrq(void);
|
||||
bool isBatChargerOverTemperatureIrq(void);
|
||||
bool isBatWorkOverTemperatureIrq(void);
|
||||
bool isBatWorkUnderTemperatureIrq(void);
|
||||
//IRQ STATUS 1
|
||||
bool isVbusInsertIrq(void);
|
||||
bool isVbusRemoveIrq(void);
|
||||
bool isBatInsertIrq(void);
|
||||
bool isBatRemoveIrq(void);
|
||||
bool isPekeyShortPressIrq(void);
|
||||
bool isPekeyLongPressIrq(void);
|
||||
bool isPekeyNegativeIrq(void);
|
||||
bool isPekeyPositiveIrq(void);
|
||||
//IRQ STATUS 2
|
||||
bool isWdtExpireIrq(void);
|
||||
bool isLdoOverCurrentIrq(void);
|
||||
bool isBatfetOverCurrentIrq(void);
|
||||
bool isBatChagerDoneIrq(void);
|
||||
bool isBatChagerStartIrq(void);
|
||||
bool isBatDieOverTemperatureIrq(void);
|
||||
bool isChagerOverTimeoutIrq(void);
|
||||
bool isBatOverVoltageIrq(void);
|
||||
|
||||
|
||||
private:
|
||||
std::uint8_t statusRegister[AXP2101_IRQSTAT_CNT];
|
||||
std::uint8_t intRegister[AXP2101_IRQSTAT_CNT];
|
||||
|
||||
std::size_t readRegister12(std::uint8_t addr);
|
||||
std::size_t readRegister14(std::uint8_t addr);
|
||||
std::size_t readRegister16(std::uint8_t addr);
|
||||
|
||||
void _set_LDO(std::uint8_t num, int voltage);
|
||||
void _set_DLDO(std::uint8_t num, int voltage);
|
||||
bool _get_LDOEn(std::uint8_t num);
|
||||
|
||||
bool setIRQEnRegister(std::uint64_t registerEn, bool enable);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
84
libraries/M5Unified/src/utility/Button_Class.cpp
Normal file
84
libraries/M5Unified/src/utility/Button_Class.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "Button_Class.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
void Button_Class::setState(std::uint32_t msec, button_state_t state)
|
||||
{
|
||||
if (_currentState == state_decide_click_count)
|
||||
{
|
||||
_clickCount = 0;
|
||||
}
|
||||
|
||||
_lastMsec = msec;
|
||||
bool flg_timeout = (msec - _lastClicked > _msecHold);
|
||||
switch (state)
|
||||
{
|
||||
case state_nochange:
|
||||
if (flg_timeout && !_press && _clickCount)
|
||||
{
|
||||
if (_oldPress == 0 && _currentState == state_nochange)
|
||||
{
|
||||
state = state_decide_click_count;
|
||||
}
|
||||
else { _clickCount = 0; }
|
||||
}
|
||||
break;
|
||||
|
||||
case state_clicked:
|
||||
++_clickCount;
|
||||
_lastClicked = msec;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_currentState = state;
|
||||
}
|
||||
|
||||
void Button_Class::setRawState(std::uint32_t msec, bool press)
|
||||
{
|
||||
button_state_t state = button_state_t::state_nochange;
|
||||
bool disable_db = (msec - _lastMsec) > _msecDebounce;
|
||||
auto oldPress = _press;
|
||||
_oldPress = oldPress;
|
||||
if (_raw_press != press)
|
||||
{
|
||||
_raw_press = press;
|
||||
_lastRawChange = msec;
|
||||
}
|
||||
if (disable_db || msec - _lastRawChange >= _msecDebounce)
|
||||
{
|
||||
if (press != (0 != oldPress))
|
||||
{
|
||||
_lastChange = msec;
|
||||
}
|
||||
|
||||
if (press)
|
||||
{
|
||||
std::uint32_t holdPeriod = msec - _lastChange;
|
||||
_lastHoldPeriod = holdPeriod;
|
||||
if (!oldPress)
|
||||
{
|
||||
_press = 1;
|
||||
} else
|
||||
if (oldPress == 1 && (holdPeriod >= _msecHold))
|
||||
{
|
||||
_press = 2;
|
||||
state = button_state_t::state_hold;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_press = 0;
|
||||
if (oldPress == 1)
|
||||
{
|
||||
state = button_state_t::state_clicked;
|
||||
}
|
||||
}
|
||||
}
|
||||
setState(msec, state);
|
||||
}
|
||||
}
|
||||
86
libraries/M5Unified/src/utility/Button_Class.hpp
Normal file
86
libraries/M5Unified/src/utility/Button_Class.hpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_BUTTON_CLASS_H__
|
||||
#define __M5_BUTTON_CLASS_H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class Button_Class
|
||||
{
|
||||
public:
|
||||
enum button_state_t : std::uint8_t
|
||||
{ state_nochange
|
||||
, state_clicked
|
||||
, state_hold
|
||||
, state_decide_click_count
|
||||
};
|
||||
|
||||
/// Returns true when the button is pressed briefly and released.
|
||||
bool wasClicked(void) const { return _currentState == state_clicked; }
|
||||
|
||||
/// Returns true when the button has been held pressed for a while.
|
||||
bool wasHold(void) const { return _currentState == state_hold; }
|
||||
|
||||
/// Returns true when some time has passed since the button was single clicked.
|
||||
bool wasSingleClicked(void) const { return _currentState == state_decide_click_count && _clickCount == 1; }
|
||||
|
||||
/// Returns true when some time has passed since the button was double clicked.
|
||||
bool wasDoubleClicked(void) const { return _currentState == state_decide_click_count && _clickCount == 2; }
|
||||
|
||||
/// Returns true when some time has passed since the button was multiple clicked.
|
||||
bool wasDecideClickCount(void) const { return _currentState == state_decide_click_count; }
|
||||
|
||||
[[deprecated("use wasDecideClickCount()")]]
|
||||
bool wasDeciedClickCount(void) const { return wasDecideClickCount(); }
|
||||
|
||||
std::uint8_t getClickCount(void) const { return _clickCount; }
|
||||
|
||||
/// Returns true if the button is currently held pressed.
|
||||
bool isHolding(void) const { return _press == 2; }
|
||||
bool wasChangePressed(void) const { return ((bool)_press) != ((bool)_oldPress); }
|
||||
|
||||
bool isPressed(void) const { return _press; }
|
||||
bool isReleased(void) const { return !_press; }
|
||||
bool wasPressed(void) const { return !_oldPress && _press; }
|
||||
bool wasReleased(void) const { return _oldPress && !_press; }
|
||||
bool wasReleasedAfterHold(void) const { return !_press && _oldPress == 2; }
|
||||
bool wasReleaseFor(std::uint32_t ms) const { return _oldPress && !_press && _lastHoldPeriod >= ms; }
|
||||
|
||||
[[deprecated("use wasReleaseFor()")]]
|
||||
bool wasReleasefor(std::uint32_t ms) const { return wasReleaseFor(ms); }
|
||||
bool pressedFor(std::uint32_t ms) const { return (_press && _lastMsec - _lastChange >= ms); }
|
||||
bool releasedFor(std::uint32_t ms) const { return (!_press && _lastMsec - _lastChange >= ms); }
|
||||
|
||||
void setDebounceThresh(std::uint32_t msec) { _msecDebounce = msec; }
|
||||
void setHoldThresh(std::uint32_t msec) { _msecHold = msec; }
|
||||
|
||||
void setRawState(std::uint32_t msec, bool press);
|
||||
void setState(std::uint32_t msec, button_state_t state);
|
||||
button_state_t getState(void) const { return _currentState; }
|
||||
std::uint32_t lastChange(void) const { return _lastChange; }
|
||||
|
||||
std::uint32_t getDebounceThresh(void) const { return _msecDebounce; }
|
||||
std::uint32_t getHoldThresh(void) const { return _msecHold; }
|
||||
|
||||
std::uint32_t getUpdateMsec(void) const { return _lastMsec; }
|
||||
private:
|
||||
std::uint32_t _lastMsec = 0;
|
||||
std::uint32_t _lastChange = 0;
|
||||
std::uint32_t _lastRawChange = 0;
|
||||
std::uint32_t _lastClicked = 0;
|
||||
std::uint16_t _msecDebounce = 10;
|
||||
std::uint16_t _msecHold = 500;
|
||||
std::uint16_t _lastHoldPeriod = 0;
|
||||
button_state_t _currentState = state_nochange; // 0:nochange 1:click 2:hold
|
||||
bool _raw_press = false;
|
||||
std::uint8_t _press = 0; // 0:release 1:click 2:holding
|
||||
std::uint8_t _oldPress = 0;
|
||||
std::uint8_t _clickCount = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
125
libraries/M5Unified/src/utility/I2C_Class.cpp
Normal file
125
libraries/M5Unified/src/utility/I2C_Class.cpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "I2C_Class.hpp"
|
||||
|
||||
#include <M5GFX.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
I2C_Class In_I2C;
|
||||
I2C_Class Ex_I2C;
|
||||
|
||||
void I2C_Class::setPort(i2c_port_t port_num, int sda, int scl)
|
||||
{
|
||||
_port_num = port_num;
|
||||
_pin_sda = sda;
|
||||
_pin_scl = scl;
|
||||
m5gfx::i2c::setPins(port_num, sda, scl).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::begin(i2c_port_t port_num, int sda, int scl)
|
||||
{
|
||||
setPort(port_num, sda, scl);
|
||||
return begin();
|
||||
}
|
||||
|
||||
bool I2C_Class::begin(void)
|
||||
{
|
||||
return m5gfx::i2c::init(_port_num).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::release(void) const
|
||||
{
|
||||
return m5gfx::i2c::release(_port_num).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::start(std::uint8_t address, bool read, std::uint32_t freq) const
|
||||
{
|
||||
return m5gfx::i2c::beginTransaction(_port_num, address, freq, read).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::restart(std::uint8_t address, bool read, std::uint32_t freq) const
|
||||
{
|
||||
return m5gfx::i2c::restart(_port_num, address, freq, read).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::stop(void) const
|
||||
{
|
||||
return m5gfx::i2c::endTransaction(_port_num).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::write(std::uint8_t data) const
|
||||
{
|
||||
return m5gfx::i2c::writeBytes(_port_num, &data, 1).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::write(const std::uint8_t* __restrict__ data, std::size_t length) const
|
||||
{
|
||||
return m5gfx::i2c::writeBytes(_port_num, data, length).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::read(std::uint8_t* __restrict__ result, std::size_t length, bool last_nack) const
|
||||
{
|
||||
return m5gfx::i2c::readBytes(_port_num, result, length, last_nack).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::writeRegister(std::uint8_t address, std::uint8_t reg, const std::uint8_t* __restrict__ data, std::size_t length, std::uint32_t freq) const
|
||||
{
|
||||
return m5gfx::i2c::beginTransaction(_port_num, address, freq, false).has_value()
|
||||
&& m5gfx::i2c::writeBytes(_port_num, ®, 1).has_value()
|
||||
&& m5gfx::i2c::writeBytes(_port_num, data, length).has_value()
|
||||
&& m5gfx::i2c::endTransaction(_port_num).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::readRegister(std::uint8_t address, std::uint8_t reg, std::uint8_t* __restrict__ result, std::size_t length, std::uint32_t freq) const
|
||||
{
|
||||
return m5gfx::i2c::readRegister(_port_num, address, reg, result, length, freq).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::writeRegister8(std::uint8_t address, std::uint8_t reg, std::uint8_t data, std::uint32_t freq) const
|
||||
{
|
||||
return m5gfx::i2c::writeRegister8(_port_num, address, reg, data, 0, freq).has_value();
|
||||
}
|
||||
|
||||
std::uint8_t I2C_Class::readRegister8(std::uint8_t address, std::uint8_t reg, std::uint32_t freq) const
|
||||
{
|
||||
return m5gfx::i2c::readRegister8(_port_num, address, reg, freq).value_or(0);
|
||||
}
|
||||
|
||||
bool I2C_Class::bitOn(std::uint8_t address, std::uint8_t reg, std::uint8_t data, std::uint32_t freq) const
|
||||
{
|
||||
return m5gfx::i2c::bitOn(_port_num, address, reg, data, freq).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::bitOff(std::uint8_t address, std::uint8_t reg, std::uint8_t data, std::uint32_t freq) const
|
||||
{
|
||||
return m5gfx::i2c::bitOff(_port_num, address, reg, data, freq).has_value();
|
||||
}
|
||||
|
||||
bool I2C_Class::scanID(uint8_t addr) const
|
||||
{
|
||||
return start(addr, false, 400000) && stop();
|
||||
}
|
||||
|
||||
void I2C_Class::scanID(bool* __restrict__ result) const
|
||||
{
|
||||
// ESP32S3ではアドレス0~7をスキャン対象に含めると動作が停止する
|
||||
for (int i = 8; i < 0x78; i++)
|
||||
{
|
||||
result[i] = start(i, false, 400000) && stop();
|
||||
}
|
||||
}
|
||||
|
||||
bool I2C_Device::writeRegister8Array(const std::uint8_t* reg_data_array, std::size_t length) const
|
||||
{
|
||||
for (size_t i = 0; i < length; i+=2)
|
||||
{
|
||||
if (!_i2c->writeRegister8(_addr, reg_data_array[i], reg_data_array[i+1], _freq))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
211
libraries/M5Unified/src/utility/I2C_Class.hpp
Normal file
211
libraries/M5Unified/src/utility/I2C_Class.hpp
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_I2C_CLASS_H__
|
||||
#define __M5_I2C_CLASS_H__
|
||||
|
||||
#include "m5unified_common.h"
|
||||
#if __has_include ( <driver/i2c.h> )
|
||||
|
||||
#include <driver/i2c.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class I2C_Class
|
||||
{
|
||||
public:
|
||||
/// setup I2C port parameters. (No begin)
|
||||
/// @param port_num I2C number. (I2C_NUM_0 or I2C_NUM_1).
|
||||
/// @param pin_sda SDA pin number.
|
||||
/// @param pin_scl SCL pin number.
|
||||
void setPort(i2c_port_t port_num, int pin_sda, int pin_scl);
|
||||
|
||||
/// setup and begin I2C peripheral. (No communication is performed.)
|
||||
/// @param port_num I2C number. (I2C_NUM_0 or I2C_NUM_1).
|
||||
/// @param pin_sda SDA pin number.
|
||||
/// @param pin_scl SCL pin number.
|
||||
/// @return success(true) or failed(false).
|
||||
bool begin(i2c_port_t port_num, int pin_sda, int pin_scl);
|
||||
|
||||
/// begin I2C peripheral. (No communication is performed.)
|
||||
/// @return success(true) or failed(false).
|
||||
bool begin(void);
|
||||
|
||||
/// release I2C peripheral.
|
||||
/// @return success(true) or failed(false).
|
||||
bool release(void) const;
|
||||
|
||||
/// Sends the I2C start condition and the address of the slave.
|
||||
/// @param address slave addr.
|
||||
/// @param read bit of read flag. true=read / false=write.
|
||||
/// @return success(true) or failed(false).
|
||||
bool start(std::uint8_t address, bool read, std::uint32_t freq) const;
|
||||
|
||||
/// Sends the I2C repeated start condition and the address of the slave.
|
||||
/// @param address slave addr.
|
||||
/// @param read bit of read flag. true=read / false=write.
|
||||
/// @return success(true) or failed(false).
|
||||
bool restart(std::uint8_t address, bool read, std::uint32_t freq) const;
|
||||
|
||||
/// Sends the I2C stop condition.
|
||||
/// If an ACK error occurs, return false.
|
||||
/// @return success(true) or failed(false).
|
||||
bool stop(void) const;
|
||||
|
||||
/// Send 1 byte of data.
|
||||
/// @param data write data.
|
||||
/// @return success(true) or failed(false).
|
||||
bool write(std::uint8_t data) const;
|
||||
|
||||
/// Send multiple bytes of data.
|
||||
/// @param[in] data write data array.
|
||||
/// @param length data array length.
|
||||
/// @return success(true) or failed(false).
|
||||
bool write(const std::uint8_t* data, std::size_t length) const;
|
||||
|
||||
/// Receive multiple bytes of data.
|
||||
/// @param[out] result read data array.
|
||||
/// @param length data array length.
|
||||
/// @return success(true) or failed(false).
|
||||
bool read(std::uint8_t* result, std::size_t length, bool last_nack = false) const;
|
||||
|
||||
//----------
|
||||
|
||||
/// Write multiple bytes value to the register. Performs a series of communications from START to STOP.
|
||||
/// @param address slave addr.
|
||||
/// @param reg register number.
|
||||
/// @param[in] data write data array.
|
||||
/// @param length data array length.
|
||||
/// @return success(true) or failed(false).
|
||||
bool writeRegister(std::uint8_t address, std::uint8_t reg, const std::uint8_t* data, std::size_t length, std::uint32_t freq) const;
|
||||
|
||||
/// Read multiple bytes value from the register. Performs a series of communications from START to STOP.
|
||||
/// @param address slave addr.
|
||||
/// @param reg register number.
|
||||
/// @param[out] result read data array.
|
||||
/// @param length data array length.
|
||||
/// @return success(true) or failed(false).
|
||||
bool readRegister(std::uint8_t address, std::uint8_t reg, std::uint8_t* result, std::size_t length, std::uint32_t freq) const;
|
||||
|
||||
/// Write a 1-byte value to the register. Performs a series of communications from START to STOP.
|
||||
/// @param address slave addr.
|
||||
/// @param reg register number.
|
||||
/// @param data write data.
|
||||
/// @return success(true) or failed(false).
|
||||
bool writeRegister8(std::uint8_t address, std::uint8_t reg, std::uint8_t data, std::uint32_t freq) const;
|
||||
|
||||
/// Read a 1-byte value from the register. Performs a series of communications from START to STOP.
|
||||
/// @param address slave addr.
|
||||
/// @param reg register number.
|
||||
/// @return read value.
|
||||
std::uint8_t readRegister8(std::uint8_t address, std::uint8_t reg, std::uint32_t freq) const;
|
||||
|
||||
/// Write a 1-byte value to the register by bit add operation. Performs a series of communications from START to STOP.
|
||||
/// @param address slave addr.
|
||||
/// @param reg register number.
|
||||
/// @param data add bit data.
|
||||
/// @return success(true) or failed(false).
|
||||
bool bitOn(std::uint8_t address, std::uint8_t reg, std::uint8_t data, std::uint32_t freq) const;
|
||||
|
||||
/// Write a 1-byte value to the register by bit erase operation. Performs a series of communications from START to STOP.
|
||||
/// @param address slave addr.
|
||||
/// @param reg register number.
|
||||
/// @param data erase bit data.
|
||||
/// @return success(true) or failed(false).
|
||||
bool bitOff(std::uint8_t address, std::uint8_t reg, std::uint8_t data, std::uint32_t freq) const;
|
||||
|
||||
/// execute I2C scan. (for 7bit address)
|
||||
/// @param[out] result data array needs 120 Bytes.
|
||||
void scanID(bool* result) const;
|
||||
|
||||
bool scanID(uint8_t addr) const;
|
||||
|
||||
i2c_port_t getPort(void) const { return _port_num; }
|
||||
int8_t getSDA(void) const { return _pin_sda; }
|
||||
int8_t getSCL(void) const { return _pin_scl; }
|
||||
|
||||
bool isEnabled(void) const { return _port_num >= 0; }
|
||||
|
||||
private:
|
||||
i2c_port_t _port_num = (i2c_port_t)-1;
|
||||
int8_t _pin_sda = -1;
|
||||
int8_t _pin_scl = -1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// for internal I2C device
|
||||
extern I2C_Class In_I2C;
|
||||
|
||||
/// for external I2C device
|
||||
extern I2C_Class Ex_I2C;
|
||||
|
||||
|
||||
|
||||
class I2C_Device
|
||||
{
|
||||
public:
|
||||
I2C_Device(std::uint8_t i2c_addr, std::uint32_t freq, I2C_Class* i2c = &In_I2C)
|
||||
: _i2c { i2c }
|
||||
, _freq { freq }
|
||||
, _addr { i2c_addr }
|
||||
, _init { false }
|
||||
{}
|
||||
|
||||
void setPort(I2C_Class* i2c) { _i2c = i2c; }
|
||||
|
||||
void setClock(std::uint32_t freq) { _freq = freq; }
|
||||
|
||||
void setAddress(std::uint8_t i2c_addr) { _addr = i2c_addr; }
|
||||
|
||||
std::uint8_t getAddress(void) const { return _addr; }
|
||||
|
||||
bool writeRegister8(std::uint8_t reg, std::uint8_t data) const
|
||||
{
|
||||
return _i2c->writeRegister8(_addr, reg, data, _freq);
|
||||
}
|
||||
|
||||
std::uint8_t readRegister8(std::uint8_t reg) const
|
||||
{
|
||||
return _i2c->readRegister8(_addr, reg, _freq);
|
||||
}
|
||||
|
||||
bool writeRegister8Array(const std::uint8_t* reg_data_array, std::size_t length) const;
|
||||
|
||||
bool writeRegister(std::uint8_t reg, const std::uint8_t* data, std::size_t length) const
|
||||
{
|
||||
return _i2c->writeRegister(_addr, reg, data, length, _freq);
|
||||
}
|
||||
|
||||
bool readRegister(std::uint8_t reg, std::uint8_t* result, std::size_t length) const
|
||||
{
|
||||
return _i2c->readRegister(_addr, reg, result, length, _freq);
|
||||
}
|
||||
|
||||
bool bitOn(std::uint8_t reg, std::uint8_t bit) const
|
||||
{
|
||||
return _i2c->bitOn(_addr, reg, bit, _freq);
|
||||
}
|
||||
|
||||
bool bitOff(std::uint8_t reg, std::uint8_t bit) const
|
||||
{
|
||||
return _i2c->bitOff(_addr, reg, bit, _freq);
|
||||
}
|
||||
|
||||
bool isEnabled(void) const { return _init; }
|
||||
|
||||
protected:
|
||||
I2C_Class *_i2c;
|
||||
std::uint32_t _freq;
|
||||
std::uint8_t _addr;
|
||||
bool _init;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
597
libraries/M5Unified/src/utility/IMU_Class.cpp
Normal file
597
libraries/M5Unified/src/utility/IMU_Class.cpp
Normal file
|
|
@ -0,0 +1,597 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "../M5Unified.hpp"
|
||||
#include "IMU_Class.hpp"
|
||||
|
||||
#include "m5unified_common.h"
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
|
||||
#include <sdkconfig.h>
|
||||
#include <nvs.h>
|
||||
|
||||
#include "imu/MPU6886_Class.hpp"
|
||||
#include "imu/SH200Q_Class.hpp"
|
||||
#include "imu/BMI270_Class.hpp"
|
||||
#include "imu/BMM150_Class.hpp"
|
||||
#include "imu/AK8963_Class.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
static constexpr char LIBRARY_NAME[] = "M5Unified";
|
||||
|
||||
namespace m5
|
||||
{
|
||||
static constexpr const char* nvs_key_names[9] = { "ax", "ay", "az", "gx", "gy", "gz", "mx", "my", "mz" };
|
||||
|
||||
bool IMU_Class::begin(I2C_Class* i2c, m5::board_t board)
|
||||
{
|
||||
#if defined(M5UNIFIED_PC_BUILD)
|
||||
(void)i2c;
|
||||
(void)board;
|
||||
#else
|
||||
if (i2c)
|
||||
{
|
||||
i2c->begin();
|
||||
}
|
||||
|
||||
_imu = imu_t::imu_none;
|
||||
_has_sensor_mask = sensor_mask_none;
|
||||
|
||||
{
|
||||
auto mpu6886 = new MPU6886_Class();
|
||||
auto res = mpu6886->begin(i2c);
|
||||
if (!res) { delete mpu6886; }
|
||||
else
|
||||
{
|
||||
_imu_instance[0].reset(mpu6886);
|
||||
switch (mpu6886->whoAmI())
|
||||
{
|
||||
case MPU6886_Class::DEV_ID_MPU6050:
|
||||
_imu = imu_t::imu_mpu6050;
|
||||
break;
|
||||
case MPU6886_Class::DEV_ID_MPU6886:
|
||||
_imu = imu_t::imu_mpu6886;
|
||||
break;
|
||||
case MPU6886_Class::DEV_ID_MPU9250:
|
||||
_imu = imu_t::imu_mpu9250;
|
||||
break;
|
||||
default:
|
||||
_imu = imu_t::imu_unknown;
|
||||
break;
|
||||
}
|
||||
#if defined (CONFIG_IDF_TARGET_ESP32) || !defined ( CONFIG_IDF_TARGET )
|
||||
if (board == m5::board_t::board_M5AtomMatrix)
|
||||
{ // ATOM Matrix's IMU is oriented differently, so change the setting.
|
||||
_internal_axisorder_fixed[sensor_index_accel] = (internal_axisorder_t)(axis_invert_x | axis_invert_z); // X軸,Z軸反転
|
||||
_internal_axisorder_fixed[sensor_index_gyro ] = (internal_axisorder_t)(axis_invert_x | axis_invert_z); // X軸,Z軸反転
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (_imu == imu_t::imu_none)
|
||||
{
|
||||
auto bmi2 = new BMI270_Class();
|
||||
if (!bmi2->begin(i2c)) {
|
||||
bmi2->setAddress(bmi2->getAddress() == 0x68 ? 0x69 : 0x68);
|
||||
if (!bmi2->begin(i2c)) {
|
||||
delete bmi2;
|
||||
bmi2 = nullptr;
|
||||
}
|
||||
}
|
||||
if (bmi2 != nullptr)
|
||||
{
|
||||
_imu_instance[0].reset(bmi2);
|
||||
_imu = imu_t::imu_bmi270;
|
||||
|
||||
#if defined ( CONFIG_IDF_TARGET_ESP32S3 )
|
||||
if (board == m5::board_t::board_M5StackCoreS3 && bmi2->getAddress() == 0x69)
|
||||
{ // CoreS3 では、地磁気のY軸Z軸をそれぞれ反転する
|
||||
_internal_axisorder_fixed[sensor_index_mag] = (internal_axisorder_t)(axis_invert_y | axis_invert_z); // Y軸,Z軸反転
|
||||
} else
|
||||
if (board == m5::board_t::board_M5AtomS3R || board == m5::board_t::board_M5AtomS3RCam || board == m5::board_t::board_M5AtomS3RExt)
|
||||
{ // AtomS3Rシリーズ では、ジャイロと加速度のY軸とX軸を入れ替え、Y軸を反転するほか、地磁気のX軸とZ軸をそれぞれ反転する
|
||||
_internal_axisorder_fixed[sensor_index_accel] = (internal_axisorder_t)(axis_order_yxz | axis_invert_y);
|
||||
_internal_axisorder_fixed[sensor_index_gyro ] = (internal_axisorder_t)(axis_order_yxz | axis_invert_y);
|
||||
_internal_axisorder_fixed[sensor_index_mag ] = (internal_axisorder_t)(axis_invert_x | axis_invert_z); // X軸,Z軸反転
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (_imu == imu_t::imu_none)
|
||||
{
|
||||
auto sh200q = new SH200Q_Class();
|
||||
if (!sh200q->begin(i2c)) { delete sh200q; }
|
||||
else
|
||||
{
|
||||
_imu_instance[0].reset(sh200q);
|
||||
_imu = imu_t::imu_sh200q;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto bmm150 = new BMM150_Class();
|
||||
if (!bmm150->begin(i2c)) {
|
||||
delete bmm150;
|
||||
}
|
||||
else
|
||||
{
|
||||
_imu_instance[1].reset(bmm150);
|
||||
if (board == m5::board_t::board_M5Stack)
|
||||
{ // M5Stack MPU6886 + BMM150構成では、地磁気のX軸とZ軸をそれぞれ反転する
|
||||
// M5Stack SH200Q + BMM150構成での動作は未確認。(過去に一時期製造されている)
|
||||
_internal_axisorder_fixed[sensor_index_mag] = (internal_axisorder_t)(axis_invert_x | axis_invert_z); // X軸,Z軸反転
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto ak8963 = new AK8963_Class();
|
||||
if (!ak8963->begin(i2c)) {
|
||||
delete ak8963;
|
||||
}
|
||||
else
|
||||
{
|
||||
_imu_instance[1].reset(ak8963);
|
||||
if (_imu == imu_t::imu_mpu9250)
|
||||
{ // MPU9250内蔵AK8963は地磁気のX軸とY軸を取り換え、Z軸の向きを反転する
|
||||
_internal_axisorder_fixed[sensor_index_mag ] = (internal_axisorder_t)(axis_order_yxz | axis_invert_z); // Y軸X軸を入替, Z軸反転
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (_imu == imu_t::imu_none)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&_offset_data, 0, sizeof(imu_offset_data_t));
|
||||
_update_convert_param();
|
||||
_update_axis_order();
|
||||
|
||||
if (!loadOffsetFromNVS())
|
||||
{
|
||||
setCalibration(255, 255, 255);
|
||||
update();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
int32_t d = _raw_data.sensor[i].value[j] << 16;
|
||||
_offset_data.sensor[i].prev_value[j] = d;
|
||||
_offset_data.sensor[i].avg_value[j] = d;
|
||||
}
|
||||
_offset_data.sensor[i].stillness = 255;
|
||||
_offset_data.sensor[i].calibration();
|
||||
}
|
||||
}
|
||||
setCalibration(0, 0, 0);
|
||||
|
||||
// debug
|
||||
// for(int i=0;i<3;++i){for(int j=0;j<3;++j){_offset_data.sensor[i].value[j] = 65536*512;}}
|
||||
// for(int i=0;i<3;++i){for(int j=0;j<3;++j){_offset_data.sensor[i].value[j] = 0;}}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IMU_Class::sleep(void)
|
||||
{
|
||||
bool res = false;
|
||||
for (size_t i = 0; i < 2; ++i)
|
||||
{
|
||||
if (_imu_instance[i].get())
|
||||
{
|
||||
res = _imu_instance[i]->sleep() || res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void IMU_Class::setClock(std::uint32_t freq)
|
||||
{
|
||||
for (size_t i = 0; i < 2; ++i)
|
||||
{
|
||||
if (_imu_instance[i].get())
|
||||
{
|
||||
_imu_instance[i]->setClock(freq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IMU_Class::_update_convert_param(void)
|
||||
{
|
||||
if (_imu_instance[0]) { _imu_instance[0]->getConvertParam(&_convert_param); }
|
||||
if (_imu_instance[1]) { _imu_instance[1]->getConvertParam(&_convert_param); }
|
||||
|
||||
// 加速度は 1.0G ± 0.000488f の範囲に収まるよう調整
|
||||
_offset_data.accel.radius = 1.0f / _convert_param.accel_res;
|
||||
_offset_data.accel.tolerance = (1.0f / 2048.0f) / _convert_param.accel_res;
|
||||
_offset_data.accel.noise_level = 0.0625f / _convert_param.accel_res;
|
||||
_offset_data.accel.average_shifter = 1;
|
||||
|
||||
// ジャイロは 誤差 ±2.0度/sec の範囲に収まるよう調整
|
||||
_offset_data.gyro.radius = 0;
|
||||
_offset_data.gyro.tolerance = 0.0f / _convert_param.gyro_res;
|
||||
_offset_data.gyro.noise_level = 2.0f / _convert_param.gyro_res;
|
||||
_offset_data.gyro.average_shifter = 6;
|
||||
|
||||
// 地磁気は…パラメータ模索中…
|
||||
_offset_data.mag.radius = 384.0f / _convert_param.mag_res;
|
||||
_offset_data.mag.tolerance = 64.0f / _convert_param.mag_res;
|
||||
_offset_data.mag.noise_level = 96.0f / _convert_param.mag_res;
|
||||
_offset_data.mag.average_shifter = 1;
|
||||
}
|
||||
|
||||
void IMU_Class::setCalibration(uint8_t accel, uint8_t gyro, uint8_t mag)
|
||||
{
|
||||
_offset_data.accel.strength = accel;
|
||||
_offset_data.gyro.strength = gyro;
|
||||
_offset_data.mag.strength = mag;
|
||||
_calibration_flg = (sensor_mask_t)((accel ? sensor_mask_accel : 0)
|
||||
| (gyro ? sensor_mask_gyro : 0)
|
||||
| (mag ? sensor_mask_mag : 0));
|
||||
}
|
||||
|
||||
bool IMU_Class::setAxisOrder(axis_t axis0, axis_t axis1, axis_t axis2)
|
||||
{ // データの取り出し順序を指定する
|
||||
uint_fast8_t result;
|
||||
switch ((axis0 >> 1) + ((axis1 >> 1) << 2) + ((axis2 >> 1) << 4))
|
||||
{
|
||||
case 0 << 0 | 1 << 2 | 2 << 4: result = axis_order_xyz; break;
|
||||
case 0 << 0 | 2 << 2 | 1 << 4: result = axis_order_xzy; break;
|
||||
case 1 << 0 | 0 << 2 | 2 << 4: result = axis_order_yxz; break;
|
||||
case 1 << 0 | 2 << 2 | 0 << 4: result = axis_order_yzx; break;
|
||||
case 2 << 0 | 0 << 2 | 1 << 4: result = axis_order_zxy; break;
|
||||
case 2 << 0 | 1 << 2 | 0 << 4: result = axis_order_zyx; break;
|
||||
default: return false;
|
||||
}
|
||||
result += (axis0 & 1) + ((axis1 & 1) << 1) + ((axis2 & 1) << 2);
|
||||
_internal_axisorder_user = (internal_axisorder_t)result;
|
||||
_update_axis_order();
|
||||
return true;
|
||||
}
|
||||
|
||||
void IMU_Class::_update_axis_order(void)
|
||||
{ // システムの軸設定とユーザの軸設定を反映したデータの取り出し順序を求める
|
||||
static constexpr const uint8_t internal_axisorder_table[6] =
|
||||
{//X idx | Y idx | Z idx
|
||||
0 << 0 | 1 << 2 | 2 << 4, // axis_order_xyz
|
||||
0 << 0 | 2 << 2 | 1 << 4, // axis_order_xzy
|
||||
1 << 0 | 0 << 2 | 2 << 4, // axis_order_yxz
|
||||
1 << 0 | 2 << 2 | 0 << 4, // axis_order_yzx
|
||||
2 << 0 | 0 << 2 | 1 << 4, // axis_order_zxy
|
||||
2 << 0 | 1 << 2 | 0 << 4, // axis_order_zyx
|
||||
};
|
||||
|
||||
std::uint32_t result = 0;
|
||||
std::uint32_t bitshift = 0;
|
||||
auto axis_order_user = _internal_axisorder_user;
|
||||
auto order_user_tbl = internal_axisorder_table[axis_order_user >> axis_order_shift];
|
||||
for (std::size_t sensor = 0; sensor < 3; ++sensor)
|
||||
{
|
||||
auto axis_order_fixed = _internal_axisorder_fixed[sensor];
|
||||
auto order_fixed_tbl = internal_axisorder_table[axis_order_fixed >> axis_order_shift];
|
||||
for (std::size_t j = 0; j < 3; ++j, bitshift += 3)
|
||||
{ // ユーザが要求している軸順と反転指定を求める
|
||||
std::uint_fast8_t axis_user_index = (order_user_tbl >> (j << 1)) & 3;
|
||||
bool invert_user = axis_order_user & (1 << j);
|
||||
|
||||
// システムで設定された軸順テーブルを、ユーザーが要求している軸順で取得する
|
||||
std::uint_fast8_t axis_fixed_index = (order_fixed_tbl >> (axis_user_index << 1)) & 3;
|
||||
bool invert_fixed = axis_order_fixed & (1 << axis_user_index);
|
||||
|
||||
// 3ビットでx=0b000,y=b010,z=0b100 | 反転フラグ0b001 を表現する。
|
||||
// これを3軸×3センサの9個分を並べて保持する。合計3bit×9の27ビットが使用される。
|
||||
result |= ((axis_fixed_index << 1) + (invert_user != invert_fixed ? 1 : 0)) << bitshift;
|
||||
// printf("user_index:%d invert_user:%d fixed_index:%d invert_fixed:%d res:%08x\n", axis_user_index, invert_user, axis_fixed_index, invert_fixed, result);
|
||||
}
|
||||
}
|
||||
_axis_order_3bit_x9 = result;
|
||||
}
|
||||
|
||||
// 指定された2軸を元に、残りの1軸を求める (右手系)
|
||||
static IMU_Class::axis_t getAxis2(IMU_Class::axis_t axis0, IMU_Class::axis_t axis1)
|
||||
{
|
||||
std::uint_fast8_t axis2 = (1 << (axis0 >> 1) | 1 << (axis1 >> 1)) ^ 0b111;
|
||||
axis2 &= 0b110;
|
||||
std::uint_fast8_t ax0 = axis2 ? (axis2 - 2) : 4;
|
||||
axis2 += (bool)((axis0 & 0b110) == ax0) == (bool)((axis0 & 1) == (axis1 & 1));
|
||||
return (IMU_Class::axis_t)axis2;
|
||||
}
|
||||
|
||||
bool IMU_Class::setAxisOrderRightHanded(axis_t axis0, axis_t axis1)
|
||||
{
|
||||
return setAxisOrder(axis0, axis1, getAxis2(axis0, axis1));
|
||||
}
|
||||
|
||||
bool IMU_Class::setAxisOrderLeftHanded(axis_t axis0, axis_t axis1)
|
||||
{
|
||||
// 右手系で求めた軸に反転フラグを設定し、左手系とする。
|
||||
auto axis2 = getAxis2(axis0, axis1) ^ 1;
|
||||
return setAxisOrder(axis0, axis1, (axis_t)axis2);
|
||||
}
|
||||
|
||||
bool IMU_Class::saveOffsetToNVS(void)
|
||||
{ // NVSへオフセット値を保存する
|
||||
#if !defined(M5UNIFIED_PC_BUILD)
|
||||
std::uint32_t nvs_handle = 0;
|
||||
if (ESP_OK != nvs_open(LIBRARY_NAME, NVS_READWRITE, &nvs_handle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
size_t index = 0;
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < 3; ++j, ++index)
|
||||
{
|
||||
int32_t val = _offset_data.sensor[i].value[j];
|
||||
nvs_set_i32(nvs_handle, nvs_key_names[index], val);
|
||||
M5_LOGV("%s:%d", nvs_key_names[index], val);
|
||||
}
|
||||
}
|
||||
nvs_close(nvs_handle);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IMU_Class::loadOffsetFromNVS(void)
|
||||
{ // NVSからオフセット値を読み込む
|
||||
#if !defined(M5UNIFIED_PC_BUILD)
|
||||
std::uint32_t nvs_handle = 0;
|
||||
if (ESP_OK != nvs_open(LIBRARY_NAME, NVS_READONLY, &nvs_handle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
size_t index = 0;
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < 3; ++j, ++index)
|
||||
{
|
||||
int32_t val = 0;
|
||||
nvs_get_i32(nvs_handle, nvs_key_names[index], &val);
|
||||
_offset_data.sensor[i].value[j] = val;
|
||||
M5_LOGD("%s:%d", nvs_key_names[index], val);
|
||||
}
|
||||
}
|
||||
nvs_close(nvs_handle);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void IMU_Class::clearOffsetData(void)
|
||||
{
|
||||
size_t index = 0;
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < 3; ++j, ++index)
|
||||
{
|
||||
_offset_data.sensor[i].value[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IMU_Class::setOffsetData(size_t index, int32_t value)
|
||||
{
|
||||
if (index < 9) {
|
||||
_offset_data.sensor[index / 3].value[index % 3] = value;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t IMU_Class::getOffsetData(size_t index)
|
||||
{
|
||||
return index < 9 ? _offset_data.sensor[index / 3].value[index % 3] : 0;
|
||||
}
|
||||
|
||||
int16_t IMU_Class::getRawData(size_t index)
|
||||
{
|
||||
return index < 9 ? _raw_data.value[index] : 0;
|
||||
}
|
||||
|
||||
IMU_Class::sensor_mask_t IMU_Class::update(void)
|
||||
{
|
||||
sensor_mask_t res = (sensor_mask_t)0;
|
||||
for (size_t i = 0; i < 2; ++i)
|
||||
{
|
||||
if (_imu_instance[i].get())
|
||||
{
|
||||
uint_fast8_t t = _imu_instance[i]->getImuRawData(&_raw_data);
|
||||
if (t)
|
||||
{
|
||||
res = (sensor_mask_t)(res | t);
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
_latest_micros = m5gfx::micros();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res)
|
||||
{
|
||||
std::uint_fast8_t mask_flg = _calibration_flg & res;
|
||||
// キャリブレーション処理
|
||||
for (size_t i = 0; mask_flg && i < 3; ++i, mask_flg >>= 1)
|
||||
{
|
||||
// if ((mask_flg & 1) && (16 < _offset_data.sensor[i].updateStillness(_raw_data.sensor[i])))
|
||||
if (mask_flg & 1)
|
||||
{
|
||||
auto st = _offset_data.sensor[i].updateStillness(_raw_data.sensor[i]);
|
||||
if (16 < st)
|
||||
{
|
||||
_offset_data.sensor[i].calibration();
|
||||
// if (i == 1) { printf("Ok %d\n" ,st); }
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// if (i == 1) { printf(" NG %d\n", st); }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void IMU_Class::getImuData(imu_data_t* data)
|
||||
{
|
||||
data->usec = _latest_micros;
|
||||
auto &raw = _raw_data;
|
||||
// data->temp = raw.temp * _convert_param.temp_res + _convert_param.temp_offset;
|
||||
auto &offset = _offset_data;
|
||||
auto order = _axis_order_3bit_x9;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
float resolution = _convert_param.value[i] * (1.0f / 65536.0f);
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
auto axis_index = (order >> 1) & 3;
|
||||
int32_t value = (raw.sensor[i].value[axis_index] << 16) - offset.sensor[i].value[axis_index];
|
||||
if (order & 1) { value = -value; }
|
||||
data->sensor[i].value[j] = resolution * value;
|
||||
order >>= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IMU_Class::getAccel(float *x, float *y, float *z)
|
||||
{
|
||||
bool res = true;
|
||||
uint32_t us = m5gfx::micros();
|
||||
if (us - _latest_micros > 256)
|
||||
{
|
||||
res = update();
|
||||
}
|
||||
imu_data_t data;
|
||||
getImuData(&data);
|
||||
*x = data.accel.x;
|
||||
*y = data.accel.y;
|
||||
*z = data.accel.z;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool IMU_Class::getGyro(float *x, float *y, float *z)
|
||||
{
|
||||
bool res = true;
|
||||
uint32_t us = m5gfx::micros();
|
||||
if (us - _latest_micros > 256)
|
||||
{
|
||||
res = update();
|
||||
}
|
||||
imu_data_t data;
|
||||
getImuData(&data);
|
||||
*x = data.gyro.x;
|
||||
*y = data.gyro.y;
|
||||
*z = data.gyro.z;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool IMU_Class::getMag(float* x, float* y, float* z)
|
||||
{
|
||||
bool res = true;
|
||||
uint32_t us = m5gfx::micros();
|
||||
if (us - _latest_micros > 256)
|
||||
{
|
||||
res = update();
|
||||
}
|
||||
imu_data_t data;
|
||||
getImuData(&data);
|
||||
*x = data.mag.x;
|
||||
*y = data.mag.y;
|
||||
*z = data.mag.z;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool IMU_Class::getTemp(float *t)
|
||||
{
|
||||
int16_t temp;
|
||||
if (_imu_instance[0].get() && _imu_instance[0]->getTempAdc(&temp))
|
||||
{
|
||||
_raw_data.temp = temp;
|
||||
*t = temp * _convert_param.temp_res + _convert_param.temp_offset;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IMU_Class::setINTPinActiveLogic(bool level)
|
||||
{
|
||||
return _imu_instance[0].get() && _imu_instance[0]->setINTPinActiveLogic(level);
|
||||
}
|
||||
|
||||
|
||||
std::uint_fast8_t IMU_Class::offset_point_t::updateStillness(const IMU_Base::point3d_i16_t& dst)
|
||||
{ // 前回の座標情報との差が許容範囲以内か調べる
|
||||
int32_t res = stillness + 1;
|
||||
|
||||
int32_t maxdiff = 0;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
int32_t d = dst.value[i] << 16;
|
||||
int32_t pv = prev_value[i];
|
||||
int32_t diff = d - pv;
|
||||
prev_value[i] = d;
|
||||
maxdiff = std::max(maxdiff, abs(diff));
|
||||
|
||||
int32_t av = avg_value[i];
|
||||
diff = d - av;
|
||||
maxdiff = std::max(maxdiff, abs(diff));
|
||||
|
||||
diff = (diff + (1 << (average_shifter - 1))) >> average_shifter;
|
||||
avg_value[i] = av + diff;
|
||||
// maxdiff = std::max(maxdiff, abs(diff) << (average_shifter));
|
||||
}
|
||||
|
||||
int32_t rt = noise_level << 8;
|
||||
maxdiff >>= 8;
|
||||
if (rt > maxdiff)
|
||||
{
|
||||
maxdiff = rt - (maxdiff + 1);
|
||||
maxdiff = (maxdiff << 8) / rt;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxdiff = 0;
|
||||
}
|
||||
res = std::min(res, maxdiff);
|
||||
|
||||
stillness = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
void IMU_Class::offset_point_t::calibration(void)
|
||||
{
|
||||
if (stillness * strength == 0) return;
|
||||
float distance = 0;
|
||||
float diffs[3];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
// int p = ((average_shifter) ? avg_value : prev_value)[i];
|
||||
auto p = prev_value[i];
|
||||
// auto p = avg_value[i];
|
||||
// auto p = (prev_value[i] + avg_value[i]) >> 1;
|
||||
float f = p - value[i];
|
||||
diffs[i] = f;
|
||||
distance += f * f;
|
||||
}
|
||||
distance = sqrtf(distance * (1.0f / (65536.0f * 65536.0f)));
|
||||
if (distance < 1.0f) { return; }
|
||||
|
||||
// 誤差を求める (目的の半径と現在の距離の差)
|
||||
float measure_error = distance - radius;
|
||||
// if (signbit(measure_error)) { return; }
|
||||
// float tole_half = tolerance;
|
||||
float force = fabsf(measure_error);
|
||||
// if (force <= 0.0f) { return; }
|
||||
if (force <= tolerance) { return; }
|
||||
// if (force > tolerance) { force = tolerance; }
|
||||
if (measure_error < 0.0f) { force = -force; }
|
||||
float fk = force * (stillness * strength) / (distance * (255.0f * 255.0f));
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
value[i] += roundf(diffs[i] * fk);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
268
libraries/M5Unified/src/utility/IMU_Class.hpp
Normal file
268
libraries/M5Unified/src/utility/IMU_Class.hpp
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_IMU_CLASS_H__
|
||||
#define __M5_IMU_CLASS_H__
|
||||
|
||||
#include "I2C_Class.hpp"
|
||||
#include "imu/IMU_Base.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
enum imu_t
|
||||
{ imu_none,
|
||||
imu_unknown,
|
||||
imu_sh200q,
|
||||
imu_mpu6050,
|
||||
imu_mpu6886,
|
||||
imu_mpu9250,
|
||||
imu_bmi270,
|
||||
};
|
||||
|
||||
class IMU_Class
|
||||
{
|
||||
public:
|
||||
|
||||
struct imu_3d_t
|
||||
{
|
||||
union
|
||||
{
|
||||
float value[3];
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct imu_data_t
|
||||
{
|
||||
uint32_t usec;
|
||||
union
|
||||
{
|
||||
float value[9];
|
||||
imu_3d_t sensor[3];
|
||||
struct
|
||||
{
|
||||
imu_3d_t accel;
|
||||
imu_3d_t gyro;
|
||||
imu_3d_t mag;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
enum axis_t
|
||||
{
|
||||
axis_x_pos = 0,
|
||||
axis_x_neg = 1,
|
||||
axis_y_pos = 2,
|
||||
axis_y_neg = 3,
|
||||
axis_z_pos = 4,
|
||||
axis_z_neg = 5,
|
||||
};
|
||||
|
||||
enum sensor_index_t
|
||||
{
|
||||
sensor_index_accel = 0,
|
||||
sensor_index_gyro = 1,
|
||||
sensor_index_mag = 2,
|
||||
};
|
||||
|
||||
enum sensor_mask_t
|
||||
{
|
||||
sensor_mask_none = 0,
|
||||
sensor_mask_accel = 1 << sensor_index_accel,
|
||||
sensor_mask_gyro = 1 << sensor_index_gyro,
|
||||
sensor_mask_mag = 1 << sensor_index_mag,
|
||||
};
|
||||
|
||||
bool begin(I2C_Class* i2c = nullptr, board_t board = board_t::board_unknown);
|
||||
bool init(I2C_Class* i2c = nullptr) { return begin(i2c); }
|
||||
bool sleep(void);
|
||||
|
||||
void setClock(std::uint32_t freq);
|
||||
|
||||
sensor_mask_t update(void);
|
||||
|
||||
void getImuData(imu_data_t* imu_data);
|
||||
|
||||
const imu_data_t& getImuData(void) { getImuData(&_last_data); return _last_data; }
|
||||
|
||||
// 軸の順序を指定する。デフォルトはX+,Y+,Z+
|
||||
bool setAxisOrder(axis_t axis0, axis_t axis1, axis_t axis2);
|
||||
|
||||
// 軸の順序を右手系で指定する。最初の2軸のみ指定し、3軸目は省略
|
||||
bool setAxisOrderRightHanded(axis_t axis0, axis_t axis1);
|
||||
|
||||
// 軸の順序を左手系で指定する。最初の2軸のみ指定し、3軸目は省略
|
||||
bool setAxisOrderLeftHanded(axis_t axis0, axis_t axis1);
|
||||
|
||||
bool getAccel(float* ax, float* ay, float* az);
|
||||
bool getGyro(float* gx, float* gy, float* gz);
|
||||
bool getMag(float* mx, float* my, float* mz);
|
||||
bool getAccelData(float* ax, float* ay, float* az) { return getAccel(ax, ay, az); }
|
||||
bool getGyroData(float* gx, float* gy, float* gz) { return getGyro(gx, gy, gz); }
|
||||
bool getGyroMag(float* mx, float* my, float* mz) { return getMag(mx, my, mz); }
|
||||
bool getTemp(float *t);
|
||||
|
||||
bool isEnabled(void) const { return _imu != imu_none; }
|
||||
|
||||
imu_t getType(void) const { return _imu; }
|
||||
|
||||
// 実装予定
|
||||
// void getAhrsData(float *pitch, float *roll, float *yaw);
|
||||
|
||||
// 廃止
|
||||
// void setRotation(uint_fast8_t rotation) { _rotation = rotation & 3; };
|
||||
|
||||
bool setINTPinActiveLogic(bool level);
|
||||
|
||||
// 各センサの自動オフセット調整機能の強さを指定する。 0=自動調整なし 1~255=自動調整あり
|
||||
void setCalibration(uint8_t accel_strength, uint8_t gyro_strength, uint8_t mag_strength);
|
||||
|
||||
// 現在のオフセット調整値をNVSに保存する
|
||||
bool saveOffsetToNVS(void);
|
||||
|
||||
// NVSからオフセット調整値を読み込む
|
||||
bool loadOffsetFromNVS(void);
|
||||
|
||||
// オフセットデータをクリアする
|
||||
void clearOffsetData(void);
|
||||
|
||||
// OffsetData は RawData<<16 スケール(16bit固定小数扱い)
|
||||
void setOffsetData(size_t index, int32_t value);
|
||||
|
||||
int32_t getOffsetData(size_t index);
|
||||
|
||||
int16_t getRawData(size_t index);
|
||||
|
||||
IMU_Base* getImuInstancePtr(int idx) const { return _imu_instance[idx].get(); }
|
||||
|
||||
private:
|
||||
|
||||
struct offset_point_t
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t value[3];
|
||||
struct
|
||||
{
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t z;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t prev_value[3];
|
||||
struct
|
||||
{
|
||||
int32_t prev_x;
|
||||
int32_t prev_y;
|
||||
int32_t prev_z;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t avg_value[3];
|
||||
struct
|
||||
{
|
||||
int32_t avg_x;
|
||||
int32_t avg_y;
|
||||
int32_t avg_z;
|
||||
};
|
||||
};
|
||||
float radius;
|
||||
float tolerance;
|
||||
uint16_t noise_level;
|
||||
uint8_t average_shifter; // 前回値への移動平均設定
|
||||
uint8_t stillness; // 移動量の少なさ(変動が大きい時0になり、静止時に255に近付く)
|
||||
uint8_t strength; // キャリブレーションの強さ(ユーザー指定)
|
||||
|
||||
std::uint_fast8_t updateStillness(const IMU_Base::point3d_i16_t& dst);
|
||||
void calibration(void);
|
||||
inline void setValue16(size_t index, int16_t val) { value[index] = val << 16; }
|
||||
inline int32_t getValue16(size_t index) const { return value[index] >> 16; }
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct imu_offset_data_t
|
||||
{
|
||||
union
|
||||
{
|
||||
offset_point_t sensor[3];
|
||||
struct
|
||||
{
|
||||
offset_point_t accel;
|
||||
offset_point_t gyro;
|
||||
offset_point_t mag;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
void _update_convert_param(void);
|
||||
void _update_axis_order(void);
|
||||
void _proc_calibration(void);
|
||||
|
||||
// update成功時のマイクロ秒情報
|
||||
uint32_t _latest_micros;
|
||||
|
||||
// センサのインスタンス保持用 ([0]=加速度+ジャイロ / [1]=地磁気)
|
||||
std::unique_ptr<IMU_Base> _imu_instance[2];
|
||||
|
||||
// 生の値を測定値に変換するための補正値
|
||||
IMU_Base::imu_convert_param_t _convert_param;
|
||||
|
||||
// updateで得た最新の生値
|
||||
IMU_Base::imu_raw_data_t _raw_data;
|
||||
|
||||
// オフセット補正用の値
|
||||
imu_offset_data_t _offset_data;
|
||||
|
||||
// 最後に得たセンサ値
|
||||
imu_data_t _last_data;
|
||||
|
||||
// 最後に動きがあった時のusec
|
||||
uint32_t _moving_micros;
|
||||
|
||||
// ユーザ側で任意の軸割当を行うための設定項目
|
||||
uint8_t _assign_axis_x;
|
||||
uint8_t _assign_axis_y;
|
||||
uint8_t _assign_axis_z;
|
||||
|
||||
sensor_mask_t _calibration_flg;
|
||||
|
||||
sensor_mask_t _has_sensor_mask;
|
||||
|
||||
imu_t _imu = imu_t::imu_none;
|
||||
|
||||
// 機種別設定とユーザー設定の両方を反映した後のデータ取得順の値
|
||||
uint32_t _axis_order_3bit_x9;
|
||||
|
||||
enum internal_axisorder_t : uint8_t
|
||||
{
|
||||
axis_invert_x = 1,
|
||||
axis_invert_y = 2,
|
||||
axis_invert_z = 4,
|
||||
axis_order_shift = 3,
|
||||
axis_order_xyz = 0 << axis_order_shift,
|
||||
axis_order_xzy = 1 << axis_order_shift,
|
||||
axis_order_yxz = 2 << axis_order_shift,
|
||||
axis_order_yzx = 3 << axis_order_shift,
|
||||
axis_order_zxy = 4 << axis_order_shift,
|
||||
axis_order_zyx = 5 << axis_order_shift,
|
||||
};
|
||||
|
||||
// 機種別の軸の不一致を統一するための設定項目(システム自動設定)
|
||||
internal_axisorder_t _internal_axisorder_fixed[3] = { (internal_axisorder_t)0, (internal_axisorder_t)0, (internal_axisorder_t)0 };
|
||||
|
||||
// ユーザーによる設定値
|
||||
internal_axisorder_t _internal_axisorder_user = (internal_axisorder_t)0;
|
||||
};
|
||||
|
||||
typedef IMU_Class::imu_3d_t imu_3d_t;
|
||||
typedef IMU_Class::imu_data_t imu_data_t;
|
||||
}
|
||||
#endif
|
||||
75
libraries/M5Unified/src/utility/INA3221_Class.cpp
Normal file
75
libraries/M5Unified/src/utility/INA3221_Class.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "INA3221_Class.hpp"
|
||||
|
||||
#if __has_include(<esp_log.h>)
|
||||
#include <esp_log.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
bool INA3221_Class::begin(void)
|
||||
{
|
||||
uint16_t id = readRegister16(0xFF);
|
||||
#if defined (ESP_LOGV)
|
||||
// ESP_LOGV("INA3221", "regFFh:%04x", id);
|
||||
#endif
|
||||
_init = (id == 0x3220);
|
||||
return _init;
|
||||
}
|
||||
|
||||
void INA3221_Class::setShuntRes(uint8_t channel, uint32_t res)
|
||||
{
|
||||
if (channel < INA3221_CH_NUM_MAX) {
|
||||
_shunt_res[channel] = res;
|
||||
}
|
||||
}
|
||||
|
||||
int_fast16_t INA3221_Class::getBusMilliVoltage(uint8_t channel)
|
||||
{
|
||||
int_fast16_t res = 0;
|
||||
if (channel < INA3221_CH_NUM_MAX) {
|
||||
res = (int16_t)readRegister16(INA3221_CH1_BUS_V + (channel * 2));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t INA3221_Class::getShuntMilliVoltage(uint8_t channel)
|
||||
{
|
||||
int32_t res = 0;
|
||||
if (channel < INA3221_CH_NUM_MAX) {
|
||||
res = (int16_t)readRegister16(INA3221_CH1_SHUNT_V + (channel * 2));
|
||||
res *= 5;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
float INA3221_Class::getBusVoltage(uint8_t channel)
|
||||
{
|
||||
return getBusMilliVoltage(channel) / 1000.0f;
|
||||
}
|
||||
|
||||
float INA3221_Class::getShuntVoltage(uint8_t channel)
|
||||
{
|
||||
return getShuntMilliVoltage(channel) / 1000.0f;
|
||||
}
|
||||
|
||||
float INA3221_Class::getCurrent(uint8_t channel)
|
||||
{
|
||||
float res = 0.0f;
|
||||
if (channel < INA3221_CH_NUM_MAX) {
|
||||
res = getShuntVoltage(channel) / _shunt_res[channel];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::size_t INA3221_Class::readRegister16(std::uint8_t addr)
|
||||
{
|
||||
std::uint8_t buf[2] = {0};
|
||||
readRegister(addr, buf, 2);
|
||||
return buf[0] << 8 | buf[1];
|
||||
}
|
||||
}
|
||||
53
libraries/M5Unified/src/utility/INA3221_Class.hpp
Normal file
53
libraries/M5Unified/src/utility/INA3221_Class.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_INA3221_CLASS_H__
|
||||
#define __M5_INA3221_CLASS_H__
|
||||
|
||||
#include "I2C_Class.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class INA3221_Class : public I2C_Device
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t INA3221_CH1_SHUNT_V = 0x01;
|
||||
static constexpr uint8_t INA3221_CH1_BUS_V = 0x02;
|
||||
static constexpr uint8_t INA3221_CH2_SHUNT_V = 0x03;
|
||||
static constexpr uint8_t INA3221_CH2_BUS_V = 0x04;
|
||||
static constexpr uint8_t INA3221_CH3_SHUNT_V = 0x05;
|
||||
static constexpr uint8_t INA3221_CH3_BUS_V = 0x06;
|
||||
static constexpr std::uint8_t INA3221_CH_NUM_MAX = 3;
|
||||
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x40;
|
||||
|
||||
INA3221_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C)
|
||||
: I2C_Device ( i2c_addr, freq, i2c )
|
||||
{
|
||||
_shunt_res[0] = 10;
|
||||
_shunt_res[1] = 10;
|
||||
_shunt_res[2] = 10;
|
||||
}
|
||||
|
||||
bool begin(void);
|
||||
|
||||
/// Get the voltage of the specified channel.
|
||||
/// @param channel 0=1ch / 1=2ch / 2=3ch / other=invalid
|
||||
/// @return voltage [mV]
|
||||
float getBusVoltage(uint8_t channel);
|
||||
float getShuntVoltage(uint8_t channel);
|
||||
float getCurrent(uint8_t channel);
|
||||
|
||||
int_fast16_t getBusMilliVoltage(uint8_t channel);
|
||||
int32_t getShuntMilliVoltage(uint8_t channel);
|
||||
|
||||
void setShuntRes(uint8_t channel, uint32_t res);
|
||||
|
||||
private:
|
||||
std::size_t readRegister16(std::uint8_t addr);
|
||||
|
||||
uint32_t _shunt_res[INA3221_CH_NUM_MAX];
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
121
libraries/M5Unified/src/utility/IP5306_Class.cpp
Normal file
121
libraries/M5Unified/src/utility/IP5306_Class.cpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "IP5306_Class.hpp"
|
||||
|
||||
#if __has_include(<esp_log.h>)
|
||||
#include <esp_log.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
static constexpr std::uint8_t REG_SYS_CTL0 = 0x00;
|
||||
static constexpr std::uint8_t REG_SYS_CTL1 = 0x01;
|
||||
static constexpr std::uint8_t REG_SYS_CTL2 = 0x02;
|
||||
static constexpr std::uint8_t REG_READ0 = 0x70;
|
||||
static constexpr std::uint8_t REG_READ1 = 0x71;
|
||||
static constexpr std::uint8_t REG_READ2 = 0x72;
|
||||
static constexpr std::uint8_t REG_READ3 = 0x77;
|
||||
static constexpr std::uint8_t REG_READ4 = 0x78;
|
||||
static constexpr std::uint8_t REG_CHG_CTL0 = 0x20;
|
||||
static constexpr std::uint8_t REG_CHG_CTL1 = 0x21;
|
||||
static constexpr std::uint8_t REG_CHG_CTL2 = 0x22;
|
||||
static constexpr std::uint8_t REG_CHG_CTL3 = 0x23;
|
||||
static constexpr std::uint8_t REG_CHG_DIG_CTL0 = 0x24;
|
||||
|
||||
static constexpr std::uint8_t BOOST_OUT_BIT = 0x02;
|
||||
|
||||
bool IP5306_Class::begin(void)
|
||||
{
|
||||
std::uint8_t val = 0;
|
||||
writeRegister(0x06, &val, 1); // reg06h WLED flashlight disabled
|
||||
val = 2;
|
||||
_init = writeRegister(0x06, &val, 1);
|
||||
if (_init)
|
||||
{
|
||||
#if defined (ESP_LOGV)
|
||||
// ESP_LOGV("IP5306", "found");
|
||||
#endif
|
||||
}
|
||||
return _init;
|
||||
}
|
||||
|
||||
std::int8_t IP5306_Class::getBatteryLevel(void)
|
||||
{
|
||||
std::uint8_t data;
|
||||
if (readRegister(REG_READ4, &data, 1)) {
|
||||
switch (data >> 4) {
|
||||
case 0x00: return 100;
|
||||
case 0x08: return 75;
|
||||
case 0x0C: return 50;
|
||||
case 0x0E: return 25;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void IP5306_Class::setBatteryCharge(bool enable)
|
||||
{
|
||||
static constexpr std::uint8_t CHARGE_OUT_BIT = 0x10;
|
||||
|
||||
std::uint8_t val = 0;
|
||||
if (readRegister(REG_SYS_CTL0, &val, 1))
|
||||
{
|
||||
writeRegister8(REG_SYS_CTL0, enable ? (val | CHARGE_OUT_BIT) : (val & (~CHARGE_OUT_BIT)));
|
||||
}
|
||||
}
|
||||
|
||||
void IP5306_Class::setChargeCurrent(std::uint16_t max_mA)
|
||||
{
|
||||
max_mA = (max_mA > 50) ? (max_mA - 50) / 100 : 0;
|
||||
if (max_mA > 31) { max_mA = 31; }
|
||||
|
||||
std::uint8_t val = 0;
|
||||
if (readRegister(REG_CHG_DIG_CTL0, &val, 1))
|
||||
{
|
||||
writeRegister8(REG_CHG_DIG_CTL0, (val & 0xE0) + max_mA);
|
||||
}
|
||||
}
|
||||
|
||||
void IP5306_Class::setChargeVoltage(std::uint16_t max_mV)
|
||||
{
|
||||
max_mV = (max_mV / 10);
|
||||
max_mV = (max_mV > 410) ? max_mV - 410 : 0;
|
||||
if (max_mV > 436 - 410) { max_mV = 436 - 410; }
|
||||
static constexpr std::uint8_t table[] =
|
||||
{ 430 - 410 /// 4300mV
|
||||
, 435 - 410 /// 4350mV
|
||||
, 440 - 410 /// 4400mV
|
||||
, 255
|
||||
};
|
||||
size_t i = 0;
|
||||
while (table[i] <= max_mV) { ++i; }
|
||||
|
||||
static constexpr std::uint8_t regdata[4] =
|
||||
{ 0x02 // 4.2v + boost 28mV
|
||||
, 0x05 // 4.3v + boost 14mV
|
||||
, 0x09 // 4.35v + boost 14mV
|
||||
, 0x0D // 4.4v + boost 14mV
|
||||
};
|
||||
writeRegister8(REG_CHG_CTL2, regdata[i]);
|
||||
}
|
||||
|
||||
bool IP5306_Class::isCharging(void)
|
||||
{
|
||||
std::uint8_t val = 0;
|
||||
return (readRegister(0x71, &val, 1)) && (val % 0x0C);
|
||||
}
|
||||
|
||||
bool IP5306_Class::setPowerBoostKeepOn(bool en) {
|
||||
std::uint8_t data;
|
||||
if (readRegister(REG_SYS_CTL0, &data, 1) == true)
|
||||
{
|
||||
data = en ? (data | BOOST_OUT_BIT) : (data & (~BOOST_OUT_BIT));
|
||||
return writeRegister(REG_SYS_CTL0, &data, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
49
libraries/M5Unified/src/utility/IP5306_Class.hpp
Normal file
49
libraries/M5Unified/src/utility/IP5306_Class.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_IP5306_CLASS_H__
|
||||
#define __M5_IP5306_CLASS_H__
|
||||
|
||||
#include "I2C_Class.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class IP5306_Class : public I2C_Device
|
||||
{
|
||||
public:
|
||||
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x75;
|
||||
|
||||
IP5306_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C)
|
||||
: I2C_Device ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
|
||||
bool begin(void);
|
||||
|
||||
/// Get the remaining battery power.
|
||||
/// @return 0-100 level
|
||||
std::int8_t getBatteryLevel(void);
|
||||
|
||||
/// set battery charge enable.
|
||||
/// @param enable true=enable / false=disable
|
||||
void setBatteryCharge(bool enable);
|
||||
|
||||
/// set battery charge current
|
||||
/// @param max_mA milli ampere. (150 - 3150).
|
||||
void setChargeCurrent(std::uint16_t max_mA);
|
||||
|
||||
/// set battery charge voltage
|
||||
/// @param max_mV milli volt. (4200 - 4400).
|
||||
void setChargeVoltage(std::uint16_t max_mV);
|
||||
|
||||
/// Get whether the battery is currently charging or not.
|
||||
bool isCharging(void);
|
||||
|
||||
/// Set whether or not to continue supplying power even at low loads.
|
||||
bool setPowerBoostKeepOn(bool en);
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
164
libraries/M5Unified/src/utility/Log_Class.cpp
Normal file
164
libraries/M5Unified/src/utility/Log_Class.cpp
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "Log_Class.hpp"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#if defined ( M5UNIFIED_PC_BUILD )
|
||||
#include <iostream>
|
||||
static constexpr const uint8_t log_colors_serial[] = { 98, 91, 93, 92, 96, 97, };
|
||||
#else
|
||||
static constexpr const uint8_t log_colors_serial[] = { 38, 31, 33, 32, 36, 37, };
|
||||
#endif
|
||||
static constexpr const uint8_t log_colors_display[] = { 0xFF, 0xE0, 0xFC, 0x18, 0x1F, 0x92, };
|
||||
|
||||
namespace m5
|
||||
{
|
||||
constexpr const char Log_Class::str_crlf[3];
|
||||
|
||||
const char* Log_Class::pathToFileName(const char* path)
|
||||
{
|
||||
size_t i = 0;
|
||||
size_t pos = 0;
|
||||
char * p = (char *)path;
|
||||
while(*p)
|
||||
{
|
||||
i++;
|
||||
if(*p == '/' || *p == '\\')
|
||||
{
|
||||
pos = i;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return path+pos;
|
||||
}
|
||||
|
||||
void Log_Class::operator() (esp_log_level_t level, const char* format, ...)
|
||||
{
|
||||
if (_level_maximum < level) { return; }
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
output(level, true, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log_Class::printf(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
output(esp_log_level_t::ESP_LOG_NONE, false, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log_Class::update_level(void)
|
||||
{
|
||||
_level_maximum = std::max(std::max(_log_level[log_target_serial], _log_level[log_target_display]), _log_level[log_target_callback]);
|
||||
}
|
||||
|
||||
void Log_Class::output(esp_log_level_t level, bool suffix, const char* __restrict format, va_list arg)
|
||||
{
|
||||
char loc_buf[64];
|
||||
char * str = loc_buf;
|
||||
va_list copy;
|
||||
va_copy(copy, arg);
|
||||
int len = vsnprintf(str, sizeof(loc_buf), format, copy);
|
||||
va_end(copy);
|
||||
if (len < 0) { return; }
|
||||
if ((size_t)len >= sizeof(loc_buf))
|
||||
{
|
||||
auto tmp = (char*) alloca(len + 1);
|
||||
if (tmp)
|
||||
{
|
||||
str = tmp;
|
||||
len = vsnprintf(str, len+1, format, arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (_log_level[log_target_serial] >= level)
|
||||
{
|
||||
const char* suf = (suffix && _suffix[log_target_serial]) ? _suffix[log_target_serial] : "";
|
||||
|
||||
if (level != ESP_LOG_NONE && _use_color[log_target_serial])
|
||||
{
|
||||
::printf("\033[0;%dm%s\033[0m%s", log_colors_serial[level], str, suf);
|
||||
}
|
||||
else
|
||||
{
|
||||
::printf("%s%s", str, suf);
|
||||
}
|
||||
|
||||
#if defined(M5UNIFIED_PC_BUILD)
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_display && _log_level[log_target_display] >= level)
|
||||
{
|
||||
if (level != ESP_LOG_NONE && _use_color[log_target_display])
|
||||
{
|
||||
auto style = _display->getTextStyle();
|
||||
if (style.fore_rgb888 == style.back_rgb888)
|
||||
{
|
||||
_display->setTextColor(log_colors_display[level]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_display->setTextColor(log_colors_display[level], m5gfx::color_convert<m5gfx::rgb332_t, m5gfx::rgb888_t>(style.back_rgb888));
|
||||
}
|
||||
_display->print(str);
|
||||
_display->setTextStyle(style);
|
||||
}
|
||||
else
|
||||
{
|
||||
_display->print(str);
|
||||
}
|
||||
if (suffix && _suffix[log_target_display]) { _display->print(_suffix[log_target_display]); }
|
||||
}
|
||||
|
||||
if (_log_level[log_target_callback] >= level && _callback != nullptr)
|
||||
{
|
||||
_callback(level, _log_level[log_target_callback], str);
|
||||
if (suffix && _suffix[log_target_callback]) { _callback(level, _log_level[log_target_callback], _suffix[log_target_callback]); }
|
||||
}
|
||||
}
|
||||
|
||||
void Log_Class::setDisplay(M5GFX* target)
|
||||
{
|
||||
_display = target;
|
||||
}
|
||||
|
||||
void Log_Class::dump(const void* a, uint32_t len, esp_log_level_t level)
|
||||
{
|
||||
len = (len + 3) >> 2;
|
||||
if (!len) return;
|
||||
auto addr = reinterpret_cast<uint32_t*>((uintptr_t)a & ~0x03);
|
||||
char buf[84];
|
||||
do {
|
||||
int pos = snprintf(buf, sizeof(buf), "0x%08" PRIxPTR "|", (uintptr_t)addr);
|
||||
// printf("0x%08x|", (uintptr_t)addr);
|
||||
int l = len > 4 ? 4 : len;
|
||||
for (int i = 0; i < l; ++i) {
|
||||
unsigned int tmp = addr[i];
|
||||
pos += snprintf(&buf[pos], (int)sizeof(buf) - pos, " %02x %02x %02x %02x ", tmp&0xFF, (tmp>>8)&0xFF, (tmp>>16)&0xFF,(tmp>>24));
|
||||
}
|
||||
for (int i = l; i < 4; ++i) {
|
||||
pos += snprintf(&buf[pos], (int)sizeof(buf) - pos, " __ __ __ __ ");
|
||||
}
|
||||
buf[pos] = '|';
|
||||
++pos;
|
||||
for (int i = 0; i < l; ++i) {
|
||||
unsigned int tmp = addr[i];
|
||||
pos += snprintf(&buf[pos], (int)sizeof(buf) - pos, "%c%c%c%c"
|
||||
, std::max(' ', (char)tmp)
|
||||
, std::max(' ', (char)(tmp>>8))
|
||||
, std::max(' ', (char)(tmp>>16))
|
||||
, std::max(' ', (char)(tmp>>24)));
|
||||
}
|
||||
buf[pos] = 0;
|
||||
operator()(level, buf);
|
||||
addr += l;
|
||||
len -= l;
|
||||
} while (len);
|
||||
}
|
||||
}
|
||||
128
libraries/M5Unified/src/utility/Log_Class.hpp
Normal file
128
libraries/M5Unified/src/utility/Log_Class.hpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_Log_Class_H__
|
||||
#define __M5_Log_Class_H__
|
||||
|
||||
#include "m5unified_common.h"
|
||||
|
||||
#if !defined ( M5UNIFIED_PC_BUILD )
|
||||
#include <esp_log.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <functional>
|
||||
|
||||
#include <M5GFX.h>
|
||||
|
||||
/// Output log with source info.
|
||||
#ifndef M5UNIFIED_LOG_FORMAT
|
||||
#define M5UNIFIED_LOG_FORMAT(letter, format) "[%6u][" #letter "][%s:%u] %s(): " format, m5gfx::millis(), m5::Log_Class::pathToFileName(__FILE__), __LINE__, __FUNCTION__
|
||||
#endif
|
||||
|
||||
/// Output Error log with source info.
|
||||
#define M5_LOGE(format, ...) M5.Log(ESP_LOG_ERROR , M5UNIFIED_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
|
||||
/// Output Warn log with source info.
|
||||
#define M5_LOGW(format, ...) M5.Log(ESP_LOG_WARN , M5UNIFIED_LOG_FORMAT(W, format), ##__VA_ARGS__)
|
||||
|
||||
/// Output Info log with source info.
|
||||
#define M5_LOGI(format, ...) M5.Log(ESP_LOG_INFO , M5UNIFIED_LOG_FORMAT(I, format), ##__VA_ARGS__)
|
||||
|
||||
/// Output Debug log with source info.
|
||||
#define M5_LOGD(format, ...) M5.Log(ESP_LOG_DEBUG , M5UNIFIED_LOG_FORMAT(D, format), ##__VA_ARGS__)
|
||||
|
||||
/// Output Verbose log with source info.
|
||||
#define M5_LOGV(format, ...) M5.Log(ESP_LOG_VERBOSE, M5UNIFIED_LOG_FORMAT(V, format), ##__VA_ARGS__)
|
||||
|
||||
namespace m5
|
||||
{
|
||||
enum log_target_t : uint8_t
|
||||
{
|
||||
log_target_serial,
|
||||
log_target_display,
|
||||
log_target_callback,
|
||||
log_target_max,
|
||||
};
|
||||
|
||||
class Log_Class
|
||||
{
|
||||
public:
|
||||
/// Output log.
|
||||
void operator() (esp_log_level_t level, const char* format, ...);
|
||||
|
||||
/// Output text in a specified format.
|
||||
/// @attention Output regardless of log level setting.
|
||||
void printf(const char* format, ...);
|
||||
|
||||
/// Output text.
|
||||
/// @attention Output regardless of log level setting.
|
||||
void print(const char* string) { return printf("%s", string); }
|
||||
|
||||
/// Output text with line feeds.
|
||||
/// @attention Output regardless of log level setting.
|
||||
void println(const char* string) { return printf("%s\n", string); }
|
||||
|
||||
/// Output line feeds.
|
||||
/// @attention Output regardless of log level setting.
|
||||
void println(void) { return printf(str_crlf); }
|
||||
|
||||
/// Set whether or not to change the color for each log level.
|
||||
void setEnableColor(log_target_t target, bool enable) { if (target < log_target_max) { _use_color[target] = enable; } }
|
||||
|
||||
/// Get whether or not to change the color for each log level.
|
||||
bool getEnableColor(log_target_t target) const { return _use_color[target]; }
|
||||
|
||||
/// Set log level.
|
||||
void setLogLevel(log_target_t target, esp_log_level_t level) { if (target < log_target_max) { _log_level[target] = level; update_level(); } }
|
||||
|
||||
/// Get log level for serial output.
|
||||
esp_log_level_t getLogLevel(log_target_t target) const { return _log_level[target]; }
|
||||
|
||||
/// Set the text to be added to the end of the log.
|
||||
void setSuffix(log_target_t target, const char* suffix) { if (target < log_target_max) { _suffix[target] = suffix; } }
|
||||
|
||||
/// set logging callback function / functor .
|
||||
/// @param function Pointer to a user-defined function that takes three arguments: esp_log_level_t , bool, const char*.
|
||||
void setCallback(std::function<void(esp_log_level_t log_level, bool use_color, const char* log_text)> function) { _callback = function; };
|
||||
|
||||
/// Set the display to show logs.
|
||||
/// @param target target display.
|
||||
void setDisplay(M5GFX* target);
|
||||
|
||||
/// Set the display to show logs.
|
||||
/// @param target target display.
|
||||
void setDisplay(M5GFX& target) { setDisplay(&target); }
|
||||
|
||||
|
||||
void dump(const void* addr, uint32_t len, esp_log_level_t level = esp_log_level_t::ESP_LOG_NONE);
|
||||
|
||||
/// not for use.
|
||||
static const char* pathToFileName(const char * path);
|
||||
|
||||
private:
|
||||
M5GFX* _display = nullptr;
|
||||
|
||||
static constexpr const char str_crlf[3] = "\r\n";
|
||||
static constexpr const char *str_lf = &str_crlf[1];
|
||||
|
||||
void output(esp_log_level_t level, bool suffix, const char* __restrict format, va_list arg);
|
||||
void update_level(void);
|
||||
|
||||
std::function<void(esp_log_level_t log_level, bool use_color, const char* log_text)> _callback;
|
||||
|
||||
#if defined ( CORE_DEBUG_LEVEL )
|
||||
esp_log_level_t _level_maximum = (esp_log_level_t)CORE_DEBUG_LEVEL;
|
||||
#elif defined ( CONFIG_LOG_DEFAULT_LEVEL )
|
||||
esp_log_level_t _level_maximum = (esp_log_level_t)CONFIG_LOG_DEFAULT_LEVEL;
|
||||
#else
|
||||
esp_log_level_t _level_maximum = esp_log_level_t::ESP_LOG_VERBOSE;
|
||||
#endif
|
||||
esp_log_level_t _log_level[log_target_max] = { _level_maximum, _level_maximum, _level_maximum };
|
||||
|
||||
const char* _suffix[log_target_max] = { str_lf, str_lf, str_crlf };
|
||||
|
||||
bool _use_color[log_target_max] = { true, true, true };
|
||||
};
|
||||
}
|
||||
#endif
|
||||
80
libraries/M5Unified/src/utility/M5Timer.cpp
Normal file
80
libraries/M5Unified/src/utility/M5Timer.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "M5Timer.h"
|
||||
#include <M5GFX.h>
|
||||
|
||||
M5Timer::M5Timer(void) {
|
||||
_enable_count = 0;
|
||||
for (uint_fast8_t i = 0; i < MAX_TIMERS; i++) {
|
||||
_timer_info[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void M5Timer::timer_info_t::clear(void) {
|
||||
_callback = 0;
|
||||
_enabled = false;
|
||||
_interval = 0;
|
||||
_remain = 0;
|
||||
}
|
||||
|
||||
void M5Timer::timer_info_t::set(uint32_t interval_msec, timer_callback cb, uint32_t times) {
|
||||
_callback = cb;
|
||||
_interval = interval_msec;
|
||||
_remain = times;
|
||||
_enabled = true;
|
||||
_prev_msec = m5gfx::millis();
|
||||
}
|
||||
|
||||
bool M5Timer::timer_info_t::run(uint32_t current_msec) {
|
||||
if (_callback != nullptr && current_msec - _prev_msec >= _interval) {
|
||||
_prev_msec += _interval;
|
||||
|
||||
if (_enabled) {
|
||||
_callback();
|
||||
// Check the remaining number of executions; if 0, assume unlimited.
|
||||
if (_remain != 0) {
|
||||
return --_remain;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void M5Timer::run(void) {
|
||||
auto msec = m5gfx::millis();
|
||||
|
||||
for (auto &t : _timer_info) {
|
||||
if (!t.getCallback()) { continue; }
|
||||
if (!t.run(msec)) {
|
||||
t.clear();
|
||||
_enable_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int_fast8_t M5Timer::setTimer(uint32_t interval, timer_callback cb, uint32_t times) {
|
||||
if (cb == nullptr || _enable_count >= MAX_TIMERS) {
|
||||
return -1;
|
||||
}
|
||||
for (uint_fast8_t i = 0; i < MAX_TIMERS; i++) {
|
||||
if (_timer_info[i].getCallback()) { continue; }
|
||||
_timer_info[i].set(interval, cb, times);
|
||||
_enable_count++;
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void M5Timer::deleteTimer(int_fast8_t id) {
|
||||
if ((uint_fast8_t)id < MAX_TIMERS && _timer_info[id].getCallback() != nullptr) {
|
||||
_timer_info[id].clear();
|
||||
_enable_count--;
|
||||
}
|
||||
}
|
||||
|
||||
void M5Timer::restartTimer(int_fast8_t id) {
|
||||
if ((uint_fast8_t)id < MAX_TIMERS) {
|
||||
_timer_info[id].setPreviousMsec(m5gfx::millis());
|
||||
}
|
||||
}
|
||||
124
libraries/M5Unified/src/utility/M5Timer.h
Normal file
124
libraries/M5Unified/src/utility/M5Timer.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_Timer_H__
|
||||
#define __M5_Timer_H__
|
||||
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef std::function<void(void)> timer_callback;
|
||||
|
||||
class M5Timer {
|
||||
public:
|
||||
/// maximum number of timers
|
||||
static constexpr const uint32_t MAX_TIMERS = 10;
|
||||
|
||||
/// constructor
|
||||
M5Timer(void);
|
||||
|
||||
/// this function must be called inside loop()
|
||||
void run(void);
|
||||
|
||||
/// Call function every interval [msec] for specified times.
|
||||
/// @param interval_msec interval [msec]
|
||||
/// @param function target function.
|
||||
/// @return -1 = failed / 0 or more = target timer id.
|
||||
int_fast8_t setTimer(uint32_t interval_msec, timer_callback function, uint32_t times);
|
||||
|
||||
/// Call function every interval [msec].
|
||||
/// @param interval_msec interval [msec]
|
||||
/// @param function target function.
|
||||
/// @return -1 = failed / 0 or more = target timer id.
|
||||
inline int_fast8_t setInterval(uint32_t interval_msec, timer_callback function) {
|
||||
return setTimer(interval_msec, function, 0);
|
||||
}
|
||||
|
||||
/// Call function once after interval [msec].
|
||||
/// @param interval_msec interval [msec]
|
||||
/// @param function target function.
|
||||
/// @return -1 = failed / 0 or more = target timer id.
|
||||
inline int_fast8_t setTimeout(uint32_t interval_msec, timer_callback function) {
|
||||
return setTimer(interval_msec, function, 1);
|
||||
}
|
||||
|
||||
/// Destroy the specified timer.
|
||||
/// @param id target timer id.
|
||||
void deleteTimer(int_fast8_t id);
|
||||
|
||||
/// Restart the specified timer.
|
||||
/// @param id target timer id.
|
||||
void restartTimer(int_fast8_t id);
|
||||
|
||||
/// Enables the specified timer.
|
||||
/// @param id target timer id.
|
||||
void enable(int_fast8_t id) {
|
||||
if ((uint_fast8_t)id < MAX_TIMERS) {
|
||||
_timer_info[id].setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Disables the specified timer.
|
||||
/// @param id target timer id.
|
||||
void disable(int_fast8_t id) {
|
||||
if ((uint_fast8_t)id < MAX_TIMERS) {
|
||||
_timer_info[id].setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables the specified timer if it is currently disabled, and vice versa.
|
||||
/// @param id target timer id.
|
||||
void toggle(int_fast8_t id) {
|
||||
if ((uint_fast8_t)id < MAX_TIMERS) {
|
||||
_timer_info[id].toggle();
|
||||
}
|
||||
}
|
||||
|
||||
/// gets true if the specified timer is enabled
|
||||
/// @param id target timer id.
|
||||
/// @return false=disabled / true=enabled.
|
||||
bool isEnabled(int_fast8_t id) const {
|
||||
return ((uint_fast8_t)id < MAX_TIMERS) ? _timer_info[id].getEnabled() : false;
|
||||
}
|
||||
|
||||
/// gets the number of used timers.
|
||||
/// @return number of used timers.
|
||||
uint_fast8_t getNumTimers(void) const {
|
||||
return _enable_count;
|
||||
}
|
||||
|
||||
/// gets the number of available timers.
|
||||
/// @return number of available timers.
|
||||
uint_fast8_t getNumAvailableTimers(void) const {
|
||||
return MAX_TIMERS - _enable_count;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
class timer_info_t {
|
||||
public:
|
||||
void set(uint32_t interval_msec, timer_callback function, uint32_t times);
|
||||
bool run(uint32_t interval_msec);
|
||||
void clear(void);
|
||||
|
||||
inline timer_callback getCallback(void) const { return _callback; }
|
||||
inline bool getEnabled(void) const { return _enabled; }
|
||||
inline void setEnabled(bool flg) { _enabled = flg; }
|
||||
inline void toggle(void) { _enabled = !_enabled; }
|
||||
inline void setPreviousMsec(uint32_t msec) { _prev_msec = msec; }
|
||||
|
||||
private:
|
||||
timer_callback _callback = nullptr;
|
||||
uint32_t _prev_msec = 0;
|
||||
uint32_t _interval = 0;
|
||||
uint32_t _remain = 0;
|
||||
bool _enabled = false;
|
||||
};
|
||||
|
||||
timer_info_t _timer_info[MAX_TIMERS];
|
||||
|
||||
uint8_t _enable_count = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
783
libraries/M5Unified/src/utility/Mic_Class.cpp
Normal file
783
libraries/M5Unified/src/utility/Mic_Class.cpp
Normal file
|
|
@ -0,0 +1,783 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "Mic_Class.hpp"
|
||||
|
||||
#include "../M5Unified.hpp"
|
||||
|
||||
#if __has_include (<esp_idf_version.h>)
|
||||
#include <esp_idf_version.h>
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4
|
||||
#define NON_BREAK ;[[fallthrough]];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __has_include (<soc/pcr_struct.h>)
|
||||
#include <soc/pcr_struct.h>
|
||||
#endif
|
||||
|
||||
#ifndef NON_BREAK
|
||||
#define NON_BREAK ;
|
||||
#endif
|
||||
|
||||
#if __has_include(<sdkconfig.h>)
|
||||
#include <sdkconfig.h>
|
||||
#include <esp_log.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined ( CONFIG_IDF_TARGET_ESP32C3 ) || defined ( CONFIG_IDF_TARGET_ESP32C6 ) || defined ( CONFIG_IDF_TARGET_ESP32S3 ) || defined ( CONFIG_IDF_TARGET_ESP32P4 )
|
||||
#if __has_include(<driver/i2s_std.h>)
|
||||
#if __has_include(<hal/i2s_ll.h>)
|
||||
#include <hal/i2s_ll.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
|
||||
#if __has_include (<hal/adc_ll.h>)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
|
||||
#include <hal/adc_ll.h>
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
#if defined ( ESP_PLATFORM )
|
||||
#if defined (ESP_IDF_VERSION_VAL)
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
#define COMM_FORMAT_I2S (I2S_COMM_FORMAT_STAND_I2S)
|
||||
#define COMM_FORMAT_MSB (I2S_COMM_FORMAT_STAND_MSB)
|
||||
#endif
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 3)
|
||||
#define SAMPLE_RATE_TYPE uint32_t
|
||||
#endif
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
#define MIC_CLASS_ADC_WIDTH_BITS ADC_WIDTH_BIT_12
|
||||
#define MIC_CLASS_ADC_ATTEN_DB ADC_ATTEN_DB_12
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef COMM_FORMAT_I2S
|
||||
#define COMM_FORMAT_I2S (I2S_COMM_FORMAT_I2S)
|
||||
#define COMM_FORMAT_MSB (I2S_COMM_FORMAT_I2S_MSB)
|
||||
#endif
|
||||
|
||||
#ifndef SAMPLE_RATE_TYPE
|
||||
#define SAMPLE_RATE_TYPE int
|
||||
#endif
|
||||
|
||||
#ifndef MIC_CLASS_ADC_WIDTH_BITS
|
||||
#define MIC_CLASS_ADC_WIDTH_BITS ADC_WIDTH_12Bit
|
||||
#define MIC_CLASS_ADC_ATTEN_DB ADC_ATTEN_11db
|
||||
#endif
|
||||
|
||||
|
||||
uint32_t Mic_Class::_calc_rec_rate(void) const
|
||||
{
|
||||
int rate = (_cfg.sample_rate * _cfg.over_sampling);
|
||||
return rate;
|
||||
}
|
||||
|
||||
#if __has_include(<driver/i2s_std.h>)
|
||||
|
||||
static i2s_chan_handle_t _i2s_handle[SOC_I2S_NUM] = { nullptr, };
|
||||
|
||||
static esp_err_t _i2s_start(i2s_port_t port) {
|
||||
return i2s_channel_enable(_i2s_handle[port]);
|
||||
}
|
||||
static esp_err_t _i2s_stop(i2s_port_t port)
|
||||
{
|
||||
return i2s_channel_disable(_i2s_handle[port]);
|
||||
}
|
||||
static esp_err_t _i2s_read(i2s_port_t port, void* buf, size_t len, size_t* result, TickType_t tick) {
|
||||
return i2s_channel_read(_i2s_handle[port], buf, len, result, tick);
|
||||
}
|
||||
static esp_err_t _i2s_driver_uninstall(i2s_port_t port)
|
||||
{
|
||||
if (_i2s_handle[port] != nullptr) {
|
||||
auto res = i2s_del_channel(_i2s_handle[port]);
|
||||
_i2s_handle[port] = nullptr;
|
||||
return res;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
|
||||
|
||||
struct adc_digi_pattern_table_t {
|
||||
union {
|
||||
struct {
|
||||
uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements.
|
||||
0: measurement range 0 - 800mV,
|
||||
1: measurement range 0 - 1100mV,
|
||||
2: measurement range 0 - 1350mV,
|
||||
3: measurement range 0 - 2600mV. */
|
||||
uint8_t bit_width: 2; /*!< ADC resolution.
|
||||
- 0: 9 bit;
|
||||
- 1: 10 bit;
|
||||
- 2: 11 bit;
|
||||
- 3: 12 bit. */
|
||||
int8_t channel: 4; /*!< ADC channel index. */
|
||||
};
|
||||
uint8_t val; /*!<Raw data value */
|
||||
};
|
||||
};
|
||||
|
||||
static esp_err_t _i2s_set_adc(i2s_port_t port, gpio_num_t pin_data_in) {
|
||||
if (port == I2S_NUM_0)
|
||||
{ /// レジスタを操作してADCモードの設定を有効にする ;
|
||||
if (((size_t)pin_data_in) > 39) { return ESP_FAIL; }
|
||||
static constexpr const uint8_t adc_table[] =
|
||||
{
|
||||
ADC2_GPIO0_CHANNEL , // GPIO 0
|
||||
255 ,
|
||||
ADC2_GPIO2_CHANNEL , // GPIO 2
|
||||
255 ,
|
||||
ADC2_GPIO4_CHANNEL , // GPIO 4
|
||||
255, 255, 255, 255, 255, 255, 255,
|
||||
ADC2_GPIO12_CHANNEL , // GPIO 12
|
||||
ADC2_GPIO13_CHANNEL , // GPIO 13
|
||||
ADC2_GPIO14_CHANNEL , // GPIO 14
|
||||
ADC2_GPIO15_CHANNEL , // GPIO 15
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
ADC2_GPIO25_CHANNEL , // GPIO 25
|
||||
ADC2_GPIO26_CHANNEL , // GPIO 26
|
||||
ADC2_GPIO27_CHANNEL , // GPIO 27
|
||||
255, 255, 255, 255,
|
||||
ADC1_GPIO32_CHANNEL , // GPIO 32
|
||||
ADC1_GPIO33_CHANNEL , // GPIO 33
|
||||
ADC1_GPIO34_CHANNEL , // GPIO 34
|
||||
ADC1_GPIO35_CHANNEL , // GPIO 35
|
||||
ADC1_GPIO36_CHANNEL , // GPIO 36
|
||||
ADC1_GPIO37_CHANNEL , // GPIO 37
|
||||
ADC1_GPIO38_CHANNEL , // GPIO 38
|
||||
ADC1_GPIO39_CHANNEL , // GPIO 39
|
||||
};
|
||||
int adc_ch = adc_table[pin_data_in];
|
||||
if (adc_ch == 255) { return ESP_FAIL; }
|
||||
|
||||
adc_unit_t unit = pin_data_in >= 32 ? ADC_UNIT_1 : ADC_UNIT_2;
|
||||
|
||||
adc_oneshot_ll_set_output_bits(unit, ADC_BITWIDTH_12);
|
||||
|
||||
{
|
||||
rtc_gpio_init(pin_data_in);
|
||||
rtc_gpio_set_direction(pin_data_in, RTC_GPIO_MODE_DISABLED);
|
||||
rtc_gpio_pullup_dis(pin_data_in);
|
||||
rtc_gpio_pulldown_dis(pin_data_in);
|
||||
|
||||
adc_ll_digi_set_fsm_time(8/*ADC_HAL_FSM_RSTB_WAIT_DEFAULT*/,
|
||||
16/*ADC_HAL_FSM_START_WAIT_DEFAULT*/,
|
||||
100/*ADC_HAL_FSM_STANDBY_WAIT_DEFAULT*/);
|
||||
adc_ll_set_sample_cycle(2/*ADC_HAL_SAMPLE_CYCLE_DEFAULT*/);
|
||||
adc_ll_pwdet_set_cct(4/*ADC_HAL_PWDET_CCT_DEFAULT*/);
|
||||
adc_ll_digi_set_clk_div(16/*ADC_HAL_DIGI_SAR_CLK_DIV_DEFAULT*/);
|
||||
adc_ll_digi_output_invert(unit, ADC_LL_DIGI_DATA_INVERT_DEFAULT(unit));
|
||||
adc_ll_digi_set_convert_mode((unit == ADC_UNIT_1) ? ADC_LL_DIGI_CONV_ONLY_ADC1 : ADC_LL_DIGI_CONV_ONLY_ADC2);
|
||||
adc_ll_set_controller(unit, ADC_LL_CTRL_DIG);
|
||||
adc_ll_digi_clear_pattern_table(unit);
|
||||
adc_ll_digi_set_pattern_table_len(unit, 1);
|
||||
adc_digi_pattern_table_t pattern;
|
||||
pattern.atten = ADC_ATTEN_DB_12;
|
||||
pattern.bit_width = 3;
|
||||
pattern.channel = adc_ch;
|
||||
{
|
||||
uint8_t index = 0;
|
||||
uint8_t offset = 0;
|
||||
auto saradc_tab = (adc_ch == ADC_UNIT_1)
|
||||
? SYSCON.saradc_sar1_patt_tab
|
||||
: SYSCON.saradc_sar2_patt_tab;
|
||||
uint32_t tab = saradc_tab[index]; // Read old register value
|
||||
tab &= (~(0xFF000000 >> offset)); // clear old data
|
||||
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
|
||||
saradc_tab[index] = tab; // Write back
|
||||
}
|
||||
SYSCON.saradc_ctrl.data_sar_sel = 0; // ADC_DIGI_FORMAT_12BIT;
|
||||
adc_ll_digi_convert_limit_enable(ADC_LL_DEFAULT_CONV_LIMIT_EN);
|
||||
adc_ll_digi_set_convert_limit_num(ADC_LL_DEFAULT_CONV_LIMIT_NUM);
|
||||
adc_ll_digi_set_data_source(1); //ADC_I2S_DATA_SRC_ADC;
|
||||
}
|
||||
I2S0.conf2.lcd_en = true;
|
||||
I2S0.conf.rx_right_first = 0;
|
||||
I2S0.conf.rx_msb_shift = 0;
|
||||
I2S0.conf.rx_mono = 0;
|
||||
I2S0.conf.rx_short_sync = 0;
|
||||
I2S0.fifo_conf.rx_fifo_mod = true;
|
||||
I2S0.conf_chan.rx_chan_mod = true;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
static esp_err_t _i2s_start(i2s_port_t port)
|
||||
{
|
||||
return i2s_start(port);
|
||||
}
|
||||
static esp_err_t _i2s_stop(i2s_port_t port)
|
||||
{
|
||||
return i2s_stop(port);
|
||||
}
|
||||
static esp_err_t _i2s_read(i2s_port_t port, void* buf, size_t len, size_t* result, TickType_t tick)
|
||||
{
|
||||
return i2s_read(port, buf, len, result, tick);
|
||||
}
|
||||
static esp_err_t _i2s_driver_uninstall(i2s_port_t port)
|
||||
{
|
||||
return i2s_driver_uninstall(port);
|
||||
}
|
||||
#if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
|
||||
static esp_err_t _i2s_set_adc(i2s_port_t port, gpio_num_t pin_data_in) {
|
||||
if (port == I2S_NUM_0)
|
||||
{ /// レジスタを操作してADCモードの設定を有効にする ;
|
||||
if (((size_t)pin_data_in) > 39) { return ESP_FAIL; }
|
||||
static constexpr const uint8_t adc_table[] =
|
||||
{
|
||||
ADC2_CHANNEL_1 , // GPIO 0
|
||||
255 ,
|
||||
ADC2_CHANNEL_2 , // GPIO 2
|
||||
255 ,
|
||||
ADC2_CHANNEL_0 , // GPIO 4
|
||||
255, 255, 255, 255, 255, 255, 255,
|
||||
ADC2_CHANNEL_5 , // GPIO 12
|
||||
ADC2_CHANNEL_4 , // GPIO 13
|
||||
ADC2_CHANNEL_6 , // GPIO 14
|
||||
ADC2_CHANNEL_3 , // GPIO 15
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
ADC2_CHANNEL_8 , // GPIO 25
|
||||
ADC2_CHANNEL_9 , // GPIO 26
|
||||
ADC2_CHANNEL_7 , // GPIO 27
|
||||
255, 255, 255, 255,
|
||||
ADC1_CHANNEL_4 , // GPIO 32
|
||||
ADC1_CHANNEL_5 , // GPIO 33
|
||||
ADC1_CHANNEL_6 , // GPIO 34
|
||||
ADC1_CHANNEL_7 , // GPIO 35
|
||||
ADC1_CHANNEL_0 , // GPIO 36
|
||||
ADC1_CHANNEL_1 , // GPIO 37
|
||||
ADC1_CHANNEL_2 , // GPIO 38
|
||||
ADC1_CHANNEL_3 , // GPIO 39
|
||||
};
|
||||
int adc_ch = adc_table[pin_data_in];
|
||||
if (adc_ch == 255) { return ESP_FAIL; }
|
||||
|
||||
adc_unit_t unit = pin_data_in >= 32 ? ADC_UNIT_1 : ADC_UNIT_2;
|
||||
adc_set_data_width(unit, MIC_CLASS_ADC_WIDTH_BITS);
|
||||
esp_err_t err = i2s_set_adc_mode(unit, (adc1_channel_t)adc_ch);
|
||||
if (unit == ADC_UNIT_1)
|
||||
{
|
||||
adc1_config_channel_atten((adc1_channel_t)adc_ch, MIC_CLASS_ADC_ATTEN_DB);
|
||||
}
|
||||
else
|
||||
{
|
||||
adc2_config_channel_atten((adc2_channel_t)adc_ch, MIC_CLASS_ADC_ATTEN_DB);
|
||||
}
|
||||
I2S0.conf2.lcd_en = true;
|
||||
I2S0.conf.rx_right_first = 0;
|
||||
I2S0.conf.rx_msb_shift = 0;
|
||||
I2S0.conf.rx_mono = 0;
|
||||
I2S0.conf.rx_short_sync = 0;
|
||||
I2S0.fifo_conf.rx_fifo_mod = true;
|
||||
I2S0.conf_chan.rx_chan_mod = true;
|
||||
return err;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
esp_err_t Mic_Class::_setup_i2s(void)
|
||||
{
|
||||
if (_cfg.pin_data_in < 0) { return ESP_FAIL; }
|
||||
#if __has_include(<driver/i2s_std.h>)
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(_cfg.i2s_port, I2S_ROLE_MASTER);
|
||||
chan_cfg.dma_desc_num = _cfg.dma_buf_count;
|
||||
chan_cfg.dma_frame_num = _cfg.dma_buf_len;
|
||||
_i2s_driver_uninstall(_cfg.i2s_port);
|
||||
esp_err_t err = i2s_new_channel(&chan_cfg, nullptr, &_i2s_handle[_cfg.i2s_port]);
|
||||
if (err != ESP_OK) { return err; }
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX
|
||||
if (_cfg.pin_bck < 0 || _cfg.pin_ws < 0) {
|
||||
i2s_pdm_rx_config_t i2s_config;
|
||||
memset(&i2s_config, 0, sizeof(i2s_pdm_rx_config_t));
|
||||
#if defined ( CONFIG_IDF_TARGET_ESP32P4 )
|
||||
i2s_config.clk_cfg.clk_src = i2s_clock_src_t::I2S_CLK_SRC_DEFAULT;
|
||||
#else
|
||||
i2s_config.clk_cfg.clk_src = i2s_clock_src_t::I2S_CLK_SRC_PLL_160M;
|
||||
#endif
|
||||
i2s_config.clk_cfg.sample_rate_hz = 48000; // dummy setting
|
||||
i2s_config.clk_cfg.mclk_multiple = i2s_mclk_multiple_t::I2S_MCLK_MULTIPLE_128; // dummy setting
|
||||
i2s_config.slot_cfg.data_bit_width = i2s_data_bit_width_t::I2S_DATA_BIT_WIDTH_16BIT;
|
||||
i2s_config.slot_cfg.slot_bit_width = i2s_slot_bit_width_t::I2S_SLOT_BIT_WIDTH_16BIT;
|
||||
i2s_config.slot_cfg.slot_mode = (_cfg.stereo) ? i2s_slot_mode_t::I2S_SLOT_MODE_STEREO : i2s_slot_mode_t::I2S_SLOT_MODE_MONO;
|
||||
i2s_config.slot_cfg.slot_mask = (_cfg.stereo) ? i2s_pdm_slot_mask_t::I2S_PDM_SLOT_BOTH : (_cfg.left_channel ? i2s_pdm_slot_mask_t::I2S_PDM_SLOT_LEFT : i2s_pdm_slot_mask_t::I2S_PDM_SLOT_RIGHT);
|
||||
i2s_config.gpio_cfg.clk = (gpio_num_t)_cfg.pin_ws;
|
||||
i2s_config.gpio_cfg.din = (gpio_num_t)_cfg.pin_data_in;
|
||||
err = i2s_channel_init_pdm_rx_mode(_i2s_handle[_cfg.i2s_port], &i2s_config);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
i2s_std_config_t i2s_config;
|
||||
memset(&i2s_config, 0, sizeof(i2s_std_config_t));
|
||||
#if defined ( CONFIG_IDF_TARGET_ESP32P4 )
|
||||
i2s_config.clk_cfg.clk_src = i2s_clock_src_t::I2S_CLK_SRC_DEFAULT;
|
||||
#else
|
||||
i2s_config.clk_cfg.clk_src = i2s_clock_src_t::I2S_CLK_SRC_PLL_160M;
|
||||
#endif
|
||||
i2s_config.clk_cfg.sample_rate_hz = 48000; // dummy setting
|
||||
i2s_config.clk_cfg.mclk_multiple = i2s_mclk_multiple_t::I2S_MCLK_MULTIPLE_128; // dummy setting
|
||||
i2s_config.slot_cfg.data_bit_width = i2s_data_bit_width_t::I2S_DATA_BIT_WIDTH_16BIT;
|
||||
i2s_config.slot_cfg.slot_bit_width = i2s_slot_bit_width_t::I2S_SLOT_BIT_WIDTH_16BIT;
|
||||
i2s_config.slot_cfg.slot_mode = (_cfg.stereo) ? i2s_slot_mode_t::I2S_SLOT_MODE_STEREO : i2s_slot_mode_t::I2S_SLOT_MODE_MONO;
|
||||
i2s_config.slot_cfg.slot_mask = (_cfg.stereo) ? i2s_std_slot_mask_t::I2S_STD_SLOT_BOTH : (_cfg.left_channel ? i2s_std_slot_mask_t::I2S_STD_SLOT_LEFT : i2s_std_slot_mask_t::I2S_STD_SLOT_RIGHT);
|
||||
i2s_config.slot_cfg.ws_width = 16;
|
||||
i2s_config.slot_cfg.bit_shift = true;
|
||||
#if SOC_I2S_HW_VERSION_1 // For esp32/esp32-s2
|
||||
i2s_config.slot_cfg.msb_right = false;
|
||||
#else
|
||||
i2s_config.slot_cfg.left_align = true;
|
||||
i2s_config.slot_cfg.big_endian = false;
|
||||
i2s_config.slot_cfg.bit_order_lsb = false;
|
||||
#endif
|
||||
i2s_config.gpio_cfg.bclk = (gpio_num_t)_cfg.pin_bck;
|
||||
i2s_config.gpio_cfg.ws = (gpio_num_t)_cfg.pin_ws;
|
||||
i2s_config.gpio_cfg.dout = (gpio_num_t)I2S_PIN_NO_CHANGE;
|
||||
i2s_config.gpio_cfg.mclk = (gpio_num_t)_cfg.pin_mck;
|
||||
i2s_config.gpio_cfg.din = (gpio_num_t)_cfg.pin_data_in;
|
||||
err = i2s_channel_init_std_mode(_i2s_handle[_cfg.i2s_port], &i2s_config);
|
||||
}
|
||||
|
||||
#if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
|
||||
if (_cfg.use_adc)
|
||||
{
|
||||
err = _i2s_set_adc(_cfg.i2s_port, (gpio_num_t)_cfg.pin_data_in);
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
|
||||
#else
|
||||
i2s_config_t i2s_config;
|
||||
memset(&i2s_config, 0, sizeof(i2s_config_t));
|
||||
i2s_config.mode = (i2s_mode_t)( I2S_MODE_MASTER | I2S_MODE_RX );
|
||||
i2s_config.sample_rate = 48000; // dummy setting.
|
||||
i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
|
||||
i2s_config.channel_format = _cfg.stereo ? I2S_CHANNEL_FMT_RIGHT_LEFT : _cfg.left_channel ? I2S_CHANNEL_FMT_ONLY_LEFT : I2S_CHANNEL_FMT_ONLY_RIGHT;
|
||||
i2s_config.communication_format = (i2s_comm_format_t)( COMM_FORMAT_I2S );
|
||||
i2s_config.dma_buf_count = _cfg.dma_buf_count;
|
||||
i2s_config.dma_buf_len = _cfg.dma_buf_len;
|
||||
|
||||
i2s_pin_config_t pin_config;
|
||||
memset(&pin_config, ~0u, sizeof(i2s_pin_config_t)); /// all pin set to I2S_PIN_NO_CHANGE
|
||||
#if defined (ESP_IDF_VERSION_VAL)
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 1)
|
||||
pin_config.mck_io_num = _cfg.pin_mck;
|
||||
#endif
|
||||
#endif
|
||||
pin_config.bck_io_num = _cfg.pin_bck;
|
||||
pin_config.ws_io_num = _cfg.pin_ws;
|
||||
pin_config.data_in_num = _cfg.pin_data_in;
|
||||
|
||||
if (_cfg.pin_bck < 0 || _cfg.pin_ws < 0) {
|
||||
i2s_config.mode = (i2s_mode_t)( I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM );
|
||||
i2s_config.communication_format = i2s_comm_format_t::I2S_COMM_FORMAT_STAND_PCM_SHORT;
|
||||
}
|
||||
esp_err_t err;
|
||||
if (ESP_OK != (err = i2s_driver_install(_cfg.i2s_port, &i2s_config, 0, nullptr)))
|
||||
{
|
||||
_i2s_driver_uninstall(_cfg.i2s_port);
|
||||
err = i2s_driver_install(_cfg.i2s_port, &i2s_config, 0, nullptr);
|
||||
}
|
||||
if (err != ESP_OK) { return err; }
|
||||
|
||||
#if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
|
||||
if (_cfg.use_adc)
|
||||
{
|
||||
err = _i2s_set_adc(_cfg.i2s_port, (gpio_num_t)_cfg.pin_data_in);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
err = i2s_set_pin(_cfg.i2s_port, &pin_config);
|
||||
}
|
||||
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
||||
// クロックディバイダー計算用関数 (実装は Speaker_Class.cpp内)
|
||||
void calcClockDiv(uint32_t* div_a, uint32_t* div_b, uint32_t* div_n, uint32_t baseClock, uint32_t targetFreq);
|
||||
|
||||
void Mic_Class::mic_task(void* args)
|
||||
{
|
||||
auto self = (Mic_Class*)args;
|
||||
int oversampling = self->_cfg.over_sampling;
|
||||
if ( oversampling < 1) { oversampling = 1; }
|
||||
else if (oversampling > 8) { oversampling = 8; }
|
||||
|
||||
bool use_pdm = (self->_cfg.pin_bck < 0 && !self->_cfg.use_adc);
|
||||
|
||||
#if defined ( CONFIG_IDF_TARGET_ESP32C3 ) || defined (CONFIG_IDF_TARGET_ESP32C6) || defined ( CONFIG_IDF_TARGET_ESP32S3 )
|
||||
static constexpr uint32_t PLL_D2_CLK = 120*1000*1000; // 240 MHz/2
|
||||
#elif defined ( CONFIG_IDF_TARGET_ESP32P4 )
|
||||
static constexpr uint32_t PLL_D2_CLK = 20*1000*1000; // 20 MHz
|
||||
#else
|
||||
static constexpr uint32_t PLL_D2_CLK = 80*1000*1000; // 160 MHz/2
|
||||
#endif
|
||||
|
||||
uint32_t bits = (self->_cfg.use_adc) ? 1 : 16; /// 1サンプリング当たりの出力ビット数;
|
||||
uint32_t div_a, div_b, div_n;
|
||||
|
||||
// CoreS3 のマイクはmclkの倍率(div_m)の値を8以上に設定しないと精度が落ちる。
|
||||
uint32_t div_m = 8;
|
||||
|
||||
// PDM録音時、DSR(データサンプリングレート) 64に設定する
|
||||
if (use_pdm) { bits = 64; div_m = 2; }
|
||||
calcClockDiv(&div_a, &div_b, &div_n, PLL_D2_CLK / (bits * div_m), self->_cfg.sample_rate * oversampling);
|
||||
|
||||
auto dev = &I2S0;
|
||||
#if SOC_I2S_NUM >= 2
|
||||
if (self->_cfg.i2s_port == i2s_port_t::I2S_NUM_1) { dev = &I2S1; }
|
||||
#if SOC_I2S_NUM >= 3
|
||||
else if (self->_cfg.i2s_port == i2s_port_t::I2S_NUM_2) { dev = &I2S2; }
|
||||
#if SOC_I2S_NUM >= 4
|
||||
else if (self->_cfg.i2s_port == i2s_port_t::I2S_NUM_3) { dev = &I2S3; }
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined ( CONFIG_IDF_TARGET_ESP32C3 ) || defined ( CONFIG_IDF_TARGET_ESP32C6 ) || defined ( CONFIG_IDF_TARGET_ESP32S3 ) || defined ( CONFIG_IDF_TARGET_ESP32P4 )
|
||||
|
||||
dev->rx_conf.rx_pdm_en = use_pdm;
|
||||
dev->rx_conf.rx_tdm_en = !use_pdm;
|
||||
#if defined ( I2S_RX_PDM2PCM_CONF_REG )
|
||||
dev->rx_pdm2pcm_conf.rx_pdm2pcm_en = use_pdm;
|
||||
dev->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en = 0;
|
||||
#elif defined (I2S_RX_PDM2PCM_EN)
|
||||
dev->rx_conf.rx_pdm2pcm_en = use_pdm;
|
||||
dev->rx_conf.rx_pdm_sinc_dsr_16_en = 0;
|
||||
#endif
|
||||
dev->rx_conf.rx_update = 1;
|
||||
|
||||
#if defined ( CONFIG_IDF_TARGET_ESP32P4 )
|
||||
dev->rx_conf.rx_bck_div_num = div_m - 1;
|
||||
#else
|
||||
dev->rx_conf1.rx_bck_div_num = div_m - 1;
|
||||
#endif
|
||||
|
||||
bool yn1 = (div_b > (div_a >> 1));
|
||||
if (yn1) {
|
||||
div_b = div_a - div_b;
|
||||
}
|
||||
int div_y = 1;
|
||||
int div_x = 0;
|
||||
if (div_b)
|
||||
{
|
||||
div_x = div_a / div_b - 1;
|
||||
div_y = div_a % div_b;
|
||||
|
||||
if (div_y == 0)
|
||||
{ // div_yが0になる場合、分数成分が無視される不具合があり、
|
||||
// 指定よりクロックが速くなってしまう。
|
||||
// 回避策として、誤差が少なくなる設定値を導入する。
|
||||
// これにより、誤差をクロック周期512回に1回程度のズレに抑える。;
|
||||
div_y = 1;
|
||||
div_b = 511;
|
||||
}
|
||||
}
|
||||
|
||||
#if __has_include(<driver/i2s_std.h>)
|
||||
i2s_ll_rx_set_raw_clk_div(dev, div_n, div_x, div_y, div_b, yn1);
|
||||
#endif
|
||||
|
||||
#if __has_include (<soc/pcr_struct.h>) // for C6
|
||||
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = div_x;
|
||||
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = div_y;
|
||||
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = div_b;
|
||||
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = yn1;
|
||||
PCR.i2s_rx_clkm_conf.i2s_rx_clkm_div_num = div_n;
|
||||
PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 1; // PLL_240M_CLK
|
||||
PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 1;
|
||||
PCR.pll_div_clk_en.pll_240m_clk_en = 1;
|
||||
#elif defined ( I2S_RX_CLKM_DIV_X )
|
||||
dev->rx_clkm_div_conf.rx_clkm_div_x = div_x;
|
||||
dev->rx_clkm_div_conf.rx_clkm_div_y = div_y;
|
||||
dev->rx_clkm_div_conf.rx_clkm_div_z = div_b;
|
||||
dev->rx_clkm_div_conf.rx_clkm_div_yn1 = yn1;
|
||||
dev->rx_clkm_conf.rx_clkm_div_num = div_n;
|
||||
dev->rx_clkm_conf.rx_clk_sel = 1; // PLL_240M_CLK
|
||||
dev->tx_clkm_conf.clk_en = 1;
|
||||
dev->rx_clkm_conf.rx_clk_active = 1;
|
||||
|
||||
dev->rx_conf.rx_update = 1;
|
||||
dev->rx_conf.rx_update = 0;
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
if (use_pdm)
|
||||
{
|
||||
dev->pdm_conf.rx_sinc_dsr_16_en = 1; // 0=DSR64 / 1=DSR128
|
||||
dev->pdm_conf.pdm2pcm_conv_en = 1;
|
||||
dev->pdm_conf.rx_pdm_en = 1;
|
||||
}
|
||||
|
||||
dev->sample_rate_conf.rx_bck_div_num = div_m;
|
||||
dev->clkm_conf.clkm_div_a = div_a;
|
||||
dev->clkm_conf.clkm_div_b = div_b;
|
||||
dev->clkm_conf.clkm_div_num = div_n;
|
||||
dev->clkm_conf.clka_en = 0; // APLL disable : PLL_160M
|
||||
|
||||
// If RX is not reset here, BCK polarity may be inverted.
|
||||
dev->conf.rx_reset = 1;
|
||||
dev->conf.rx_fifo_reset = 1;
|
||||
dev->conf.rx_reset = 0;
|
||||
dev->conf.rx_fifo_reset = 0;
|
||||
|
||||
#endif
|
||||
|
||||
_i2s_start(self->_cfg.i2s_port);
|
||||
|
||||
int32_t gain = self->_cfg.magnification;
|
||||
const float f_gain = (float)gain / (oversampling << 1);
|
||||
size_t src_idx = ~0u;
|
||||
size_t src_len = 0;
|
||||
int32_t sum_value[4] = { 0,0 };
|
||||
int32_t prev_value[2] = { 0, 0 };
|
||||
const bool in_stereo = self->_cfg.stereo;
|
||||
int32_t os_remain = oversampling;
|
||||
const size_t dma_buf_len = self->_cfg.dma_buf_len;
|
||||
int16_t* src_buf = (int16_t*)alloca(dma_buf_len * sizeof(int16_t));
|
||||
memset(src_buf, 0, dma_buf_len * sizeof(int16_t));
|
||||
|
||||
_i2s_read(self->_cfg.i2s_port, src_buf, dma_buf_len, &src_len, portTICK_PERIOD_MS);
|
||||
_i2s_read(self->_cfg.i2s_port, src_buf, dma_buf_len, &src_len, portTICK_PERIOD_MS);
|
||||
|
||||
while (self->_task_running)
|
||||
{
|
||||
bool rec_flip = self->_rec_flip;
|
||||
recording_info_t* current_rec = &(self->_rec_info[!rec_flip]);
|
||||
recording_info_t* next_rec = &(self->_rec_info[ rec_flip]);
|
||||
|
||||
size_t dst_remain = current_rec->length;
|
||||
if (dst_remain == 0)
|
||||
{
|
||||
rec_flip = !rec_flip;
|
||||
self->_rec_flip = rec_flip;
|
||||
xSemaphoreGive(self->_task_semaphore);
|
||||
std::swap(current_rec, next_rec);
|
||||
dst_remain = current_rec->length;
|
||||
if (dst_remain == 0)
|
||||
{
|
||||
self->_is_recording = false;
|
||||
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
|
||||
src_idx = ~0u;
|
||||
src_len = 0;
|
||||
sum_value[0] = 0;
|
||||
sum_value[1] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
self->_is_recording = true;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (src_idx >= src_len)
|
||||
{
|
||||
_i2s_read(self->_cfg.i2s_port, src_buf, dma_buf_len, &src_len, 100 / portTICK_PERIOD_MS);
|
||||
src_len >>= 1;
|
||||
src_idx = 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
sum_value[0] += src_buf[src_idx ];
|
||||
sum_value[1] += src_buf[src_idx+1];
|
||||
src_idx += 2;
|
||||
} while (--os_remain && (src_idx < src_len));
|
||||
|
||||
if (os_remain) { continue; }
|
||||
os_remain = oversampling;
|
||||
|
||||
#if defined (CONFIG_IDF_TARGET_ESP32)
|
||||
auto sv0 = sum_value[1];
|
||||
auto sv1 = sum_value[0];
|
||||
#else
|
||||
auto sv0 = sum_value[0];
|
||||
auto sv1 = sum_value[1];
|
||||
#endif
|
||||
if (self->_cfg.use_adc) {
|
||||
sv0 -= 2048 * oversampling;
|
||||
sv1 -= 2048 * oversampling;
|
||||
}
|
||||
|
||||
auto value_tmp = (sv0 + sv1) << 3;
|
||||
int32_t offset = self->_offset;
|
||||
// Automatic zero level adjustment
|
||||
offset -= (value_tmp + offset + 16) >> 5;
|
||||
self->_offset = offset;
|
||||
offset = (offset + 8) >> 4;
|
||||
sum_value[0] = sv0 + offset;
|
||||
sum_value[1] = sv1 + offset;
|
||||
|
||||
int32_t noise_filter = self->_cfg.noise_filter_level;
|
||||
if (noise_filter)
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
int32_t v = (sum_value[i] * (256 - noise_filter) + prev_value[i] * noise_filter + 128) >> 8;
|
||||
prev_value[i] = v;
|
||||
sum_value[i] = v * f_gain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
sum_value[i] *= f_gain;
|
||||
}
|
||||
}
|
||||
|
||||
int output_num = 2;
|
||||
|
||||
if (in_stereo != current_rec->is_stereo)
|
||||
{
|
||||
if (in_stereo)
|
||||
{ // stereo -> mono convert.
|
||||
sum_value[0] = (sum_value[0] + sum_value[1] + 1) >> 1;
|
||||
output_num = 1;
|
||||
}
|
||||
else
|
||||
{ // mono -> stereo convert.
|
||||
auto tmp = sum_value[1];
|
||||
sum_value[3] = tmp;
|
||||
sum_value[2] = tmp;
|
||||
sum_value[1] = sum_value[0];
|
||||
output_num = 4;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < output_num; ++i)
|
||||
{
|
||||
auto value = sum_value[i];
|
||||
if (current_rec->is_16bit)
|
||||
{
|
||||
if ( value < INT16_MIN+16) { value = INT16_MIN+16; }
|
||||
else if (value > INT16_MAX-16) { value = INT16_MAX-16; }
|
||||
auto dst = (int16_t*)(current_rec->data);
|
||||
*dst++ = value;
|
||||
current_rec->data = dst;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = ((value + 128) >> 8) + 128;
|
||||
if ( value < 0) { value = 0; }
|
||||
else if (value > 255) { value = 255; }
|
||||
auto dst = (uint8_t*)(current_rec->data);
|
||||
*dst++ = value;
|
||||
current_rec->data = dst;
|
||||
}
|
||||
}
|
||||
sum_value[0] = 0;
|
||||
sum_value[1] = 0;
|
||||
dst_remain -= output_num;
|
||||
if ((int32_t)dst_remain <= 0)
|
||||
{
|
||||
current_rec->length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self->_is_recording = false;
|
||||
_i2s_stop(self->_cfg.i2s_port);
|
||||
|
||||
self->_task_handle = nullptr;
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
|
||||
bool Mic_Class::begin(void)
|
||||
{
|
||||
if (_task_running)
|
||||
{
|
||||
auto rate = _calc_rec_rate();
|
||||
if (_rec_sample_rate == rate)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
do { vTaskDelay(1); } while (isRecording());
|
||||
end();
|
||||
_rec_sample_rate = rate;
|
||||
}
|
||||
|
||||
if (_task_semaphore == nullptr) { _task_semaphore = xSemaphoreCreateBinary(); }
|
||||
|
||||
bool res = true;
|
||||
if (_cb_set_enabled) { res = _cb_set_enabled(_cb_set_enabled_args, true); }
|
||||
|
||||
res = (ESP_OK == _setup_i2s()) && res;
|
||||
if (res)
|
||||
{
|
||||
size_t stack_size = 2048 + (_cfg.dma_buf_len * sizeof(uint16_t));
|
||||
_task_running = true;
|
||||
#if portNUM_PROCESSORS > 1
|
||||
if (_cfg.task_pinned_core < portNUM_PROCESSORS)
|
||||
{
|
||||
xTaskCreatePinnedToCore(mic_task, "mic_task", stack_size, this, _cfg.task_priority, &_task_handle, _cfg.task_pinned_core);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
xTaskCreate(mic_task, "mic_task", stack_size, this, _cfg.task_priority, &_task_handle);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Mic_Class::end(void)
|
||||
{
|
||||
if (!_task_running) { return; }
|
||||
_task_running = false;
|
||||
if (_task_handle)
|
||||
{
|
||||
if (_task_handle) { xTaskNotifyGive(_task_handle); }
|
||||
do { vTaskDelay(1); } while (_task_handle);
|
||||
}
|
||||
|
||||
if (_cb_set_enabled) { _cb_set_enabled(_cb_set_enabled_args, false); }
|
||||
_i2s_driver_uninstall(_cfg.i2s_port);
|
||||
}
|
||||
|
||||
bool Mic_Class::_rec_raw(void* recdata, size_t array_len, bool flg_16bit, uint32_t sample_rate, bool flg_stereo)
|
||||
{
|
||||
recording_info_t info;
|
||||
info.data = recdata;
|
||||
info.length = array_len;
|
||||
info.is_16bit = flg_16bit;
|
||||
info.is_stereo = flg_stereo;
|
||||
|
||||
_cfg.sample_rate = sample_rate;
|
||||
|
||||
if (!begin()) { return false; }
|
||||
if (array_len == 0) { return true; }
|
||||
while (_rec_info[_rec_flip].length) { xSemaphoreTake(_task_semaphore, 1); }
|
||||
_rec_info[_rec_flip] = info;
|
||||
if (this->_task_handle)
|
||||
{
|
||||
xTaskNotifyGive(this->_task_handle);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
199
libraries/M5Unified/src/utility/Mic_Class.hpp
Normal file
199
libraries/M5Unified/src/utility/Mic_Class.hpp
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_Mic_Class_H__
|
||||
#define __M5_Mic_Class_H__
|
||||
|
||||
#include "m5unified_common.h"
|
||||
|
||||
#if defined ( ESP_PLATFORM )
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
#include <soc/i2s_struct.h>
|
||||
|
||||
#if __has_include(<driver/i2s_std.h>)
|
||||
#include <driver/i2s_std.h>
|
||||
#include <driver/i2s_pdm.h>
|
||||
#else
|
||||
#include <driver/i2s.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef I2S_PIN_NO_CHANGE
|
||||
#define I2S_PIN_NO_CHANGE (-1)
|
||||
#endif
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class M5Unified;
|
||||
|
||||
enum input_channel_t : uint8_t
|
||||
{
|
||||
input_only_right = 0,
|
||||
input_only_left = 1,
|
||||
input_stereo = 2,
|
||||
};
|
||||
|
||||
struct mic_config_t
|
||||
{
|
||||
/// i2s_data_in (for mic)
|
||||
int pin_data_in = -1;
|
||||
|
||||
/// i2s_bclk
|
||||
int pin_bck = I2S_PIN_NO_CHANGE;
|
||||
|
||||
/// i2s_mclk
|
||||
int pin_mck = I2S_PIN_NO_CHANGE;
|
||||
|
||||
/// i2s_ws (lrck)
|
||||
int pin_ws = I2S_PIN_NO_CHANGE;
|
||||
|
||||
/// input sampling rate (Hz)
|
||||
uint32_t sample_rate = 16000;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t left_channel : 1;
|
||||
uint8_t stereo : 1;
|
||||
uint8_t reserve : 6;
|
||||
};
|
||||
input_channel_t input_channel = input_only_right;
|
||||
};
|
||||
|
||||
/// Sampling times of obtain the average value
|
||||
uint8_t over_sampling = 2;
|
||||
|
||||
/// multiplier for input value
|
||||
uint8_t magnification = 16;
|
||||
|
||||
/// Coefficient of the previous value, used for noise filtering.
|
||||
uint8_t noise_filter_level = 0;
|
||||
|
||||
/// use analog input mic ( need only pin_data_in )
|
||||
bool use_adc = false;
|
||||
|
||||
/// for I2S dma_buf_len
|
||||
size_t dma_buf_len = 128;
|
||||
|
||||
/// for I2S dma_buf_count
|
||||
size_t dma_buf_count = 8;
|
||||
|
||||
/// background task priority
|
||||
uint8_t task_priority = 2;
|
||||
|
||||
/// background task pinned core
|
||||
uint8_t task_pinned_core = -1;
|
||||
|
||||
/// I2S port
|
||||
i2s_port_t i2s_port = i2s_port_t::I2S_NUM_0;
|
||||
};
|
||||
|
||||
class Mic_Class
|
||||
{
|
||||
friend M5Unified;
|
||||
|
||||
public:
|
||||
|
||||
mic_config_t config(void) const { return _cfg; }
|
||||
void config(const mic_config_t& cfg) { _cfg = cfg; }
|
||||
|
||||
bool begin(void);
|
||||
|
||||
void end(void);
|
||||
|
||||
bool isRunning(void) const { return _task_running; }
|
||||
|
||||
bool isEnabled(void) const { return _cfg.pin_data_in >= 0; }
|
||||
|
||||
/// now in recording or not.
|
||||
/// @return 0=not recording / 1=recording (There's room in the queue) / 2=recording (There's no room in the queue.)
|
||||
size_t isRecording(void) const { return _is_recording ? ((bool)_rec_info[0].length) + ((bool)_rec_info[1].length) : 0; }
|
||||
|
||||
/// set recording sampling rate.
|
||||
/// @param sample_rate the sampling rate (Hz)
|
||||
void setSampleRate(uint32_t sample_rate) { _cfg.sample_rate = sample_rate; }
|
||||
|
||||
/// record raw sound wave data.
|
||||
/// @param rec_data Recording destination array.
|
||||
/// @param array_len Number of data array elements.
|
||||
/// @param sample_rate the sampling rate (Hz)
|
||||
/// @param stereo true=data is stereo / false=data is monaural.
|
||||
bool record(uint8_t* rec_data, size_t array_len, uint32_t sample_rate, bool stereo = false)
|
||||
{
|
||||
return _rec_raw(rec_data, array_len, false, sample_rate, stereo);
|
||||
}
|
||||
|
||||
/// record raw sound wave data.
|
||||
/// @param rec_data Recording destination array.
|
||||
/// @param array_len Number of data array elements.
|
||||
/// @param sample_rate the sampling rate (Hz)
|
||||
/// @param stereo true=data is stereo / false=data is monaural.
|
||||
bool record(int16_t* rec_data, size_t array_len, uint32_t sample_rate, bool stereo = false)
|
||||
{
|
||||
return _rec_raw(rec_data, array_len, true, sample_rate, stereo);
|
||||
}
|
||||
|
||||
/// record raw sound wave data.
|
||||
/// @param rec_data Recording destination array.
|
||||
/// @param array_len Number of data array elements.
|
||||
bool record(uint8_t* rec_data, size_t array_len)
|
||||
{
|
||||
return _rec_raw(rec_data, array_len, false, _cfg.sample_rate, false);
|
||||
}
|
||||
|
||||
/// record raw sound wave data.
|
||||
/// @param rec_data Recording destination array.
|
||||
/// @param array_len Number of data array elements.
|
||||
bool record(int16_t* rec_data, size_t array_len)
|
||||
{
|
||||
return _rec_raw(rec_data, array_len, true, _cfg.sample_rate, false);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void setCallback(void* args, bool(*func)(void*, bool)) { _cb_set_enabled = func; _cb_set_enabled_args = args; }
|
||||
|
||||
struct recording_info_t
|
||||
{
|
||||
void* data = nullptr;
|
||||
size_t length = 0;
|
||||
size_t index = 0;
|
||||
bool is_stereo = false;
|
||||
bool is_16bit = false;
|
||||
};
|
||||
|
||||
recording_info_t _rec_info[2];
|
||||
volatile bool _rec_flip = false;
|
||||
|
||||
static void mic_task(void* args);
|
||||
|
||||
uint32_t _calc_rec_rate(void) const;
|
||||
esp_err_t _setup_i2s(void);
|
||||
bool _rec_raw(void* recdata, size_t array_len, bool flg_16bit, uint32_t sample_rate, bool stereo);
|
||||
|
||||
mic_config_t _cfg;
|
||||
uint32_t _rec_sample_rate = 0;
|
||||
|
||||
bool (*_cb_set_enabled)(void* args, bool enabled) = nullptr;
|
||||
void* _cb_set_enabled_args = nullptr;
|
||||
|
||||
int32_t _offset = 0;
|
||||
volatile bool _task_running = false;
|
||||
volatile bool _is_recording = false;
|
||||
#if defined (SDL_h_)
|
||||
SDL_Thread* _task_handle = nullptr;
|
||||
#else
|
||||
TaskHandle_t _task_handle = nullptr;
|
||||
volatile SemaphoreHandle_t _task_semaphore = nullptr;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
111
libraries/M5Unified/src/utility/PI4IOE5V6408_Class.cpp
Normal file
111
libraries/M5Unified/src/utility/PI4IOE5V6408_Class.cpp
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* @file pi4ioe5v6408.cpp
|
||||
* @author Forairaaaaa
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2024-06-26
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*
|
||||
*/
|
||||
#include "PI4IOE5V6408_Class.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
bool PI4IOE5V6408_Class::begin()
|
||||
{
|
||||
auto id = readRegister8(0x01);
|
||||
if (id == 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// false input, true output
|
||||
void PI4IOE5V6408_Class::setDirection(uint8_t pin, bool direction)
|
||||
{
|
||||
// Input, set 0
|
||||
if (!direction) {
|
||||
auto data = readRegister8(0x03);
|
||||
data &= ~(1 << pin);
|
||||
writeRegister8(0x03, data);
|
||||
}
|
||||
// Output, set 1
|
||||
else {
|
||||
auto data = readRegister8(0x03);
|
||||
data |= (1 << pin);
|
||||
writeRegister8(0x03, data);
|
||||
}
|
||||
}
|
||||
|
||||
void PI4IOE5V6408_Class::enablePull(uint8_t pin, bool enablePull)
|
||||
{
|
||||
if (enablePull) {
|
||||
auto data = readRegister8(0x0B);
|
||||
data |= (1 << pin);
|
||||
writeRegister8(0x0B, data);
|
||||
} else {
|
||||
auto data = readRegister8(0x0B);
|
||||
data &= ~(1 << pin);
|
||||
writeRegister8(0x0B, data);
|
||||
}
|
||||
}
|
||||
|
||||
// false down, true up
|
||||
void PI4IOE5V6408_Class::setPullMode(uint8_t pin, bool mode)
|
||||
{
|
||||
if (mode) {
|
||||
auto data = readRegister8(0x0D);
|
||||
data |= (1 << pin);
|
||||
writeRegister8(0x0D, data);
|
||||
} else {
|
||||
auto data = readRegister8(0x0D);
|
||||
data &= ~(1 << pin);
|
||||
writeRegister8(0x0D, data);
|
||||
}
|
||||
}
|
||||
|
||||
void PI4IOE5V6408_Class::setHighImpedance(uint8_t pin, bool enable)
|
||||
{
|
||||
auto data = readRegister8(0x07);
|
||||
|
||||
if (enable)
|
||||
data |= (1 << pin);
|
||||
else
|
||||
data &= ~(1 << pin);
|
||||
|
||||
writeRegister8(0x07, data);
|
||||
}
|
||||
|
||||
void PI4IOE5V6408_Class::digitalWrite(uint8_t pin, bool level)
|
||||
{
|
||||
auto data = readRegister8(0x05);
|
||||
// spdlog::info("data: {}", data);
|
||||
|
||||
if (level)
|
||||
data |= (1 << pin);
|
||||
else
|
||||
data &= ~(1 << pin);
|
||||
|
||||
writeRegister8(0x05, data);
|
||||
}
|
||||
|
||||
bool PI4IOE5V6408_Class::digitalRead(uint8_t pin)
|
||||
{
|
||||
auto data = readRegister8(0x0F);
|
||||
return (data & (1 << pin)) != 0;
|
||||
}
|
||||
|
||||
void PI4IOE5V6408_Class::resetIrq()
|
||||
{
|
||||
readRegister8(0x13);
|
||||
}
|
||||
|
||||
void PI4IOE5V6408_Class::disableIrq()
|
||||
{
|
||||
writeRegister8(0x11, 0B11111111);
|
||||
}
|
||||
|
||||
void PI4IOE5V6408_Class::enableIrq()
|
||||
{
|
||||
writeRegister8(0x11, 0x0);
|
||||
}
|
||||
}
|
||||
52
libraries/M5Unified/src/utility/PI4IOE5V6408_Class.hpp
Normal file
52
libraries/M5Unified/src/utility/PI4IOE5V6408_Class.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* @file pi4ioe5v6408.h
|
||||
* @author Forairaaaaa
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2024-06-26
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*
|
||||
*/
|
||||
#ifndef __M5_PI4IOE5V6408_H__
|
||||
#define __M5_PI4IOE5V6408_H__
|
||||
|
||||
#include "m5unified_common.h"
|
||||
|
||||
#include "I2C_Class.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
// https://www.diodes.com/assets/Datasheets/PI4IOE5V6408.pdf
|
||||
class PI4IOE5V6408_Class : public m5::I2C_Device
|
||||
{
|
||||
public:
|
||||
PI4IOE5V6408_Class(std::uint8_t i2c_addr = 0x43, std::uint32_t freq = 400000, m5::I2C_Class* i2c = &m5::In_I2C)
|
||||
: I2C_Device(i2c_addr, freq, i2c)
|
||||
{}
|
||||
|
||||
bool begin();
|
||||
|
||||
// false input, true output
|
||||
void setDirection(uint8_t pin, bool direction);
|
||||
|
||||
void enablePull(uint8_t pin, bool enablePull);
|
||||
|
||||
// false down, true up
|
||||
void setPullMode(uint8_t pin, bool mode);
|
||||
|
||||
void setHighImpedance(uint8_t pin, bool enable);
|
||||
|
||||
void digitalWrite(uint8_t pin, bool level);
|
||||
|
||||
bool digitalRead(uint8_t pin);
|
||||
|
||||
void resetIrq();
|
||||
|
||||
void disableIrq();
|
||||
|
||||
void enableIrq();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
1307
libraries/M5Unified/src/utility/Power_Class.cpp
Normal file
1307
libraries/M5Unified/src/utility/Power_Class.cpp
Normal file
File diff suppressed because it is too large
Load diff
203
libraries/M5Unified/src/utility/Power_Class.hpp
Normal file
203
libraries/M5Unified/src/utility/Power_Class.hpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_Power_Class_H__
|
||||
#define __M5_Power_Class_H__
|
||||
|
||||
#include "m5unified_common.h"
|
||||
|
||||
#include "I2C_Class.hpp"
|
||||
#include "AXP192_Class.hpp"
|
||||
#include "AXP2101_Class.hpp"
|
||||
#include "IP5306_Class.hpp"
|
||||
#include "INA3221_Class.hpp"
|
||||
#include "RTC8563_Class.hpp"
|
||||
|
||||
#if __has_include (<sdkconfig.h>)
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if __has_include (<esp_adc/adc_oneshot.h>) // ESP-IDF v5 or later
|
||||
#include <esp_adc/adc_oneshot.h>
|
||||
#if __has_include(<esp_adc/adc_cali.h>)
|
||||
#include <esp_adc/adc_cali.h>
|
||||
#endif
|
||||
#elif __has_include (<driver/adc.h>)
|
||||
#include <driver/adc.h>
|
||||
#include <esp_adc_cal.h>
|
||||
#endif
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class M5Unified;
|
||||
|
||||
enum ext_port_mask_t
|
||||
{ ext_none = 0
|
||||
// For individual control of external ports of M5Station
|
||||
, ext_PA = 0b00000001
|
||||
, ext_PB1 = 0b00000010
|
||||
, ext_PB2 = 0b00000100
|
||||
, ext_PC1 = 0b00001000
|
||||
, ext_PC2 = 0b00010000
|
||||
, ext_USB = 0b00100000 // M5Station external USB. ※ Not for CoreS3 main USB.
|
||||
, ext_MAIN = 0b10000000
|
||||
};
|
||||
|
||||
class Power_Class
|
||||
{
|
||||
friend M5Unified;
|
||||
public:
|
||||
|
||||
enum pmic_t
|
||||
{ pmic_unknown
|
||||
, pmic_adc
|
||||
, pmic_axp192
|
||||
, pmic_ip5306
|
||||
, pmic_axp2101
|
||||
};
|
||||
|
||||
enum is_charging_t
|
||||
{ is_discharging = 0
|
||||
, is_charging
|
||||
, charge_unknown
|
||||
};
|
||||
|
||||
bool begin(void);
|
||||
|
||||
/// Set power output of the external ports.
|
||||
/// @param enable true=output / false=input
|
||||
/// @param port_mask for M5Station. ext_port (bitmask).
|
||||
void setExtOutput(bool enable, ext_port_mask_t port_mask = (ext_port_mask_t)0xFF);
|
||||
|
||||
/// deprecated : Change to "setExtOutput"
|
||||
[[deprecated("Change to setExtOutput")]]
|
||||
void setExtPower(bool enable, ext_port_mask_t port_mask = (ext_port_mask_t)0xFF) { setExtOutput(enable, port_mask); }
|
||||
|
||||
/// Get power output of the external ports.
|
||||
/// @return true=output enabled / false=output disabled
|
||||
bool getExtOutput(void);
|
||||
|
||||
/// Set power output of the main USB port.
|
||||
/// @param enable true=output / false=input
|
||||
/// @attention for M5Stack CoreS3 main USB port.
|
||||
/// @attention ※ Not for M5Station external USB.
|
||||
void setUsbOutput(bool enable);
|
||||
|
||||
/// Get power output of the main USB port.
|
||||
/// @return true=output enabled / false=output disabled
|
||||
/// @attention for M5Stack CoreS3 main USB port.
|
||||
/// @attention ※ Not for M5Station external USB.
|
||||
bool getUsbOutput(void);
|
||||
|
||||
/// Turn on/off the power LED.
|
||||
/// @param brightness 0=OFF: 1~255=ON (Set brightness if possible.)
|
||||
void setLed(uint8_t brightness = 255);
|
||||
|
||||
/// all power off.
|
||||
void powerOff(void);
|
||||
|
||||
/// sleep and timer boot. The boot condition can be specified by the argument.
|
||||
/// @param seconds Number of seconds to boot.
|
||||
void timerSleep(int seconds);
|
||||
|
||||
/// sleep and timer boot. The boot condition can be specified by the argument.
|
||||
/// @param time Time to boot. (only minutes and hours can be specified. Ignore seconds)
|
||||
/// @attention CoreInk and M5Paper can't alarm boot because it can't be turned off while connected to USB.
|
||||
/// @attention CoreInk と M5Paper は USB接続中はRTCタイマー起動が出来ない。;
|
||||
void timerSleep(const rtc_time_t& time);
|
||||
|
||||
/// sleep and timer boot. The boot condition can be specified by the argument.
|
||||
/// @param date Date to boot. (only date and weekDay can be specified. Ignore year and month)
|
||||
/// @param time Time to boot. (only minutes and hours can be specified. Ignore seconds)
|
||||
/// @attention CoreInk and M5Paper can't alarm boot because it can't be turned off while connected to USB.
|
||||
/// @attention CoreInk と M5Paper は USB接続中はRTCタイマー起動が出来ない。;
|
||||
void timerSleep(const rtc_date_t& date, const rtc_time_t& time);
|
||||
|
||||
/// ESP32 deepsleep
|
||||
/// @param seconds Number of micro seconds to wakeup.
|
||||
void deepSleep(std::uint64_t micro_seconds = 0, bool touch_wakeup = true);
|
||||
|
||||
/// ESP32 lightsleep
|
||||
/// @param seconds Number of micro seconds to wakeup.
|
||||
void lightSleep(std::uint64_t micro_seconds = 0, bool touch_wakeup = true);
|
||||
|
||||
/// Get the remaining battery power.
|
||||
/// @return 0-100 level
|
||||
std::int32_t getBatteryLevel(void);
|
||||
|
||||
/// set battery charge enable.
|
||||
/// @param enable true=enable / false=disable
|
||||
void setBatteryCharge(bool enable);
|
||||
|
||||
/// set battery charge current
|
||||
/// @param max_mA milli ampere.
|
||||
/// @attention Non-functioning models : CoreInk , M5Paper , M5Stack(with non I2C IP5306)
|
||||
void setChargeCurrent(std::uint16_t max_mA);
|
||||
|
||||
/// set battery charge voltage
|
||||
/// @param max_mV milli volt.
|
||||
/// @attention Non-functioning models : CoreInk , M5Paper , M5Stack(with non I2C IP5306)
|
||||
void setChargeVoltage(std::uint16_t max_mV);
|
||||
|
||||
/// Get whether the battery is currently charging or not.
|
||||
/// @attention Non-functioning models : CoreInk , M5Paper , M5Stack(with non I2C IP5306)
|
||||
is_charging_t isCharging(void);
|
||||
|
||||
/// Get VBUS voltage
|
||||
/// @return VBUS voltage [mV] / -1=not supported model
|
||||
/// @attention Only for models with AXP192 or AXP2101
|
||||
int16_t getVBUSVoltage(void);
|
||||
|
||||
/// Get battery voltage
|
||||
/// @return battery voltage [mV]
|
||||
int16_t getBatteryVoltage(void);
|
||||
|
||||
/// get battery current
|
||||
/// @return battery current [mA] ( +=charge / -=discharge )
|
||||
int32_t getBatteryCurrent(void);
|
||||
|
||||
/// Get Power Key Press condition.
|
||||
/// @return 0=none / 1=long pressed / 2=short clicked / 3=both
|
||||
/// @attention Only for models with AXP192 or AXP2101
|
||||
/// @attention Once this function is called, the value is reset to 0, and the next time it is pressed on, the value changes.
|
||||
uint8_t getKeyState(void);
|
||||
|
||||
/// Operate the vibration motor
|
||||
/// @param level Vibration strength of the motor. (0=stop)
|
||||
void setVibration(uint8_t level);
|
||||
|
||||
pmic_t getType(void) const { return _pmic; }
|
||||
|
||||
#if defined (CONFIG_IDF_TARGET_ESP32S3)
|
||||
|
||||
AXP2101_Class Axp2101;
|
||||
|
||||
#elif defined (CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#else
|
||||
|
||||
AXP2101_Class Axp2101;
|
||||
AXP192_Class Axp192;
|
||||
IP5306_Class Ip5306;
|
||||
// secondery INA3221 for M5Station.
|
||||
INA3221_Class Ina3221[2] = { { 0x40 }, { 0x41 } };
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::int32_t _getBatteryAdcRaw(void);
|
||||
void _powerOff(bool withTimer);
|
||||
void _timerSleep(void);
|
||||
|
||||
float _adc_ratio = 0;
|
||||
std::uint8_t _wakeupPin = 255;
|
||||
std::uint8_t _rtcIntPin = 255;
|
||||
pmic_t _pmic = pmic_t::pmic_unknown;
|
||||
#if !defined (M5UNIFIED_PC_BUILD)
|
||||
uint8_t _batAdcCh;
|
||||
uint8_t _batAdcUnit;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
311
libraries/M5Unified/src/utility/RTC8563_Class.cpp
Normal file
311
libraries/M5Unified/src/utility/RTC8563_Class.cpp
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "RTC8563_Class.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
tm rtc_datetime_t::get_tm(void) const
|
||||
{
|
||||
tm t_st = {
|
||||
time.seconds,
|
||||
time.minutes,
|
||||
time.hours,
|
||||
date.date,
|
||||
date.month - 1,
|
||||
date.year - 1900,
|
||||
date.weekDay,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
return t_st;
|
||||
}
|
||||
|
||||
void rtc_datetime_t::set_tm(tm& datetime)
|
||||
{
|
||||
date = rtc_date_t { datetime };
|
||||
time = rtc_time_t { datetime };
|
||||
}
|
||||
|
||||
static std::uint8_t bcd2ToByte(std::uint8_t value)
|
||||
{
|
||||
return ((value >> 4) * 10) + (value & 0x0F);
|
||||
}
|
||||
|
||||
static std::uint8_t byteToBcd2(std::uint8_t value)
|
||||
{
|
||||
std::uint_fast8_t bcdhigh = value / 10;
|
||||
return (bcdhigh << 4) | (value - (bcdhigh * 10));
|
||||
}
|
||||
|
||||
bool RTC8563_Class::begin(I2C_Class* i2c)
|
||||
{
|
||||
if (i2c)
|
||||
{
|
||||
_i2c = i2c;
|
||||
i2c->begin();
|
||||
}
|
||||
/// TimerCameraの内蔵RTCが初期化に失敗することがあったため、最初に空打ちする;
|
||||
writeRegister8(0x00, 0x00);
|
||||
_init = writeRegister8(0x00, 0x00) && writeRegister8(0x0E, 0x03);
|
||||
return _init;
|
||||
}
|
||||
|
||||
bool RTC8563_Class::getVoltLow(void)
|
||||
{
|
||||
return readRegister8(0x02) & 0x80; // RTCC_VLSEC_MASK
|
||||
}
|
||||
|
||||
bool RTC8563_Class::getDateTime(rtc_datetime_t* datetime) const
|
||||
{
|
||||
std::uint8_t buf[7] = { 0 };
|
||||
|
||||
if (!isEnabled() || !readRegister(0x02, buf, 7)) { return false; }
|
||||
|
||||
datetime->time.seconds = bcd2ToByte(buf[0] & 0x7f);
|
||||
datetime->time.minutes = bcd2ToByte(buf[1] & 0x7f);
|
||||
datetime->time.hours = bcd2ToByte(buf[2] & 0x3f);
|
||||
|
||||
datetime->date.date = bcd2ToByte(buf[3] & 0x3f);
|
||||
datetime->date.weekDay = bcd2ToByte(buf[4] & 0x07);
|
||||
datetime->date.month = bcd2ToByte(buf[5] & 0x1f);
|
||||
datetime->date.year = bcd2ToByte(buf[6] & 0xff)
|
||||
+ ((0x80 & buf[5]) ? 1900 : 2000);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RTC8563_Class::getTime(rtc_time_t* time) const
|
||||
{
|
||||
std::uint8_t buf[3] = { 0 };
|
||||
|
||||
if (!isEnabled() || !readRegister(0x02, buf, 3)) { return false; }
|
||||
|
||||
time->seconds = bcd2ToByte(buf[0] & 0x7f);
|
||||
time->minutes = bcd2ToByte(buf[1] & 0x7f);
|
||||
time->hours = bcd2ToByte(buf[2] & 0x3f);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTC8563_Class::setTime(const rtc_time_t& time)
|
||||
{
|
||||
std::uint8_t buf[] =
|
||||
{ byteToBcd2(time.seconds)
|
||||
, byteToBcd2(time.minutes)
|
||||
, byteToBcd2(time.hours)
|
||||
};
|
||||
writeRegister(0x02, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
bool RTC8563_Class::getDate(rtc_date_t* date) const
|
||||
{
|
||||
std::uint8_t buf[4] = {0};
|
||||
|
||||
if (!readRegister(0x05, buf, 4)) { return false; }
|
||||
|
||||
date->date = bcd2ToByte(buf[0] & 0x3f);
|
||||
date->weekDay = bcd2ToByte(buf[1] & 0x07);
|
||||
date->month = bcd2ToByte(buf[2] & 0x1f);
|
||||
date->year = bcd2ToByte(buf[3] & 0xff)
|
||||
+ ((0x80 & buf[2]) ? 1900 : 2000);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTC8563_Class::setDate(const rtc_date_t& date)
|
||||
{
|
||||
std::uint8_t w = date.weekDay;
|
||||
if (w > 6 && date.year >= 1900 && ((std::size_t)(date.month - 1)) < 12)
|
||||
{ /// weekDay auto adjust
|
||||
int32_t year = date.year;
|
||||
int32_t month = date.month;
|
||||
int32_t day = date.date;
|
||||
if (month < 3) {
|
||||
year--;
|
||||
month += 12;
|
||||
}
|
||||
int32_t ydiv100 = year / 100;
|
||||
w = (year + (year >> 2) - ydiv100 + (ydiv100 >> 2) + (13 * month + 8) / 5 + day) % 7;
|
||||
}
|
||||
|
||||
std::uint8_t buf[] =
|
||||
{ byteToBcd2(date.date)
|
||||
, w
|
||||
, (std::uint8_t)(byteToBcd2(date.month) + (date.year < 2000 ? 0x80 : 0))
|
||||
, byteToBcd2(date.year % 100)
|
||||
};
|
||||
writeRegister(0x05, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
int RTC8563_Class::setAlarmIRQ(int afterSeconds)
|
||||
{
|
||||
std::uint8_t reg_value = readRegister8(0x01) & ~0x0C;
|
||||
|
||||
if (afterSeconds < 0)
|
||||
{ // disable timer
|
||||
writeRegister8(0x01, reg_value & ~0x01);
|
||||
writeRegister8(0x0E, 0x03);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::size_t div = 1;
|
||||
std::uint8_t type_value = 0x82;
|
||||
if (afterSeconds < 270)
|
||||
{
|
||||
if (afterSeconds > 255) { afterSeconds = 255; }
|
||||
}
|
||||
else
|
||||
{
|
||||
div = 60;
|
||||
afterSeconds = (afterSeconds + 30) / div;
|
||||
if (afterSeconds > 255) { afterSeconds = 255; }
|
||||
type_value = 0x83;
|
||||
}
|
||||
|
||||
writeRegister8(0x0E, type_value);
|
||||
writeRegister8(0x0F, afterSeconds);
|
||||
|
||||
writeRegister8(0x01, (reg_value | 0x01) & ~0x80);
|
||||
return afterSeconds * div;
|
||||
}
|
||||
|
||||
int RTC8563_Class::setAlarmIRQ(const rtc_time_t &time)
|
||||
{
|
||||
union
|
||||
{
|
||||
std::uint32_t raw = ~0;
|
||||
std::uint8_t buf[4];
|
||||
};
|
||||
bool irq_enable = false;
|
||||
|
||||
if (time.minutes >= 0)
|
||||
{
|
||||
irq_enable = true;
|
||||
buf[0] = byteToBcd2(time.minutes) & 0x7f;
|
||||
}
|
||||
|
||||
if (time.hours >= 0)
|
||||
{
|
||||
irq_enable = true;
|
||||
buf[1] = byteToBcd2(time.hours) & 0x3f;
|
||||
}
|
||||
|
||||
writeRegister(0x09, buf, 4);
|
||||
|
||||
if (irq_enable)
|
||||
{
|
||||
bitOn(0x01, 0x02);
|
||||
} else {
|
||||
bitOff(0x01, 0x02);
|
||||
}
|
||||
|
||||
return irq_enable;
|
||||
}
|
||||
|
||||
int RTC8563_Class::setAlarmIRQ(const rtc_date_t &date, const rtc_time_t &time)
|
||||
{
|
||||
union
|
||||
{
|
||||
std::uint32_t raw = ~0;
|
||||
std::uint8_t buf[4];
|
||||
};
|
||||
bool irq_enable = false;
|
||||
|
||||
if (time.minutes >= 0)
|
||||
{
|
||||
irq_enable = true;
|
||||
buf[0] = byteToBcd2(time.minutes) & 0x7f;
|
||||
}
|
||||
|
||||
if (time.hours >= 0)
|
||||
{
|
||||
irq_enable = true;
|
||||
buf[1] = byteToBcd2(time.hours) & 0x3f;
|
||||
}
|
||||
|
||||
if (date.date >= 0)
|
||||
{
|
||||
irq_enable = true;
|
||||
buf[2] = byteToBcd2(date.date) & 0x3f;
|
||||
}
|
||||
|
||||
if (date.weekDay >= 0)
|
||||
{
|
||||
irq_enable = true;
|
||||
buf[3] = byteToBcd2(date.weekDay) & 0x07;
|
||||
}
|
||||
|
||||
writeRegister(0x09, buf, 4);
|
||||
|
||||
if (irq_enable)
|
||||
{
|
||||
bitOn(0x01, 0x02);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitOff(0x01, 0x02);
|
||||
}
|
||||
|
||||
return irq_enable;
|
||||
}
|
||||
|
||||
bool RTC8563_Class::getIRQstatus(void)
|
||||
{
|
||||
return _init && (0x0C & readRegister8(0x01));
|
||||
}
|
||||
|
||||
void RTC8563_Class::clearIRQ(void)
|
||||
{
|
||||
if (!_init) { return; }
|
||||
bitOff(0x01, 0x0C);
|
||||
}
|
||||
|
||||
void RTC8563_Class::disableIRQ(void)
|
||||
{
|
||||
if (!_init) { return; }
|
||||
// disable alerm (bit7:1=disabled)
|
||||
static constexpr const std::uint8_t buf[4] = { 0x80, 0x80, 0x80, 0x80 };
|
||||
writeRegister(0x09, buf, 4);
|
||||
|
||||
// disable timer (bit7:0=disabled)
|
||||
writeRegister8(0x0E, 0);
|
||||
|
||||
// clear flag and INT enable bits
|
||||
writeRegister8(0x01, 0x00);
|
||||
}
|
||||
|
||||
void RTC8563_Class::setSystemTimeFromRtc(struct timezone* tz)
|
||||
{
|
||||
#if defined (M5UNIFIED_PC_BUILD)
|
||||
(void)tz;
|
||||
#else
|
||||
rtc_datetime_t dt;
|
||||
if (getDateTime(&dt))
|
||||
{
|
||||
tm t_st;
|
||||
t_st.tm_isdst = -1;
|
||||
t_st.tm_year = dt.date.year - 1900;
|
||||
t_st.tm_mon = dt.date.month - 1;
|
||||
t_st.tm_mday = dt.date.date;
|
||||
t_st.tm_hour = dt.time.hours;
|
||||
t_st.tm_min = dt.time.minutes;
|
||||
t_st.tm_sec = dt.time.seconds;
|
||||
timeval now;
|
||||
// mktime(3) uses localtime, force UTC
|
||||
char *oldtz = getenv("TZ");
|
||||
setenv("TZ", "GMT0", 1);
|
||||
tzset(); // Workaround for https://github.com/espressif/esp-idf/issues/11455
|
||||
now.tv_sec = mktime(&t_st);
|
||||
if (oldtz)
|
||||
{
|
||||
setenv("TZ", oldtz, 1);
|
||||
} else {
|
||||
unsetenv("TZ");
|
||||
}
|
||||
now.tv_usec = 0;
|
||||
settimeofday(&now, tz);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
153
libraries/M5Unified/src/utility/RTC8563_Class.hpp
Normal file
153
libraries/M5Unified/src/utility/RTC8563_Class.hpp
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_RTC8563_CLASS_H__
|
||||
#define __M5_RTC8563_CLASS_H__
|
||||
|
||||
#include "m5unified_common.h"
|
||||
|
||||
#include "I2C_Class.hpp"
|
||||
|
||||
#if __has_include(<sys/time.h>)
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
typedef void timezone;
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
struct __attribute__((packed)) rtc_time_t
|
||||
{
|
||||
std::int8_t hours;
|
||||
std::int8_t minutes;
|
||||
std::int8_t seconds;
|
||||
|
||||
rtc_time_t(std::int8_t hours_ = -1, std::int8_t minutes_ = -1, std::int8_t seconds_ = -1)
|
||||
: hours { hours_ }
|
||||
, minutes { minutes_ }
|
||||
, seconds { seconds_ }
|
||||
{}
|
||||
|
||||
rtc_time_t(const tm& t)
|
||||
: hours { (int8_t)t.tm_hour }
|
||||
, minutes { (int8_t)t.tm_min }
|
||||
, seconds { (int8_t)t.tm_sec }
|
||||
{}
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) rtc_date_t
|
||||
{
|
||||
/// year 1900-2099
|
||||
std::int16_t year;
|
||||
|
||||
/// month 1-12
|
||||
std::int8_t month;
|
||||
|
||||
/// date 1-31
|
||||
std::int8_t date;
|
||||
|
||||
/// weekDay 0:sun / 1:mon / 2:tue / 3:wed / 4:thu / 5:fri / 6:sat
|
||||
std::int8_t weekDay;
|
||||
|
||||
rtc_date_t(std::int16_t year_ = 2000, std::int8_t month_ = 1, std::int8_t date_ = -1, std::int8_t weekDay_ = -1)
|
||||
: year { year_ }
|
||||
, month { month_ }
|
||||
, date { date_ }
|
||||
, weekDay { weekDay_ }
|
||||
{}
|
||||
|
||||
rtc_date_t(const tm& t)
|
||||
: year { (int16_t)(t.tm_year + 1900) }
|
||||
, month { (int8_t )(t.tm_mon + 1 ) }
|
||||
, date { (int8_t ) t.tm_mday }
|
||||
, weekDay { (int8_t ) t.tm_wday }
|
||||
{}
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) rtc_datetime_t
|
||||
{
|
||||
rtc_date_t date;
|
||||
rtc_time_t time;
|
||||
rtc_datetime_t() = default;
|
||||
rtc_datetime_t(const rtc_date_t& d, const rtc_time_t& t) : date { d }, time { t } {};
|
||||
rtc_datetime_t(const tm& t) : date { t }, time { t } {}
|
||||
tm get_tm(void) const;
|
||||
void set_tm(tm& time);
|
||||
void set_tm(tm* t) { if (t) set_tm(*t); }
|
||||
};
|
||||
|
||||
class RTC8563_Class : public I2C_Device
|
||||
{
|
||||
public:
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x51;
|
||||
|
||||
RTC8563_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C)
|
||||
: I2C_Device ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
|
||||
bool begin(I2C_Class* i2c = nullptr);
|
||||
|
||||
bool getVoltLow(void);
|
||||
|
||||
bool getTime(rtc_time_t* time) const;
|
||||
bool getDate(rtc_date_t* date) const;
|
||||
bool getDateTime(rtc_datetime_t* datetime) const;
|
||||
|
||||
void setTime(const rtc_time_t &time);
|
||||
void setTime(const rtc_time_t* const time) { if (time) { setTime(*time); } }
|
||||
|
||||
void setDate(const rtc_date_t &date);
|
||||
void setDate(const rtc_date_t* const date) { if (date) { setDate(*date); } }
|
||||
|
||||
void setDateTime(const rtc_datetime_t &datetime) { setDate(datetime.date); setTime(datetime.time); }
|
||||
void setDateTime(const rtc_datetime_t* const datetime) { if (datetime) { setDateTime(*datetime); } }
|
||||
void setDateTime(const tm* const datetime)
|
||||
{
|
||||
if (datetime)
|
||||
{
|
||||
rtc_datetime_t dt { *datetime };
|
||||
setDateTime(dt);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set timer IRQ
|
||||
/// @param afterSeconds 1 - 15,300. If 256 or more, 1-minute cycle. (max 255 minute.)
|
||||
/// @return the set number of seconds.
|
||||
int setAlarmIRQ(int afterSeconds);
|
||||
|
||||
/// Set alarm by time
|
||||
int setAlarmIRQ(const rtc_time_t &time);
|
||||
int setAlarmIRQ(const rtc_date_t &date, const rtc_time_t &time);
|
||||
|
||||
void setSystemTimeFromRtc(struct timezone* tz = nullptr);
|
||||
|
||||
bool getIRQstatus(void);
|
||||
void clearIRQ(void);
|
||||
void disableIRQ(void);
|
||||
|
||||
rtc_time_t getTime(void) const
|
||||
{
|
||||
rtc_time_t time;
|
||||
getTime(&time);
|
||||
return time;
|
||||
}
|
||||
|
||||
rtc_date_t getDate(void) const
|
||||
{
|
||||
rtc_date_t date;
|
||||
getDate(&date);
|
||||
return date;
|
||||
}
|
||||
|
||||
rtc_datetime_t getDateTime(void) const
|
||||
{
|
||||
rtc_datetime_t res;
|
||||
getDateTime(&res);
|
||||
return res;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
1148
libraries/M5Unified/src/utility/Speaker_Class.cpp
Normal file
1148
libraries/M5Unified/src/utility/Speaker_Class.cpp
Normal file
File diff suppressed because it is too large
Load diff
301
libraries/M5Unified/src/utility/Speaker_Class.hpp
Normal file
301
libraries/M5Unified/src/utility/Speaker_Class.hpp
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_Speaker_Class_H__
|
||||
#define __M5_Speaker_Class_H__
|
||||
|
||||
#include "m5unified_common.h"
|
||||
|
||||
#if defined ( ESP_PLATFORM )
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#if __has_include(<driver/i2s_std.h>)
|
||||
#include <driver/i2s_std.h>
|
||||
#else
|
||||
#include <driver/i2s.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#ifndef I2S_PIN_NO_CHANGE
|
||||
#define I2S_PIN_NO_CHANGE (-1)
|
||||
#endif
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class M5Unified;
|
||||
|
||||
struct speaker_config_t
|
||||
{
|
||||
/// i2s_data_out (for spk)
|
||||
int pin_data_out = I2S_PIN_NO_CHANGE;
|
||||
|
||||
/// i2s_bck
|
||||
int pin_bck = I2S_PIN_NO_CHANGE;
|
||||
|
||||
/// i2s_mclk
|
||||
int pin_mck = I2S_PIN_NO_CHANGE;
|
||||
|
||||
/// i2s_ws (lrck)
|
||||
int pin_ws = I2S_PIN_NO_CHANGE;
|
||||
|
||||
/// output sampling rate (Hz)
|
||||
uint32_t sample_rate = 48000;
|
||||
|
||||
/// use stereo output
|
||||
bool stereo = false;
|
||||
|
||||
/// use single gpio buzzer, ( need only pin_data_out )
|
||||
bool buzzer = false;
|
||||
|
||||
/// use DAC speaker, ( need only pin_data_out ) ( for ESP32, only GPIO_NUM_25 or GPIO_NUM_26 )
|
||||
/// ※ for ESP32, need `i2s_port = I2S_NUM_0`. ( DAC+I2S_NUM_1 is not available )
|
||||
bool use_dac = false;
|
||||
|
||||
/// Zero level reference value when using DAC ( 0=Dynamic change )
|
||||
uint8_t dac_zero_level = 0;
|
||||
|
||||
/// multiplier for output value
|
||||
uint8_t magnification = 16;
|
||||
|
||||
/// for I2S dma_buf_len (max 1024)
|
||||
size_t dma_buf_len = 256;
|
||||
|
||||
/// for I2S dma_buf_count
|
||||
size_t dma_buf_count = 8;
|
||||
|
||||
/// background task priority
|
||||
uint8_t task_priority = 2;
|
||||
|
||||
/// background task pinned core
|
||||
uint8_t task_pinned_core = ~0;
|
||||
|
||||
/// I2S port
|
||||
i2s_port_t i2s_port = i2s_port_t::I2S_NUM_0;
|
||||
};
|
||||
|
||||
class Speaker_Class
|
||||
{
|
||||
friend M5Unified;
|
||||
public:
|
||||
virtual ~Speaker_Class(void) {}
|
||||
|
||||
speaker_config_t config(void) const { return _cfg; }
|
||||
void config(const speaker_config_t& cfg) { _cfg = cfg; }
|
||||
|
||||
bool begin(void);
|
||||
|
||||
void end(void);
|
||||
|
||||
bool isRunning(void) const { return _task_running; }
|
||||
|
||||
bool isEnabled(void) const
|
||||
{
|
||||
#if defined (ESP_PLATFORM)
|
||||
return _cfg.pin_data_out >= 0;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// now in playing or not.
|
||||
/// @return false=not playing / true=playing
|
||||
bool isPlaying(void) const volatile { return _play_channel_bits.load(); }
|
||||
|
||||
/// now in playing or not.
|
||||
/// @param channel virtual channel number. (0~7), (default = automatically selected)
|
||||
/// @return 0=not playing / 1=playing (There's room in the queue) / 2=playing (There's no room in the queue.)
|
||||
size_t isPlaying(uint8_t channel) const volatile { return (channel < sound_channel_max) ? ((bool)_ch_info[channel].wavinfo[0].repeat) + ((bool)_ch_info[channel].wavinfo[1].repeat) : 0; }
|
||||
|
||||
/// Get the number of channels that are playing.
|
||||
/// @return number of channels that are playing.
|
||||
size_t getPlayingChannels(void) const volatile { return __builtin_popcount(_play_channel_bits.load()); }
|
||||
|
||||
/// sets the output master volume of the sound.
|
||||
/// @param master_volume master volume (0~255)
|
||||
void setVolume(uint8_t master_volume) { _master_volume = master_volume; }
|
||||
|
||||
/// gets the output master volume of the sound.
|
||||
/// @return master volume.
|
||||
uint8_t getVolume(void) const { return _master_volume; }
|
||||
|
||||
/// sets the output volume of the sound for the all virtual channel.
|
||||
/// @param volume channel volume (0~255)
|
||||
void setAllChannelVolume(uint8_t volume) { for (size_t ch = 0; ch < sound_channel_max; ++ch) { _ch_info[ch].volume = volume; } }
|
||||
|
||||
/// sets the output volume of the sound for the specified virtual channel.
|
||||
/// @param channel virtual channel number. (0~7)
|
||||
/// @param volume channel volume (0~255)
|
||||
void setChannelVolume(uint8_t channel, uint8_t volume) { if (channel < sound_channel_max) { _ch_info[channel].volume = volume; } }
|
||||
|
||||
/// gets the output volume of the sound for the specified virtual channel.
|
||||
/// @param channel virtual channel number. (0~7)
|
||||
/// @return channel volume.
|
||||
uint8_t getChannelVolume(uint8_t channel) const { return (channel < sound_channel_max) ? _ch_info[channel].volume : 0; }
|
||||
|
||||
/// stop sound output.
|
||||
void stop(void);
|
||||
|
||||
/// stop sound output for the specified virtual channel.
|
||||
/// @param channel virtual channel number. (0~7)
|
||||
void stop(uint8_t channel);
|
||||
|
||||
/// play simple tone sound.
|
||||
/// @param frequency tone frequency (Hz)
|
||||
/// @param duration tone duration (msec)
|
||||
/// @param channel virtual channel number. (0~7), (default = automatically selected)
|
||||
/// @param stop_current_sound true=start a new output without waiting for the current one to finish.
|
||||
/// @param raw_data Single amplitude audio data. 8bit unsigned wav.
|
||||
/// @param array_len size of raw_data.
|
||||
/// @param stereo true=data is stereo / false=data is mono.
|
||||
bool tone(float frequency, uint32_t duration, int channel, bool stop_current_sound, const uint8_t* raw_data, size_t array_len, bool stereo = false)
|
||||
{
|
||||
return _play_raw(raw_data, array_len, false, false, frequency * (array_len >> stereo), stereo, (duration != UINT32_MAX) ? (uint32_t)(duration * frequency / 1000) : UINT32_MAX, channel, stop_current_sound, true);
|
||||
}
|
||||
|
||||
/// play simple tone sound.
|
||||
/// @param frequency tone frequency (Hz)
|
||||
/// @param duration tone duration (msec)
|
||||
/// @param channel virtual channel number. (0~7), (default = automatically selected)
|
||||
bool tone(float frequency, uint32_t duration = UINT32_MAX, int channel = -1, bool stop_current_sound = true) { return tone(frequency, duration, channel, stop_current_sound, _default_tone_wav, sizeof(_default_tone_wav), false); }
|
||||
|
||||
/// play raw sound wave data. (for signed 8bit wav data)
|
||||
/// @param raw_data wave data.
|
||||
/// @param array_len Number of data array elements.
|
||||
/// @param sample_rate the sampling rate (Hz) (default = 44100)
|
||||
/// @param stereo true=data is stereo / false=data is monaural.
|
||||
/// @param repeat number of times played repeatedly. (default = 1)
|
||||
/// @param channel virtual channel number (If omitted, use an available channel.)
|
||||
/// @param stop_current_sound true=start a new output without waiting for the current one to finish.
|
||||
/// @attention If you want to use the data generated at runtime, you can either have three buffers and use them in sequence, or have two buffers and use them alternately, then split them in half and call playRaw twice.
|
||||
/// @attention If noise is present in the output sounds, consider increasing the priority of the task that generates the data.
|
||||
bool playRaw(const int8_t* raw_data, size_t array_len, uint32_t sample_rate = 44100, bool stereo = false, uint32_t repeat = 1, int channel = -1, bool stop_current_sound = false)
|
||||
{
|
||||
return _play_raw(static_cast<const void* >(raw_data), array_len, false, true, sample_rate, stereo, repeat, channel, stop_current_sound, false);
|
||||
}
|
||||
[[deprecated("The playRAW function has been renamed to playRaw")]]
|
||||
bool playRAW(const int8_t* raw_data, size_t array_len, uint32_t sample_rate = 44100, bool stereo = false, uint32_t repeat = 1, int channel = -1, bool stop_current_sound = false)
|
||||
{
|
||||
return _play_raw(static_cast<const void* >(raw_data), array_len, false, true, sample_rate, stereo, repeat, channel, stop_current_sound, false);
|
||||
}
|
||||
|
||||
/// play raw sound wave data. (for unsigned 8bit wav data)
|
||||
/// @param raw_data wave data.
|
||||
/// @param array_len Number of data array elements.
|
||||
/// @param sample_rate the sampling rate (Hz) (default = 44100)
|
||||
/// @param stereo true=data is stereo / false=data is monaural.
|
||||
/// @param repeat number of times played repeatedly. (default = 1)
|
||||
/// @param channel virtual channel number (If omitted, use an available channel.)
|
||||
/// @param stop_current_sound true=start a new output without waiting for the current one to finish.
|
||||
/// @attention If you want to use the data generated at runtime, you can either have three buffers and use them in sequence, or have two buffers and use them alternately, then split them in half and call playRaw twice.
|
||||
/// @attention If noise is present in the output sounds, consider increasing the priority of the task that generates the data.
|
||||
bool playRaw(const uint8_t* raw_data, size_t array_len, uint32_t sample_rate = 44100, bool stereo = false, uint32_t repeat = 1, int channel = -1, bool stop_current_sound = false)
|
||||
{
|
||||
return _play_raw(static_cast<const void* >(raw_data), array_len, false, false, sample_rate, stereo, repeat, channel, stop_current_sound, false);
|
||||
}
|
||||
[[deprecated("The playRAW function has been renamed to playRaw")]]
|
||||
bool playRAW(const uint8_t* raw_data, size_t array_len, uint32_t sample_rate = 44100, bool stereo = false, uint32_t repeat = 1, int channel = -1, bool stop_current_sound = false)
|
||||
{
|
||||
return _play_raw(static_cast<const void* >(raw_data), array_len, false, false, sample_rate, stereo, repeat, channel, stop_current_sound, false);
|
||||
}
|
||||
|
||||
/// play raw sound wave data. (for signed 16bit wav data)
|
||||
/// @param raw_data wave data.
|
||||
/// @param array_len Number of data array elements.
|
||||
/// @param sample_rate the sampling rate (Hz) (default = 44100)
|
||||
/// @param stereo true=data is stereo / false=data is monaural.
|
||||
/// @param repeat number of times played repeatedly. (default = 1)
|
||||
/// @param channel virtual channel number (If omitted, use an available channel.)
|
||||
/// @param stop_current_sound true=start a new output without waiting for the current one to finish.
|
||||
/// @attention If you want to use the data generated at runtime, you can either have three buffers and use them in sequence, or have two buffers and use them alternately, then split them in half and call playRaw twice.
|
||||
/// @attention If noise is present in the output sounds, consider increasing the priority of the task that generates the data.
|
||||
bool playRaw(const int16_t* raw_data, size_t array_len, uint32_t sample_rate = 44100, bool stereo = false, uint32_t repeat = 1, int channel = -1, bool stop_current_sound = false)
|
||||
{
|
||||
return _play_raw(static_cast<const void* >(raw_data), array_len, true, true, sample_rate, stereo, repeat, channel, stop_current_sound, false);
|
||||
}
|
||||
|
||||
/// @deprecated "playRAW" function has been renamed to "playRaw"
|
||||
[[deprecated("The playRAW function has been renamed to playRaw")]]
|
||||
bool playRAW(const int16_t* raw_data, size_t array_len, uint32_t sample_rate = 44100, bool stereo = false, uint32_t repeat = 1, int channel = -1, bool stop_current_sound = false)
|
||||
{
|
||||
return _play_raw(static_cast<const void* >(raw_data), array_len, true, true, sample_rate, stereo, repeat, channel, stop_current_sound, false);
|
||||
}
|
||||
|
||||
/// play WAV format sound data.
|
||||
/// @param wav_data wave data. (WAV header included)
|
||||
/// @param repeat number of times played repeatedly. (default = 1)
|
||||
/// @param channel virtual channel number (If omitted, use an available channel.)
|
||||
/// @param stop_current_sound true=start a new output without waiting for the current one to finish.
|
||||
bool playWav(const uint8_t* wav_data, size_t data_len = ~0u, uint32_t repeat = 1, int channel = -1, bool stop_current_sound = false);
|
||||
|
||||
protected:
|
||||
|
||||
static constexpr const size_t sound_channel_max = 8;
|
||||
|
||||
static const uint8_t _default_tone_wav[16];
|
||||
|
||||
void setCallback(void* args, bool(*func)(void*, bool)) { _cb_set_enabled = func; _cb_set_enabled_args = args; }
|
||||
|
||||
struct wav_info_t
|
||||
{
|
||||
volatile uint32_t repeat = 0; /// -1 mean infinity repeat
|
||||
uint32_t sample_rate_x256 = 0;
|
||||
const void* data = nullptr;
|
||||
size_t length = 0;
|
||||
union
|
||||
{
|
||||
volatile uint8_t flg = 0;
|
||||
struct
|
||||
{
|
||||
uint8_t is_stereo : 1;
|
||||
uint8_t is_16bit : 1;
|
||||
uint8_t is_signed : 1;
|
||||
uint8_t stop_current : 1;
|
||||
uint8_t no_clear_index : 1;
|
||||
};
|
||||
};
|
||||
void clear(void);
|
||||
};
|
||||
|
||||
struct channel_info_t
|
||||
{
|
||||
wav_info_t wavinfo[2]; // current/next flip info.
|
||||
size_t index = 0;
|
||||
int diff = 0;
|
||||
volatile uint8_t volume = 255; // channel volume (not master volume)
|
||||
volatile bool flip = false;
|
||||
|
||||
float liner_buf[2][2] = { { 0, 0 }, { 0, 0 } };
|
||||
};
|
||||
|
||||
channel_info_t _ch_info[sound_channel_max];
|
||||
|
||||
static void spk_task(void* args);
|
||||
|
||||
esp_err_t _setup_i2s(void);
|
||||
bool _play_raw(const void* wav, size_t array_len, bool flg_16bit, bool flg_signed, float sample_rate, bool flg_stereo, uint32_t repeat_count, int channel, bool stop_current_sound, bool no_clear_index);
|
||||
bool _set_next_wav(size_t ch, const wav_info_t& wav);
|
||||
|
||||
speaker_config_t _cfg;
|
||||
volatile uint8_t _master_volume = 64;
|
||||
|
||||
bool (*_cb_set_enabled)(void* args, bool enabled) = nullptr;
|
||||
void* _cb_set_enabled_args = nullptr;
|
||||
|
||||
volatile bool _task_running = false;
|
||||
std::atomic<uint16_t> _play_channel_bits = { 0 };
|
||||
#if defined (SDL_h_)
|
||||
SDL_Thread* _task_handle = nullptr;
|
||||
#else
|
||||
TaskHandle_t _task_handle = nullptr;
|
||||
volatile SemaphoreHandle_t _task_semaphore = nullptr;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
147
libraries/M5Unified/src/utility/Touch_Class.cpp
Normal file
147
libraries/M5Unified/src/utility/Touch_Class.cpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "Touch_Class.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
void Touch_Class::update(std::uint32_t msec)
|
||||
{
|
||||
if (msec - _last_msec <= TOUCH_MIN_UPDATE_MSEC) /// Avoid high frequency updates
|
||||
{
|
||||
if (_detail_count == 0) { return; }
|
||||
std::size_t count = 0;
|
||||
for (std::size_t i = 0; i < TOUCH_MAX_POINTS; ++i)
|
||||
{
|
||||
count += update_detail(&_touch_detail[i], msec);
|
||||
}
|
||||
_detail_count = count;
|
||||
return;
|
||||
}
|
||||
|
||||
_last_msec = msec;
|
||||
std::size_t count = _gfx->getTouchRaw(_touch_raw, TOUCH_MAX_POINTS);
|
||||
if (!(count || _detail_count)) { return; }
|
||||
|
||||
uint32_t updated_id = 0;
|
||||
if (count)
|
||||
{
|
||||
m5gfx::touch_point_t tp[TOUCH_MAX_POINTS];
|
||||
memcpy(tp, _touch_raw, sizeof(m5gfx::touch_point_t) * count);
|
||||
_gfx->convertRawXY(tp, count);
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (tp[i].id < TOUCH_MAX_POINTS)
|
||||
{
|
||||
updated_id |= 1 << tp[i].id;
|
||||
update_detail(&_touch_detail[tp[i].id], msec, true, &tp[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
for (std::size_t i = 0; i < TOUCH_MAX_POINTS; ++i)
|
||||
{
|
||||
if ((!(updated_id & (1 << i)))
|
||||
&& update_detail(&_touch_detail[i], msec, false, nullptr)
|
||||
&& (count < TOUCH_MAX_POINTS))
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
_detail_count = count;
|
||||
}
|
||||
|
||||
bool Touch_Class::update_detail(touch_detail_t* det, std::uint32_t msec, bool pressed, m5gfx::touch_point_t* tp)
|
||||
{
|
||||
touch_state_t tm = det->state;
|
||||
if (tm == touch_state_t::none && !pressed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
tm = static_cast<touch_state_t>(tm & ~touch_state_t::mask_change);
|
||||
if (pressed)
|
||||
{
|
||||
det->prev_x = det->x;
|
||||
det->prev_y = det->y;
|
||||
det->size = tp->size;
|
||||
det->id = tp->id;
|
||||
if (!(tm & touch_state_t::mask_moving))
|
||||
{ // Processing when not flicked.
|
||||
if (tm & touch_state_t::mask_touch)
|
||||
{ // Not immediately after the touch.
|
||||
if (abs(det->base_x - tp->x) > _flickThresh
|
||||
|| abs(det->base_y - tp->y) > _flickThresh)
|
||||
{
|
||||
det->prev = det->base;
|
||||
tm = static_cast<touch_state_t>(tm | touch_state_t::flick_begin);
|
||||
}
|
||||
else
|
||||
if ((tm == touch) && (msec - det->base_msec > _msecHold))
|
||||
{
|
||||
tm = touch_state_t::hold_begin;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*(static_cast<m5gfx::touch_point_t*>(det)) = *tp;
|
||||
tm = touch_state_t::touch_begin;
|
||||
|
||||
if (msec - det->base_msec > _msecHold
|
||||
|| abs(det->base_x - tp->x) > ((_flickThresh+1) << 2) // TODO:検討、タッチ座標が大きくずれた場合にカウントをクリアするか否か
|
||||
|| abs(det->base_y - tp->y) > ((_flickThresh+1) << 2)
|
||||
)
|
||||
{ det->click_count = 0; }
|
||||
det->base_msec = msec;
|
||||
det->base_x = tp->x;
|
||||
det->base_y = tp->y;
|
||||
det->prev = det->base;
|
||||
}
|
||||
}
|
||||
if (tm & mask_moving)
|
||||
{
|
||||
det->x = tp->x;
|
||||
det->y = tp->y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tm = (tm & touch_state_t::mask_touch)
|
||||
? static_cast<touch_state_t>((tm | touch_state_t::mask_change) & ~touch_state_t::mask_touch)
|
||||
: touch_state_t::none;
|
||||
|
||||
if (tm == touch_state_t::touch_end) {
|
||||
// 連続タップ判定のためにbase_msecを更新
|
||||
det->base_msec = msec;
|
||||
det->click_count++;
|
||||
}
|
||||
}
|
||||
det->state = tm;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Touch_Class::update_detail(touch_detail_t* det, std::uint32_t msec)
|
||||
{
|
||||
touch_state_t tm = det->state;
|
||||
if (tm == touch_state_t::none)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
tm = static_cast<touch_state_t>(tm & ~touch_state_t::mask_change);
|
||||
if (tm & touch)
|
||||
{
|
||||
det->prev_x = det->x;
|
||||
det->prev_y = det->y;
|
||||
if ((tm == touch) && (msec - det->base_msec > _msecHold))
|
||||
{
|
||||
tm = touch_state_t::hold_begin;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tm = touch_state_t::none;
|
||||
}
|
||||
det->state = tm;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
127
libraries/M5Unified/src/utility/Touch_Class.hpp
Normal file
127
libraries/M5Unified/src/utility/Touch_Class.hpp
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_Touch_Class_H__
|
||||
#define __M5_Touch_Class_H__
|
||||
|
||||
#include <M5GFX.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
enum touch_state_t : uint8_t
|
||||
{ none = 0b0000
|
||||
, touch = 0b0001
|
||||
, touch_end = 0b0010
|
||||
, touch_begin = 0b0011
|
||||
|
||||
, hold = 0b0101
|
||||
, hold_end = 0b0110
|
||||
, hold_begin = 0b0111
|
||||
|
||||
, flick = 0b1001
|
||||
, flick_end = 0b1010
|
||||
, flick_begin = 0b1011
|
||||
|
||||
, drag = 0b1101
|
||||
, drag_end = 0b1110
|
||||
, drag_begin = 0b1111
|
||||
|
||||
, mask_touch = 0b0001
|
||||
, mask_change = 0b0010
|
||||
, mask_holding = 0b0100
|
||||
, mask_moving = 0b1000
|
||||
};
|
||||
|
||||
class Touch_Class
|
||||
{
|
||||
public:
|
||||
static constexpr std::size_t TOUCH_MAX_POINTS = 3;
|
||||
static constexpr std::size_t TOUCH_MIN_UPDATE_MSEC = 4;
|
||||
|
||||
struct point_t
|
||||
{
|
||||
std::int16_t x;
|
||||
std::int16_t y;
|
||||
};
|
||||
|
||||
struct touch_detail_t : public m5gfx::touch_point_t
|
||||
{
|
||||
union
|
||||
{ /// Previous point
|
||||
point_t prev;
|
||||
struct
|
||||
{
|
||||
std::int16_t prev_x;
|
||||
std::int16_t prev_y;
|
||||
};
|
||||
};
|
||||
union
|
||||
{ /// Flick start point
|
||||
point_t base;
|
||||
struct
|
||||
{
|
||||
std::int16_t base_x;
|
||||
std::int16_t base_y;
|
||||
};
|
||||
};
|
||||
|
||||
std::uint32_t base_msec;
|
||||
touch_state_t state = touch_state_t::none;
|
||||
std::uint8_t click_count = 0;
|
||||
|
||||
inline int deltaX(void) const { return x - prev_x; }
|
||||
inline int deltaY(void) const { return y - prev_y; }
|
||||
inline int distanceX(void) const { return x - base_x; }
|
||||
inline int distanceY(void) const { return y - base_y; }
|
||||
inline bool isPressed(void) const { return state & touch_state_t::mask_touch; };
|
||||
inline bool wasPressed(void) const { return state == touch_state_t::touch_begin; };
|
||||
inline bool wasClicked(void) const { return state == touch_state_t::touch_end; };
|
||||
inline bool isReleased(void) const { return !(state & touch_state_t::mask_touch); };
|
||||
inline bool wasReleased(void) const { return (state & (touch_state_t::mask_touch | touch_state_t::mask_change)) == touch_state_t::mask_change; };
|
||||
inline bool isHolding(void) const { return (state & (touch_state_t::mask_touch | touch_state_t::mask_holding)) == (touch_state_t::mask_touch | touch_state_t::mask_holding); }
|
||||
inline bool wasHold(void) const { return state == touch_state_t::hold_begin; }
|
||||
inline bool wasFlickStart(void) const { return state == touch_state_t::flick_begin; }
|
||||
inline bool isFlicking(void) const { return (state & touch_state_t::drag) == touch_state_t::flick; }
|
||||
inline bool wasFlicked(void) const { return state == touch_state_t::flick_end; }
|
||||
inline bool wasDragStart(void) const { return state == touch_state_t::drag_begin; }
|
||||
inline bool isDragging(void) const { return (state & touch_state_t::drag) == touch_state_t::drag; }
|
||||
inline bool wasDragged(void) const { return state == touch_state_t::drag_end; }
|
||||
inline std::uint8_t getClickCount(void) const { return click_count; }
|
||||
};
|
||||
|
||||
/// Get the current number of touchpoints.
|
||||
/// @return number of touchpoints.
|
||||
inline std::uint8_t getCount(void) const { return _detail_count; }
|
||||
|
||||
///
|
||||
inline const touch_detail_t& getDetail(std::size_t index = 0) const { return _touch_detail[_touch_raw[index].id < TOUCH_MAX_POINTS ? _touch_raw[index].id : 0]; }
|
||||
|
||||
|
||||
inline const m5gfx::touch_point_t& getTouchPointRaw(std::size_t index = 0) const { return _touch_raw[index < _detail_count ? index : 0]; }
|
||||
|
||||
void setHoldThresh(std::uint16_t msec) { _msecHold = msec; }
|
||||
|
||||
void setFlickThresh(std::uint16_t distance) { _flickThresh = distance; }
|
||||
|
||||
bool isEnabled(void) const { return _gfx; }
|
||||
|
||||
void begin(m5gfx::LGFX_Device* gfx) { _gfx = gfx; }
|
||||
void update(std::uint32_t msec);
|
||||
void end(void) { _gfx = nullptr; }
|
||||
|
||||
protected:
|
||||
std::uint32_t _last_msec = 0;
|
||||
std::int32_t _flickThresh = 8;
|
||||
std::uint32_t _msecHold = 500;
|
||||
m5gfx::LGFX_Device* _gfx = nullptr;
|
||||
touch_detail_t _touch_detail[TOUCH_MAX_POINTS];
|
||||
m5gfx::touch_point_t _touch_raw[TOUCH_MAX_POINTS];
|
||||
std::uint8_t _detail_count;
|
||||
|
||||
bool update_detail(touch_detail_t* dt, std::uint32_t msec, bool pressed, m5gfx::touch_point_t* tp);
|
||||
bool update_detail(touch_detail_t* dt, std::uint32_t msec);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
78
libraries/M5Unified/src/utility/imu/AK8963_Class.cpp
Normal file
78
libraries/M5Unified/src/utility/imu/AK8963_Class.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if defined (ESP_PLATFORM)
|
||||
|
||||
#include "AK8963_Class.hpp"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
AK8963_Class::~AK8963_Class() {}
|
||||
AK8963_Class::AK8963_Class(std::uint8_t i2c_addr, std::uint32_t freq, I2C_Class* i2c)
|
||||
: IMU_Base ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
|
||||
IMU_Base::imu_spec_t AK8963_Class::begin(I2C_Class* i2c)
|
||||
{
|
||||
if (i2c)
|
||||
{
|
||||
_i2c = i2c;
|
||||
}
|
||||
|
||||
uint8_t rawData[3]; // x/y/z gyro calibration data stored here
|
||||
writeRegister8(CTRL_CMD_ADDR, POWER_DOWN_CMD); // Power down magnetometer
|
||||
vTaskDelay(10);
|
||||
writeRegister8(CTRL_CMD_ADDR, FUSE_ROM_CMD); // Enter Fuse ROM access mode
|
||||
vTaskDelay(10);
|
||||
readRegister(ASAX_ADDR, rawData, 3); // Read the x-, y-, and z-axis calibration values
|
||||
|
||||
writeRegister8(CTRL_CMD_ADDR, POWER_DOWN_CMD); // Power down magnetometer
|
||||
vTaskDelay(10);
|
||||
// Configure the magnetometer for continuous read and highest resolution
|
||||
// set Mscale bit 4 to 1 (0) to enable 16 (14) bit resolution in CNTL
|
||||
// register, and enable continuous mode data acquisition Mmode (bits [3:0]),
|
||||
// 0010 for 8 Hz and 0110 for 100 Hz sample rates
|
||||
writeRegister8(CTRL_CMD_ADDR, 1 << 4 | 0x06); // Power down magnetometer
|
||||
|
||||
WhoAmI();
|
||||
// printf("AK8963 : %02x\n", WhoAmI());
|
||||
if (WhoAmI() == 0x48)
|
||||
{
|
||||
_init = true;
|
||||
return imu_spec_mag;
|
||||
}
|
||||
return imu_spec_none;
|
||||
}
|
||||
|
||||
std::uint8_t AK8963_Class::WhoAmI(void)
|
||||
{
|
||||
return readRegister8(WHO_AM_I_ADDR);
|
||||
}
|
||||
|
||||
IMU_Base::imu_spec_t AK8963_Class::getImuRawData(imu_raw_data_t* data) const
|
||||
{
|
||||
union
|
||||
{
|
||||
std::uint8_t buf8[10];
|
||||
std::int16_t buf16[5];
|
||||
};
|
||||
bool res = readRegister(STATUS1_ADDR, &buf8[1], 8) && buf8[1] && (0 == (buf8[8] & 0x08));
|
||||
if (res)
|
||||
{
|
||||
data->mag.x = buf16[1];
|
||||
data->mag.y = buf16[2];
|
||||
data->mag.z = buf16[3];
|
||||
return imu_spec_mag;
|
||||
}
|
||||
return imu_spec_none;
|
||||
}
|
||||
|
||||
void AK8963_Class::getConvertParam(imu_convert_param_t* param) const
|
||||
{ // Proper scale to return milliGauss
|
||||
param->mag_res = 10.0f * 4912.0f / 32760.0f;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
38
libraries/M5Unified/src/utility/imu/AK8963_Class.hpp
Normal file
38
libraries/M5Unified/src/utility/imu/AK8963_Class.hpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_AK8963_CLASS_H__
|
||||
#define __M5_AK8963_CLASS_H__
|
||||
|
||||
#include "IMU_Base.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class AK8963_Class : public IMU_Base
|
||||
{
|
||||
public:
|
||||
static constexpr const std::uint8_t WHO_AM_I_ADDR = 0x00;
|
||||
static constexpr const std::uint8_t STATUS1_ADDR = 0x02;
|
||||
static constexpr const std::uint8_t XOUT_L_ADDR = 0x03;
|
||||
static constexpr const std::uint8_t CTRL_CMD_ADDR = 0x0A;
|
||||
static constexpr const std::uint8_t ASAX_ADDR = 0x10;
|
||||
|
||||
static constexpr const std::uint8_t POWER_DOWN_CMD = 0x00;
|
||||
static constexpr const std::uint8_t SINGLE_MEASURE_CMD = 0x01;
|
||||
static constexpr const std::uint8_t SELF_TEST_CMD = 0x08;
|
||||
static constexpr const std::uint8_t FUSE_ROM_CMD = 0x0F;
|
||||
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x0C;
|
||||
|
||||
virtual ~AK8963_Class();
|
||||
AK8963_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C);
|
||||
|
||||
imu_spec_t begin(I2C_Class* i2c = nullptr) override;
|
||||
imu_spec_t getImuRawData(imu_raw_data_t* data) const override;
|
||||
void getConvertParam(imu_convert_param_t* param) const override;
|
||||
|
||||
std::uint8_t WhoAmI(void);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
224
libraries/M5Unified/src/utility/imu/BMI270_Class.cpp
Normal file
224
libraries/M5Unified/src/utility/imu/BMI270_Class.cpp
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if defined (ESP_PLATFORM)
|
||||
|
||||
#include "BMI270_Class.hpp"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
#include "BMI270_config.inl"
|
||||
|
||||
BMI270_Class::~BMI270_Class() {}
|
||||
BMI270_Class::BMI270_Class(std::uint8_t i2c_addr, std::uint32_t freq, I2C_Class* i2c)
|
||||
: IMU_Base ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
|
||||
bool BMI270_Class::_upload_file(const uint8_t *config_data, size_t index, size_t write_len)
|
||||
{
|
||||
uint8_t addr_array[2] = {
|
||||
(uint8_t)((index >> 1) & 0x0F),
|
||||
(uint8_t)(index >> 5)
|
||||
};
|
||||
|
||||
if (config_data != nullptr
|
||||
&& writeRegister( INIT_ADDR_0, addr_array, 2 )
|
||||
&& writeRegister( INIT_DATA_ADDR, (uint8_t *)config_data, write_len))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IMU_Base::imu_spec_t BMI270_Class::begin(I2C_Class* i2c)
|
||||
{
|
||||
if (i2c)
|
||||
{
|
||||
_i2c = i2c;
|
||||
}
|
||||
|
||||
WhoAmI();
|
||||
if (WhoAmI() != 0x24)
|
||||
{
|
||||
return imu_spec_none;
|
||||
}
|
||||
|
||||
writeRegister8(CMD_REG_ADDR, SOFT_RESET_CMD); // software reset.
|
||||
{
|
||||
int retry = 16;
|
||||
do { vTaskDelay(1); }
|
||||
while (0 == readRegister8(PWR_CONF_ADDR) && --retry);
|
||||
}
|
||||
|
||||
writeRegister8(PWR_CONF_ADDR, 0x00); // Power save disabled.
|
||||
vTaskDelay(1);
|
||||
bool res = _upload_file(bmi270_config_file, 0, sizeof(bmi270_config_file));
|
||||
writeRegister8(INIT_CTRL_ADDR, 0x01);
|
||||
writeRegister8(INT_MAP_DATA_ADDR, 0xFF);
|
||||
|
||||
_init = res;
|
||||
if (!res)
|
||||
{
|
||||
return imu_spec_none;
|
||||
}
|
||||
|
||||
imu_spec_t spec = (imu_spec_t)(imu_spec_accel | imu_spec_gyro);
|
||||
int retry = 16;
|
||||
do { vTaskDelay(1);}
|
||||
while (0 == readRegister8(INTERNAL_STATUS_ADDR) && --retry);
|
||||
res = retry > 0;
|
||||
|
||||
// 以下は AUXセンサとしてBMM150が接続されている想定の設定
|
||||
auxSetupMode(0x10); // 0x10 = BMM150 I2C Addr
|
||||
auxWriteRegister8(0x4B, 0x83); // software reset + power on
|
||||
auxReadRegister8(0x40); // 0x40 = WhoAmI
|
||||
auto who_am_i = auxReadRegister8(0x40); // 0x40 = WhoAmI
|
||||
if (who_am_i == 0x32)
|
||||
{
|
||||
auxWriteRegister8(0x4C, 0x38); // normal mode / ODR 30Hz
|
||||
spec = (imu_spec_t)(imu_spec_accel | imu_spec_gyro | imu_spec_mag);
|
||||
writeRegister8(AUX_IF_CONF_ADDR, 0x4F); // FCU_WRITE_EN + Manual BurstLength 8 + BurstLength 8
|
||||
writeRegister8(AUX_RD_ADDR , 0x42); // 0x42 = BMM150 I2C Data X LSB reg
|
||||
writeRegister8(PWR_CTRL_ADDR, 0x0F); // temp en | ACC en | GYR en | AUX en
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
|
||||
bool BMI270_Class::auxSetupMode(std::uint8_t i2c_addr)
|
||||
{
|
||||
writeRegister8(IF_CONF_ADDR, 0x20); // AUX I2C enable.
|
||||
writeRegister8(PWR_CONF_ADDR, 0x00); // Power save disabled.
|
||||
writeRegister8(PWR_CTRL_ADDR, 0x0E); // AUX sensor disable.
|
||||
writeRegister8(AUX_IF_CONF_ADDR, 0x80);
|
||||
return writeRegister8(AUX_DEV_ID_ADDR , i2c_addr << 1);
|
||||
}
|
||||
|
||||
bool BMI270_Class::auxWriteRegister8(std::uint8_t reg, std::uint8_t data)
|
||||
{
|
||||
writeRegister8(AUX_WR_DATA_ADDR, data); // AUXセンサに書き込む値
|
||||
writeRegister8(AUX_WR_ADDR, reg); // AUXセンサに書き込むレジスタ番号
|
||||
int retry = 3;
|
||||
while ((readRegister8(STATUS_ADDR) & 0b100) && --retry) { vTaskDelay(1); }
|
||||
return retry;
|
||||
}
|
||||
|
||||
std::uint8_t BMI270_Class::auxReadRegister8(std::uint8_t reg)
|
||||
{
|
||||
writeRegister8(AUX_IF_CONF_ADDR, 0x80); // enable read write. Burst length 1
|
||||
writeRegister8(AUX_RD_ADDR, reg); // AUXセンサから読み取るレジスタ番号
|
||||
int retry = 3;
|
||||
while ((readRegister8(STATUS_ADDR) & 0b100) && --retry) { vTaskDelay(1); }
|
||||
return readRegister8(AUX_X_LSB_ADDR);
|
||||
}
|
||||
|
||||
std::uint8_t BMI270_Class::WhoAmI(void)
|
||||
{
|
||||
return readRegister8(CHIP_ID_ADDR);
|
||||
}
|
||||
|
||||
IMU_Base::imu_spec_t BMI270_Class::getImuRawData(imu_raw_data_t* data) const
|
||||
{
|
||||
imu_spec_t res = imu_spec_none;
|
||||
std::uint8_t intstat = readRegister8(INT_STATUS_1_ADDR);
|
||||
if (intstat & 0xE0)
|
||||
{
|
||||
std::int16_t buf[10];
|
||||
if (readRegister(AUX_X_LSB_ADDR, (std::uint8_t*)buf, 20))
|
||||
{
|
||||
if (intstat & 0x80u)
|
||||
{
|
||||
data->accel.x = buf[4];
|
||||
data->accel.y = buf[5];
|
||||
data->accel.z = buf[6];
|
||||
res = (imu_spec_t)(res | imu_spec_accel);
|
||||
}
|
||||
if (intstat & 0x40u)
|
||||
{
|
||||
data->gyro.x = buf[7];
|
||||
data->gyro.y = buf[8];
|
||||
data->gyro.z = buf[9];
|
||||
res = (imu_spec_t)(res | imu_spec_gyro);
|
||||
}
|
||||
if (intstat & 0x20u)
|
||||
{
|
||||
data->mag.x = buf[0] >> 2;
|
||||
data->mag.y = buf[1] >> 2;
|
||||
data->mag.z = buf[2] & 0xFFFE;
|
||||
res = (imu_spec_t)(res | imu_spec_mag);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void BMI270_Class::getConvertParam(imu_convert_param_t* param) const
|
||||
{
|
||||
param->mag_res = 10.0f * 4912.0f / 32760.0f;
|
||||
param->temp_offset = 23.0f;
|
||||
param->temp_res = 1.0f / 512.0f;
|
||||
}
|
||||
|
||||
bool BMI270_Class::getTempAdc(int16_t *t) const
|
||||
{
|
||||
std::int16_t buf;
|
||||
bool res = readRegister(TEMPERATURE_0_ADDR, (std::uint8_t*)&buf, 2);
|
||||
if (res) { *t = buf; }
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
bool BMI270_Class::getAccelAdc(std::int16_t* ax, std::int16_t* ay, std::int16_t* az) const
|
||||
{
|
||||
std::int16_t buf[3];
|
||||
bool res = readRegister(ACC_X_LSB_ADDR, (std::uint8_t*)buf, 6);
|
||||
*ax = buf[0];
|
||||
*ay = buf[1];
|
||||
*az = buf[2];
|
||||
return res;
|
||||
}
|
||||
|
||||
bool BMI270_Class::getGyroAdc(std::int16_t* gx, std::int16_t* gy, std::int16_t* gz) const
|
||||
{
|
||||
std::int16_t buf[3];
|
||||
bool res = readRegister(GYR_X_LSB_ADDR, (std::uint8_t*)buf, 6);
|
||||
*gx = buf[0];
|
||||
*gy = buf[1];
|
||||
*gz = buf[2];
|
||||
return res;
|
||||
}
|
||||
|
||||
bool BMI270_Class::getAccel(float* ax, float* ay, float* az) const
|
||||
{
|
||||
static constexpr float aRes = 8.0f / 32768.0f;
|
||||
std::int16_t buf[3];
|
||||
bool res = readRegister(ACC_X_LSB_ADDR, (std::uint8_t*)buf, 6);
|
||||
*ax = buf[0] * aRes;
|
||||
*ay = buf[1] * aRes;
|
||||
*az = buf[2] * aRes;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool BMI270_Class::getGyro(float* gx, float* gy, float* gz) const
|
||||
{
|
||||
static constexpr float gRes = 2000.0f / 32768.0f;
|
||||
std::int16_t buf[3];
|
||||
bool res = readRegister(GYR_X_LSB_ADDR, (std::uint8_t*)buf, 6);
|
||||
*gx = buf[0] * gRes;
|
||||
*gy = buf[1] * gRes;
|
||||
*gz = buf[2] * gRes;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool BMI270_Class::getTemp(float *t) const
|
||||
{
|
||||
std::int16_t buf;
|
||||
bool res = readRegister(TEMPERATURE_0_ADDR, (std::uint8_t*)&buf, 2);
|
||||
*t = 23.0f + buf / 512.0f;
|
||||
return res;
|
||||
}
|
||||
//*/
|
||||
}
|
||||
|
||||
#endif
|
||||
107
libraries/M5Unified/src/utility/imu/BMI270_Class.hpp
Normal file
107
libraries/M5Unified/src/utility/imu/BMI270_Class.hpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_BMI270_CLASS_H__
|
||||
#define __M5_BMI270_CLASS_H__
|
||||
|
||||
#include "IMU_Base.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class BMI270_Class : public IMU_Base
|
||||
{
|
||||
public:
|
||||
static constexpr const std::uint8_t CHIP_ID_ADDR = 0x00;
|
||||
static constexpr const std::uint8_t ERR_REG_ADDR = 0x02;
|
||||
static constexpr const std::uint8_t STATUS_ADDR = 0x03;
|
||||
static constexpr const std::uint8_t AUX_X_LSB_ADDR = 0x04;
|
||||
static constexpr const std::uint8_t ACC_X_LSB_ADDR = 0x0C;
|
||||
static constexpr const std::uint8_t GYR_X_LSB_ADDR = 0x12;
|
||||
static constexpr const std::uint8_t SENSORTIME_ADDR = 0x18;
|
||||
static constexpr const std::uint8_t EVENT_ADDR = 0x1B;
|
||||
static constexpr const std::uint8_t INT_STATUS_0_ADDR = 0x1C;
|
||||
static constexpr const std::uint8_t INT_STATUS_1_ADDR = 0x1D;
|
||||
static constexpr const std::uint8_t SC_OUT_0_ADDR = 0x1E;
|
||||
static constexpr const std::uint8_t SYNC_COMMAND_ADDR = 0x1E;
|
||||
static constexpr const std::uint8_t GYR_CAS_GPIO0_ADDR = 0x1E;
|
||||
static constexpr const std::uint8_t INTERNAL_STATUS_ADDR = 0x21;
|
||||
static constexpr const std::uint8_t TEMPERATURE_0_ADDR = 0x22;
|
||||
static constexpr const std::uint8_t FIFO_LENGTH_0_ADDR = 0x24;
|
||||
static constexpr const std::uint8_t FIFO_DATA_ADDR = 0x26;
|
||||
static constexpr const std::uint8_t FEAT_PAGE_ADDR = 0x2F;
|
||||
static constexpr const std::uint8_t FEATURES_REG_ADDR = 0x30;
|
||||
static constexpr const std::uint8_t ACC_CONF_ADDR = 0x40;
|
||||
static constexpr const std::uint8_t GYR_CONF_ADDR = 0x42;
|
||||
static constexpr const std::uint8_t AUX_CONF_ADDR = 0x44;
|
||||
static constexpr const std::uint8_t FIFO_DOWNS_ADDR = 0x45;
|
||||
static constexpr const std::uint8_t FIFO_WTM_0_ADDR = 0x46;
|
||||
static constexpr const std::uint8_t FIFO_WTM_1_ADDR = 0x47;
|
||||
static constexpr const std::uint8_t FIFO_CONFIG_0_ADDR = 0x48;
|
||||
static constexpr const std::uint8_t FIFO_CONFIG_1_ADDR = 0x49;
|
||||
static constexpr const std::uint8_t AUX_DEV_ID_ADDR = 0x4B;
|
||||
static constexpr const std::uint8_t AUX_IF_CONF_ADDR = 0x4C;
|
||||
static constexpr const std::uint8_t AUX_RD_ADDR = 0x4D;
|
||||
static constexpr const std::uint8_t AUX_WR_ADDR = 0x4E;
|
||||
static constexpr const std::uint8_t AUX_WR_DATA_ADDR = 0x4F;
|
||||
static constexpr const std::uint8_t INT1_IO_CTRL_ADDR = 0x53;
|
||||
static constexpr const std::uint8_t INT2_IO_CTRL_ADDR = 0x54;
|
||||
static constexpr const std::uint8_t INT_LATCH_ADDR = 0x55;
|
||||
static constexpr const std::uint8_t INT1_MAP_FEAT_ADDR = 0x56;
|
||||
static constexpr const std::uint8_t INT2_MAP_FEAT_ADDR = 0x57;
|
||||
static constexpr const std::uint8_t INT_MAP_DATA_ADDR = 0x58;
|
||||
static constexpr const std::uint8_t INIT_CTRL_ADDR = 0x59;
|
||||
static constexpr const std::uint8_t INIT_ADDR_0 = 0x5B;
|
||||
static constexpr const std::uint8_t INIT_ADDR_1 = 0x5C;
|
||||
static constexpr const std::uint8_t INIT_DATA_ADDR = 0x5E;
|
||||
static constexpr const std::uint8_t AUX_IF_TRIM = 0x68;
|
||||
static constexpr const std::uint8_t GYR_CRT_CONF_ADDR = 0x69;
|
||||
static constexpr const std::uint8_t NVM_CONF_ADDR = 0x6A;
|
||||
static constexpr const std::uint8_t IF_CONF_ADDR = 0x6B;
|
||||
static constexpr const std::uint8_t ACC_SELF_TEST_ADDR = 0x6D;
|
||||
static constexpr const std::uint8_t GYR_SELF_TEST_AXES_ADDR = 0x6E;
|
||||
static constexpr const std::uint8_t SELF_TEST_MEMS_ADDR = 0x6F;
|
||||
static constexpr const std::uint8_t NV_CONF_ADDR = 0x70;
|
||||
static constexpr const std::uint8_t ACC_OFF_COMP_0_ADDR = 0x71;
|
||||
static constexpr const std::uint8_t GYR_OFF_COMP_3_ADDR = 0x74;
|
||||
static constexpr const std::uint8_t GYR_OFF_COMP_6_ADDR = 0x77;
|
||||
static constexpr const std::uint8_t GYR_USR_GAIN_0_ADDR = 0x78;
|
||||
static constexpr const std::uint8_t PWR_CONF_ADDR = 0x7C;
|
||||
static constexpr const std::uint8_t PWR_CTRL_ADDR = 0x7D;
|
||||
static constexpr const std::uint8_t CMD_REG_ADDR = 0x7E;
|
||||
|
||||
|
||||
static constexpr const std::uint8_t G_TRIGGER_CMD = 0x02;
|
||||
static constexpr const std::uint8_t USR_GAIN_CMD = 0x03;
|
||||
static constexpr const std::uint8_t NVM_PROG_CMD = 0xA0;
|
||||
static constexpr const std::uint8_t SOFT_RESET_CMD = 0xB6;
|
||||
static constexpr const std::uint8_t FIFO_FLUSH_CMD = 0xB0;
|
||||
|
||||
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x69;
|
||||
|
||||
virtual ~BMI270_Class();
|
||||
BMI270_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C);
|
||||
|
||||
imu_spec_t begin(I2C_Class* i2c = nullptr) override;
|
||||
imu_spec_t getImuRawData(imu_raw_data_t* data) const override;
|
||||
void getConvertParam(imu_convert_param_t* param) const override;
|
||||
bool getTempAdc(int16_t* adc) const override;
|
||||
|
||||
std::uint8_t WhoAmI(void);
|
||||
/*
|
||||
bool getAccelAdc(std::int16_t* ax, std::int16_t* ay, std::int16_t* az) const override;
|
||||
bool getGyroAdc(std::int16_t* gx, std::int16_t* gy, std::int16_t* gz) const override;
|
||||
bool getAccel(float* ax, float* ay, float* az) const override;
|
||||
bool getGyro(float* gx, float* gy, float* gz) const override;
|
||||
bool getTemp(float *t) const override;
|
||||
//*/
|
||||
protected:
|
||||
bool _upload_file(const std::uint8_t *config_data, std::size_t index, std::size_t write_len);
|
||||
|
||||
bool auxSetupMode(std::uint8_t i2c_addr);
|
||||
bool auxWriteRegister8(std::uint8_t reg, std::uint8_t data);
|
||||
std::uint8_t auxReadRegister8(std::uint8_t reg);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
435
libraries/M5Unified/src/utility/imu/BMI270_config.inl
Normal file
435
libraries/M5Unified/src/utility/imu/BMI270_config.inl
Normal file
|
|
@ -0,0 +1,435 @@
|
|||
|
||||
static constexpr const uint8_t bmi270_config_file[] = {
|
||||
0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x3d, 0xb1, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x91, 0x03, 0x80, 0x2e, 0xbc,
|
||||
0xb0, 0x80, 0x2e, 0xa3, 0x03, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x00, 0xb0, 0x50, 0x30, 0x21, 0x2e, 0x59, 0xf5,
|
||||
0x10, 0x30, 0x21, 0x2e, 0x6a, 0xf5, 0x80, 0x2e, 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x19, 0x01, 0x00, 0x22,
|
||||
0x00, 0x75, 0x00, 0x00, 0x10, 0x00, 0x10, 0xd1, 0x00, 0xb3, 0x43, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0xe0, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x19, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
|
||||
0xe0, 0xaa, 0x38, 0x05, 0xe0, 0x90, 0x30, 0xfa, 0x00, 0x96, 0x00, 0x4b, 0x09, 0x11, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||
0x2d, 0x01, 0xd4, 0x7b, 0x3b, 0x01, 0xdb, 0x7a, 0x04, 0x00, 0x3f, 0x7b, 0xcd, 0x6c, 0xc3, 0x04, 0x85, 0x09, 0xc3,
|
||||
0x04, 0xec, 0xe6, 0x0c, 0x46, 0x01, 0x00, 0x27, 0x00, 0x19, 0x00, 0x96, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x0c, 0x00,
|
||||
0xf0, 0x3c, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x32, 0x00, 0x05, 0x00, 0xee,
|
||||
0x06, 0x04, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa8, 0x05, 0xee, 0x06, 0x00, 0x04, 0xbc, 0x02, 0xb3, 0x00,
|
||||
0x85, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xb4, 0x00, 0x01, 0x00, 0xb9, 0x00, 0x01, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x2e, 0x00, 0xc1, 0xfd, 0x2d, 0xde,
|
||||
0x00, 0xeb, 0x00, 0xda, 0x00, 0x00, 0x0c, 0xff, 0x0f, 0x00, 0x04, 0xc0, 0x00, 0x5b, 0xf5, 0xc9, 0x01, 0x1e, 0xf2,
|
||||
0x80, 0x00, 0x3f, 0xff, 0x19, 0xf4, 0x58, 0xf5, 0x66, 0xf5, 0x64, 0xf5, 0xc0, 0xf1, 0xf0, 0x00, 0xe0, 0x00, 0xcd,
|
||||
0x01, 0xd3, 0x01, 0xdb, 0x01, 0xff, 0x7f, 0xff, 0x01, 0xe4, 0x00, 0x74, 0xf7, 0xf3, 0x00, 0xfa, 0x00, 0xff, 0x3f,
|
||||
0xca, 0x03, 0x6c, 0x38, 0x56, 0xfe, 0x44, 0xfd, 0xbc, 0x02, 0xf9, 0x06, 0x00, 0xfc, 0x12, 0x02, 0xae, 0x01, 0x58,
|
||||
0xfa, 0x9a, 0xfd, 0x77, 0x05, 0xbb, 0x02, 0x96, 0x01, 0x95, 0x01, 0x7f, 0x01, 0x82, 0x01, 0x89, 0x01, 0x87, 0x01,
|
||||
0x88, 0x01, 0x8a, 0x01, 0x8c, 0x01, 0x8f, 0x01, 0x8d, 0x01, 0x92, 0x01, 0x91, 0x01, 0xdd, 0x00, 0x9f, 0x01, 0x7e,
|
||||
0x01, 0xdb, 0x00, 0xb6, 0x01, 0x70, 0x69, 0x26, 0xd3, 0x9c, 0x07, 0x1f, 0x05, 0x9d, 0x00, 0x00, 0x08, 0xbc, 0x05,
|
||||
0x37, 0xfa, 0xa2, 0x01, 0xaa, 0x01, 0xa1, 0x01, 0xa8, 0x01, 0xa0, 0x01, 0xa8, 0x05, 0xb4, 0x01, 0xb4, 0x01, 0xce,
|
||||
0x00, 0xd0, 0x00, 0xfc, 0x00, 0xc5, 0x01, 0xff, 0xfb, 0xb1, 0x00, 0x00, 0x38, 0x00, 0x30, 0xfd, 0xf5, 0xfc, 0xf5,
|
||||
0xcd, 0x01, 0xa0, 0x00, 0x5f, 0xff, 0x00, 0x40, 0xff, 0x00, 0x00, 0x80, 0x6d, 0x0f, 0xeb, 0x00, 0x7f, 0xff, 0xc2,
|
||||
0xf5, 0x68, 0xf7, 0xb3, 0xf1, 0x67, 0x0f, 0x5b, 0x0f, 0x61, 0x0f, 0x80, 0x0f, 0x58, 0xf7, 0x5b, 0xf7, 0x83, 0x0f,
|
||||
0x86, 0x00, 0x72, 0x0f, 0x85, 0x0f, 0xc6, 0xf1, 0x7f, 0x0f, 0x6c, 0xf7, 0x00, 0xe0, 0x00, 0xff, 0xd1, 0xf5, 0x87,
|
||||
0x0f, 0x8a, 0x0f, 0xff, 0x03, 0xf0, 0x3f, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0xb9, 0x00, 0x2d, 0xf5, 0xca, 0xf5,
|
||||
0xcb, 0x01, 0x20, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x50, 0x98, 0x2e,
|
||||
0xd7, 0x0e, 0x50, 0x32, 0x98, 0x2e, 0xfa, 0x03, 0x00, 0x30, 0xf0, 0x7f, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x00,
|
||||
0x2e, 0x01, 0x80, 0x08, 0xa2, 0xfb, 0x2f, 0x98, 0x2e, 0xba, 0x03, 0x21, 0x2e, 0x19, 0x00, 0x01, 0x2e, 0xee, 0x00,
|
||||
0x00, 0xb2, 0x07, 0x2f, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x03, 0x2f, 0x01, 0x50, 0x03, 0x52, 0x98, 0x2e, 0x07,
|
||||
0xcc, 0x01, 0x2e, 0xdd, 0x00, 0x00, 0xb2, 0x27, 0x2f, 0x05, 0x2e, 0x8a, 0x00, 0x05, 0x52, 0x98, 0x2e, 0xc7, 0xc1,
|
||||
0x03, 0x2e, 0xe9, 0x00, 0x40, 0xb2, 0xf0, 0x7f, 0x08, 0x2f, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x04, 0x2f, 0x00,
|
||||
0x30, 0x21, 0x2e, 0xe9, 0x00, 0x98, 0x2e, 0xb4, 0xb1, 0x01, 0x2e, 0x18, 0x00, 0x00, 0xb2, 0x10, 0x2f, 0x05, 0x50,
|
||||
0x98, 0x2e, 0x4d, 0xc3, 0x05, 0x50, 0x98, 0x2e, 0x5a, 0xc7, 0x98, 0x2e, 0xf9, 0xb4, 0x98, 0x2e, 0x54, 0xb2, 0x98,
|
||||
0x2e, 0x67, 0xb6, 0x98, 0x2e, 0x17, 0xb2, 0x10, 0x30, 0x21, 0x2e, 0x77, 0x00, 0x01, 0x2e, 0xef, 0x00, 0x00, 0xb2,
|
||||
0x04, 0x2f, 0x98, 0x2e, 0x7a, 0xb7, 0x00, 0x30, 0x21, 0x2e, 0xef, 0x00, 0x01, 0x2e, 0xd4, 0x00, 0x04, 0xae, 0x0b,
|
||||
0x2f, 0x01, 0x2e, 0xdd, 0x00, 0x00, 0xb2, 0x07, 0x2f, 0x05, 0x52, 0x98, 0x2e, 0x8e, 0x0e, 0x00, 0xb2, 0x02, 0x2f,
|
||||
0x10, 0x30, 0x21, 0x2e, 0x7d, 0x00, 0x01, 0x2e, 0x7d, 0x00, 0x00, 0x90, 0x90, 0x2e, 0xf1, 0x02, 0x01, 0x2e, 0xd7,
|
||||
0x00, 0x00, 0xb2, 0x04, 0x2f, 0x98, 0x2e, 0x2f, 0x0e, 0x00, 0x30, 0x21, 0x2e, 0x7b, 0x00, 0x01, 0x2e, 0x7b, 0x00,
|
||||
0x00, 0xb2, 0x12, 0x2f, 0x01, 0x2e, 0xd4, 0x00, 0x00, 0x90, 0x02, 0x2f, 0x98, 0x2e, 0x1f, 0x0e, 0x09, 0x2d, 0x98,
|
||||
0x2e, 0x81, 0x0d, 0x01, 0x2e, 0xd4, 0x00, 0x04, 0x90, 0x02, 0x2f, 0x50, 0x32, 0x98, 0x2e, 0xfa, 0x03, 0x00, 0x30,
|
||||
0x21, 0x2e, 0x7b, 0x00, 0x01, 0x2e, 0x7c, 0x00, 0x00, 0xb2, 0x90, 0x2e, 0x09, 0x03, 0x01, 0x2e, 0x7c, 0x00, 0x01,
|
||||
0x31, 0x01, 0x08, 0x00, 0xb2, 0x04, 0x2f, 0x98, 0x2e, 0x47, 0xcb, 0x10, 0x30, 0x21, 0x2e, 0x77, 0x00, 0x81, 0x30,
|
||||
0x01, 0x2e, 0x7c, 0x00, 0x01, 0x08, 0x00, 0xb2, 0x61, 0x2f, 0x03, 0x2e, 0x89, 0x00, 0x01, 0x2e, 0xd4, 0x00, 0x98,
|
||||
0xbc, 0x98, 0xb8, 0x05, 0xb2, 0x0f, 0x58, 0x23, 0x2f, 0x07, 0x90, 0x09, 0x54, 0x00, 0x30, 0x37, 0x2f, 0x15, 0x41,
|
||||
0x04, 0x41, 0xdc, 0xbe, 0x44, 0xbe, 0xdc, 0xba, 0x2c, 0x01, 0x61, 0x00, 0x0f, 0x56, 0x4a, 0x0f, 0x0c, 0x2f, 0xd1,
|
||||
0x42, 0x94, 0xb8, 0xc1, 0x42, 0x11, 0x30, 0x05, 0x2e, 0x6a, 0xf7, 0x2c, 0xbd, 0x2f, 0xb9, 0x80, 0xb2, 0x08, 0x22,
|
||||
0x98, 0x2e, 0xc3, 0xb7, 0x21, 0x2d, 0x61, 0x30, 0x23, 0x2e, 0xd4, 0x00, 0x98, 0x2e, 0xc3, 0xb7, 0x00, 0x30, 0x21,
|
||||
0x2e, 0x5a, 0xf5, 0x18, 0x2d, 0xe1, 0x7f, 0x50, 0x30, 0x98, 0x2e, 0xfa, 0x03, 0x0f, 0x52, 0x07, 0x50, 0x50, 0x42,
|
||||
0x70, 0x30, 0x0d, 0x54, 0x42, 0x42, 0x7e, 0x82, 0xe2, 0x6f, 0x80, 0xb2, 0x42, 0x42, 0x05, 0x2f, 0x21, 0x2e, 0xd4,
|
||||
0x00, 0x10, 0x30, 0x98, 0x2e, 0xc3, 0xb7, 0x03, 0x2d, 0x60, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0x01, 0x2e, 0xd4, 0x00,
|
||||
0x06, 0x90, 0x18, 0x2f, 0x01, 0x2e, 0x76, 0x00, 0x0b, 0x54, 0x07, 0x52, 0xe0, 0x7f, 0x98, 0x2e, 0x7a, 0xc1, 0xe1,
|
||||
0x6f, 0x08, 0x1a, 0x40, 0x30, 0x08, 0x2f, 0x21, 0x2e, 0xd4, 0x00, 0x20, 0x30, 0x98, 0x2e, 0xaf, 0xb7, 0x50, 0x32,
|
||||
0x98, 0x2e, 0xfa, 0x03, 0x05, 0x2d, 0x98, 0x2e, 0x38, 0x0e, 0x00, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0x00, 0x30, 0x21,
|
||||
0x2e, 0x7c, 0x00, 0x18, 0x2d, 0x01, 0x2e, 0xd4, 0x00, 0x03, 0xaa, 0x01, 0x2f, 0x98, 0x2e, 0x45, 0x0e, 0x01, 0x2e,
|
||||
0xd4, 0x00, 0x3f, 0x80, 0x03, 0xa2, 0x01, 0x2f, 0x00, 0x2e, 0x02, 0x2d, 0x98, 0x2e, 0x5b, 0x0e, 0x30, 0x30, 0x98,
|
||||
0x2e, 0xce, 0xb7, 0x00, 0x30, 0x21, 0x2e, 0x7d, 0x00, 0x50, 0x32, 0x98, 0x2e, 0xfa, 0x03, 0x01, 0x2e, 0x77, 0x00,
|
||||
0x00, 0xb2, 0x24, 0x2f, 0x98, 0x2e, 0xf5, 0xcb, 0x03, 0x2e, 0xd5, 0x00, 0x11, 0x54, 0x01, 0x0a, 0xbc, 0x84, 0x83,
|
||||
0x86, 0x21, 0x2e, 0xc9, 0x01, 0xe0, 0x40, 0x13, 0x52, 0xc4, 0x40, 0x82, 0x40, 0xa8, 0xb9, 0x52, 0x42, 0x43, 0xbe,
|
||||
0x53, 0x42, 0x04, 0x0a, 0x50, 0x42, 0xe1, 0x7f, 0xf0, 0x31, 0x41, 0x40, 0xf2, 0x6f, 0x25, 0xbd, 0x08, 0x08, 0x02,
|
||||
0x0a, 0xd0, 0x7f, 0x98, 0x2e, 0xa8, 0xcf, 0x06, 0xbc, 0xd1, 0x6f, 0xe2, 0x6f, 0x08, 0x0a, 0x80, 0x42, 0x98, 0x2e,
|
||||
0x58, 0xb7, 0x00, 0x30, 0x21, 0x2e, 0xee, 0x00, 0x21, 0x2e, 0x77, 0x00, 0x21, 0x2e, 0xdd, 0x00, 0x80, 0x2e, 0xf4,
|
||||
0x01, 0x1a, 0x24, 0x22, 0x00, 0x80, 0x2e, 0xec, 0x01, 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0xf3, 0x03, 0x57, 0x50,
|
||||
0xfb, 0x6f, 0x01, 0x30, 0x71, 0x54, 0x11, 0x42, 0x42, 0x0e, 0xfc, 0x2f, 0xc0, 0x2e, 0x01, 0x42, 0xf0, 0x5f, 0x80,
|
||||
0x2e, 0x00, 0xc1, 0xfd, 0x2d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x01,
|
||||
0x34, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x20, 0x50, 0xe7, 0x7f, 0xf6, 0x7f, 0x06, 0x32, 0x0f, 0x2e, 0x61, 0xf5, 0xfe, 0x09, 0xc0, 0xb3, 0x04,
|
||||
0x2f, 0x17, 0x30, 0x2f, 0x2e, 0xef, 0x00, 0x2d, 0x2e, 0x61, 0xf5, 0xf6, 0x6f, 0xe7, 0x6f, 0xe0, 0x5f, 0xc8, 0x2e,
|
||||
0x20, 0x50, 0xe7, 0x7f, 0xf6, 0x7f, 0x46, 0x30, 0x0f, 0x2e, 0xa4, 0xf1, 0xbe, 0x09, 0x80, 0xb3, 0x06, 0x2f, 0x0d,
|
||||
0x2e, 0xd4, 0x00, 0x84, 0xaf, 0x02, 0x2f, 0x16, 0x30, 0x2d, 0x2e, 0x7b, 0x00, 0x86, 0x30, 0x2d, 0x2e, 0x60, 0xf5,
|
||||
0xf6, 0x6f, 0xe7, 0x6f, 0xe0, 0x5f, 0xc8, 0x2e, 0x01, 0x2e, 0x77, 0xf7, 0x09, 0xbc, 0x0f, 0xb8, 0x00, 0xb2, 0x10,
|
||||
0x50, 0xfb, 0x7f, 0x10, 0x30, 0x0b, 0x2f, 0x03, 0x2e, 0x8a, 0x00, 0x96, 0xbc, 0x9f, 0xb8, 0x40, 0xb2, 0x05, 0x2f,
|
||||
0x03, 0x2e, 0x68, 0xf7, 0x9e, 0xbc, 0x9f, 0xb8, 0x40, 0xb2, 0x07, 0x2f, 0x03, 0x2e, 0x7e, 0x00, 0x41, 0x90, 0x01,
|
||||
0x2f, 0x98, 0x2e, 0xdc, 0x03, 0x03, 0x2c, 0x00, 0x30, 0x21, 0x2e, 0x7e, 0x00, 0xfb, 0x6f, 0xf0, 0x5f, 0xb8, 0x2e,
|
||||
0x20, 0x50, 0xe0, 0x7f, 0xfb, 0x7f, 0x00, 0x2e, 0x27, 0x50, 0x98, 0x2e, 0x3b, 0xc8, 0x29, 0x50, 0x98, 0x2e, 0xa7,
|
||||
0xc8, 0x01, 0x50, 0x98, 0x2e, 0x55, 0xcc, 0xe1, 0x6f, 0x2b, 0x50, 0x98, 0x2e, 0xe0, 0xc9, 0xfb, 0x6f, 0x00, 0x30,
|
||||
0xe0, 0x5f, 0x21, 0x2e, 0x7e, 0x00, 0xb8, 0x2e, 0x73, 0x50, 0x01, 0x30, 0x57, 0x54, 0x11, 0x42, 0x42, 0x0e, 0xfc,
|
||||
0x2f, 0xb8, 0x2e, 0x21, 0x2e, 0x59, 0xf5, 0x10, 0x30, 0xc0, 0x2e, 0x21, 0x2e, 0x4a, 0xf1, 0x90, 0x50, 0xf7, 0x7f,
|
||||
0xe6, 0x7f, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0xa1, 0x7f, 0x90, 0x7f, 0x82, 0x7f, 0x7b, 0x7f, 0x98, 0x2e, 0x35,
|
||||
0xb7, 0x00, 0xb2, 0x90, 0x2e, 0x97, 0xb0, 0x03, 0x2e, 0x8f, 0x00, 0x07, 0x2e, 0x91, 0x00, 0x05, 0x2e, 0xb1, 0x00,
|
||||
0x3f, 0xba, 0x9f, 0xb8, 0x01, 0x2e, 0xb1, 0x00, 0xa3, 0xbd, 0x4c, 0x0a, 0x05, 0x2e, 0xb1, 0x00, 0x04, 0xbe, 0xbf,
|
||||
0xb9, 0xcb, 0x0a, 0x4f, 0xba, 0x22, 0xbd, 0x01, 0x2e, 0xb3, 0x00, 0xdc, 0x0a, 0x2f, 0xb9, 0x03, 0x2e, 0xb8, 0x00,
|
||||
0x0a, 0xbe, 0x9a, 0x0a, 0xcf, 0xb9, 0x9b, 0xbc, 0x01, 0x2e, 0x97, 0x00, 0x9f, 0xb8, 0x93, 0x0a, 0x0f, 0xbc, 0x91,
|
||||
0x0a, 0x0f, 0xb8, 0x90, 0x0a, 0x25, 0x2e, 0x18, 0x00, 0x05, 0x2e, 0xc1, 0xf5, 0x2e, 0xbd, 0x2e, 0xb9, 0x01, 0x2e,
|
||||
0x19, 0x00, 0x31, 0x30, 0x8a, 0x04, 0x00, 0x90, 0x07, 0x2f, 0x01, 0x2e, 0xd4, 0x00, 0x04, 0xa2, 0x03, 0x2f, 0x01,
|
||||
0x2e, 0x18, 0x00, 0x00, 0xb2, 0x0c, 0x2f, 0x19, 0x50, 0x05, 0x52, 0x98, 0x2e, 0x4d, 0xb7, 0x05, 0x2e, 0x78, 0x00,
|
||||
0x80, 0x90, 0x10, 0x30, 0x01, 0x2f, 0x21, 0x2e, 0x78, 0x00, 0x25, 0x2e, 0xdd, 0x00, 0x98, 0x2e, 0x3e, 0xb7, 0x00,
|
||||
0xb2, 0x02, 0x30, 0x01, 0x30, 0x04, 0x2f, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x00, 0x2f, 0x21, 0x30, 0x01, 0x2e,
|
||||
0xea, 0x00, 0x08, 0x1a, 0x0e, 0x2f, 0x23, 0x2e, 0xea, 0x00, 0x33, 0x30, 0x1b, 0x50, 0x0b, 0x09, 0x01, 0x40, 0x17,
|
||||
0x56, 0x46, 0xbe, 0x4b, 0x08, 0x4c, 0x0a, 0x01, 0x42, 0x0a, 0x80, 0x15, 0x52, 0x01, 0x42, 0x00, 0x2e, 0x01, 0x2e,
|
||||
0x18, 0x00, 0x00, 0xb2, 0x1f, 0x2f, 0x03, 0x2e, 0xc0, 0xf5, 0xf0, 0x30, 0x48, 0x08, 0x47, 0xaa, 0x74, 0x30, 0x07,
|
||||
0x2e, 0x7a, 0x00, 0x61, 0x22, 0x4b, 0x1a, 0x05, 0x2f, 0x07, 0x2e, 0x66, 0xf5, 0xbf, 0xbd, 0xbf, 0xb9, 0xc0, 0x90,
|
||||
0x0b, 0x2f, 0x1d, 0x56, 0x2b, 0x30, 0xd2, 0x42, 0xdb, 0x42, 0x01, 0x04, 0xc2, 0x42, 0x04, 0xbd, 0xfe, 0x80, 0x81,
|
||||
0x84, 0x23, 0x2e, 0x7a, 0x00, 0x02, 0x42, 0x02, 0x32, 0x25, 0x2e, 0x62, 0xf5, 0x05, 0x2e, 0xd6, 0x00, 0x81, 0x84,
|
||||
0x25, 0x2e, 0xd6, 0x00, 0x02, 0x31, 0x25, 0x2e, 0x60, 0xf5, 0x05, 0x2e, 0x8a, 0x00, 0x0b, 0x50, 0x90, 0x08, 0x80,
|
||||
0xb2, 0x0b, 0x2f, 0x05, 0x2e, 0xca, 0xf5, 0xf0, 0x3e, 0x90, 0x08, 0x25, 0x2e, 0xca, 0xf5, 0x05, 0x2e, 0x59, 0xf5,
|
||||
0xe0, 0x3f, 0x90, 0x08, 0x25, 0x2e, 0x59, 0xf5, 0x90, 0x6f, 0xa1, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0xe6,
|
||||
0x6f, 0xf7, 0x6f, 0x7b, 0x6f, 0x82, 0x6f, 0x70, 0x5f, 0xc8, 0x2e, 0xc0, 0x50, 0x90, 0x7f, 0xe5, 0x7f, 0xd4, 0x7f,
|
||||
0xc3, 0x7f, 0xb1, 0x7f, 0xa2, 0x7f, 0x87, 0x7f, 0xf6, 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x60, 0xf5, 0x60,
|
||||
0x7f, 0x98, 0x2e, 0x35, 0xb7, 0x02, 0x30, 0x63, 0x6f, 0x15, 0x52, 0x50, 0x7f, 0x62, 0x7f, 0x5a, 0x2c, 0x02, 0x32,
|
||||
0x1a, 0x09, 0x00, 0xb3, 0x14, 0x2f, 0x00, 0xb2, 0x03, 0x2f, 0x09, 0x2e, 0x18, 0x00, 0x00, 0x91, 0x0c, 0x2f, 0x43,
|
||||
0x7f, 0x98, 0x2e, 0x97, 0xb7, 0x1f, 0x50, 0x02, 0x8a, 0x02, 0x32, 0x04, 0x30, 0x25, 0x2e, 0x64, 0xf5, 0x15, 0x52,
|
||||
0x50, 0x6f, 0x43, 0x6f, 0x44, 0x43, 0x25, 0x2e, 0x60, 0xf5, 0xd9, 0x08, 0xc0, 0xb2, 0x36, 0x2f, 0x98, 0x2e, 0x3e,
|
||||
0xb7, 0x00, 0xb2, 0x06, 0x2f, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x02, 0x2f, 0x50, 0x6f, 0x00, 0x90, 0x0a, 0x2f,
|
||||
0x01, 0x2e, 0x79, 0x00, 0x00, 0x90, 0x19, 0x2f, 0x10, 0x30, 0x21, 0x2e, 0x79, 0x00, 0x00, 0x30, 0x98, 0x2e, 0xdc,
|
||||
0x03, 0x13, 0x2d, 0x01, 0x2e, 0xc3, 0xf5, 0x0c, 0xbc, 0x0f, 0xb8, 0x12, 0x30, 0x10, 0x04, 0x03, 0xb0, 0x26, 0x25,
|
||||
0x21, 0x50, 0x03, 0x52, 0x98, 0x2e, 0x4d, 0xb7, 0x10, 0x30, 0x21, 0x2e, 0xee, 0x00, 0x02, 0x30, 0x60, 0x7f, 0x25,
|
||||
0x2e, 0x79, 0x00, 0x60, 0x6f, 0x00, 0x90, 0x05, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0xea, 0x00, 0x15, 0x50, 0x21, 0x2e,
|
||||
0x64, 0xf5, 0x15, 0x52, 0x23, 0x2e, 0x60, 0xf5, 0x02, 0x32, 0x50, 0x6f, 0x00, 0x90, 0x02, 0x2f, 0x03, 0x30, 0x27,
|
||||
0x2e, 0x78, 0x00, 0x07, 0x2e, 0x60, 0xf5, 0x1a, 0x09, 0x00, 0x91, 0xa3, 0x2f, 0x19, 0x09, 0x00, 0x91, 0xa0, 0x2f,
|
||||
0x90, 0x6f, 0xa2, 0x6f, 0xb1, 0x6f, 0xc3, 0x6f, 0xd4, 0x6f, 0xe5, 0x6f, 0x7b, 0x6f, 0xf6, 0x6f, 0x87, 0x6f, 0x40,
|
||||
0x5f, 0xc8, 0x2e, 0xc0, 0x50, 0xe7, 0x7f, 0xf6, 0x7f, 0x26, 0x30, 0x0f, 0x2e, 0x61, 0xf5, 0x2f, 0x2e, 0x7c, 0x00,
|
||||
0x0f, 0x2e, 0x7c, 0x00, 0xbe, 0x09, 0xa2, 0x7f, 0x80, 0x7f, 0x80, 0xb3, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0x91,
|
||||
0x7f, 0x7b, 0x7f, 0x0b, 0x2f, 0x23, 0x50, 0x1a, 0x25, 0x12, 0x40, 0x42, 0x7f, 0x74, 0x82, 0x12, 0x40, 0x52, 0x7f,
|
||||
0x00, 0x2e, 0x00, 0x40, 0x60, 0x7f, 0x98, 0x2e, 0x6a, 0xd6, 0x81, 0x30, 0x01, 0x2e, 0x7c, 0x00, 0x01, 0x08, 0x00,
|
||||
0xb2, 0x42, 0x2f, 0x03, 0x2e, 0x89, 0x00, 0x01, 0x2e, 0x89, 0x00, 0x97, 0xbc, 0x06, 0xbc, 0x9f, 0xb8, 0x0f, 0xb8,
|
||||
0x00, 0x90, 0x23, 0x2e, 0xd8, 0x00, 0x10, 0x30, 0x01, 0x30, 0x2a, 0x2f, 0x03, 0x2e, 0xd4, 0x00, 0x44, 0xb2, 0x05,
|
||||
0x2f, 0x47, 0xb2, 0x00, 0x30, 0x2d, 0x2f, 0x21, 0x2e, 0x7c, 0x00, 0x2b, 0x2d, 0x03, 0x2e, 0xfd, 0xf5, 0x9e, 0xbc,
|
||||
0x9f, 0xb8, 0x40, 0x90, 0x14, 0x2f, 0x03, 0x2e, 0xfc, 0xf5, 0x99, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x0e, 0x2f, 0x03,
|
||||
0x2e, 0x49, 0xf1, 0x25, 0x54, 0x4a, 0x08, 0x40, 0x90, 0x08, 0x2f, 0x98, 0x2e, 0x35, 0xb7, 0x00, 0xb2, 0x10, 0x30,
|
||||
0x03, 0x2f, 0x50, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0x10, 0x2d, 0x98, 0x2e, 0xaf, 0xb7, 0x00, 0x30, 0x21, 0x2e, 0x7c,
|
||||
0x00, 0x0a, 0x2d, 0x05, 0x2e, 0x69, 0xf7, 0x2d, 0xbd, 0x2f, 0xb9, 0x80, 0xb2, 0x01, 0x2f, 0x21, 0x2e, 0x7d, 0x00,
|
||||
0x23, 0x2e, 0x7c, 0x00, 0xe0, 0x31, 0x21, 0x2e, 0x61, 0xf5, 0xf6, 0x6f, 0xe7, 0x6f, 0x80, 0x6f, 0xa2, 0x6f, 0xb3,
|
||||
0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0x7b, 0x6f, 0x91, 0x6f, 0x40, 0x5f, 0xc8, 0x2e, 0x60, 0x51, 0x0a, 0x25, 0x36, 0x88,
|
||||
0xf4, 0x7f, 0xeb, 0x7f, 0x00, 0x32, 0x31, 0x52, 0x32, 0x30, 0x13, 0x30, 0x98, 0x2e, 0x15, 0xcb, 0x0a, 0x25, 0x33,
|
||||
0x84, 0xd2, 0x7f, 0x43, 0x30, 0x05, 0x50, 0x2d, 0x52, 0x98, 0x2e, 0x95, 0xc1, 0xd2, 0x6f, 0x27, 0x52, 0x98, 0x2e,
|
||||
0xd7, 0xc7, 0x2a, 0x25, 0xb0, 0x86, 0xc0, 0x7f, 0xd3, 0x7f, 0xaf, 0x84, 0x29, 0x50, 0xf1, 0x6f, 0x98, 0x2e, 0x4d,
|
||||
0xc8, 0x2a, 0x25, 0xae, 0x8a, 0xaa, 0x88, 0xf2, 0x6e, 0x2b, 0x50, 0xc1, 0x6f, 0xd3, 0x6f, 0xf4, 0x7f, 0x98, 0x2e,
|
||||
0xb6, 0xc8, 0xe0, 0x6e, 0x00, 0xb2, 0x32, 0x2f, 0x33, 0x54, 0x83, 0x86, 0xf1, 0x6f, 0xc3, 0x7f, 0x04, 0x30, 0x30,
|
||||
0x30, 0xf4, 0x7f, 0xd0, 0x7f, 0xb2, 0x7f, 0xe3, 0x30, 0xc5, 0x6f, 0x56, 0x40, 0x45, 0x41, 0x28, 0x08, 0x03, 0x14,
|
||||
0x0e, 0xb4, 0x08, 0xbc, 0x82, 0x40, 0x10, 0x0a, 0x2f, 0x54, 0x26, 0x05, 0x91, 0x7f, 0x44, 0x28, 0xa3, 0x7f, 0x98,
|
||||
0x2e, 0xd9, 0xc0, 0x08, 0xb9, 0x33, 0x30, 0x53, 0x09, 0xc1, 0x6f, 0xd3, 0x6f, 0xf4, 0x6f, 0x83, 0x17, 0x47, 0x40,
|
||||
0x6c, 0x15, 0xb2, 0x6f, 0xbe, 0x09, 0x75, 0x0b, 0x90, 0x42, 0x45, 0x42, 0x51, 0x0e, 0x32, 0xbc, 0x02, 0x89, 0xa1,
|
||||
0x6f, 0x7e, 0x86, 0xf4, 0x7f, 0xd0, 0x7f, 0xb2, 0x7f, 0x04, 0x30, 0x91, 0x6f, 0xd6, 0x2f, 0xeb, 0x6f, 0xa0, 0x5e,
|
||||
0xb8, 0x2e, 0x03, 0x2e, 0x97, 0x00, 0x1b, 0xbc, 0x60, 0x50, 0x9f, 0xbc, 0x0c, 0xb8, 0xf0, 0x7f, 0x40, 0xb2, 0xeb,
|
||||
0x7f, 0x2b, 0x2f, 0x03, 0x2e, 0x7f, 0x00, 0x41, 0x40, 0x01, 0x2e, 0xc8, 0x00, 0x01, 0x1a, 0x11, 0x2f, 0x37, 0x58,
|
||||
0x23, 0x2e, 0xc8, 0x00, 0x10, 0x41, 0xa0, 0x7f, 0x38, 0x81, 0x01, 0x41, 0xd0, 0x7f, 0xb1, 0x7f, 0x98, 0x2e, 0x64,
|
||||
0xcf, 0xd0, 0x6f, 0x07, 0x80, 0xa1, 0x6f, 0x11, 0x42, 0x00, 0x2e, 0xb1, 0x6f, 0x01, 0x42, 0x11, 0x30, 0x01, 0x2e,
|
||||
0xfc, 0x00, 0x00, 0xa8, 0x03, 0x30, 0xcb, 0x22, 0x4a, 0x25, 0x01, 0x2e, 0x7f, 0x00, 0x3c, 0x89, 0x35, 0x52, 0x05,
|
||||
0x54, 0x98, 0x2e, 0xc4, 0xce, 0xc1, 0x6f, 0xf0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0x04, 0x2d, 0x01, 0x30, 0xf0, 0x6f,
|
||||
0x98, 0x2e, 0x95, 0xcf, 0xeb, 0x6f, 0xa0, 0x5f, 0xb8, 0x2e, 0x03, 0x2e, 0xb3, 0x00, 0x02, 0x32, 0xf0, 0x30, 0x03,
|
||||
0x31, 0x30, 0x50, 0x8a, 0x08, 0x08, 0x08, 0xcb, 0x08, 0xe0, 0x7f, 0x80, 0xb2, 0xf3, 0x7f, 0xdb, 0x7f, 0x25, 0x2f,
|
||||
0x03, 0x2e, 0xca, 0x00, 0x41, 0x90, 0x04, 0x2f, 0x01, 0x30, 0x23, 0x2e, 0xca, 0x00, 0x98, 0x2e, 0x3f, 0x03, 0xc0,
|
||||
0xb2, 0x05, 0x2f, 0x03, 0x2e, 0xda, 0x00, 0x00, 0x30, 0x41, 0x04, 0x23, 0x2e, 0xda, 0x00, 0x98, 0x2e, 0x92, 0xb2,
|
||||
0x10, 0x25, 0xf0, 0x6f, 0x00, 0xb2, 0x05, 0x2f, 0x01, 0x2e, 0xda, 0x00, 0x02, 0x30, 0x10, 0x04, 0x21, 0x2e, 0xda,
|
||||
0x00, 0x40, 0xb2, 0x01, 0x2f, 0x23, 0x2e, 0xc8, 0x01, 0xdb, 0x6f, 0xe0, 0x6f, 0xd0, 0x5f, 0x80, 0x2e, 0x95, 0xcf,
|
||||
0x01, 0x30, 0xe0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0x11, 0x30, 0x23, 0x2e, 0xca, 0x00, 0xdb, 0x6f, 0xd0, 0x5f, 0xb8,
|
||||
0x2e, 0xd0, 0x50, 0x0a, 0x25, 0x33, 0x84, 0x55, 0x50, 0xd2, 0x7f, 0xe2, 0x7f, 0x03, 0x8c, 0xc0, 0x7f, 0xbb, 0x7f,
|
||||
0x00, 0x30, 0x05, 0x5a, 0x39, 0x54, 0x51, 0x41, 0xa5, 0x7f, 0x96, 0x7f, 0x80, 0x7f, 0x98, 0x2e, 0xd9, 0xc0, 0x05,
|
||||
0x30, 0xf5, 0x7f, 0x20, 0x25, 0x91, 0x6f, 0x3b, 0x58, 0x3d, 0x5c, 0x3b, 0x56, 0x98, 0x2e, 0x67, 0xcc, 0xc1, 0x6f,
|
||||
0xd5, 0x6f, 0x52, 0x40, 0x50, 0x43, 0xc1, 0x7f, 0xd5, 0x7f, 0x10, 0x25, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0x98,
|
||||
0x2e, 0x74, 0xc0, 0x86, 0x6f, 0x30, 0x28, 0x92, 0x6f, 0x82, 0x8c, 0xa5, 0x6f, 0x6f, 0x52, 0x69, 0x0e, 0x39, 0x54,
|
||||
0xdb, 0x2f, 0x19, 0xa0, 0x15, 0x30, 0x03, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0x81, 0x01, 0x0a, 0x2d, 0x01, 0x2e, 0x81,
|
||||
0x01, 0x05, 0x28, 0x42, 0x36, 0x21, 0x2e, 0x81, 0x01, 0x02, 0x0e, 0x01, 0x2f, 0x98, 0x2e, 0xf3, 0x03, 0x57, 0x50,
|
||||
0x12, 0x30, 0x01, 0x40, 0x98, 0x2e, 0xfe, 0xc9, 0x51, 0x6f, 0x0b, 0x5c, 0x8e, 0x0e, 0x3b, 0x6f, 0x57, 0x58, 0x02,
|
||||
0x30, 0x21, 0x2e, 0x95, 0x01, 0x45, 0x6f, 0x2a, 0x8d, 0xd2, 0x7f, 0xcb, 0x7f, 0x13, 0x2f, 0x02, 0x30, 0x3f, 0x50,
|
||||
0xd2, 0x7f, 0xa8, 0x0e, 0x0e, 0x2f, 0xc0, 0x6f, 0x53, 0x54, 0x02, 0x00, 0x51, 0x54, 0x42, 0x0e, 0x10, 0x30, 0x59,
|
||||
0x52, 0x02, 0x30, 0x01, 0x2f, 0x00, 0x2e, 0x03, 0x2d, 0x50, 0x42, 0x42, 0x42, 0x12, 0x30, 0xd2, 0x7f, 0x80, 0xb2,
|
||||
0x03, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0x80, 0x01, 0x12, 0x2d, 0x01, 0x2e, 0xc9, 0x00, 0x02, 0x80, 0x05, 0x2e, 0x80,
|
||||
0x01, 0x11, 0x30, 0x91, 0x28, 0x00, 0x40, 0x25, 0x2e, 0x80, 0x01, 0x10, 0x0e, 0x05, 0x2f, 0x01, 0x2e, 0x7f, 0x01,
|
||||
0x01, 0x90, 0x01, 0x2f, 0x98, 0x2e, 0xf3, 0x03, 0x00, 0x2e, 0xa0, 0x41, 0x01, 0x90, 0xa6, 0x7f, 0x90, 0x2e, 0xe3,
|
||||
0xb4, 0x01, 0x2e, 0x95, 0x01, 0x00, 0xa8, 0x90, 0x2e, 0xe3, 0xb4, 0x5b, 0x54, 0x95, 0x80, 0x82, 0x40, 0x80, 0xb2,
|
||||
0x02, 0x40, 0x2d, 0x8c, 0x3f, 0x52, 0x96, 0x7f, 0x90, 0x2e, 0xc2, 0xb3, 0x29, 0x0e, 0x76, 0x2f, 0x01, 0x2e, 0xc9,
|
||||
0x00, 0x00, 0x40, 0x81, 0x28, 0x45, 0x52, 0xb3, 0x30, 0x98, 0x2e, 0x0f, 0xca, 0x5d, 0x54, 0x80, 0x7f, 0x00, 0x2e,
|
||||
0xa1, 0x40, 0x72, 0x7f, 0x82, 0x80, 0x82, 0x40, 0x60, 0x7f, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0x98, 0x2e, 0x74,
|
||||
0xc0, 0x62, 0x6f, 0x05, 0x30, 0x87, 0x40, 0xc0, 0x91, 0x04, 0x30, 0x05, 0x2f, 0x05, 0x2e, 0x83, 0x01, 0x80, 0xb2,
|
||||
0x14, 0x30, 0x00, 0x2f, 0x04, 0x30, 0x05, 0x2e, 0xc9, 0x00, 0x73, 0x6f, 0x81, 0x40, 0xe2, 0x40, 0x69, 0x04, 0x11,
|
||||
0x0f, 0xe1, 0x40, 0x16, 0x30, 0xfe, 0x29, 0xcb, 0x40, 0x02, 0x2f, 0x83, 0x6f, 0x83, 0x0f, 0x22, 0x2f, 0x47, 0x56,
|
||||
0x13, 0x0f, 0x12, 0x30, 0x77, 0x2f, 0x49, 0x54, 0x42, 0x0e, 0x12, 0x30, 0x73, 0x2f, 0x00, 0x91, 0x0a, 0x2f, 0x01,
|
||||
0x2e, 0x8b, 0x01, 0x19, 0xa8, 0x02, 0x30, 0x6c, 0x2f, 0x63, 0x50, 0x00, 0x2e, 0x17, 0x42, 0x05, 0x42, 0x68, 0x2c,
|
||||
0x12, 0x30, 0x0b, 0x25, 0x08, 0x0f, 0x50, 0x30, 0x02, 0x2f, 0x21, 0x2e, 0x83, 0x01, 0x03, 0x2d, 0x40, 0x30, 0x21,
|
||||
0x2e, 0x83, 0x01, 0x2b, 0x2e, 0x85, 0x01, 0x5a, 0x2c, 0x12, 0x30, 0x00, 0x91, 0x2b, 0x25, 0x04, 0x2f, 0x63, 0x50,
|
||||
0x02, 0x30, 0x17, 0x42, 0x17, 0x2c, 0x02, 0x42, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0x98, 0x2e, 0x74, 0xc0, 0x05,
|
||||
0x2e, 0xc9, 0x00, 0x81, 0x84, 0x5b, 0x30, 0x82, 0x40, 0x37, 0x2e, 0x83, 0x01, 0x02, 0x0e, 0x07, 0x2f, 0x5f, 0x52,
|
||||
0x40, 0x30, 0x62, 0x40, 0x41, 0x40, 0x91, 0x0e, 0x01, 0x2f, 0x21, 0x2e, 0x83, 0x01, 0x05, 0x30, 0x2b, 0x2e, 0x85,
|
||||
0x01, 0x12, 0x30, 0x36, 0x2c, 0x16, 0x30, 0x15, 0x25, 0x81, 0x7f, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0x98, 0x2e,
|
||||
0x74, 0xc0, 0x19, 0xa2, 0x16, 0x30, 0x15, 0x2f, 0x05, 0x2e, 0x97, 0x01, 0x80, 0x6f, 0x82, 0x0e, 0x05, 0x2f, 0x01,
|
||||
0x2e, 0x86, 0x01, 0x06, 0x28, 0x21, 0x2e, 0x86, 0x01, 0x0b, 0x2d, 0x03, 0x2e, 0x87, 0x01, 0x5f, 0x54, 0x4e, 0x28,
|
||||
0x91, 0x42, 0x00, 0x2e, 0x82, 0x40, 0x90, 0x0e, 0x01, 0x2f, 0x21, 0x2e, 0x88, 0x01, 0x02, 0x30, 0x13, 0x2c, 0x05,
|
||||
0x30, 0xc0, 0x6f, 0x08, 0x1c, 0xa8, 0x0f, 0x16, 0x30, 0x05, 0x30, 0x5b, 0x50, 0x09, 0x2f, 0x02, 0x80, 0x2d, 0x2e,
|
||||
0x82, 0x01, 0x05, 0x42, 0x05, 0x80, 0x00, 0x2e, 0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x06, 0x42, 0x02, 0x30, 0x90,
|
||||
0x6f, 0x3e, 0x88, 0x01, 0x40, 0x04, 0x41, 0x4c, 0x28, 0x01, 0x42, 0x07, 0x80, 0x10, 0x25, 0x24, 0x40, 0x00, 0x40,
|
||||
0x00, 0xa8, 0xf5, 0x22, 0x23, 0x29, 0x44, 0x42, 0x7a, 0x82, 0x7e, 0x88, 0x43, 0x40, 0x04, 0x41, 0x00, 0xab, 0xf5,
|
||||
0x23, 0xdf, 0x28, 0x43, 0x42, 0xd9, 0xa0, 0x14, 0x2f, 0x00, 0x90, 0x02, 0x2f, 0xd2, 0x6f, 0x81, 0xb2, 0x05, 0x2f,
|
||||
0x63, 0x54, 0x06, 0x28, 0x90, 0x42, 0x85, 0x42, 0x09, 0x2c, 0x02, 0x30, 0x5b, 0x50, 0x03, 0x80, 0x29, 0x2e, 0x7e,
|
||||
0x01, 0x2b, 0x2e, 0x82, 0x01, 0x05, 0x42, 0x12, 0x30, 0x2b, 0x2e, 0x83, 0x01, 0x45, 0x82, 0x00, 0x2e, 0x40, 0x40,
|
||||
0x7a, 0x82, 0x02, 0xa0, 0x08, 0x2f, 0x63, 0x50, 0x3b, 0x30, 0x15, 0x42, 0x05, 0x42, 0x37, 0x80, 0x37, 0x2e, 0x7e,
|
||||
0x01, 0x05, 0x42, 0x12, 0x30, 0x01, 0x2e, 0xc9, 0x00, 0x02, 0x8c, 0x40, 0x40, 0x84, 0x41, 0x7a, 0x8c, 0x04, 0x0f,
|
||||
0x03, 0x2f, 0x01, 0x2e, 0x8b, 0x01, 0x19, 0xa4, 0x04, 0x2f, 0x2b, 0x2e, 0x82, 0x01, 0x98, 0x2e, 0xf3, 0x03, 0x12,
|
||||
0x30, 0x81, 0x90, 0x61, 0x52, 0x08, 0x2f, 0x65, 0x42, 0x65, 0x42, 0x43, 0x80, 0x39, 0x84, 0x82, 0x88, 0x05, 0x42,
|
||||
0x45, 0x42, 0x85, 0x42, 0x05, 0x43, 0x00, 0x2e, 0x80, 0x41, 0x00, 0x90, 0x90, 0x2e, 0xe1, 0xb4, 0x65, 0x54, 0xc1,
|
||||
0x6f, 0x80, 0x40, 0x00, 0xb2, 0x43, 0x58, 0x69, 0x50, 0x44, 0x2f, 0x55, 0x5c, 0xb7, 0x87, 0x8c, 0x0f, 0x0d, 0x2e,
|
||||
0x96, 0x01, 0xc4, 0x40, 0x36, 0x2f, 0x41, 0x56, 0x8b, 0x0e, 0x2a, 0x2f, 0x0b, 0x52, 0xa1, 0x0e, 0x0a, 0x2f, 0x05,
|
||||
0x2e, 0x8f, 0x01, 0x14, 0x25, 0x98, 0x2e, 0xfe, 0xc9, 0x4b, 0x54, 0x02, 0x0f, 0x69, 0x50, 0x05, 0x30, 0x65, 0x54,
|
||||
0x15, 0x2f, 0x03, 0x2e, 0x8e, 0x01, 0x4d, 0x5c, 0x8e, 0x0f, 0x3a, 0x2f, 0x05, 0x2e, 0x8f, 0x01, 0x98, 0x2e, 0xfe,
|
||||
0xc9, 0x4f, 0x54, 0x82, 0x0f, 0x05, 0x30, 0x69, 0x50, 0x65, 0x54, 0x30, 0x2f, 0x6d, 0x52, 0x15, 0x30, 0x42, 0x8c,
|
||||
0x45, 0x42, 0x04, 0x30, 0x2b, 0x2c, 0x84, 0x43, 0x6b, 0x52, 0x42, 0x8c, 0x00, 0x2e, 0x85, 0x43, 0x15, 0x30, 0x24,
|
||||
0x2c, 0x45, 0x42, 0x8e, 0x0f, 0x20, 0x2f, 0x0d, 0x2e, 0x8e, 0x01, 0xb1, 0x0e, 0x1c, 0x2f, 0x23, 0x2e, 0x8e, 0x01,
|
||||
0x1a, 0x2d, 0x0e, 0x0e, 0x17, 0x2f, 0xa1, 0x0f, 0x15, 0x2f, 0x23, 0x2e, 0x8d, 0x01, 0x13, 0x2d, 0x98, 0x2e, 0x74,
|
||||
0xc0, 0x43, 0x54, 0xc2, 0x0e, 0x0a, 0x2f, 0x65, 0x50, 0x04, 0x80, 0x0b, 0x30, 0x06, 0x82, 0x0b, 0x42, 0x79, 0x80,
|
||||
0x41, 0x40, 0x12, 0x30, 0x25, 0x2e, 0x8c, 0x01, 0x01, 0x42, 0x05, 0x30, 0x69, 0x50, 0x65, 0x54, 0x84, 0x82, 0x43,
|
||||
0x84, 0xbe, 0x8c, 0x84, 0x40, 0x86, 0x41, 0x26, 0x29, 0x94, 0x42, 0xbe, 0x8e, 0xd5, 0x7f, 0x19, 0xa1, 0x43, 0x40,
|
||||
0x0b, 0x2e, 0x8c, 0x01, 0x84, 0x40, 0xc7, 0x41, 0x5d, 0x29, 0x27, 0x29, 0x45, 0x42, 0x84, 0x42, 0xc2, 0x7f, 0x01,
|
||||
0x2f, 0xc0, 0xb3, 0x1d, 0x2f, 0x05, 0x2e, 0x94, 0x01, 0x99, 0xa0, 0x01, 0x2f, 0x80, 0xb3, 0x13, 0x2f, 0x80, 0xb3,
|
||||
0x18, 0x2f, 0xc0, 0xb3, 0x16, 0x2f, 0x12, 0x40, 0x01, 0x40, 0x92, 0x7f, 0x98, 0x2e, 0x74, 0xc0, 0x92, 0x6f, 0x10,
|
||||
0x0f, 0x20, 0x30, 0x03, 0x2f, 0x10, 0x30, 0x21, 0x2e, 0x7e, 0x01, 0x0a, 0x2d, 0x21, 0x2e, 0x7e, 0x01, 0x07, 0x2d,
|
||||
0x20, 0x30, 0x21, 0x2e, 0x7e, 0x01, 0x03, 0x2d, 0x10, 0x30, 0x21, 0x2e, 0x7e, 0x01, 0xc2, 0x6f, 0x01, 0x2e, 0xc9,
|
||||
0x00, 0xbc, 0x84, 0x02, 0x80, 0x82, 0x40, 0x00, 0x40, 0x90, 0x0e, 0xd5, 0x6f, 0x02, 0x2f, 0x15, 0x30, 0x98, 0x2e,
|
||||
0xf3, 0x03, 0x41, 0x91, 0x05, 0x30, 0x07, 0x2f, 0x67, 0x50, 0x3d, 0x80, 0x2b, 0x2e, 0x8f, 0x01, 0x05, 0x42, 0x04,
|
||||
0x80, 0x00, 0x2e, 0x05, 0x42, 0x02, 0x2c, 0x00, 0x30, 0x00, 0x30, 0xa2, 0x6f, 0x98, 0x8a, 0x86, 0x40, 0x80, 0xa7,
|
||||
0x05, 0x2f, 0x98, 0x2e, 0xf3, 0x03, 0xc0, 0x30, 0x21, 0x2e, 0x95, 0x01, 0x06, 0x25, 0x1a, 0x25, 0xe2, 0x6f, 0x76,
|
||||
0x82, 0x96, 0x40, 0x56, 0x43, 0x51, 0x0e, 0xfb, 0x2f, 0xbb, 0x6f, 0x30, 0x5f, 0xb8, 0x2e, 0x01, 0x2e, 0xb8, 0x00,
|
||||
0x01, 0x31, 0x41, 0x08, 0x40, 0xb2, 0x20, 0x50, 0xf2, 0x30, 0x02, 0x08, 0xfb, 0x7f, 0x01, 0x30, 0x10, 0x2f, 0x05,
|
||||
0x2e, 0xcc, 0x00, 0x81, 0x90, 0xe0, 0x7f, 0x03, 0x2f, 0x23, 0x2e, 0xcc, 0x00, 0x98, 0x2e, 0x55, 0xb6, 0x98, 0x2e,
|
||||
0x1d, 0xb5, 0x10, 0x25, 0xfb, 0x6f, 0xe0, 0x6f, 0xe0, 0x5f, 0x80, 0x2e, 0x95, 0xcf, 0x98, 0x2e, 0x95, 0xcf, 0x10,
|
||||
0x30, 0x21, 0x2e, 0xcc, 0x00, 0xfb, 0x6f, 0xe0, 0x5f, 0xb8, 0x2e, 0x00, 0x51, 0x05, 0x58, 0xeb, 0x7f, 0x2a, 0x25,
|
||||
0x89, 0x52, 0x6f, 0x5a, 0x89, 0x50, 0x13, 0x41, 0x06, 0x40, 0xb3, 0x01, 0x16, 0x42, 0xcb, 0x16, 0x06, 0x40, 0xf3,
|
||||
0x02, 0x13, 0x42, 0x65, 0x0e, 0xf5, 0x2f, 0x05, 0x40, 0x14, 0x30, 0x2c, 0x29, 0x04, 0x42, 0x08, 0xa1, 0x00, 0x30,
|
||||
0x90, 0x2e, 0x52, 0xb6, 0xb3, 0x88, 0xb0, 0x8a, 0xb6, 0x84, 0xa4, 0x7f, 0xc4, 0x7f, 0xb5, 0x7f, 0xd5, 0x7f, 0x92,
|
||||
0x7f, 0x73, 0x30, 0x04, 0x30, 0x55, 0x40, 0x42, 0x40, 0x8a, 0x17, 0xf3, 0x08, 0x6b, 0x01, 0x90, 0x02, 0x53, 0xb8,
|
||||
0x4b, 0x82, 0xad, 0xbe, 0x71, 0x7f, 0x45, 0x0a, 0x09, 0x54, 0x84, 0x7f, 0x98, 0x2e, 0xd9, 0xc0, 0xa3, 0x6f, 0x7b,
|
||||
0x54, 0xd0, 0x42, 0xa3, 0x7f, 0xf2, 0x7f, 0x60, 0x7f, 0x20, 0x25, 0x71, 0x6f, 0x75, 0x5a, 0x77, 0x58, 0x79, 0x5c,
|
||||
0x75, 0x56, 0x98, 0x2e, 0x67, 0xcc, 0xb1, 0x6f, 0x62, 0x6f, 0x50, 0x42, 0xb1, 0x7f, 0xb3, 0x30, 0x10, 0x25, 0x98,
|
||||
0x2e, 0x0f, 0xca, 0x84, 0x6f, 0x20, 0x29, 0x71, 0x6f, 0x92, 0x6f, 0xa5, 0x6f, 0x76, 0x82, 0x6a, 0x0e, 0x73, 0x30,
|
||||
0x00, 0x30, 0xd0, 0x2f, 0xd2, 0x6f, 0xd1, 0x7f, 0xb4, 0x7f, 0x98, 0x2e, 0x2b, 0xb7, 0x15, 0xbd, 0x0b, 0xb8, 0x02,
|
||||
0x0a, 0xc2, 0x6f, 0xc0, 0x7f, 0x98, 0x2e, 0x2b, 0xb7, 0x15, 0xbd, 0x0b, 0xb8, 0x42, 0x0a, 0xc0, 0x6f, 0x08, 0x17,
|
||||
0x41, 0x18, 0x89, 0x16, 0xe1, 0x18, 0xd0, 0x18, 0xa1, 0x7f, 0x27, 0x25, 0x16, 0x25, 0x98, 0x2e, 0x79, 0xc0, 0x8b,
|
||||
0x54, 0x90, 0x7f, 0xb3, 0x30, 0x82, 0x40, 0x80, 0x90, 0x0d, 0x2f, 0x7d, 0x52, 0x92, 0x6f, 0x98, 0x2e, 0x0f, 0xca,
|
||||
0xb2, 0x6f, 0x90, 0x0e, 0x06, 0x2f, 0x8b, 0x50, 0x14, 0x30, 0x42, 0x6f, 0x51, 0x6f, 0x14, 0x42, 0x12, 0x42, 0x01,
|
||||
0x42, 0x00, 0x2e, 0x31, 0x6f, 0x98, 0x2e, 0x74, 0xc0, 0x41, 0x6f, 0x80, 0x7f, 0x98, 0x2e, 0x74, 0xc0, 0x82, 0x6f,
|
||||
0x10, 0x04, 0x43, 0x52, 0x01, 0x0f, 0x05, 0x2e, 0xcb, 0x00, 0x00, 0x30, 0x04, 0x30, 0x21, 0x2f, 0x51, 0x6f, 0x43,
|
||||
0x58, 0x8c, 0x0e, 0x04, 0x30, 0x1c, 0x2f, 0x85, 0x88, 0x41, 0x6f, 0x04, 0x41, 0x8c, 0x0f, 0x04, 0x30, 0x16, 0x2f,
|
||||
0x84, 0x88, 0x00, 0x2e, 0x04, 0x41, 0x04, 0x05, 0x8c, 0x0e, 0x04, 0x30, 0x0f, 0x2f, 0x82, 0x88, 0x31, 0x6f, 0x04,
|
||||
0x41, 0x04, 0x05, 0x8c, 0x0e, 0x04, 0x30, 0x08, 0x2f, 0x83, 0x88, 0x00, 0x2e, 0x04, 0x41, 0x8c, 0x0f, 0x04, 0x30,
|
||||
0x02, 0x2f, 0x21, 0x2e, 0xad, 0x01, 0x14, 0x30, 0x00, 0x91, 0x14, 0x2f, 0x03, 0x2e, 0xa1, 0x01, 0x41, 0x90, 0x0e,
|
||||
0x2f, 0x03, 0x2e, 0xad, 0x01, 0x14, 0x30, 0x4c, 0x28, 0x23, 0x2e, 0xad, 0x01, 0x46, 0xa0, 0x06, 0x2f, 0x81, 0x84,
|
||||
0x8d, 0x52, 0x48, 0x82, 0x82, 0x40, 0x21, 0x2e, 0xa1, 0x01, 0x42, 0x42, 0x5c, 0x2c, 0x02, 0x30, 0x05, 0x2e, 0xaa,
|
||||
0x01, 0x80, 0xb2, 0x02, 0x30, 0x55, 0x2f, 0x03, 0x2e, 0xa9, 0x01, 0x92, 0x6f, 0xb3, 0x30, 0x98, 0x2e, 0x0f, 0xca,
|
||||
0xb2, 0x6f, 0x90, 0x0f, 0x00, 0x30, 0x02, 0x30, 0x4a, 0x2f, 0xa2, 0x6f, 0x87, 0x52, 0x91, 0x00, 0x85, 0x52, 0x51,
|
||||
0x0e, 0x02, 0x2f, 0x00, 0x2e, 0x43, 0x2c, 0x02, 0x30, 0xc2, 0x6f, 0x7f, 0x52, 0x91, 0x0e, 0x02, 0x30, 0x3c, 0x2f,
|
||||
0x51, 0x6f, 0x81, 0x54, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0xb3, 0x30, 0x21, 0x25, 0x98, 0x2e, 0x0f, 0xca, 0x32,
|
||||
0x6f, 0xc0, 0x7f, 0xb3, 0x30, 0x12, 0x25, 0x98, 0x2e, 0x0f, 0xca, 0x42, 0x6f, 0xb0, 0x7f, 0xb3, 0x30, 0x12, 0x25,
|
||||
0x98, 0x2e, 0x0f, 0xca, 0xb2, 0x6f, 0x90, 0x28, 0x83, 0x52, 0x98, 0x2e, 0xfe, 0xc9, 0xc2, 0x6f, 0x90, 0x0f, 0x00,
|
||||
0x30, 0x02, 0x30, 0x1d, 0x2f, 0x05, 0x2e, 0xa1, 0x01, 0x80, 0xb2, 0x12, 0x30, 0x0f, 0x2f, 0x42, 0x6f, 0x03, 0x2e,
|
||||
0xab, 0x01, 0x91, 0x0e, 0x02, 0x30, 0x12, 0x2f, 0x52, 0x6f, 0x03, 0x2e, 0xac, 0x01, 0x91, 0x0f, 0x02, 0x30, 0x0c,
|
||||
0x2f, 0x21, 0x2e, 0xaa, 0x01, 0x0a, 0x2c, 0x12, 0x30, 0x03, 0x2e, 0xcb, 0x00, 0x8d, 0x58, 0x08, 0x89, 0x41, 0x40,
|
||||
0x11, 0x43, 0x00, 0x43, 0x25, 0x2e, 0xa1, 0x01, 0xd4, 0x6f, 0x8f, 0x52, 0x00, 0x43, 0x3a, 0x89, 0x00, 0x2e, 0x10,
|
||||
0x43, 0x10, 0x43, 0x61, 0x0e, 0xfb, 0x2f, 0x03, 0x2e, 0xa0, 0x01, 0x11, 0x1a, 0x02, 0x2f, 0x02, 0x25, 0x21, 0x2e,
|
||||
0xa0, 0x01, 0xeb, 0x6f, 0x00, 0x5f, 0xb8, 0x2e, 0x91, 0x52, 0x10, 0x30, 0x02, 0x30, 0x95, 0x56, 0x52, 0x42, 0x4b,
|
||||
0x0e, 0xfc, 0x2f, 0x8d, 0x54, 0x88, 0x82, 0x93, 0x56, 0x80, 0x42, 0x53, 0x42, 0x40, 0x42, 0x42, 0x86, 0x83, 0x54,
|
||||
0xc0, 0x2e, 0xc2, 0x42, 0x00, 0x2e, 0xa3, 0x52, 0x00, 0x51, 0x52, 0x40, 0x47, 0x40, 0x1a, 0x25, 0x01, 0x2e, 0x97,
|
||||
0x00, 0x8f, 0xbe, 0x72, 0x86, 0xfb, 0x7f, 0x0b, 0x30, 0x7c, 0xbf, 0xa5, 0x50, 0x10, 0x08, 0xdf, 0xba, 0x70, 0x88,
|
||||
0xf8, 0xbf, 0xcb, 0x42, 0xd3, 0x7f, 0x6c, 0xbb, 0xfc, 0xbb, 0xc5, 0x0a, 0x90, 0x7f, 0x1b, 0x7f, 0x0b, 0x43, 0xc0,
|
||||
0xb2, 0xe5, 0x7f, 0xb7, 0x7f, 0xa6, 0x7f, 0xc4, 0x7f, 0x90, 0x2e, 0x1c, 0xb7, 0x07, 0x2e, 0xd2, 0x00, 0xc0, 0xb2,
|
||||
0x0b, 0x2f, 0x97, 0x52, 0x01, 0x2e, 0xcd, 0x00, 0x82, 0x7f, 0x98, 0x2e, 0xbb, 0xcc, 0x0b, 0x30, 0x37, 0x2e, 0xd2,
|
||||
0x00, 0x82, 0x6f, 0x90, 0x6f, 0x1a, 0x25, 0x00, 0xb2, 0x8b, 0x7f, 0x14, 0x2f, 0xa6, 0xbd, 0x25, 0xbd, 0xb6, 0xb9,
|
||||
0x2f, 0xb9, 0x80, 0xb2, 0xd4, 0xb0, 0x0c, 0x2f, 0x99, 0x54, 0x9b, 0x56, 0x0b, 0x30, 0x0b, 0x2e, 0xb1, 0x00, 0xa1,
|
||||
0x58, 0x9b, 0x42, 0xdb, 0x42, 0x6c, 0x09, 0x2b, 0x2e, 0xb1, 0x00, 0x8b, 0x42, 0xcb, 0x42, 0x86, 0x7f, 0x73, 0x84,
|
||||
0xa7, 0x56, 0xc3, 0x08, 0x39, 0x52, 0x05, 0x50, 0x72, 0x7f, 0x63, 0x7f, 0x98, 0x2e, 0xc2, 0xc0, 0xe1, 0x6f, 0x62,
|
||||
0x6f, 0xd1, 0x0a, 0x01, 0x2e, 0xcd, 0x00, 0xd5, 0x6f, 0xc4, 0x6f, 0x72, 0x6f, 0x97, 0x52, 0x9d, 0x5c, 0x98, 0x2e,
|
||||
0x06, 0xcd, 0x23, 0x6f, 0x90, 0x6f, 0x99, 0x52, 0xc0, 0xb2, 0x04, 0xbd, 0x54, 0x40, 0xaf, 0xb9, 0x45, 0x40, 0xe1,
|
||||
0x7f, 0x02, 0x30, 0x06, 0x2f, 0xc0, 0xb2, 0x02, 0x30, 0x03, 0x2f, 0x9b, 0x5c, 0x12, 0x30, 0x94, 0x43, 0x85, 0x43,
|
||||
0x03, 0xbf, 0x6f, 0xbb, 0x80, 0xb3, 0x20, 0x2f, 0x06, 0x6f, 0x26, 0x01, 0x16, 0x6f, 0x6e, 0x03, 0x45, 0x42, 0xc0,
|
||||
0x90, 0x29, 0x2e, 0xce, 0x00, 0x9b, 0x52, 0x14, 0x2f, 0x9b, 0x5c, 0x00, 0x2e, 0x93, 0x41, 0x86, 0x41, 0xe3, 0x04,
|
||||
0xae, 0x07, 0x80, 0xab, 0x04, 0x2f, 0x80, 0x91, 0x0a, 0x2f, 0x86, 0x6f, 0x73, 0x0f, 0x07, 0x2f, 0x83, 0x6f, 0xc0,
|
||||
0xb2, 0x04, 0x2f, 0x54, 0x42, 0x45, 0x42, 0x12, 0x30, 0x04, 0x2c, 0x11, 0x30, 0x02, 0x2c, 0x11, 0x30, 0x11, 0x30,
|
||||
0x02, 0xbc, 0x0f, 0xb8, 0xd2, 0x7f, 0x00, 0xb2, 0x0a, 0x2f, 0x01, 0x2e, 0xfc, 0x00, 0x05, 0x2e, 0xc7, 0x01, 0x10,
|
||||
0x1a, 0x02, 0x2f, 0x21, 0x2e, 0xc7, 0x01, 0x03, 0x2d, 0x02, 0x2c, 0x01, 0x30, 0x01, 0x30, 0xb0, 0x6f, 0x98, 0x2e,
|
||||
0x95, 0xcf, 0xd1, 0x6f, 0xa0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0xe2, 0x6f, 0x9f, 0x52, 0x01, 0x2e, 0xce, 0x00, 0x82,
|
||||
0x40, 0x50, 0x42, 0x0c, 0x2c, 0x42, 0x42, 0x11, 0x30, 0x23, 0x2e, 0xd2, 0x00, 0x01, 0x30, 0xb0, 0x6f, 0x98, 0x2e,
|
||||
0x95, 0xcf, 0xa0, 0x6f, 0x01, 0x30, 0x98, 0x2e, 0x95, 0xcf, 0x00, 0x2e, 0xfb, 0x6f, 0x00, 0x5f, 0xb8, 0x2e, 0x83,
|
||||
0x86, 0x01, 0x30, 0x00, 0x30, 0x94, 0x40, 0x24, 0x18, 0x06, 0x00, 0x53, 0x0e, 0x4f, 0x02, 0xf9, 0x2f, 0xb8, 0x2e,
|
||||
0xa9, 0x52, 0x00, 0x2e, 0x60, 0x40, 0x41, 0x40, 0x0d, 0xbc, 0x98, 0xbc, 0xc0, 0x2e, 0x01, 0x0a, 0x0f, 0xb8, 0xab,
|
||||
0x52, 0x53, 0x3c, 0x52, 0x40, 0x40, 0x40, 0x4b, 0x00, 0x82, 0x16, 0x26, 0xb9, 0x01, 0xb8, 0x41, 0x40, 0x10, 0x08,
|
||||
0x97, 0xb8, 0x01, 0x08, 0xc0, 0x2e, 0x11, 0x30, 0x01, 0x08, 0x43, 0x86, 0x25, 0x40, 0x04, 0x40, 0xd8, 0xbe, 0x2c,
|
||||
0x0b, 0x22, 0x11, 0x54, 0x42, 0x03, 0x80, 0x4b, 0x0e, 0xf6, 0x2f, 0xb8, 0x2e, 0x9f, 0x50, 0x10, 0x50, 0xad, 0x52,
|
||||
0x05, 0x2e, 0xd3, 0x00, 0xfb, 0x7f, 0x00, 0x2e, 0x13, 0x40, 0x93, 0x42, 0x41, 0x0e, 0xfb, 0x2f, 0x98, 0x2e, 0xa5,
|
||||
0xb7, 0x98, 0x2e, 0x87, 0xcf, 0x01, 0x2e, 0xd9, 0x00, 0x00, 0xb2, 0xfb, 0x6f, 0x0b, 0x2f, 0x01, 0x2e, 0x69, 0xf7,
|
||||
0xb1, 0x3f, 0x01, 0x08, 0x01, 0x30, 0xf0, 0x5f, 0x23, 0x2e, 0xd9, 0x00, 0x21, 0x2e, 0x69, 0xf7, 0x80, 0x2e, 0x7a,
|
||||
0xb7, 0xf0, 0x5f, 0xb8, 0x2e, 0x01, 0x2e, 0xc0, 0xf8, 0x03, 0x2e, 0xfc, 0xf5, 0x15, 0x54, 0xaf, 0x56, 0x82, 0x08,
|
||||
0x0b, 0x2e, 0x69, 0xf7, 0xcb, 0x0a, 0xb1, 0x58, 0x80, 0x90, 0xdd, 0xbe, 0x4c, 0x08, 0x5f, 0xb9, 0x59, 0x22, 0x80,
|
||||
0x90, 0x07, 0x2f, 0x03, 0x34, 0xc3, 0x08, 0xf2, 0x3a, 0x0a, 0x08, 0x02, 0x35, 0xc0, 0x90, 0x4a, 0x0a, 0x48, 0x22,
|
||||
0xc0, 0x2e, 0x23, 0x2e, 0xfc, 0xf5, 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x56, 0xc7, 0x98, 0x2e, 0x49, 0xc3, 0x10,
|
||||
0x30, 0xfb, 0x6f, 0xf0, 0x5f, 0x21, 0x2e, 0xcc, 0x00, 0x21, 0x2e, 0xca, 0x00, 0xb8, 0x2e, 0x03, 0x2e, 0xd3, 0x00,
|
||||
0x16, 0xb8, 0x02, 0x34, 0x4a, 0x0c, 0x21, 0x2e, 0x2d, 0xf5, 0xc0, 0x2e, 0x23, 0x2e, 0xd3, 0x00, 0x03, 0xbc, 0x21,
|
||||
0x2e, 0xd5, 0x00, 0x03, 0x2e, 0xd5, 0x00, 0x40, 0xb2, 0x10, 0x30, 0x21, 0x2e, 0x77, 0x00, 0x01, 0x30, 0x05, 0x2f,
|
||||
0x05, 0x2e, 0xd8, 0x00, 0x80, 0x90, 0x01, 0x2f, 0x23, 0x2e, 0x6f, 0xf5, 0xc0, 0x2e, 0x21, 0x2e, 0xd9, 0x00, 0x11,
|
||||
0x30, 0x81, 0x08, 0x01, 0x2e, 0x6a, 0xf7, 0x71, 0x3f, 0x23, 0xbd, 0x01, 0x08, 0x02, 0x0a, 0xc0, 0x2e, 0x21, 0x2e,
|
||||
0x6a, 0xf7, 0x30, 0x25, 0x00, 0x30, 0x21, 0x2e, 0x5a, 0xf5, 0x10, 0x50, 0x21, 0x2e, 0x7b, 0x00, 0x21, 0x2e, 0x7c,
|
||||
0x00, 0xfb, 0x7f, 0x98, 0x2e, 0xc3, 0xb7, 0x40, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0xfb, 0x6f, 0xf0, 0x5f, 0x03, 0x25,
|
||||
0x80, 0x2e, 0xaf, 0xb7, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x01, 0x2e, 0x5d, 0xf7, 0x08, 0xbc, 0x80, 0xac, 0x0e, 0xbb, 0x02, 0x2f,
|
||||
0x00, 0x30, 0x41, 0x04, 0x82, 0x06, 0xc0, 0xa4, 0x00, 0x30, 0x11, 0x2f, 0x40, 0xa9, 0x03, 0x2f, 0x40, 0x91, 0x0d,
|
||||
0x2f, 0x00, 0xa7, 0x0b, 0x2f, 0x80, 0xb3, 0xb3, 0x58, 0x02, 0x2f, 0x90, 0xa1, 0x26, 0x13, 0x20, 0x23, 0x80, 0x90,
|
||||
0x10, 0x30, 0x01, 0x2f, 0xcc, 0x0e, 0x00, 0x2f, 0x00, 0x30, 0xb8, 0x2e, 0xb5, 0x50, 0x18, 0x08, 0x08, 0xbc, 0x88,
|
||||
0xb6, 0x0d, 0x17, 0xc6, 0xbd, 0x56, 0xbc, 0xb7, 0x58, 0xda, 0xba, 0x04, 0x01, 0x1d, 0x0a, 0x10, 0x50, 0x05, 0x30,
|
||||
0x32, 0x25, 0x45, 0x03, 0xfb, 0x7f, 0xf6, 0x30, 0x21, 0x25, 0x98, 0x2e, 0x37, 0xca, 0x16, 0xb5, 0x9a, 0xbc, 0x06,
|
||||
0xb8, 0x80, 0xa8, 0x41, 0x0a, 0x0e, 0x2f, 0x80, 0x90, 0x02, 0x2f, 0x2d, 0x50, 0x48, 0x0f, 0x09, 0x2f, 0xbf, 0xa0,
|
||||
0x04, 0x2f, 0xbf, 0x90, 0x06, 0x2f, 0xb7, 0x54, 0xca, 0x0f, 0x03, 0x2f, 0x00, 0x2e, 0x02, 0x2c, 0xb7, 0x52, 0x2d,
|
||||
0x52, 0xf2, 0x33, 0x98, 0x2e, 0xd9, 0xc0, 0xfb, 0x6f, 0xf1, 0x37, 0xc0, 0x2e, 0x01, 0x08, 0xf0, 0x5f, 0xbf, 0x56,
|
||||
0xb9, 0x54, 0xd0, 0x40, 0xc4, 0x40, 0x0b, 0x2e, 0xfd, 0xf3, 0xbf, 0x52, 0x90, 0x42, 0x94, 0x42, 0x95, 0x42, 0x05,
|
||||
0x30, 0xc1, 0x50, 0x0f, 0x88, 0x06, 0x40, 0x04, 0x41, 0x96, 0x42, 0xc5, 0x42, 0x48, 0xbe, 0x73, 0x30, 0x0d, 0x2e,
|
||||
0xd8, 0x00, 0x4f, 0xba, 0x84, 0x42, 0x03, 0x42, 0x81, 0xb3, 0x02, 0x2f, 0x2b, 0x2e, 0x6f, 0xf5, 0x06, 0x2d, 0x05,
|
||||
0x2e, 0x77, 0xf7, 0xbd, 0x56, 0x93, 0x08, 0x25, 0x2e, 0x77, 0xf7, 0xbb, 0x54, 0x25, 0x2e, 0xc2, 0xf5, 0x07, 0x2e,
|
||||
0xfd, 0xf3, 0x42, 0x30, 0xb4, 0x33, 0xda, 0x0a, 0x4c, 0x00, 0x27, 0x2e, 0xfd, 0xf3, 0x43, 0x40, 0xd4, 0x3f, 0xdc,
|
||||
0x08, 0x43, 0x42, 0x00, 0x2e, 0x00, 0x2e, 0x43, 0x40, 0x24, 0x30, 0xdc, 0x0a, 0x43, 0x42, 0x04, 0x80, 0x03, 0x2e,
|
||||
0xfd, 0xf3, 0x4a, 0x0a, 0x23, 0x2e, 0xfd, 0xf3, 0x61, 0x34, 0xc0, 0x2e, 0x01, 0x42, 0x00, 0x2e, 0x60, 0x50, 0x1a,
|
||||
0x25, 0x7a, 0x86, 0xe0, 0x7f, 0xf3, 0x7f, 0x03, 0x25, 0xc3, 0x52, 0x41, 0x84, 0xdb, 0x7f, 0x33, 0x30, 0x98, 0x2e,
|
||||
0x16, 0xc2, 0x1a, 0x25, 0x7d, 0x82, 0xf0, 0x6f, 0xe2, 0x6f, 0x32, 0x25, 0x16, 0x40, 0x94, 0x40, 0x26, 0x01, 0x85,
|
||||
0x40, 0x8e, 0x17, 0xc4, 0x42, 0x6e, 0x03, 0x95, 0x42, 0x41, 0x0e, 0xf4, 0x2f, 0xdb, 0x6f, 0xa0, 0x5f, 0xb8, 0x2e,
|
||||
0xb0, 0x51, 0xfb, 0x7f, 0x98, 0x2e, 0xe8, 0x0d, 0x5a, 0x25, 0x98, 0x2e, 0x0f, 0x0e, 0xcb, 0x58, 0x32, 0x87, 0xc4,
|
||||
0x7f, 0x65, 0x89, 0x6b, 0x8d, 0xc5, 0x5a, 0x65, 0x7f, 0xe1, 0x7f, 0x83, 0x7f, 0xa6, 0x7f, 0x74, 0x7f, 0xd0, 0x7f,
|
||||
0xb6, 0x7f, 0x94, 0x7f, 0x17, 0x30, 0xc7, 0x52, 0xc9, 0x54, 0x51, 0x7f, 0x00, 0x2e, 0x85, 0x6f, 0x42, 0x7f, 0x00,
|
||||
0x2e, 0x51, 0x41, 0x45, 0x81, 0x42, 0x41, 0x13, 0x40, 0x3b, 0x8a, 0x00, 0x40, 0x4b, 0x04, 0xd0, 0x06, 0xc0, 0xac,
|
||||
0x85, 0x7f, 0x02, 0x2f, 0x02, 0x30, 0x51, 0x04, 0xd3, 0x06, 0x41, 0x84, 0x05, 0x30, 0x5d, 0x02, 0xc9, 0x16, 0xdf,
|
||||
0x08, 0xd3, 0x00, 0x8d, 0x02, 0xaf, 0xbc, 0xb1, 0xb9, 0x59, 0x0a, 0x65, 0x6f, 0x11, 0x43, 0xa1, 0xb4, 0x52, 0x41,
|
||||
0x53, 0x41, 0x01, 0x43, 0x34, 0x7f, 0x65, 0x7f, 0x26, 0x31, 0xe5, 0x6f, 0xd4, 0x6f, 0x98, 0x2e, 0x37, 0xca, 0x32,
|
||||
0x6f, 0x75, 0x6f, 0x83, 0x40, 0x42, 0x41, 0x23, 0x7f, 0x12, 0x7f, 0xf6, 0x30, 0x40, 0x25, 0x51, 0x25, 0x98, 0x2e,
|
||||
0x37, 0xca, 0x14, 0x6f, 0x20, 0x05, 0x70, 0x6f, 0x25, 0x6f, 0x69, 0x07, 0xa2, 0x6f, 0x31, 0x6f, 0x0b, 0x30, 0x04,
|
||||
0x42, 0x9b, 0x42, 0x8b, 0x42, 0x55, 0x42, 0x32, 0x7f, 0x40, 0xa9, 0xc3, 0x6f, 0x71, 0x7f, 0x02, 0x30, 0xd0, 0x40,
|
||||
0xc3, 0x7f, 0x03, 0x2f, 0x40, 0x91, 0x15, 0x2f, 0x00, 0xa7, 0x13, 0x2f, 0x00, 0xa4, 0x11, 0x2f, 0x84, 0xbd, 0x98,
|
||||
0x2e, 0x79, 0xca, 0x55, 0x6f, 0xb7, 0x54, 0x54, 0x41, 0x82, 0x00, 0xf3, 0x3f, 0x45, 0x41, 0xcb, 0x02, 0xf6, 0x30,
|
||||
0x98, 0x2e, 0x37, 0xca, 0x35, 0x6f, 0xa4, 0x6f, 0x41, 0x43, 0x03, 0x2c, 0x00, 0x43, 0xa4, 0x6f, 0x35, 0x6f, 0x17,
|
||||
0x30, 0x42, 0x6f, 0x51, 0x6f, 0x93, 0x40, 0x42, 0x82, 0x00, 0x41, 0xc3, 0x00, 0x03, 0x43, 0x51, 0x7f, 0x00, 0x2e,
|
||||
0x94, 0x40, 0x41, 0x41, 0x4c, 0x02, 0xc4, 0x6f, 0xd1, 0x56, 0x63, 0x0e, 0x74, 0x6f, 0x51, 0x43, 0xa5, 0x7f, 0x8a,
|
||||
0x2f, 0x09, 0x2e, 0xd8, 0x00, 0x01, 0xb3, 0x21, 0x2f, 0xcb, 0x58, 0x90, 0x6f, 0x13, 0x41, 0xb6, 0x6f, 0xe4, 0x7f,
|
||||
0x00, 0x2e, 0x91, 0x41, 0x14, 0x40, 0x92, 0x41, 0x15, 0x40, 0x17, 0x2e, 0x6f, 0xf5, 0xb6, 0x7f, 0xd0, 0x7f, 0xcb,
|
||||
0x7f, 0x98, 0x2e, 0x00, 0x0c, 0x07, 0x15, 0xc2, 0x6f, 0x14, 0x0b, 0x29, 0x2e, 0x6f, 0xf5, 0xc3, 0xa3, 0xc1, 0x8f,
|
||||
0xe4, 0x6f, 0xd0, 0x6f, 0xe6, 0x2f, 0x14, 0x30, 0x05, 0x2e, 0x6f, 0xf5, 0x14, 0x0b, 0x29, 0x2e, 0x6f, 0xf5, 0x18,
|
||||
0x2d, 0xcd, 0x56, 0x04, 0x32, 0xb5, 0x6f, 0x1c, 0x01, 0x51, 0x41, 0x52, 0x41, 0xc3, 0x40, 0xb5, 0x7f, 0xe4, 0x7f,
|
||||
0x98, 0x2e, 0x1f, 0x0c, 0xe4, 0x6f, 0x21, 0x87, 0x00, 0x43, 0x04, 0x32, 0xcf, 0x54, 0x5a, 0x0e, 0xef, 0x2f, 0x15,
|
||||
0x54, 0x09, 0x2e, 0x77, 0xf7, 0x22, 0x0b, 0x29, 0x2e, 0x77, 0xf7, 0xfb, 0x6f, 0x50, 0x5e, 0xb8, 0x2e, 0x10, 0x50,
|
||||
0x01, 0x2e, 0xd4, 0x00, 0x00, 0xb2, 0xfb, 0x7f, 0x51, 0x2f, 0x01, 0xb2, 0x48, 0x2f, 0x02, 0xb2, 0x42, 0x2f, 0x03,
|
||||
0x90, 0x56, 0x2f, 0xd7, 0x52, 0x79, 0x80, 0x42, 0x40, 0x81, 0x84, 0x00, 0x40, 0x42, 0x42, 0x98, 0x2e, 0x93, 0x0c,
|
||||
0xd9, 0x54, 0xd7, 0x50, 0xa1, 0x40, 0x98, 0xbd, 0x82, 0x40, 0x3e, 0x82, 0xda, 0x0a, 0x44, 0x40, 0x8b, 0x16, 0xe3,
|
||||
0x00, 0x53, 0x42, 0x00, 0x2e, 0x43, 0x40, 0x9a, 0x02, 0x52, 0x42, 0x00, 0x2e, 0x41, 0x40, 0x15, 0x54, 0x4a, 0x0e,
|
||||
0x3a, 0x2f, 0x3a, 0x82, 0x00, 0x30, 0x41, 0x40, 0x21, 0x2e, 0x85, 0x0f, 0x40, 0xb2, 0x0a, 0x2f, 0x98, 0x2e, 0xb1,
|
||||
0x0c, 0x98, 0x2e, 0x45, 0x0e, 0x98, 0x2e, 0x5b, 0x0e, 0xfb, 0x6f, 0xf0, 0x5f, 0x00, 0x30, 0x80, 0x2e, 0xce, 0xb7,
|
||||
0xdd, 0x52, 0xd3, 0x54, 0x42, 0x42, 0x4f, 0x84, 0x73, 0x30, 0xdb, 0x52, 0x83, 0x42, 0x1b, 0x30, 0x6b, 0x42, 0x23,
|
||||
0x30, 0x27, 0x2e, 0xd7, 0x00, 0x37, 0x2e, 0xd4, 0x00, 0x21, 0x2e, 0xd6, 0x00, 0x7a, 0x84, 0x17, 0x2c, 0x42, 0x42,
|
||||
0x30, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0x12, 0x2d, 0x21, 0x30, 0x00, 0x30, 0x23, 0x2e, 0xd4, 0x00, 0x21, 0x2e, 0x7b,
|
||||
0xf7, 0x0b, 0x2d, 0x17, 0x30, 0x98, 0x2e, 0x51, 0x0c, 0xd5, 0x50, 0x0c, 0x82, 0x72, 0x30, 0x2f, 0x2e, 0xd4, 0x00,
|
||||
0x25, 0x2e, 0x7b, 0xf7, 0x40, 0x42, 0x00, 0x2e, 0xfb, 0x6f, 0xf0, 0x5f, 0xb8, 0x2e, 0x70, 0x50, 0x0a, 0x25, 0x39,
|
||||
0x86, 0xfb, 0x7f, 0xe1, 0x32, 0x62, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0xb5, 0x56, 0xa5, 0x6f, 0xab, 0x08, 0x91, 0x6f,
|
||||
0x4b, 0x08, 0xdf, 0x56, 0xc4, 0x6f, 0x23, 0x09, 0x4d, 0xba, 0x93, 0xbc, 0x8c, 0x0b, 0xd1, 0x6f, 0x0b, 0x09, 0xcb,
|
||||
0x52, 0xe1, 0x5e, 0x56, 0x42, 0xaf, 0x09, 0x4d, 0xba, 0x23, 0xbd, 0x94, 0x0a, 0xe5, 0x6f, 0x68, 0xbb, 0xeb, 0x08,
|
||||
0xbd, 0xb9, 0x63, 0xbe, 0xfb, 0x6f, 0x52, 0x42, 0xe3, 0x0a, 0xc0, 0x2e, 0x43, 0x42, 0x90, 0x5f, 0xd1, 0x50, 0x03,
|
||||
0x2e, 0x25, 0xf3, 0x13, 0x40, 0x00, 0x40, 0x9b, 0xbc, 0x9b, 0xb4, 0x08, 0xbd, 0xb8, 0xb9, 0x98, 0xbc, 0xda, 0x0a,
|
||||
0x08, 0xb6, 0x89, 0x16, 0xc0, 0x2e, 0x19, 0x00, 0x62, 0x02, 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x81, 0x0d, 0x01,
|
||||
0x2e, 0xd4, 0x00, 0x31, 0x30, 0x08, 0x04, 0xfb, 0x6f, 0x01, 0x30, 0xf0, 0x5f, 0x23, 0x2e, 0xd6, 0x00, 0x21, 0x2e,
|
||||
0xd7, 0x00, 0xb8, 0x2e, 0x01, 0x2e, 0xd7, 0x00, 0x03, 0x2e, 0xd6, 0x00, 0x48, 0x0e, 0x01, 0x2f, 0x80, 0x2e, 0x1f,
|
||||
0x0e, 0xb8, 0x2e, 0xe3, 0x50, 0x21, 0x34, 0x01, 0x42, 0x82, 0x30, 0xc1, 0x32, 0x25, 0x2e, 0x62, 0xf5, 0x01, 0x00,
|
||||
0x22, 0x30, 0x01, 0x40, 0x4a, 0x0a, 0x01, 0x42, 0xb8, 0x2e, 0xe3, 0x54, 0xf0, 0x3b, 0x83, 0x40, 0xd8, 0x08, 0xe5,
|
||||
0x52, 0x83, 0x42, 0x00, 0x30, 0x83, 0x30, 0x50, 0x42, 0xc4, 0x32, 0x27, 0x2e, 0x64, 0xf5, 0x94, 0x00, 0x50, 0x42,
|
||||
0x40, 0x42, 0xd3, 0x3f, 0x84, 0x40, 0x7d, 0x82, 0xe3, 0x08, 0x40, 0x42, 0x83, 0x42, 0xb8, 0x2e, 0xdd, 0x52, 0x00,
|
||||
0x30, 0x40, 0x42, 0x7c, 0x86, 0xb9, 0x52, 0x09, 0x2e, 0x70, 0x0f, 0xbf, 0x54, 0xc4, 0x42, 0xd3, 0x86, 0x54, 0x40,
|
||||
0x55, 0x40, 0x94, 0x42, 0x85, 0x42, 0x21, 0x2e, 0xd7, 0x00, 0x42, 0x40, 0x25, 0x2e, 0xfd, 0xf3, 0xc0, 0x42, 0x7e,
|
||||
0x82, 0x05, 0x2e, 0x7d, 0x00, 0x80, 0xb2, 0x14, 0x2f, 0x05, 0x2e, 0x89, 0x00, 0x27, 0xbd, 0x2f, 0xb9, 0x80, 0x90,
|
||||
0x02, 0x2f, 0x21, 0x2e, 0x6f, 0xf5, 0x0c, 0x2d, 0x07, 0x2e, 0x71, 0x0f, 0x14, 0x30, 0x1c, 0x09, 0x05, 0x2e, 0x77,
|
||||
0xf7, 0xbd, 0x56, 0x47, 0xbe, 0x93, 0x08, 0x94, 0x0a, 0x25, 0x2e, 0x77, 0xf7, 0xe7, 0x54, 0x50, 0x42, 0x4a, 0x0e,
|
||||
0xfc, 0x2f, 0xb8, 0x2e, 0x50, 0x50, 0x02, 0x30, 0x43, 0x86, 0xe5, 0x50, 0xfb, 0x7f, 0xe3, 0x7f, 0xd2, 0x7f, 0xc0,
|
||||
0x7f, 0xb1, 0x7f, 0x00, 0x2e, 0x41, 0x40, 0x00, 0x40, 0x48, 0x04, 0x98, 0x2e, 0x74, 0xc0, 0x1e, 0xaa, 0xd3, 0x6f,
|
||||
0x14, 0x30, 0xb1, 0x6f, 0xe3, 0x22, 0xc0, 0x6f, 0x52, 0x40, 0xe4, 0x6f, 0x4c, 0x0e, 0x12, 0x42, 0xd3, 0x7f, 0xeb,
|
||||
0x2f, 0x03, 0x2e, 0x86, 0x0f, 0x40, 0x90, 0x11, 0x30, 0x03, 0x2f, 0x23, 0x2e, 0x86, 0x0f, 0x02, 0x2c, 0x00, 0x30,
|
||||
0xd0, 0x6f, 0xfb, 0x6f, 0xb0, 0x5f, 0xb8, 0x2e, 0x40, 0x50, 0xf1, 0x7f, 0x0a, 0x25, 0x3c, 0x86, 0xeb, 0x7f, 0x41,
|
||||
0x33, 0x22, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0xd3, 0x6f, 0xf4, 0x30, 0xdc, 0x09, 0x47, 0x58, 0xc2, 0x6f, 0x94, 0x09,
|
||||
0xeb, 0x58, 0x6a, 0xbb, 0xdc, 0x08, 0xb4, 0xb9, 0xb1, 0xbd, 0xe9, 0x5a, 0x95, 0x08, 0x21, 0xbd, 0xf6, 0xbf, 0x77,
|
||||
0x0b, 0x51, 0xbe, 0xf1, 0x6f, 0xeb, 0x6f, 0x52, 0x42, 0x54, 0x42, 0xc0, 0x2e, 0x43, 0x42, 0xc0, 0x5f, 0x50, 0x50,
|
||||
0xf5, 0x50, 0x31, 0x30, 0x11, 0x42, 0xfb, 0x7f, 0x7b, 0x30, 0x0b, 0x42, 0x11, 0x30, 0x02, 0x80, 0x23, 0x33, 0x01,
|
||||
0x42, 0x03, 0x00, 0x07, 0x2e, 0x80, 0x03, 0x05, 0x2e, 0xd3, 0x00, 0x23, 0x52, 0xe2, 0x7f, 0xd3, 0x7f, 0xc0, 0x7f,
|
||||
0x98, 0x2e, 0xb6, 0x0e, 0xd1, 0x6f, 0x08, 0x0a, 0x1a, 0x25, 0x7b, 0x86, 0xd0, 0x7f, 0x01, 0x33, 0x12, 0x30, 0x98,
|
||||
0x2e, 0xc2, 0xc4, 0xd1, 0x6f, 0x08, 0x0a, 0x00, 0xb2, 0x0d, 0x2f, 0xe3, 0x6f, 0x01, 0x2e, 0x80, 0x03, 0x51, 0x30,
|
||||
0xc7, 0x86, 0x23, 0x2e, 0x21, 0xf2, 0x08, 0xbc, 0xc0, 0x42, 0x98, 0x2e, 0xa5, 0xb7, 0x00, 0x2e, 0x00, 0x2e, 0xd0,
|
||||
0x2e, 0xb0, 0x6f, 0x0b, 0xb8, 0x03, 0x2e, 0x1b, 0x00, 0x08, 0x1a, 0xb0, 0x7f, 0x70, 0x30, 0x04, 0x2f, 0x21, 0x2e,
|
||||
0x21, 0xf2, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x98, 0x2e, 0x6d, 0xc0, 0x98, 0x2e, 0x5d, 0xc0, 0xed, 0x50, 0x98,
|
||||
0x2e, 0x44, 0xcb, 0xef, 0x50, 0x98, 0x2e, 0x46, 0xc3, 0xf1, 0x50, 0x98, 0x2e, 0x53, 0xc7, 0x35, 0x50, 0x98, 0x2e,
|
||||
0x64, 0xcf, 0x10, 0x30, 0x98, 0x2e, 0xdc, 0x03, 0x20, 0x26, 0xc0, 0x6f, 0x02, 0x31, 0x12, 0x42, 0xab, 0x33, 0x0b,
|
||||
0x42, 0x37, 0x80, 0x01, 0x30, 0x01, 0x42, 0xf3, 0x37, 0xf7, 0x52, 0xfb, 0x50, 0x44, 0x40, 0xa2, 0x0a, 0x42, 0x42,
|
||||
0x8b, 0x31, 0x09, 0x2e, 0x5e, 0xf7, 0xf9, 0x54, 0xe3, 0x08, 0x83, 0x42, 0x1b, 0x42, 0x23, 0x33, 0x4b, 0x00, 0xbc,
|
||||
0x84, 0x0b, 0x40, 0x33, 0x30, 0x83, 0x42, 0x0b, 0x42, 0xe0, 0x7f, 0xd1, 0x7f, 0x98, 0x2e, 0x58, 0xb7, 0xd1, 0x6f,
|
||||
0x80, 0x30, 0x40, 0x42, 0x03, 0x30, 0xe0, 0x6f, 0xf3, 0x54, 0x04, 0x30, 0x00, 0x2e, 0x00, 0x2e, 0x01, 0x89, 0x62,
|
||||
0x0e, 0xfa, 0x2f, 0x43, 0x42, 0x11, 0x30, 0xfb, 0x6f, 0xc0, 0x2e, 0x01, 0x42, 0xb0, 0x5f, 0xc1, 0x4a, 0x00, 0x00,
|
||||
0x6d, 0x57, 0x00, 0x00, 0x77, 0x8e, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xd3, 0xff, 0xff, 0xff, 0xe5, 0xff, 0xff,
|
||||
0xff, 0xee, 0xe1, 0xff, 0xff, 0x7c, 0x13, 0x00, 0x00, 0x46, 0xe6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||
0x2e, 0x00, 0xc1
|
||||
};
|
||||
86
libraries/M5Unified/src/utility/imu/BMM150_Class.cpp
Normal file
86
libraries/M5Unified/src/utility/imu/BMM150_Class.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if defined (ESP_PLATFORM)
|
||||
|
||||
#include "BMM150_Class.hpp"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
BMM150_Class::~BMM150_Class() {}
|
||||
BMM150_Class::BMM150_Class(std::uint8_t i2c_addr, std::uint32_t freq, I2C_Class* i2c)
|
||||
: IMU_Base ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
|
||||
IMU_Base::imu_spec_t BMM150_Class::begin(I2C_Class* i2c)
|
||||
{
|
||||
if (i2c)
|
||||
{
|
||||
_i2c = i2c;
|
||||
}
|
||||
|
||||
writeRegister8(0x4B, 0x83); // software reset + power on
|
||||
|
||||
WhoAmI();
|
||||
// printf("BMM150 : %02x\n", WhoAmI());
|
||||
if (WhoAmI() != 0x32)
|
||||
{
|
||||
return imu_spec_none;
|
||||
}
|
||||
// printf("BMM150 found!\n");
|
||||
writeRegister8(0x4C, 0x38); // normal mode / ODR 30Hz
|
||||
|
||||
// writeRegister8(CMD_REG_ADDR, SOFT_RESET_CMD); // software reset.
|
||||
// {
|
||||
// int retry = 16;
|
||||
// while (0 == readRegister8(PWR_CONF_ADDR) && --retry);
|
||||
// }
|
||||
|
||||
// writeRegister8(PWR_CONF_ADDR, 0x00); // Power save disabled.
|
||||
// vTaskDelay(1);
|
||||
// bool res = _upload_file(BMM150_config_file, 0, sizeof(BMM150_config_file));
|
||||
// writeRegister8(INIT_CTRL_ADDR, 0x01);
|
||||
|
||||
// writeRegister8(PWR_CTRL_ADDR, 0x0F); // temp en | ACC en | GYR en | AUX en
|
||||
|
||||
// if (res) {
|
||||
// int retry = 16;
|
||||
// do { vTaskDelay(1);}
|
||||
// while (0 == readRegister8(INTERNAL_STATUS_ADDR) && --retry);
|
||||
// res = retry > 0;
|
||||
// }
|
||||
_init = true;
|
||||
return imu_spec_mag;
|
||||
}
|
||||
|
||||
std::uint8_t BMM150_Class::WhoAmI(void)
|
||||
{
|
||||
return readRegister8(CHIP_ID_ADDR);
|
||||
}
|
||||
|
||||
IMU_Base::imu_spec_t BMM150_Class::getImuRawData(imu_raw_data_t* data) const
|
||||
{
|
||||
if (readRegister8(0x48) & 1)
|
||||
{
|
||||
std::int16_t buf[3];
|
||||
if (readRegister(0x42, (std::uint8_t*)buf, 6))
|
||||
{
|
||||
data->mag.x = buf[0] >> 2;
|
||||
data->mag.y = buf[1] >> 2;
|
||||
data->mag.z = buf[2] & 0xFFFEu;
|
||||
return imu_spec_mag;
|
||||
}
|
||||
}
|
||||
return imu_spec_none;
|
||||
}
|
||||
|
||||
void BMM150_Class::getConvertParam(imu_convert_param_t* param) const
|
||||
{
|
||||
param->mag_res = 10.0f * 4912.0f / 32760.0f;
|
||||
// param->temp_offset = 23.0f;
|
||||
// param->temp_res = 1.0f / 512.0f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
29
libraries/M5Unified/src/utility/imu/BMM150_Class.hpp
Normal file
29
libraries/M5Unified/src/utility/imu/BMM150_Class.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_BMM150_CLASS_H__
|
||||
#define __M5_BMM150_CLASS_H__
|
||||
|
||||
#include "IMU_Base.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class BMM150_Class : public IMU_Base
|
||||
{
|
||||
public:
|
||||
static constexpr const std::uint8_t CHIP_ID_ADDR = 0x40;
|
||||
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x10;
|
||||
|
||||
virtual ~BMM150_Class();
|
||||
BMM150_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C);
|
||||
|
||||
imu_spec_t begin(I2C_Class* i2c = nullptr) override;
|
||||
imu_spec_t getImuRawData(imu_raw_data_t* data) const override;
|
||||
void getConvertParam(imu_convert_param_t* param) const override;
|
||||
|
||||
std::uint8_t WhoAmI(void);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
63
libraries/M5Unified/src/utility/imu/IMU_Base.cpp
Normal file
63
libraries/M5Unified/src/utility/imu/IMU_Base.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "IMU_Base.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
IMU_Base::~IMU_Base() {}
|
||||
IMU_Base::IMU_Base(std::uint8_t i2c_addr, std::uint32_t freq, I2C_Class* i2c)
|
||||
: I2C_Device ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
/*
|
||||
int32_t IMU_Base::point3d_i32_t::calibration(const point3d_i16_t& dst)
|
||||
{
|
||||
{ // 前回の座標情報との差が許容範囲よりも大きく移動しているか調べる
|
||||
int32_t moving_distance = 0;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
int32_t diff = dst.value[i] - prev_point.value[i];
|
||||
moving_distance += diff * diff;
|
||||
}
|
||||
prev_point = dst;
|
||||
uint32_t wait = wait_counter;
|
||||
if (moving_distance > (tolerance * tolerance))
|
||||
{ // 移動変化量が大きい場合は補正を暫く停止する
|
||||
wait = 16;
|
||||
}
|
||||
if (wait)
|
||||
{ // 座標移動が安定するまで待機
|
||||
wait_counter = wait - 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
float distance = 0;
|
||||
float diffs[3];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
float diff = (dst.value[i] << 16) - value[i];
|
||||
diffs[i] = diff;
|
||||
distance += diff * diff;
|
||||
}
|
||||
distance = sqrtf(distance * (1.0f / (65536.0f * 65536.0f)));
|
||||
|
||||
// 誤差を求める (目的の半径と現在の距離の差)
|
||||
float measure_error = distance - radius;
|
||||
|
||||
int32_t tol = tolerance;
|
||||
int32_t force = abs((int32_t)measure_error) - tol;
|
||||
if (force <= 0) { return 1; }
|
||||
|
||||
if (force > tol) { force = tol; }
|
||||
if (signbit(measure_error)) { force = -force; }
|
||||
|
||||
float fk = (force * strength) / (distance * 256.0f);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
value[i] += diffs[i] * fk;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//*/
|
||||
}
|
||||
87
libraries/M5Unified/src/utility/imu/IMU_Base.hpp
Normal file
87
libraries/M5Unified/src/utility/imu/IMU_Base.hpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_IMU_BASE_H__
|
||||
#define __M5_IMU_BASE_H__
|
||||
|
||||
#include "../I2C_Class.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class IMU_Base : public I2C_Device
|
||||
{
|
||||
public:
|
||||
enum imu_spec_t
|
||||
{
|
||||
imu_spec_none = 0,
|
||||
imu_spec_accel = 0b0001,
|
||||
imu_spec_gyro = 0b0010,
|
||||
imu_spec_mag = 0b0100,
|
||||
};
|
||||
|
||||
struct point3d_i16_t
|
||||
{
|
||||
union
|
||||
{
|
||||
int16_t value[3];
|
||||
struct
|
||||
{
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t z;
|
||||
};
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
|
||||
struct imu_raw_data_t
|
||||
{
|
||||
union
|
||||
{
|
||||
int16_t value[10] = { 0, };
|
||||
point3d_i16_t sensor[3];
|
||||
struct
|
||||
{
|
||||
point3d_i16_t accel;
|
||||
point3d_i16_t gyro;
|
||||
point3d_i16_t mag;
|
||||
int16_t temp;
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
};
|
||||
|
||||
struct imu_convert_param_t
|
||||
{
|
||||
union
|
||||
{
|
||||
float value[3] = { 8.0f / 32768.0f, 2000.0f / 32768.0f, 10.0f * 4912.0f / 32768.0f };
|
||||
struct
|
||||
{
|
||||
float accel_res;
|
||||
float gyro_res;
|
||||
float mag_res;
|
||||
};
|
||||
};
|
||||
float temp_res = 1.0f;
|
||||
float temp_offset = 0.0f;
|
||||
};
|
||||
|
||||
virtual ~IMU_Base();
|
||||
IMU_Base(std::uint8_t i2c_addr, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C);
|
||||
virtual imu_spec_t begin(I2C_Class* i2c = nullptr) = 0;
|
||||
virtual imu_spec_t getImuRawData(imu_raw_data_t* data) const = 0; //{ return (imu_spec_t)0; }
|
||||
virtual void getConvertParam(imu_convert_param_t* param) const = 0;//{}
|
||||
virtual bool getTempAdc(int16_t* adc) const { (void)adc; return false; };
|
||||
virtual bool sleep(void) { return false; };
|
||||
/*
|
||||
virtual bool getAccelAdc(std::int16_t* ax, std::int16_t* ay, std::int16_t* az) const { return false; }
|
||||
virtual bool getGyroAdc(std::int16_t* gx, std::int16_t* gy, std::int16_t* gz) const { return false; }
|
||||
virtual bool getAccel(float* ax, float* ay, float* az) const { return false; }
|
||||
virtual bool getGyro(float* gx, float* gy, float* gz) const { return false; }
|
||||
virtual bool getTemp(float *t) const { return false; };
|
||||
//*/
|
||||
|
||||
virtual bool setINTPinActiveLogic(bool level) { (void)level; return false; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
290
libraries/M5Unified/src/utility/imu/MPU6886_Class.cpp
Normal file
290
libraries/M5Unified/src/utility/imu/MPU6886_Class.cpp
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if defined (ESP_PLATFORM)
|
||||
|
||||
#include "MPU6886_Class.hpp"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
MPU6886_Class::~MPU6886_Class() {}
|
||||
MPU6886_Class::MPU6886_Class(std::uint8_t i2c_addr, std::uint32_t freq, I2C_Class* i2c)
|
||||
: IMU_Base ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
|
||||
IMU_Base::imu_spec_t MPU6886_Class::begin(I2C_Class* i2c)
|
||||
{
|
||||
if (i2c)
|
||||
{
|
||||
_i2c = i2c;
|
||||
}
|
||||
|
||||
// WHO_AM_I : IMU Check
|
||||
auto id = readRegister8(0x75);
|
||||
_device_id = id;
|
||||
if (id != DEV_ID_MPU6886
|
||||
&& id != DEV_ID_MPU6050
|
||||
&& id != DEV_ID_MPU9250)
|
||||
{
|
||||
return imu_spec_none;
|
||||
}
|
||||
writeRegister8(REG_PWR_MGMT_1, 0x80);
|
||||
|
||||
static constexpr std::uint8_t init_cmd[] =
|
||||
{ REG_PWR_MGMT_1 , 0x01
|
||||
, REG_ACCEL_CONFIG , 0x10 // ACCEL_CONFIG(0x1C) : +-8G
|
||||
, REG_GYRO_CONFIG , 0x18 // GYRO_CONFIG(0x1B) : +-2000dps
|
||||
, REG_CONFIG , 0x01 // CONFIG(0x1A)
|
||||
, REG_SMPLRT_DIV , 0x03 // SMPLRT_DIV(0x19)
|
||||
, REG_INT_PIN_CFG , 0xC0 // INT_PIN_CFG(0x37) : active low, open-drain
|
||||
, REG_INT_ENABLE , 0x00 // INT_ENABLE(0x38) : all disable
|
||||
, REG_ACCEL_CONFIG2 , 0x00 // ACCEL_CONFIG 2(0x1D)
|
||||
, REG_USER_CTRL , 0x00 // USER_CTRL(0x6A)
|
||||
, REG_FIFO_EN , 0x00 // FIFO_EN(0x23)
|
||||
, 0xFF, 0xFF // EOF
|
||||
};
|
||||
|
||||
for (int idx = -1;;)
|
||||
{
|
||||
std::uint8_t reg = init_cmd[++idx];
|
||||
std::uint8_t val = init_cmd[++idx];
|
||||
if ((reg & val) == 0xFF) { break; }
|
||||
uint32_t retry_count = 16;
|
||||
do {
|
||||
writeRegister8(reg, val);
|
||||
} while (readRegister8(reg) != val && --retry_count);
|
||||
}
|
||||
|
||||
setGyroFsr(Gscale::GFS_2000DPS);
|
||||
setAccelFsr(Ascale::AFS_8G);
|
||||
|
||||
_init = true;
|
||||
_fifo_en = false;
|
||||
|
||||
// enableFIFO(Fodr::ODR_500Hz);
|
||||
|
||||
return (imu_spec_t)(imu_spec_accel | imu_spec_gyro);
|
||||
}
|
||||
|
||||
bool MPU6886_Class::sleep(void)
|
||||
{
|
||||
return writeRegister8(REG_PWR_MGMT_1, 0x40u);
|
||||
}
|
||||
|
||||
bool MPU6886_Class::setGyroAdcOffset(std::int16_t gx, std::int16_t gy, std::int16_t gz)
|
||||
{
|
||||
uint8_t buffer[6] =
|
||||
{ (uint8_t)(gx >> 8), (uint8_t)gx
|
||||
, (uint8_t)(gy >> 8), (uint8_t)gy
|
||||
, (uint8_t)(gz >> 8), (uint8_t)gz
|
||||
};
|
||||
return writeRegister(0x13, buffer, 6);
|
||||
}
|
||||
|
||||
void MPU6886_Class::enableFIFO(Fodr output_data_rate)
|
||||
{
|
||||
auto regdata = readRegister8(REG_GYRO_CONFIG);
|
||||
regdata &= 0x1C; // Clear bits 7:5 and 0:1 of FCHOICE_B to enable sample
|
||||
// rate divider and DLPF setting
|
||||
writeRegister8(REG_GYRO_CONFIG, regdata);
|
||||
vTaskDelay(10);
|
||||
|
||||
regdata = output_data_rate & 0xFF; // Set sample rate clock divider based on passed
|
||||
// value for sample rate desired
|
||||
writeRegister8(REG_SMPLRT_DIV, regdata);
|
||||
vTaskDelay(10);
|
||||
|
||||
regdata = readRegister8(REG_CONFIG);
|
||||
regdata |= 0x01; // Set DLPF_CFG to 176Hz DLPF filtering (highest value
|
||||
// where sample rate clock divider still works)
|
||||
regdata &= 0xBF; // Clear bit 6 to allow overflow writes to the FIFO - Use
|
||||
// it, or lose it!
|
||||
writeRegister8(REG_CONFIG, regdata);
|
||||
vTaskDelay(10);
|
||||
|
||||
// MPU9250: 0x78(TEMP OUT + GYRO XOUT,YOUT,ZOUT + ACCEL)
|
||||
regdata = 0xF8; // Set GYRO_FIFO_EN and ACCEL_FIFO_EN bits to one in FIFO
|
||||
// Enable register to enable FIFO on ALL sensor data
|
||||
writeRegister8(REG_FIFO_EN, regdata);
|
||||
vTaskDelay(10);
|
||||
|
||||
regdata = readRegister8(REG_INT_ENABLE);
|
||||
regdata |= 0x10; // Set bit 4 to turn on interrupts on FIFO overflow events
|
||||
writeRegister8(REG_INT_ENABLE, regdata);
|
||||
vTaskDelay(10);
|
||||
|
||||
regdata = 0x44; // Set FIFO_EN and FIFO_RST bits to one in User Control
|
||||
// register to enable FIFO mode
|
||||
writeRegister8(REG_USER_CTRL, regdata);
|
||||
vTaskDelay(10);
|
||||
|
||||
_fifo_en = true;
|
||||
}
|
||||
/*
|
||||
void MPU6886_Class::disableFIFO(void)
|
||||
{
|
||||
_fifo_en = false;
|
||||
unsigned char regdata;
|
||||
regdata = 0x00; // Clear GYRO_FIFO_EN and ACCEL_FIFO_EN bits to zero in
|
||||
// FIFO Enable register
|
||||
writeRegister8(REG_FIFO_EN, regdata);
|
||||
vTaskDelay(10);
|
||||
|
||||
writeRegister8(REG_INT_ENABLE, regdata);
|
||||
regdata &=
|
||||
0xEF; // Clear bit 4 to turn off interrupts on FIFO overflow events
|
||||
writeRegister8(REG_INT_ENABLE, regdata);
|
||||
vTaskDelay(10);
|
||||
|
||||
regdata = 0x00; // Set FIFO_EN bit to zero in User Control register to
|
||||
// dsiable FIFO mode
|
||||
writeRegister8(REG_USER_CTRL, regdata);
|
||||
vTaskDelay(10);
|
||||
}
|
||||
//*/
|
||||
void MPU6886_Class::setGyroFsr(Gscale scale)
|
||||
{
|
||||
scale = (Gscale)(scale & 3);
|
||||
_gscale = scale;
|
||||
writeRegister8(REG_GYRO_CONFIG, scale << 3);
|
||||
vTaskDelay(10);
|
||||
static constexpr const float table[] =
|
||||
{ 250.0f / 32768.0f // GFS_250DPS
|
||||
, 500.0f / 32768.0f // GFS_500DPS
|
||||
, 1000.0f / 32768.0f // GFS_1000DPS
|
||||
, 2000.0f / 32768.0f // GFS_2000DPS
|
||||
};
|
||||
_gRes = table[scale];
|
||||
}
|
||||
|
||||
void MPU6886_Class::setAccelFsr(Ascale scale)
|
||||
{
|
||||
scale = (Ascale)(scale & 3);
|
||||
_ascale = scale;
|
||||
writeRegister8(REG_ACCEL_CONFIG, scale << 3);
|
||||
vTaskDelay(10);
|
||||
static constexpr const float table[] =
|
||||
{ 2.0f / 32768.0f // AFS_2G
|
||||
, 4.0f / 32768.0f // AFS_4G
|
||||
, 8.0f / 32768.0f // AFS_8G
|
||||
, 16.0f / 32768.0f // AFS_16G
|
||||
};
|
||||
_aRes = table[scale];
|
||||
}
|
||||
|
||||
bool MPU6886_Class::setINTPinActiveLogic(bool level)
|
||||
{
|
||||
// MPU6886_INT_PIN_CFG = 0x37
|
||||
std::uint8_t tmp = readRegister8(REG_INT_PIN_CFG) & 0x7F;
|
||||
tmp |= level ? 0x00 : 0x80;
|
||||
return writeRegister8(REG_INT_PIN_CFG, tmp);
|
||||
}
|
||||
/*
|
||||
bool MPU6886_Class::getAccelAdc(std::int16_t* ax, std::int16_t* ay, std::int16_t* az) const
|
||||
{
|
||||
std::uint8_t buf[6];
|
||||
bool res = readRegister(0x3B, buf, 6);
|
||||
*ax = (buf[0] << 8) + buf[1];
|
||||
*ay = (buf[2] << 8) + buf[3];
|
||||
*az = (buf[4] << 8) + buf[5];
|
||||
return res;
|
||||
}
|
||||
|
||||
bool MPU6886_Class::getGyroAdc(std::int16_t* gx, std::int16_t* gy, std::int16_t* gz) const
|
||||
{
|
||||
std::uint8_t buf[6];
|
||||
bool res = readRegister(0x43, buf, 6);
|
||||
*gx = (buf[0] << 8) + buf[1];
|
||||
*gy = (buf[2] << 8) + buf[3];
|
||||
*gz = (buf[4] << 8) + buf[5];
|
||||
return res;
|
||||
}
|
||||
|
||||
bool MPU6886_Class::getAccel(float* ax, float* ay, float* az) const
|
||||
{
|
||||
std::uint8_t buf[6];
|
||||
bool res = readRegister(0x3B, buf, 6);
|
||||
auto aRes = _aRes;
|
||||
*ax = (std::int16_t)((buf[0] << 8) + buf[1]) * aRes;
|
||||
*ay = (std::int16_t)((buf[2] << 8) + buf[3]) * aRes;
|
||||
*az = (std::int16_t)((buf[4] << 8) + buf[5]) * aRes;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool MPU6886_Class::getGyro(float* gx, float* gy, float* gz) const
|
||||
{
|
||||
std::uint8_t buf[6];
|
||||
bool res = readRegister(0x43, buf, 6);
|
||||
auto gRes = _gRes;
|
||||
*gx = (std::int16_t)((buf[0] << 8) + buf[1]) * gRes;
|
||||
*gy = (std::int16_t)((buf[2] << 8) + buf[3]) * gRes;
|
||||
*gz = (std::int16_t)((buf[4] << 8) + buf[5]) * gRes;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool MPU6886_Class::getTemp(float *t) const
|
||||
{
|
||||
std::uint8_t buf[2];
|
||||
bool res = readRegister(0x41, buf, 2);
|
||||
*t = 25.0f + ((buf[0] << 8) + buf[1]) / 326.8f;
|
||||
return res;
|
||||
}
|
||||
//*/
|
||||
IMU_Base::imu_spec_t MPU6886_Class::getImuRawData(imu_raw_data_t* data) const
|
||||
{
|
||||
std::uint8_t raw_buf[16];
|
||||
auto buf = &raw_buf[1];
|
||||
|
||||
if (_fifo_en)
|
||||
{
|
||||
if (!readRegister(REG_FIFO_COUNTH, buf, 2) || (buf[0] + buf[1] == 0))
|
||||
{
|
||||
return imu_spec_none;
|
||||
}
|
||||
if (!readRegister(REG_FIFO_R_W, buf, 14) || (buf[0] == 0x7F && buf[1] == 0x7F))
|
||||
{
|
||||
return imu_spec_none;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!readRegister(0x3A, raw_buf, 1) || ((raw_buf[0] & 1) == 0))
|
||||
{
|
||||
return imu_spec_none;
|
||||
}
|
||||
if (!readRegister(0x3B, &raw_buf[1], 14))
|
||||
{
|
||||
return imu_spec_none;
|
||||
}
|
||||
}
|
||||
|
||||
data->accel.x = (std::int16_t)((buf[0] << 8) + buf[1]);
|
||||
data->accel.y = (std::int16_t)((buf[2] << 8) + buf[3]);
|
||||
data->accel.z = (std::int16_t)((buf[4] << 8) + buf[5]);
|
||||
// data->temp = (std::int16_t)((buf[6] << 8) + buf[7]);
|
||||
|
||||
data->gyro.x = (std::int16_t)((buf[ 8] << 8) + buf[ 9]);
|
||||
data->gyro.y = (std::int16_t)((buf[10] << 8) + buf[11]);
|
||||
data->gyro.z = (std::int16_t)((buf[12] << 8) + buf[13]);
|
||||
return (imu_spec_t)(imu_spec_accel | imu_spec_gyro);
|
||||
}
|
||||
|
||||
void MPU6886_Class::getConvertParam(imu_convert_param_t* param) const
|
||||
{
|
||||
param->accel_res = _aRes;
|
||||
param->gyro_res = _gRes;
|
||||
param->temp_res = 1.0f / 326.8f;
|
||||
param->temp_offset = 25.0f;
|
||||
}
|
||||
|
||||
bool MPU6886_Class::getTempAdc(int16_t* t) const
|
||||
{
|
||||
std::uint8_t buf[2];
|
||||
bool res = readRegister(0x41, buf, 2);
|
||||
if (res) { *t = (buf[0] << 8) + buf[1]; }
|
||||
return res;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
119
libraries/M5Unified/src/utility/imu/MPU6886_Class.hpp
Normal file
119
libraries/M5Unified/src/utility/imu/MPU6886_Class.hpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_MPU6886_CLASS_H__
|
||||
#define __M5_MPU6886_CLASS_H__
|
||||
|
||||
#include "IMU_Base.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class MPU6886_Class : public IMU_Base
|
||||
{
|
||||
public:
|
||||
static constexpr const std::uint8_t DEV_ID_MPU6886 = 0x19;
|
||||
static constexpr const std::uint8_t DEV_ID_MPU6050 = 0x68;
|
||||
static constexpr const std::uint8_t DEV_ID_MPU9250 = 0x71;
|
||||
|
||||
static constexpr const std::uint8_t REG_WHOAMI = 0x75;
|
||||
static constexpr const std::uint8_t REG_ACCEL_INTEL_CTRL = 0x69;
|
||||
static constexpr const std::uint8_t REG_SMPLRT_DIV = 0x19;
|
||||
static constexpr const std::uint8_t REG_INT_PIN_CFG = 0x37;
|
||||
static constexpr const std::uint8_t REG_INT_ENABLE = 0x38;
|
||||
static constexpr const std::uint8_t REG_ACCEL_XOUT_H = 0x3B;
|
||||
static constexpr const std::uint8_t REG_ACCEL_XOUT_L = 0x3C;
|
||||
static constexpr const std::uint8_t REG_ACCEL_YOUT_H = 0x3D;
|
||||
static constexpr const std::uint8_t REG_ACCEL_YOUT_L = 0x3E;
|
||||
static constexpr const std::uint8_t REG_ACCEL_ZOUT_H = 0x3F;
|
||||
static constexpr const std::uint8_t REG_ACCEL_ZOUT_L = 0x40;
|
||||
|
||||
static constexpr const std::uint8_t REG_TEMP_OUT_H = 0x41;
|
||||
static constexpr const std::uint8_t REG_TEMP_OUT_L = 0x42;
|
||||
|
||||
static constexpr const std::uint8_t REG_GYRO_XOUT_H = 0x43;
|
||||
static constexpr const std::uint8_t REG_GYRO_XOUT_L = 0x44;
|
||||
static constexpr const std::uint8_t REG_GYRO_YOUT_H = 0x45;
|
||||
static constexpr const std::uint8_t REG_GYRO_YOUT_L = 0x46;
|
||||
static constexpr const std::uint8_t REG_GYRO_ZOUT_H = 0x47;
|
||||
static constexpr const std::uint8_t REG_GYRO_ZOUT_L = 0x48;
|
||||
|
||||
static constexpr const std::uint8_t REG_USER_CTRL = 0x6A;
|
||||
static constexpr const std::uint8_t REG_PWR_MGMT_1 = 0x6B;
|
||||
static constexpr const std::uint8_t REG_PWR_MGMT_2 = 0x6C;
|
||||
static constexpr const std::uint8_t REG_CONFIG = 0x1A;
|
||||
static constexpr const std::uint8_t REG_GYRO_CONFIG = 0x1B;
|
||||
static constexpr const std::uint8_t REG_ACCEL_CONFIG = 0x1C;
|
||||
static constexpr const std::uint8_t REG_ACCEL_CONFIG2 = 0x1D;
|
||||
static constexpr const std::uint8_t REG_LP_MODE_CFG = 0x1E;
|
||||
static constexpr const std::uint8_t REG_FIFO_EN = 0x23;
|
||||
|
||||
static constexpr const std::uint8_t REG_FIFO_COUNTH = 0x72;
|
||||
static constexpr const std::uint8_t REG_FIFO_R_W = 0x74;
|
||||
|
||||
enum Ascale
|
||||
{ AFS_2G = 0
|
||||
, AFS_4G
|
||||
, AFS_8G
|
||||
, AFS_16G
|
||||
};
|
||||
|
||||
enum Gscale
|
||||
{ GFS_250DPS = 0
|
||||
, GFS_500DPS
|
||||
, GFS_1000DPS
|
||||
, GFS_2000DPS
|
||||
};
|
||||
|
||||
enum Fodr
|
||||
{ ODR_1kHz = 0
|
||||
, ODR_500Hz = 1
|
||||
// , ODR_333Hz = 2
|
||||
, ODR_250Hz = 3
|
||||
, ODR_200Hz = 4
|
||||
// , ODR_166Hz = 5
|
||||
// , ODR_143Hz = 6
|
||||
, ODR_125Hz = 7
|
||||
// , ODR_111Hz = 8
|
||||
, ODR_100Hz = 9
|
||||
, ODR_50Hz = 19
|
||||
, ODR_10Hz = 99
|
||||
};
|
||||
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x68;
|
||||
|
||||
virtual ~MPU6886_Class();
|
||||
MPU6886_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C);
|
||||
|
||||
imu_spec_t begin(I2C_Class* i2c = nullptr) override;
|
||||
imu_spec_t getImuRawData(imu_raw_data_t* data) const override;
|
||||
void getConvertParam(imu_convert_param_t* param) const;
|
||||
bool getTempAdc(int16_t* adc) const override;
|
||||
bool sleep(void) override;
|
||||
/*
|
||||
bool getAccelAdc(std::int16_t* ax, std::int16_t* ay, std::int16_t* az) const override;
|
||||
bool getGyroAdc(std::int16_t* gx, std::int16_t* gy, std::int16_t* gz) const override;
|
||||
bool getAccel(float* ax, float* ay, float* az) const override;
|
||||
bool getGyro(float* gx, float* gy, float* gz) const override;
|
||||
bool getTemp(float* t) const override;
|
||||
//*/
|
||||
void enableFIFO(Fodr output_data_rate);
|
||||
// void disableFIFO(void);
|
||||
|
||||
bool setGyroAdcOffset(std::int16_t gx, std::int16_t gy, std::int16_t gz);
|
||||
bool setINTPinActiveLogic(bool level) override;
|
||||
|
||||
std::uint8_t whoAmI(void) const { return _device_id; }
|
||||
|
||||
protected:
|
||||
void setGyroFsr(Gscale scale);
|
||||
void setAccelFsr(Ascale scale);
|
||||
|
||||
bool _fifo_en;
|
||||
float _aRes, _gRes;
|
||||
Gscale _gscale;
|
||||
Ascale _ascale;
|
||||
std::uint8_t _device_id = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
219
libraries/M5Unified/src/utility/imu/SH200Q_Class.cpp
Normal file
219
libraries/M5Unified/src/utility/imu/SH200Q_Class.cpp
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if defined (ESP_PLATFORM)
|
||||
|
||||
#include "SH200Q_Class.hpp"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace m5
|
||||
{
|
||||
SH200Q_Class::~SH200Q_Class() {}
|
||||
SH200Q_Class::SH200Q_Class(std::uint8_t i2c_addr, std::uint32_t freq, I2C_Class* i2c)
|
||||
: IMU_Base ( i2c_addr, freq, i2c )
|
||||
{}
|
||||
|
||||
IMU_Base::imu_spec_t SH200Q_Class::begin(I2C_Class* i2c)
|
||||
{
|
||||
if (i2c)
|
||||
{
|
||||
_i2c = i2c;
|
||||
}
|
||||
|
||||
// WHO_AM_I : IMU Check
|
||||
if (WhoAmI() != 0x18)
|
||||
{
|
||||
return imu_spec_none;
|
||||
}
|
||||
vTaskDelay(1);
|
||||
|
||||
bitOn(0xC2, 0x04);
|
||||
vTaskDelay(1);
|
||||
|
||||
bitOff(0xC2, 0x04);
|
||||
vTaskDelay(1);
|
||||
|
||||
bitOn(0xD8, 0x80);
|
||||
vTaskDelay(1);
|
||||
|
||||
bitOff(0xD8, 0x80);
|
||||
vTaskDelay(1);
|
||||
|
||||
static constexpr std::uint8_t init_cmd[] =
|
||||
{ 0x78, 0x61
|
||||
, 0x78, 0x00
|
||||
, 0x0E, 0x91 // ACC_CONFIG(0x0E) : 256Hz
|
||||
, 0x0F, 0x13 // GYRO_CONFIG(0x0F) : 500Hz
|
||||
, 0x11, 0x03 // GYRO_DLPF(0x11) : 50Hz
|
||||
, 0x12, 0x00 // FIFO_CONFIG(0x12)
|
||||
// , 0x12, 0x80 // FIFO_CONFIG(0x12) : FIFO MODE
|
||||
, 0x14, 0x20 // data ready interrupt en
|
||||
, 0x16, 0x01 // ACC_RANGE(0x16) : +-8G
|
||||
, 0x2B, 0x00 // GYRO_RANGE(0x2B) : +-2000
|
||||
, 0xBA, 0xC0 // REG_SET1(0xBA)
|
||||
, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
for (int idx = -1;;)
|
||||
{
|
||||
std::uint8_t reg = init_cmd[++idx];
|
||||
std::uint8_t val = init_cmd[++idx];
|
||||
if ((reg & val) == 0xFF) { break; }
|
||||
writeRegister8(reg, val);
|
||||
vTaskDelay(1);
|
||||
}
|
||||
|
||||
// REG_SET2(0xCA)
|
||||
bitOn(0xCA, 0x10);
|
||||
vTaskDelay(1);
|
||||
|
||||
// REG_SET2(0xCA)
|
||||
bitOff(0xCA, 0x10);
|
||||
vTaskDelay(1);
|
||||
|
||||
_init = true;
|
||||
return (imu_spec_t)(imu_spec_accel | imu_spec_gyro);
|
||||
}
|
||||
|
||||
IMU_Base::imu_spec_t SH200Q_Class::getImuRawData(imu_raw_data_t* data) const
|
||||
{
|
||||
// static constexpr float aRes = 8.0f / 32768.0f;
|
||||
// static constexpr float gRes = 2000.0f / 32768.0f;
|
||||
uint8_t st = readRegister8(0x2C);
|
||||
// printf("st:%d\n",st);
|
||||
if (st & 0x20u)
|
||||
{
|
||||
std::int16_t buf[6];
|
||||
bool res = readRegister(0x00, (std::uint8_t*)buf, 14);
|
||||
if (res)
|
||||
{
|
||||
memcpy(data->value, buf, 12);
|
||||
return (imu_spec_t)(imu_spec_accel | imu_spec_gyro);
|
||||
}
|
||||
}
|
||||
return imu_spec_none;
|
||||
}
|
||||
/*
|
||||
bool SH200Q_Class::getImuRawData(imu_raw_data_t* data) const
|
||||
{
|
||||
// static constexpr float aRes = 8.0f / 32768.0f;
|
||||
// static constexpr float gRes = 2000.0f / 32768.0f;
|
||||
std::uint8_t state[2];
|
||||
std::int16_t buf[6];
|
||||
|
||||
if (readRegister(0x2E, (std::uint8_t*)state, 2))
|
||||
{
|
||||
// 0x2E:accel FIFO Status
|
||||
// 0x2F:gyro FIFO Status
|
||||
uint32_t len = 7;
|
||||
uint32_t idx = 0;
|
||||
if (0 == (state[0] & 0x3F))
|
||||
{
|
||||
idx += 3;
|
||||
len -= 3;
|
||||
}
|
||||
if (0 == (state[1] & 0x3F))
|
||||
{
|
||||
len -= 4;
|
||||
}
|
||||
if (len > 2)
|
||||
{
|
||||
if (readRegister(idx << 1, (std::uint8_t*)(&buf[idx]), len << 1))
|
||||
{
|
||||
if (idx == 0)
|
||||
{
|
||||
data->accel.x = buf[0];
|
||||
data->accel.y = buf[1];
|
||||
data->accel.z = buf[2];
|
||||
printf("idx:%d len:%d ax:%d ay:%d az:%d gx:%d gy:%d gz:%d\n", idx, len, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
|
||||
}
|
||||
if (len > 3)
|
||||
{
|
||||
data->gyro.x = buf[3];
|
||||
data->gyro.y = buf[4];
|
||||
data->gyro.z = buf[5];
|
||||
data->temp = buf[6];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
std::uint8_t SH200Q_Class::WhoAmI(void)
|
||||
{
|
||||
return readRegister8(0x30);
|
||||
}
|
||||
/*
|
||||
bool SH200Q_Class::getAccelAdc(std::int16_t* ax, std::int16_t* ay, std::int16_t* az) const
|
||||
{
|
||||
std::int16_t buf[3];
|
||||
bool res = readRegister(0x00, (std::uint8_t*)buf, 6);
|
||||
*ax = buf[0];
|
||||
*ay = buf[1];
|
||||
*az = buf[2];
|
||||
return res;
|
||||
}
|
||||
|
||||
bool SH200Q_Class::getGyroAdc(std::int16_t* gx, std::int16_t* gy, std::int16_t* gz) const
|
||||
{
|
||||
std::int16_t buf[3];
|
||||
bool res = readRegister(0x06, (std::uint8_t*)buf, 6);
|
||||
*gx = buf[0];
|
||||
*gy = buf[1];
|
||||
*gz = buf[2];
|
||||
return res;
|
||||
}
|
||||
|
||||
bool SH200Q_Class::getAccel(float* ax, float* ay, float* az) const
|
||||
{
|
||||
static constexpr float aRes = 8.0f / 32768.0f;
|
||||
std::int16_t buf[3];
|
||||
bool res = readRegister(0x00, (std::uint8_t*)buf, 6);
|
||||
*ax = buf[0] * aRes;
|
||||
*ay = buf[1] * aRes;
|
||||
*az = buf[2] * aRes;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool SH200Q_Class::getGyro(float* gx, float* gy, float* gz) const
|
||||
{
|
||||
static constexpr float gRes = 2000.0f / 32768.0f;
|
||||
std::int16_t buf[3];
|
||||
bool res = readRegister(0x06, (std::uint8_t*)buf, 6);
|
||||
*gx = buf[0] * gRes;
|
||||
*gy = buf[1] * gRes;
|
||||
*gz = buf[2] * gRes;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool SH200Q_Class::getTemp(float *t) const
|
||||
{
|
||||
std::int16_t buf;
|
||||
bool res = readRegister(0x0C, (std::uint8_t*)&buf, 2);
|
||||
*t = 21.0f + buf / 333.87f;
|
||||
return res;
|
||||
}
|
||||
//*/
|
||||
void SH200Q_Class::getConvertParam(imu_convert_param_t* param) const
|
||||
{
|
||||
param->accel_res = 8.0f / 32768.0f;
|
||||
param->gyro_res = 2000.0f / 32768.0f;
|
||||
param->temp_res = 1.0f / 333.87f;
|
||||
param->temp_offset = 21.0f;
|
||||
}
|
||||
|
||||
bool SH200Q_Class::getTempAdc(int16_t *t) const
|
||||
{
|
||||
std::int16_t buf;
|
||||
bool res = readRegister(0x0C, (std::uint8_t*)&buf, 2);
|
||||
if (res) { *t = buf; }
|
||||
return res;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
35
libraries/M5Unified/src/utility/imu/SH200Q_Class.hpp
Normal file
35
libraries/M5Unified/src/utility/imu/SH200Q_Class.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __M5_SH200Q_CLASS_H__
|
||||
#define __M5_SH200Q_CLASS_H__
|
||||
|
||||
#include "IMU_Base.hpp"
|
||||
|
||||
namespace m5
|
||||
{
|
||||
class SH200Q_Class : public IMU_Base
|
||||
{
|
||||
public:
|
||||
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x6C;
|
||||
|
||||
virtual ~SH200Q_Class();
|
||||
SH200Q_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 400000, I2C_Class* i2c = &In_I2C);
|
||||
|
||||
imu_spec_t begin(I2C_Class* i2c = nullptr) override;
|
||||
imu_spec_t getImuRawData(imu_raw_data_t* data) const override;
|
||||
void getConvertParam(imu_convert_param_t* param) const override;
|
||||
bool getTempAdc(int16_t* adc) const override;
|
||||
|
||||
std::uint8_t WhoAmI(void);
|
||||
/*
|
||||
bool getAccelAdc(std::int16_t* ax, std::int16_t* ay, std::int16_t* az) const override;
|
||||
bool getGyroAdc(std::int16_t* gx, std::int16_t* gy, std::int16_t* gz) const override;
|
||||
bool getAccel(float* ax, float* ay, float* az) const override;
|
||||
bool getGyro(float* gx, float* gy, float* gz) const override;
|
||||
bool getTemp(float *t) const override;
|
||||
//*/
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
39
libraries/M5Unified/src/utility/m5unified_common.h
Normal file
39
libraries/M5Unified/src/utility/m5unified_common.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) M5Stack. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined ( ESP_PLATFORM )
|
||||
|
||||
#if __has_include(<SDL2/SDL.h>)
|
||||
#include <SDL2/SDL.h>
|
||||
#define M5UNIFIED_PC_BUILD
|
||||
#elif __has_include(<SDL.h>)
|
||||
#include <SDL.h>
|
||||
#define M5UNIFIED_PC_BUILD
|
||||
#endif
|
||||
|
||||
#if defined ( M5UNIFIED_PC_BUILD )
|
||||
|
||||
typedef int esp_err_t;
|
||||
typedef int i2c_port_t;
|
||||
|
||||
#define ESP_OK 0
|
||||
#define ESP_FAIL -1
|
||||
|
||||
typedef enum {
|
||||
ESP_LOG_NONE, /*!< No log output */
|
||||
ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */
|
||||
ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */
|
||||
ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */
|
||||
ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
|
||||
ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
|
||||
} esp_log_level_t;
|
||||
|
||||
typedef enum {
|
||||
I2S_NUM_0 = 0,
|
||||
I2S_NUM_MAX,
|
||||
} i2s_port_t;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue