Browse Source

System and power management supported.

Beoran 3 years ago
commit
5380ffeb62
13 changed files with 597 additions and 0 deletions
  1. 21 0
      LICENSE
  2. 6 0
      README.md
  3. 281 0
      src/twali_power.cpp
  4. 37 0
      src/twali_power.h
  5. 0 0
      src/twali_screen.cpp
  6. 15 0
      src/twali_screen.h
  7. 63 0
      src/twali_system.cpp
  8. 24 0
      src/twali_system.h
  9. 37 0
      src/twali_system_internal.h
  10. 100 0
      src/twali_task.c
  11. 13 0
      src/twali_task.h
  12. 0 0
      src/twali_touch.c
  13. 0 0
      src/twali_touch.h

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 beoran
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 6 - 0
README.md

@@ -0,0 +1,6 @@
+# twali
+
+T-Watch-2020 library for use with processing.io, wraps around Arduino and the 
+offcial T-WATCH-2020 mibrary with a C API, for people like me, who prefer pure C.
+
+It has a sort of fancy task model and can do power management as well.  

+ 281 - 0
src/twali_power.cpp

@@ -0,0 +1,281 @@
+#define TWALI_INTERNAL
+#include "twali_system_internal.h"
+#include <stdlib.h>
+
+extern "C" {
+
+#define POWER_DOWN_DELAY 11000
+#define SUSPEND_DELAY 15000
+#define SHORT_KEYPRESS_DELAY 200
+
+struct twali_power {
+    uint32_t power_down_delay;
+    uint32_t suspend_delay;
+    
+    struct twali_system * system;
+    AXP20X_Class * power;
+    
+
+    // state of the system
+    int plugged_in;
+    int low_power;    
+    int charging;
+    int read_irq;
+    long unsigned int now;
+
+    // statistics about the system
+    int battery_percentage;    
+    float battery_current;
+    float vbus_current;
+    long unsigned int last_logged;
+    
+    // managing the sleep/low_power/high_power state
+    long unsigned int last_touch;
+    long unsigned int wake_time;
+    long unsigned int sleep_time;
+    long unsigned int last_interaction;
+
+    
+};
+
+static struct twali_power twali_power_singleton;
+static struct twali_power* twali_power_singleton_pointer = NULL;
+
+struct twali_power * twali_power_make(struct twali_system *s) {
+    if (NULL != twali_power_singleton_pointer) {
+        return twali_power_singleton_pointer;
+    }
+    twali_power_singleton.power = s->handle->power;
+    twali_power_singleton.power_down_delay = POWER_DOWN_DELAY;
+    twali_power_singleton.suspend_delay = SUSPEND_DELAY;
+    twali_power_singleton.system = s;
+
+    // state of the system
+    twali_power_singleton.plugged_in = 0;
+    twali_power_singleton.charging = 0;
+    twali_power_singleton.read_irq = 0;
+    twali_power_singleton.now = 0;
+
+    // statistics about the system
+    twali_power_singleton.battery_percentage = 0;
+    twali_power_singleton.battery_current = 0.0;
+    twali_power_singleton.vbus_current = 0.0;
+    twali_power_singleton.last_logged = 0;
+    
+    // managing the sleep/low_power/high_power state
+    twali_power_singleton.last_touch = 0;
+    twali_power_singleton.wake_time = 0;
+    twali_power_singleton.sleep_time = 0;
+    twali_power_singleton.last_interaction = 0;
+    twali_power_singleton.low_power = 0;    
+    twali_power_singleton_pointer = &twali_power_singleton;
+    return twali_power_singleton_pointer;
+}
+
+
+void twali_power_interrupt(struct twali_power *p) {
+    p->read_irq = 1;
+}
+
+int twali_power_plugged_in(struct twali_power *p) {
+    return p->plugged_in;
+}
+
+int twali_power_charging(struct twali_power *p) {
+    return p->charging;
+}
+
+int twali_power_low(struct twali_power *p) {
+    return p->low_power;
+}
+
+void twali_power_run(struct twali_power *p);
+
+int twali_power_battery_percentage(struct twali_power *p) {
+  int actual_percentage = p->power->getBattPercentage();
+
+  if (twali_power_plugged_in(p)) {
+    if (actual_percentage >= p->battery_percentage) {
+      p->battery_percentage = actual_percentage;
+    }
+  } else {
+    if (actual_percentage <= p->battery_percentage) {
+        p->battery_percentage = actual_percentage;
+    }
+  }
+  return p->battery_percentage;
+}
+
+float twali_power_battery_current(struct twali_power *p) {
+    return p->battery_current;
+}
+
+float twali_power_vbus_current(struct twali_power *p) {
+    return p->vbus_current;
+}
+
+float twali_power_last_interaction(struct twali_power *p);
+float twali_power_now(struct twali_power *p);
+void twali_power_up(struct twali_power *p);
+
+void twali_power_down(struct twali_power *p) {
+    printf("%s\n", __func__);
+    p->system->handle->closeBL();
+    p->system->handle->displaySleep();
+    p->low_power = 1;
+    p->sleep_time = p->now;
+}
+
+void twali_power_up(struct twali_power *p) {
+    printf("%s\n", __func__);
+    p->system->handle->displayWakeup();
+    p->system->handle->openBL();
+    p->system->tft->fillScreen(TFT_WHITE);
+    p->wake_time = p->last_interaction = p->now;
+    p->low_power = 0;
+}
+
+void twali_power_suspend(struct twali_power *p) {
+    printf("%s\n", __func__);
+    esp_sleep_enable_gpio_wakeup();
+    p->system->tft->fillScreen(TFT_BLACK);
+    esp_light_sleep_start();
+    twali_system_wake_up(p->system);
+    printf("%s\n", "back from sleep");
+}
+
+void twali_power_task(void * object);
+void twali_power_start_task(struct twali_power * p);
+
+int twali_power_check_touch(struct twali_power *p) {
+  if (p->system->handle->touch->touched() > 0) {
+    p->last_touch = p->last_interaction = p->now;
+    return 1;
+  }
+  return 0;
+}
+
+void twali_power_init(struct twali_power *p) {
+  p->power->setPowerOutPut(
+      AXP202_EXTEN
+      | AXP202_DCDC2
+      | AXP202_LDO3
+      | AXP202_LDO4
+  , AXP202_OFF);
+
+  p->power->adc1Enable(
+      AXP202_BATT_VOL_ADC1
+      | AXP202_BATT_CUR_ADC1
+      | AXP202_VBUS_CUR_ADC1
+  , AXP202_ON);
+
+  p->power->adc1Enable(
+      AXP202_VBUS_VOL_ADC1
+  , AXP202_OFF);
+
+  gpio_wakeup_enable((gpio_num_t)AXP202_INT, GPIO_INTR_LOW_LEVEL);
+
+  p->power->enableIRQ(
+      AXP202_VBUS_REMOVED_IRQ
+      | AXP202_VBUS_CONNECT_IRQ
+      | AXP202_CHARGING_IRQ
+      | AXP202_CHARGING_FINISHED_IRQ
+      | AXP202_PEK_LONGPRESS_IRQ
+      | AXP202_PEK_SHORTPRESS_IRQ
+  , AXP202_ON);
+
+  p->power->clearIRQ();
+
+  p->plugged_in = p->power->isVBUSPlug();
+  p->charging = p->power->isChargeingEnable();
+  p->battery_percentage = p->power->getBattPercentage();
+}
+
+void twali_power_read_irq(struct twali_power *p) {
+  p->power->readIRQ();
+  p->read_irq = false;
+
+  if (p->power->isVbusPlugInIRQ())   p->plugged_in = 1;
+  if (p->power->isVbusRemoveIRQ())   p->plugged_in = 0;
+  if (p->power->isChargingIRQ())     p->charging = 0;
+  if (p->power->isChargingDoneIRQ()) p->charging = 1;
+
+  if (p->power->isPEKShortPressIRQ()) {
+    if (p->now - p->last_interaction > SHORT_KEYPRESS_DELAY) {
+      if (p->low_power) twali_power_up(p);
+      else twali_power_down(p);
+    }
+  }
+  
+  p->power->clearIRQ();
+  p->last_interaction = p->now;
+}
+
+void twali_power_up_try(struct twali_power *p) {
+  if (p->last_touch > p->sleep_time) {
+    twali_power_up(p);
+  }
+}
+
+void twali_power_down_try(struct twali_power *p) {
+  if (p->plugged_in) return;
+  if (p->now - p->last_interaction > p->power_down_delay) {
+    twali_power_down(p);
+  }
+}
+
+void twali_power_suspend_try(struct twali_power *p) {
+  if (p->plugged_in) return;
+  if (p->now - p->last_interaction > p->suspend_delay) {
+        twali_power_suspend(p);
+  }
+}
+
+void twali_log_power(struct twali_power * p) {
+    p->battery_current = (p->battery_current + p->power->getBattDischargeCurrent()) / 2;
+    p->vbus_current = (p->vbus_current + p->power->getVbusCurrent()) / 2;
+    p->last_logged = p->now;
+}
+
+void twali_power_run(struct twali_power *p) {
+    p->now = millis();
+
+    if (p->read_irq) twali_power_read_irq(p);
+    twali_power_check_touch(p);
+
+    if (p->low_power) {
+        twali_power_up_try(p);
+        if (p->low_power) { 
+            twali_power_suspend_try(p);
+        }
+    } else {
+        twali_power_down_try(p);
+    }
+
+    if (p->now - p->last_logged > 500) {    
+        twali_log_power(p);
+    }
+}
+
+
+void twali_power_task(void* object) {
+  struct twali_power * p = (struct twali_power *) object;
+
+  twali_power_init(p);
+
+  for (;;) {
+    twali_power_run(p);
+    vTaskDelay(10 / portTICK_PERIOD_MS);
+  }
+
+  printf("deleting the power management task!\n");
+  vTaskDelete(NULL);
+}
+
+void twali_power_start_task(struct twali_power * p) {
+  xTaskCreate(twali_power_task, "power_manager", 10000, (void *) p, 30, NULL);
+}
+
+
+}
+

