276 lines
6.9 KiB
C++
276 lines
6.9 KiB
C++
#include "Watchy.h"
|
|
#include "bma423.h"
|
|
|
|
WatchyDisplayBase Watchy::m_displayBase;
|
|
WatchyDisplay Watchy::m_display(Watchy::m_displayBase);
|
|
|
|
RTC_DATA_ATTR BMA423 Watchy::m_sensor;
|
|
RTC_DATA_ATTR bool g_displayFullInit = true;
|
|
|
|
Watchy::Watchy()
|
|
: m_features(m_sensor)
|
|
{
|
|
}
|
|
|
|
void Watchy::Wake()
|
|
{
|
|
esp_sleep_wakeup_cause_t wakeup_reason;
|
|
wakeup_reason = esp_sleep_get_wakeup_cause();
|
|
|
|
if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) {
|
|
if(!m_features.rtc.CheckWakeup()) {
|
|
DeepSleep();
|
|
}
|
|
}
|
|
|
|
switch(wakeup_reason) {
|
|
case ESP_SLEEP_WAKEUP_EXT0:
|
|
{
|
|
// RTC interrupt
|
|
InitWakeInternal();
|
|
ShowWatchFace(true);
|
|
break;
|
|
}
|
|
case ESP_SLEEP_WAKEUP_EXT1:
|
|
{
|
|
// Button press or accelerometer interrupt
|
|
InitWakeInternal();
|
|
uint64_t wakeupBit = esp_sleep_get_ext1_wakeup_status();
|
|
if (wakeupBit & ACC_INT_MASK) {
|
|
// Accelerometer interrupt
|
|
m_sensor.getINT();
|
|
uint8_t irqMask = m_sensor.getIRQMASK();
|
|
|
|
if(irqMask & BMA423_TILT_INT) {
|
|
HandleTilt();
|
|
}
|
|
|
|
if(irqMask & BMA423_WAKEUP_INT) {
|
|
HandleDoubleTap();
|
|
}
|
|
|
|
m_sensor.getINT();
|
|
} else if (wakeupBit & BTN_PIN_MASK) {
|
|
// Button press
|
|
HandleButtonPress(wakeupBit);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
InitBootInternal();
|
|
ShowWatchFace(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DeepSleep();
|
|
}
|
|
|
|
void Watchy::DeepSleep()
|
|
{
|
|
m_display.hibernate();
|
|
if (g_displayFullInit) { // For some reason, seems to be enabled on first boot
|
|
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
|
|
}
|
|
|
|
g_displayFullInit = false; // Notify not to init it again
|
|
|
|
// Set GPIOs 0-39 to input to avoid power leaking out
|
|
const uint64_t ignore = 0b11110001000000110000100111000010; // Ignore some GPIOs due to resets
|
|
for (int i = 0; i < GPIO_NUM_MAX; i++) {
|
|
if ((ignore >> i) & 0b1) {
|
|
continue;
|
|
}
|
|
pinMode(i, INPUT);
|
|
}
|
|
esp_sleep_enable_ext0_wakeup((gpio_num_t)RTC_INT_PIN, 0); // enable deep sleep wake on RTC interrupt
|
|
esp_sleep_enable_ext1_wakeup(
|
|
BTN_PIN_MASK | ACC_INT_MASK,
|
|
ESP_EXT1_WAKEUP_ANY_HIGH);
|
|
|
|
m_features.rtc.SetTimer();
|
|
|
|
esp_deep_sleep_start();
|
|
}
|
|
|
|
void Watchy::DisplayBusyCallback(const void *)
|
|
{
|
|
gpio_wakeup_enable((gpio_num_t)DISPLAY_BUSY, GPIO_INTR_LOW_LEVEL);
|
|
esp_sleep_enable_gpio_wakeup();
|
|
esp_light_sleep_start();
|
|
}
|
|
|
|
void Watchy::SyncNTPTime()
|
|
{
|
|
WiFiUDP ntpUDP;
|
|
// GMT offset should be 0, since RTC is set to UTC
|
|
NTPClient timeClient(ntpUDP, NTP_SERVER, 0);
|
|
timeClient.begin();
|
|
bool success = timeClient.forceUpdate();
|
|
if (success) {
|
|
tmElements_t tm;
|
|
breakTime((time_t)timeClient.getEpochTime(), tm);
|
|
m_features.rtc.Set(tm);
|
|
} else {
|
|
Serial.begin(9600);
|
|
Serial.println("Failed to get NTP time");
|
|
}
|
|
}
|
|
|
|
void Watchy::ShowWatchFace(bool partialRefresh)
|
|
{
|
|
DrawWatchFace(partialRefresh);
|
|
}
|
|
|
|
void Watchy::ClearBusyCallback()
|
|
{
|
|
m_display.epd2.setBusyCallback(nullptr);
|
|
}
|
|
|
|
void Watchy::InitBootInternal()
|
|
{
|
|
Wire.begin(SDA, SCL);
|
|
m_display.epd2.selectSPI(SPI, SPISettings(20000000, MSBFIRST, SPI_MODE0));
|
|
m_display.init(0, g_displayFullInit, 10, true);
|
|
SetBusyCallback();
|
|
BmaConfig();
|
|
m_features.storage.InitBoot();
|
|
m_features.wifi.InitBoot();
|
|
InitBoot();
|
|
}
|
|
|
|
void Watchy::InitWakeInternal()
|
|
{
|
|
Wire.begin(SDA, SCL);
|
|
m_display.epd2.selectSPI(SPI, SPISettings(20000000, MSBFIRST, SPI_MODE0));
|
|
m_display.init(0, g_displayFullInit, 10, true);
|
|
SetBusyCallback();
|
|
|
|
m_features.storage.InitWake();
|
|
InitWake();
|
|
}
|
|
|
|
void Watchy::SetBusyCallback()
|
|
{
|
|
m_display.epd2.setBusyCallback(DisplayBusyCallback);
|
|
}
|
|
|
|
uint16_t Watchy::ReadRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
|
|
{
|
|
Wire.beginTransmission(address);
|
|
Wire.write(reg);
|
|
Wire.endTransmission();
|
|
Wire.requestFrom((uint8_t)address, (uint8_t)len);
|
|
uint8_t i = 0;
|
|
while (Wire.available()) {
|
|
data[i++] = Wire.read();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint16_t Watchy::WriteRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
|
|
{
|
|
Wire.beginTransmission(address);
|
|
Wire.write(reg);
|
|
Wire.write(data, len);
|
|
return (0 != Wire.endTransmission());
|
|
}
|
|
|
|
void Watchy::BmaConfig()
|
|
{
|
|
if (m_sensor.begin(ReadRegister, WriteRegister, delay) == false) {
|
|
// fail to init BMA
|
|
return;
|
|
}
|
|
|
|
// Accel parameter structure
|
|
Acfg cfg;
|
|
/*!
|
|
Output data rate in Hz, Optional parameters:
|
|
- BMA4_OUTPUT_DATA_RATE_0_78HZ
|
|
- BMA4_OUTPUT_DATA_RATE_1_56HZ
|
|
- BMA4_OUTPUT_DATA_RATE_3_12HZ
|
|
- BMA4_OUTPUT_DATA_RATE_6_25HZ
|
|
- BMA4_OUTPUT_DATA_RATE_12_5HZ
|
|
- BMA4_OUTPUT_DATA_RATE_25HZ
|
|
- BMA4_OUTPUT_DATA_RATE_50HZ
|
|
- BMA4_OUTPUT_DATA_RATE_100HZ
|
|
- BMA4_OUTPUT_DATA_RATE_200HZ
|
|
- BMA4_OUTPUT_DATA_RATE_400HZ
|
|
- BMA4_OUTPUT_DATA_RATE_800HZ
|
|
- BMA4_OUTPUT_DATA_RATE_1600HZ
|
|
*/
|
|
cfg.odr = BMA4_OUTPUT_DATA_RATE_100HZ;
|
|
/*!
|
|
G-range, Optional parameters:
|
|
- BMA4_ACCEL_RANGE_2G
|
|
- BMA4_ACCEL_RANGE_4G
|
|
- BMA4_ACCEL_RANGE_8G
|
|
- BMA4_ACCEL_RANGE_16G
|
|
*/
|
|
cfg.range = BMA4_ACCEL_RANGE_2G;
|
|
/*!
|
|
Bandwidth parameter, determines filter configuration, Optional parameters:
|
|
- BMA4_ACCEL_OSR4_AVG1
|
|
- BMA4_ACCEL_OSR2_AVG2
|
|
- BMA4_ACCEL_NORMAL_AVG4
|
|
- BMA4_ACCEL_CIC_AVG8
|
|
- BMA4_ACCEL_RES_AVG16
|
|
- BMA4_ACCEL_RES_AVG32
|
|
- BMA4_ACCEL_RES_AVG64
|
|
- BMA4_ACCEL_RES_AVG128
|
|
*/
|
|
cfg.bandwidth = BMA4_ACCEL_NORMAL_AVG4;
|
|
|
|
/*! Filter performance mode , Optional parameters:
|
|
- BMA4_CIC_AVG_MODE
|
|
- BMA4_CONTINUOUS_MODE
|
|
*/
|
|
cfg.perf_mode = BMA4_CONTINUOUS_MODE;
|
|
|
|
// Configure the BMA423 accelerometer
|
|
m_sensor.setAccelConfig(cfg);
|
|
|
|
// Enable BMA423 accelerometer
|
|
// Warning : Need to use feature, you must first enable the accelerometer
|
|
m_sensor.enableAccel();
|
|
|
|
struct bma4_int_pin_config config;
|
|
config.edge_ctrl = BMA4_LEVEL_TRIGGER;
|
|
config.lvl = BMA4_ACTIVE_HIGH;
|
|
config.od = BMA4_PUSH_PULL;
|
|
config.output_en = BMA4_OUTPUT_ENABLE;
|
|
config.input_en = BMA4_INPUT_DISABLE;
|
|
// The correct trigger interrupt needs to be configured as needed
|
|
m_sensor.setINTPinConfig(config, BMA4_INTR1_MAP);
|
|
|
|
struct bma423_axes_remap remap_data;
|
|
remap_data.x_axis = 1;
|
|
remap_data.x_axis_sign = 0xFF;
|
|
remap_data.y_axis = 0;
|
|
remap_data.y_axis_sign = 0xFF;
|
|
remap_data.z_axis = 2;
|
|
remap_data.z_axis_sign = 0xFF;
|
|
// Need to raise the wrist function, need to set the correct axis
|
|
m_sensor.setRemapAxes(&remap_data);
|
|
|
|
// Enable BMA423 isStepCounter feature
|
|
m_sensor.enableFeature(BMA423_STEP_CNTR, true);
|
|
// Enable BMA423 isTilt feature
|
|
m_sensor.enableFeature(BMA423_TILT, true);
|
|
// Enable BMA423 isDoubleClick feature
|
|
m_sensor.enableFeature(BMA423_WAKEUP, true);
|
|
|
|
// Reset steps
|
|
//m_sensor.resetStepCounter();
|
|
|
|
// Turn on feature interrupt
|
|
//m_sensor.enableStepCountInterrupt();
|
|
|
|
if (WAKE_ON_ACCEL_EVENTS) {
|
|
m_sensor.enableTiltInterrupt();
|
|
m_sensor.enableWakeupInterrupt();
|
|
}
|
|
}
|
|
|