+ 37 - 0
src/twali_power.h

@@ -0,0 +1,37 @@
+#ifndef TWALI_POWER_H_INCLUDED
+#define TWALI_POWER_H_INCLUDED
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct twali_power;
+struct twali_task;
+
+struct twali_power * twali_power_make(struct twali_system *s);
+void twali_power_init(struct twali_power *p);
+void twali_power_interrupt(struct twali_power *p);
+void twali_power_run(struct twali_power *p);
+int twali_power_plugged_in(struct twali_power *p);
+int twali_power_charging(struct twali_power *p);
+int twali_power_low(struct twali_power *p);
+int twali_power_battery_percentage(struct twali_power *p);
+float twali_power_battery_current(struct twali_power *p);
+float twali_power_vbus_current(struct twali_power *p);
+float twali_power_last_interaction(struct twali_power *p);
+float twali_power_now(struct twali_power *p);
+void twali_power_up(struct twali_power *p);
+void twali_power_down(struct twali_power *p);
+void twali_power_suspend(struct twali_power *p);
+
+void twali_power_task(void* object);
+void twali_power_start_task(struct twali_power * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif

+ 0 - 0
src/twali_screen.cpp


+ 15 - 0
src/twali_screen.h

@@ -0,0 +1,15 @@
+#ifndef TWALI_SYSTEM_H_INCLUDED
+#define TWALI_SYSTEM_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct twali_screen
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

+ 63 - 0
src/twali_system.cpp

@@ -0,0 +1,63 @@
+
+#define LILYGO_TWATCH_2020_V1
+#include <TTGO.h>
+
+#define TWALI_INTERNAL
+#include "twali_system_internal.h"
+#include "twali_power.h"
+#include "twali_screen.h"
+
+
+extern "C" {
+
+static struct twali_system twali_system_singleton;
+static struct twali_system * twali_system_singleton_pointer = NULL;
+
+struct twali_power * twali_system_power(struct twali_system * s) {
+    return s->power;
+}
+
+
+void twali_system_power_interrupt(void) {
+    if (twali_system_singleton_pointer) {
+        twali_power_interrupt(twali_system_singleton_pointer->power);
+    }
+} 
+
+struct twali_system * twali_system_make(void) {
+    if (twali_system_singleton_pointer) {
+        return twali_system_singleton_pointer;
+    }    
+
+    twali_system_singleton.handle = TTGOClass::getWatch();
+    twali_system_singleton.handle->begin();
+    twali_system_singleton.handle->rtc->check();
+    twali_system_singleton.handle->bl->adjust(150);
+    twali_system_singleton.tft = twali_system_singleton.handle->eTFT;
+    twali_system_singleton.tft->fillScreen(TFT_BLUE);
+    twali_system_singleton.tft->setTextColor(TFT_WHITE, TFT_BLACK);
+    twali_system_singleton.tft->setTextFont(8);
+    twali_system_singleton.handle->openBL();  
+    twali_system_singleton.power  = twali_power_make(&twali_system_singleton);
+    pinMode(AXP202_INT, INPUT);
+    attachInterrupt(AXP202_INT, twali_system_power_interrupt, FALLING);
+
+    twali_system_singleton_pointer = &twali_system_singleton;
+    return twali_system_singleton_pointer;
+}
+
+void twali_system_start(struct twali_system * s) {
+      twali_power_start_task(s->power);
+}
+
+void twali_system_update(struct twali_system * s) {
+    vTaskDelay(10000);
+}
+
+
+
+void twali_system_wake_up(struct twali_system *s) {
+    // TODO
+}
+
+}

+ 24 - 0
src/twali_system.h

@@ -0,0 +1,24 @@
+#ifndef TWALI_SYSTEM_H_INCLUDED
+#define TWALI_SYSTEM_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct twali_system;
+struct twali_power;
+
+struct twali_power * twali_system_power(struct twali_system * s);
+
+void twali_system_power_interrupt(void);
+struct twali_system * twali_system_make(void);
+void twali_system_start(struct twali_system * s);
+void twali_system_update(struct twali_system * s);
+
+void twali_system_wake_up(struct twali_system *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 37 - 0
src/twali_system_internal.h

@@ -0,0 +1,37 @@
+#ifndef TWALI_SYSTEM_INTERNAL_H_INCLUDED
+#define TWALI_SYSTEM_INTERNAL_H_INCLUDED
+
+#ifndef TWALI_INTERNAL
+#error This header file is for internal use by TWALI.
+#endif
+
+#include <freertos/FreeRTOS.h>
+#include <freertos/task.h>
+#include <freertos/queue.h>
+
+#ifdef __cplusplus
+#define LILYGO_TWATCH_2020_V1
+#include <TTGO.h>
+#endif
+
+#include "twali_system.h"
+#include "twali_power.h"
+#include "twali_screen.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct twali_system {
+    TTGOClass * handle;
+    TFT_eSPI *tft;
+    struct twali_power * power;
+    struct twali_screen * screen;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

+ 100 - 0
src/twali_task.c

@@ -0,0 +1,100 @@
+#include "twali_task.h"
+
+#include "twali_system.h"
+#include "twali_power.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+#include "freertos/task.h"
+
+struct twali_task {
+    struct twali_system * system;
+    struct twali_task   * parent;
+    char                * name;
+    TaskHandle_t          task;
+    QueueHandle_t         queue;
+    void *                data;
+    int                   low_power_delay;
+    int                   delay;
+    void                  (*update)(struct twali_task *t);
+};
+
+void twali_task_task(void * object) {
+    struct twali_task * t = object;
+    struct twali_power * p = twali_system_power(t->system);
+    
+    for (;;) {
+        /* 
+        bool update_display = false;
+        unsigned int delay_time = 0;
+        */
+
+        if (twali_power_low(p) && (t->low_power_delay > 0)) {
+            vTaskDelay(t->low_power_delay / portTICK_PERIOD_MS);
+            continue;
+        }
+
+        /* twali_task_check_wake_time(t); */
+        if (t->update) {
+            t->update(t);
+        }    
+        vTaskDelay(t->delay / portTICK_PERIOD_MS);
+  }
+  printf("deleting task %s\n", t->name);
+  vTaskDelete(NULL);
+}
+
+int twali_task_start(struct twali_task * t, int priority) {
+    BaseType_t res;
+    res = xTaskCreate(twali_task_task, t->name, 10000, (void *) t, priority, &t->task);
+    return res == pdPASS;
+}
+
+/*
+class Actor {
+  public:
+    static TTGOClass *watch;
+    static TFT_eSPI *screen;
+    static PowerManager * power;
+    static TaskHandle_t display_task;
+
+    // system accessors
+    static void setPower(PowerManager * _power);
+    static void setDisplayTask(TaskHandle_t _display_task);
+    static void setWatch(TTGOClass * _watch);
+
+    // setup and init
+    bool needsInit();
+    void setup();
+    virtual void init() { }
+
+    // run and display
+    virtual void run() = 0;
+    void execute(unsigned int & sleep_time, bool & display_update);
+    virtual void display() = 0;
+    virtual const uint32_t displayIdentifier() = 0;
+
+    // low power considerations
+    virtual const bool runDuringLowPower() { return false; }
+    virtual const uint32_t delayDuringLowPower() { return 1000; }
+
+    // sleep-wake
+    static void systemWokeUp();
+    void checkWakeTime();
+    bool wakeUpRun();
+
+  protected:
+    unsigned int delay_time = 100;
+    bool refresh_display = false;
+
+  private:
+    static unsigned int woke_up_at;
+    unsigned int last_wake_up_tasked = 0;
+    bool wake_up_run = true;
+    bool inited = false;
+};
+
+void actorTask(void * object);
+void runActor(const char * name, Actor * object, int priority);
+
+*/

+ 13 - 0
src/twali_task.h

@@ -0,0 +1,13 @@
+#ifndef TWALI_PROCESS_H_INCLUDED
+#define TWALI_PROCESS_H_INCLUDED
+
+struct twali_task;
+struct twali_message;
+
+int twali_task_send(struct twali_task * from, 
+struct twali_task * to, 
+struct twali_message * msg);
+
+int twali_task_start(struct twali_task * t, int priority);
+
+#endif

+ 0 - 0
src/twali_touch.c


+ 0 - 0
src/twali_touch.h