Initialize git
This commit is contained in:
2850
hal/esp32/app_hal.cpp
Normal file
2850
hal/esp32/app_hal.cpp
Normal file
File diff suppressed because it is too large
Load Diff
88
hal/esp32/app_hal.h
Normal file
88
hal/esp32/app_hal.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef DRIVER_H
|
||||
#define DRIVER_H
|
||||
|
||||
#ifdef NO_WATCHFACES
|
||||
|
||||
|
||||
#elif ESPS3_1_69
|
||||
// 240x280 watchfaces
|
||||
|
||||
#define ENABLE_FACE_174 // (174)
|
||||
// #define ENABLE_FACE_228 // (228)
|
||||
#define ENABLE_FACE_1041 // (1041)
|
||||
// #define ENABLE_FACE_1167 // (1167)
|
||||
// #define ENABLE_FACE_1169 // (1169)
|
||||
// #define ENABLE_FACE_2051 // (2051)
|
||||
#define ENABLE_FACE_2151 // (2151)
|
||||
// #define ENABLE_FACE_3589 // (3589)
|
||||
|
||||
|
||||
#elif defined(VIEWE_SMARTRING) || defined(VIEWE_KNOB_15) || defined(ESPS3_1_75) || defined(ESPS3_2_06)
|
||||
|
||||
#define ENABLE_FACE_756_2_466 // (Red)
|
||||
#define ENABLE_FACE_RADAR_466 // (Radar)
|
||||
#define ENABLE_FACE_75_2 // (Analog)
|
||||
#define ENABLE_FACE_34_2 // (Shadow)
|
||||
|
||||
#else
|
||||
// 240x240 watchfaces
|
||||
|
||||
// #define ENABLE_FACE_ELECROW // elecrow analog
|
||||
// #define ENABLE_FACE_34_2 // (Shadow)
|
||||
// #define ENABLE_FACE_75_2 // (Analog)
|
||||
// #define ENABLE_FACE_79_2 // (Blue)
|
||||
// #define ENABLE_FACE_116_2 // (Outline)
|
||||
// #define ENABLE_FACE_756_2 // (Red)
|
||||
// #define ENABLE_FACE_B_W_RESIZED // (B & W)
|
||||
// #define ENABLE_FACE_KENYA // (Kenya)
|
||||
// #define ENABLE_FACE_PIXEL_RESIZED // (Pixel)
|
||||
// #define ENABLE_FACE_RADAR // (Radar)
|
||||
// #define ENABLE_FACE_SMART_RESIZED // (Smart)
|
||||
// #define ENABLE_FACE_TIX_RESIZED // (Tix)
|
||||
// #define ENABLE_FACE_WFB_RESIZED // (WFB)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ESPS3_1_69) || defined(ESPS3_1_28) || defined(VIEWE_SMARTRING) || defined(ESPS3_1_75) || defined(ESPS3_2_06)
|
||||
#define ENABLE_APP_QMI8658C
|
||||
#define ENABLE_APP_ATTITUDE
|
||||
#endif
|
||||
|
||||
#if defined(ELECROW_C3)
|
||||
#define ENABLE_RTC
|
||||
#endif
|
||||
|
||||
#if defined(M5_STACK_DIAL) || defined(VIEWE_KNOB_15)
|
||||
#define ENABLE_APP_RANGE
|
||||
#endif
|
||||
|
||||
// #define ENABLE_APP_CALENDAR
|
||||
// #define ENABLE_APP_SAMPLE
|
||||
// #define ENABLE_GAME_TASK
|
||||
// #define ENABLE_GAME_RACING
|
||||
|
||||
// #define ENABLE_GAME_SIMON
|
||||
|
||||
// #define ENABLE_APP_NAVIGATION
|
||||
// #define ENABLE_APP_CONTACTS
|
||||
#define ENABLE_APP_TIMER
|
||||
#define ENABLE_APP_NOTES
|
||||
#define ENABLE_WIFI_SERVER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
void hal_setup(void);
|
||||
void hal_loop(void);
|
||||
|
||||
|
||||
void vibratePin(bool state);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*DRIVER_H*/
|
||||
106
hal/esp32/displays/generic.hpp
Normal file
106
hal/esp32/displays/generic.hpp
Normal file
@@ -0,0 +1,106 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LGFX_USE_V1
|
||||
#include "Arduino.h"
|
||||
#include <LovyanGFX.hpp>
|
||||
|
||||
#include "pins.h"
|
||||
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
|
||||
lgfx::Panel_GC9A01 _panel_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
lgfx::Touch_CST816S _touch_instance;
|
||||
|
||||
public:
|
||||
LGFX(void)
|
||||
{
|
||||
{
|
||||
auto cfg = _bus_instance.config();
|
||||
|
||||
// SPI bus settings
|
||||
cfg.spi_host = SPI; // Select the SPI to use ESP32-S2,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
|
||||
// * Due to the ESP-IDF version upgrade, VSPI_HOST, The HSPI_HOST specification is deprecated, so if you get an error, use SPI2_HOST or SPI3_HOST instead.
|
||||
cfg.spi_mode = 0; // Set SPI communication mode (0 ~ 3)
|
||||
cfg.freq_write = 80000000; // SPI time (up to 80MHz, four or five inputs divided by 80MHz to get an integer)
|
||||
cfg.freq_read = 20000000; // SPI time when connected cfg.spi_3wire = true; // Set true if receiving is done via MOSI pin
|
||||
cfg.use_lock = true; // Usage lock time setting true
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // Set the DMA channel to use (0=DMA not used / 1=1ch / 2=ch / SPI_DMA_CH_AUTO=automatic setting) // * Due to the ESP-IDF version upgrade, SPI_DMA_CH_AUTO (automatic setting) is now recommended for the DMA channel. Specifying 1ch or 2ch is no longer recommended.
|
||||
cfg.pin_sclk = SCLK; // Set the SPI SCLK pin number
|
||||
cfg.pin_mosi = MOSI; // Set the SPI CLK pin number
|
||||
cfg.pin_miso = MISO; // Set the SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = DC; // Set the SPI D/C pin number (-1 = disable)
|
||||
_bus_instance.config(cfg); // Reflect the setting value to the bus.
|
||||
_panel_instance.setBus(&_bus_instance); // Set the bus to the panel.
|
||||
}
|
||||
|
||||
{ // Set the display panel control.
|
||||
auto cfg = _panel_instance.config(); // Get the structure for display panel settings.
|
||||
|
||||
cfg.pin_cs = CS; // Pin number to which CS is connected (-1 = disable)
|
||||
cfg.pin_rst = RST; // Pin number to which RST is connected (-1 = disable)
|
||||
cfg.pin_busy = -1; // Pin number to which BUSY is connected (-1 = disable)
|
||||
|
||||
/* The following settings are set to general initial values for each panel, so try commenting out any items you are unsure of. */
|
||||
|
||||
cfg.memory_width = SCREEN_WIDTH; // Maximum width supported by driver IC
|
||||
cfg.memory_height = SCREEN_HEIGHT; // Maximum height supported by driver IC
|
||||
cfg.panel_width = SCREEN_WIDTH; // Actual displayable width
|
||||
cfg.panel_height = SCREEN_HEIGHT; // Actual displayable height
|
||||
cfg.offset_x = OFFSET_X; // Panel offset in X direction
|
||||
cfg.offset_y = OFFSET_Y; // Panel offset in Y direction
|
||||
cfg.offset_rotation = 0; // Value 0~7 in rotation direction (4~7 is inverted)
|
||||
cfg.dummy_read_pixel = 8; // Virtual number of positions read before reading image
|
||||
cfg.dummy_read_bits = 1; // The number of imaginary words other than the image element
|
||||
cfg.readable = false; // As long as the number of acquisitions is as high as possible, the setting is true
|
||||
cfg.invert = true; // As a result, the brightness and darkness of the face plate is reversed, and the setting is true
|
||||
cfg.rgb_order = RGB_ORDER; // As a result, the red color and the blue color are replaced on the face plate, and the setting is true
|
||||
cfg.dlen_16bit = false; // From 16th position to 16th position, the length of the number of transfers is set to true
|
||||
cfg.bus_shared = false; // How to use drawJpgFile (e.g. summary control)
|
||||
|
||||
_panel_instance.config(cfg);
|
||||
}
|
||||
|
||||
{ // Set backlight control. (delete if not necessary)
|
||||
|
||||
auto cfg = _light_instance.config(); // Get the structure for backlight configuration.
|
||||
|
||||
cfg.pin_bl = BL; // pin number to which the backlight is connected
|
||||
cfg.invert = false; // true to invert backlight brightness
|
||||
cfg.freq = 44100; // backlight PWM frequency
|
||||
cfg.pwm_channel = 1; // PWM channel number to use
|
||||
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance); // Sets the backlight to the panel.
|
||||
}
|
||||
|
||||
{ // Sets touchscreen control. (Delete if not needed)
|
||||
|
||||
auto cfg = _touch_instance.config();
|
||||
cfg.x_min = 0; // Minimum X value obtained from touch screen (raw value)
|
||||
cfg.x_max = SCREEN_WIDTH; // Maximum X value obtained from touch screen (raw value)
|
||||
cfg.y_min = 0; // Minimum Y value obtained from touch screen (raw value)
|
||||
cfg.y_max = SCREEN_HEIGHT; // Maximum Y value obtained from touch screen (raw value)
|
||||
cfg.pin_int = TP_INT; // Pin number to which INT is connected
|
||||
cfg.pin_rst = TP_RST;
|
||||
cfg.bus_shared = true; // Set true if using a common bus with the screen
|
||||
cfg.offset_rotation = 0; // Adjust if display and touch orientation do not match. Set to a value between 0 and 7
|
||||
|
||||
cfg.i2c_port = 0; // Select the I2C to use (0 or 1)
|
||||
cfg.i2c_addr = 0x15; // I2C device address number
|
||||
cfg.pin_sda = I2C_SDA; // Pin number to which SDA is connected
|
||||
cfg.pin_scl = I2C_SCL; // Pin number to which SCL is connected
|
||||
cfg.freq = 400000; // Set the I2C clock
|
||||
_touch_instance.config(cfg);
|
||||
_panel_instance.setTouch(&_touch_instance); // Set the touch screen to the panel.
|
||||
}
|
||||
|
||||
setPanel(&_panel_instance); // Set the panel to use.
|
||||
}
|
||||
};
|
||||
|
||||
LGFX tft;
|
||||
294
hal/esp32/displays/pins.h
Normal file
294
hal/esp32/displays/pins.h
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Felix Biego
|
||||
|
||||
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.
|
||||
|
||||
______________ _____
|
||||
___ __/___ /_ ___(_)_____ _______ _______
|
||||
__ /_ __ __ \__ / _ _ \__ __ `/_ __ \
|
||||
_ __/ _ /_/ /_ / / __/_ /_/ / / /_/ /
|
||||
/_/ /_.___/ /_/ \___/ _\__, / \____/
|
||||
/____/
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ELECROW_C3
|
||||
|
||||
// screen configs
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define OFFSET_X 0
|
||||
#define OFFSET_Y 0
|
||||
#define RGB_ORDER false
|
||||
|
||||
// touch
|
||||
#define I2C_SDA 4
|
||||
#define I2C_SCL 5
|
||||
#define TP_INT 0
|
||||
#define TP_RST -1
|
||||
|
||||
// display
|
||||
#define SPI SPI2_HOST
|
||||
|
||||
#define SCLK 6
|
||||
#define MOSI 7
|
||||
#define MISO -1
|
||||
#define DC 2
|
||||
#define CS 10
|
||||
#define RST -1
|
||||
|
||||
#define BL -1 // unused (connected on IO extender)
|
||||
#define VIBRATION_PIN 0 // dummy (connected on IO extender)
|
||||
|
||||
#define BUZZER_PIN 3
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
#elif ESPC3
|
||||
|
||||
// screen configs
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define OFFSET_X 0
|
||||
#define OFFSET_Y 0
|
||||
#define RGB_ORDER false
|
||||
|
||||
// touch
|
||||
#define I2C_SDA 4
|
||||
#define I2C_SCL 5
|
||||
#define TP_INT 0
|
||||
#define TP_RST 1
|
||||
|
||||
// display
|
||||
#define SPI SPI2_HOST
|
||||
|
||||
#define SCLK 6
|
||||
#define MOSI 7
|
||||
#define MISO -1
|
||||
#define DC 2
|
||||
#define CS 10
|
||||
#define RST -1
|
||||
|
||||
#define BL 3
|
||||
|
||||
#define BUZZER_PIN -1
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
#elif ESPS3_1_28
|
||||
|
||||
// screen configs
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define OFFSET_X 0
|
||||
#define OFFSET_Y 0
|
||||
#define RGB_ORDER false
|
||||
|
||||
// touch
|
||||
#define I2C_SDA 6
|
||||
#define I2C_SCL 7
|
||||
#define TP_INT 5
|
||||
#define TP_RST 13
|
||||
|
||||
// display
|
||||
#define SPI SPI2_HOST
|
||||
|
||||
#define SCLK 10
|
||||
#define MOSI 11
|
||||
#define MISO 12
|
||||
#define DC 8
|
||||
#define CS 9
|
||||
#define RST 14
|
||||
|
||||
#define BL 2
|
||||
|
||||
#define BUZZER_PIN -1
|
||||
|
||||
#define MAX_FILE_OPEN 50
|
||||
|
||||
#elif ESPS3_1_69
|
||||
|
||||
// screen configs
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 280
|
||||
#define OFFSET_X 0
|
||||
#define OFFSET_Y 20
|
||||
#define RGB_ORDER true
|
||||
|
||||
// touch
|
||||
#define I2C_SDA 11
|
||||
#define I2C_SCL 10
|
||||
#define TP_INT 14
|
||||
#define TP_RST 13
|
||||
|
||||
// display
|
||||
#define SPI SPI2_HOST
|
||||
|
||||
#define SCLK 6
|
||||
#define MOSI 7
|
||||
#define MISO -1
|
||||
#define DC 4
|
||||
#define CS 5
|
||||
#define RST 8
|
||||
|
||||
#define BL 15
|
||||
|
||||
#define BUZZER_PIN -1 //33
|
||||
|
||||
#define MAX_FILE_OPEN 20
|
||||
|
||||
#elif ESPS3_2_06
|
||||
|
||||
#define SCREEN_WIDTH 410
|
||||
#define SCREEN_HEIGHT 502
|
||||
|
||||
#define LCD_CS 12
|
||||
#define LCD_SCK 11
|
||||
#define LCD_SD0 4
|
||||
#define LCD_SD1 5
|
||||
#define LCD_SD2 6
|
||||
#define LCD_SD3 7
|
||||
#define LCD_RST 8
|
||||
|
||||
#define TOUCH_SDA 15
|
||||
#define TOUCH_SCL 14
|
||||
#define TOUCH_RST 9
|
||||
#define TOUCH_IRQ 38
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
#elif M5_STACK_DIAL
|
||||
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 240
|
||||
|
||||
#define BUZZER_PIN 3
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
#elif ESPS3_1_75
|
||||
|
||||
#define SCREEN_WIDTH 466
|
||||
#define SCREEN_HEIGHT 466
|
||||
|
||||
#define LCD_CS 12
|
||||
#define LCD_SCK 38
|
||||
#define LCD_SD0 4
|
||||
#define LCD_SD1 5
|
||||
#define LCD_SD2 6
|
||||
#define LCD_SD3 7
|
||||
#define LCD_RST 39
|
||||
|
||||
#define TOUCH_SDA 15
|
||||
#define TOUCH_SCL 14
|
||||
#define TOUCH_RST 40
|
||||
#define TOUCH_IRQ 11
|
||||
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
|
||||
#elif M5_STACK_DIAL
|
||||
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 240
|
||||
|
||||
#define BUZZER_PIN 3
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
#elif VIEWE_SMARTRING
|
||||
#define SCREEN_WIDTH 466
|
||||
#define SCREEN_HEIGHT 466
|
||||
|
||||
#define LCD_CS 7
|
||||
#define LCD_SCK 13
|
||||
#define LCD_SD0 12
|
||||
#define LCD_SD1 8
|
||||
#define LCD_SD2 14
|
||||
#define LCD_SD3 9
|
||||
#define LCD_RST 11
|
||||
|
||||
#define TOUCH_SDA 41
|
||||
#define TOUCH_SCL 45
|
||||
#define TOUCH_RST 46
|
||||
#define TOUCH_IRQ 42
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
#elif VIEWE_KNOB_15
|
||||
#define SCREEN_WIDTH 466
|
||||
#define SCREEN_HEIGHT 466
|
||||
|
||||
#define LCD_CS 12
|
||||
#define LCD_SCK 10
|
||||
#define LCD_SD0 13
|
||||
#define LCD_SD1 11
|
||||
#define LCD_SD2 14
|
||||
#define LCD_SD3 9
|
||||
#define LCD_RST 8
|
||||
#define LCD_EN 17
|
||||
|
||||
#define TOUCH_SDA 1
|
||||
#define TOUCH_SCL 3
|
||||
#define TOUCH_RST 2
|
||||
#define TOUCH_IRQ 4
|
||||
|
||||
#define ENCODER_A 6
|
||||
#define ENCODER_B 5
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
|
||||
#else
|
||||
|
||||
// screen configs
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define OFFSET_X 0
|
||||
#define OFFSET_Y 0
|
||||
#define RGB_ORDER false
|
||||
|
||||
// touch
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
#define TP_INT 14
|
||||
#define TP_RST 5
|
||||
|
||||
// display
|
||||
#define SPI VSPI_HOST
|
||||
|
||||
#define SCLK 18
|
||||
#define MOSI 23
|
||||
#define MISO -1
|
||||
#define DC 4
|
||||
#define CS 15
|
||||
#define RST 13
|
||||
|
||||
#define BL 2
|
||||
|
||||
#define BUZZER_PIN -1
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
#endif
|
||||
123
hal/esp32/displays/viewe.hpp
Normal file
123
hal/esp32/displays/viewe.hpp
Normal file
@@ -0,0 +1,123 @@
|
||||
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "Arduino_GFX_Library.h"
|
||||
#ifdef ESPS3_2_06
|
||||
#include "TouchDrvFT6X36.hpp"
|
||||
#else
|
||||
#include "TouchDrvCSTXXX.hpp"
|
||||
#endif
|
||||
#include "pins.h"
|
||||
|
||||
#define TFT_BLACK 0x00000
|
||||
|
||||
class DisplayWrapper
|
||||
{
|
||||
public:
|
||||
Arduino_GFX *gfx;
|
||||
|
||||
#ifdef ESPS3_2_06
|
||||
TouchDrvFT6X36 touch;
|
||||
#else
|
||||
TouchDrvCSTXXX touch;
|
||||
#endif
|
||||
|
||||
DisplayWrapper()
|
||||
{
|
||||
|
||||
static Arduino_DataBus *bus = new Arduino_ESP32QSPI(
|
||||
LCD_CS /* CS */, LCD_SCK /* SCK */, LCD_SD0 /* SDIO0 */, LCD_SD1 /* SDIO1 */,
|
||||
LCD_SD2 /* SDIO2 */, LCD_SD3 /* SDIO3 */);
|
||||
|
||||
gfx = new Arduino_CO5300(
|
||||
bus,
|
||||
LCD_RST /* RST */,
|
||||
0 /* rotation */,
|
||||
false /* IPS */,
|
||||
SCREEN_WIDTH,
|
||||
SCREEN_HEIGHT,
|
||||
#ifdef ESPS3_2_06
|
||||
22 /* col_offset1 */,
|
||||
#else
|
||||
6 /* col_offset1 */,
|
||||
#endif
|
||||
0 /* row_offset1 */,
|
||||
0 /* col_offset2 */,
|
||||
0 /* row_offset2 */
|
||||
);
|
||||
}
|
||||
|
||||
bool init(void)
|
||||
{
|
||||
#ifdef LCD_EN
|
||||
pinMode(LCD_EN, OUTPUT);
|
||||
digitalWrite(LCD_EN, HIGH);
|
||||
#endif
|
||||
bool state = gfx->begin();
|
||||
touch.setPins(TOUCH_RST, TOUCH_IRQ);
|
||||
|
||||
#if defined(ESPS3_1_75)
|
||||
touch.begin(Wire, 0x5A, TOUCH_SDA, TOUCH_SCL);
|
||||
touch.setMaxCoordinates(466, 466);
|
||||
touch.setMirrorXY(true, true);
|
||||
#elif defined(ESPS3_2_06)
|
||||
touch.begin(Wire, 0x38, TOUCH_SDA, TOUCH_SCL);
|
||||
#else
|
||||
touch.begin(Wire, 0x15, TOUCH_SDA, TOUCH_SCL);
|
||||
#endif
|
||||
return state;
|
||||
}
|
||||
|
||||
void initDMA(void) {}
|
||||
|
||||
void fillScreen(uint16_t color)
|
||||
{
|
||||
gfx->fillScreen(color);
|
||||
}
|
||||
|
||||
void setRotation(uint8_t rotation)
|
||||
{
|
||||
// gfx->setRotation(rotation); // Not supported in CO5300
|
||||
}
|
||||
|
||||
void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data)
|
||||
{
|
||||
gfx->draw16bitBeRGBBitmap(x, y, data, w, h);
|
||||
}
|
||||
|
||||
void pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data)
|
||||
{
|
||||
gfx->draw16bitBeRGBBitmap(x, y, data, w, h);
|
||||
}
|
||||
|
||||
void startWrite(void) {}
|
||||
|
||||
uint32_t getStartCount(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void endWrite(void) {}
|
||||
|
||||
void setBrightness(uint8_t brightness)
|
||||
{
|
||||
((Arduino_CO5300 *)gfx)->setBrightness(brightness);
|
||||
}
|
||||
|
||||
void writePixel(int32_t x, int32_t y, const uint16_t color)
|
||||
{
|
||||
gfx->writePixel(x, y, color);
|
||||
}
|
||||
|
||||
bool getTouch(uint16_t *x, uint16_t *y)
|
||||
{
|
||||
int16_t x_arr[5], y_arr[5];
|
||||
uint8_t touched = touch.getPoint(x_arr, y_arr, touch.getSupportTouchPoint());
|
||||
*x = x_arr[0];
|
||||
*y = y_arr[0];
|
||||
return touched;
|
||||
}
|
||||
};
|
||||
|
||||
DisplayWrapper tft;
|
||||
333
hal/esp32/feedback.cpp
Normal file
333
hal/esp32/feedback.cpp
Normal file
@@ -0,0 +1,333 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "feedback.h"
|
||||
#include "app_hal.h"
|
||||
#include "displays/pins.h"
|
||||
|
||||
// A struct to hold a sequence of notes
|
||||
struct NoteSequence
|
||||
{
|
||||
Note notes[MAX_NOTES_PER_SEQUENCE];
|
||||
int count;
|
||||
int repeat;
|
||||
};
|
||||
|
||||
struct VibPattern
|
||||
{
|
||||
Vibration steps[MAX_VIB_PATTERN_LENGTH];
|
||||
int count;
|
||||
};
|
||||
|
||||
QueueHandle_t noteQueue;
|
||||
TaskHandle_t toneTaskHandle = nullptr;
|
||||
volatile bool playing = false;
|
||||
volatile ToneType currentToneType = T_USER;
|
||||
volatile bool forceInterrupt = false;
|
||||
|
||||
QueueHandle_t vibQueue;
|
||||
TaskHandle_t vibTaskHandle = nullptr;
|
||||
volatile bool vibrating = false;
|
||||
|
||||
Note tone_melody[] = {
|
||||
{440, 300}, // A4
|
||||
{0, 150}, // Rest
|
||||
{494, 300}, // B4
|
||||
{0, 150}, // Rest
|
||||
{523, 300}, // C5
|
||||
{0, 300}, // Longer rest
|
||||
{587, 300} // D5
|
||||
};
|
||||
|
||||
Note tone_startup[] = {
|
||||
{TONE_EN * 2, 170},
|
||||
{TONE_FS * 2, 170},
|
||||
{TONE_GN * 2, 170}};
|
||||
|
||||
// 📩 Notification Received (Double Beep)
|
||||
Note tone_notification[] = {
|
||||
{1000, 100},
|
||||
{0, 100},
|
||||
{1200, 100},
|
||||
};
|
||||
|
||||
// 📞 Call Received (Melody)
|
||||
Note tone_call[] = {
|
||||
{880, 200},
|
||||
{988, 200},
|
||||
{1046, 200},
|
||||
{0, 100},
|
||||
{1046, 300},
|
||||
{880, 200},
|
||||
{988, 200},
|
||||
{0, 200},
|
||||
};
|
||||
|
||||
// ⏰ Alarm Ring
|
||||
Note tone_alarm[] = {
|
||||
{1500, 150},
|
||||
{0, 100},
|
||||
{1500, 150},
|
||||
{0, 100},
|
||||
{1500, 150},
|
||||
{0, 100},
|
||||
{2000, 300},
|
||||
};
|
||||
|
||||
Note tone_off[] = {
|
||||
{0, 50}};
|
||||
|
||||
// ⏲️ Timer Ended
|
||||
Note tone_timer[] = {
|
||||
{880, 200},
|
||||
{0, 100},
|
||||
{660, 200},
|
||||
{0, 100},
|
||||
{880, 200},
|
||||
{0, 100},
|
||||
};
|
||||
|
||||
// 🔘 Button Press
|
||||
Note tone_button[] = {
|
||||
{1000, 50},
|
||||
};
|
||||
|
||||
// 🎮 Simon Says - Intro
|
||||
Note tone_simonsays_intro[] = {
|
||||
{659, 150},
|
||||
{784, 150},
|
||||
{987, 150},
|
||||
{1319, 200},
|
||||
};
|
||||
|
||||
// 🎮 Simon Says - Game Over
|
||||
Note tone_simonsays_gameover[] = {
|
||||
{659, 300},
|
||||
{622, 300},
|
||||
{587, 300},
|
||||
{554, 400},
|
||||
};
|
||||
|
||||
Vibration v_notif[] = {
|
||||
{true, 100}, // ON for 200ms
|
||||
{false, 50}, // OFF for 100ms
|
||||
};
|
||||
|
||||
Vibration pattern[] = {
|
||||
{true, 200}, // ON for 200ms
|
||||
{false, 100}, // OFF for 100ms
|
||||
{true, 300}, // ON for 300ms
|
||||
{false, 200}, // OFF for 200ms
|
||||
};
|
||||
|
||||
void toneTask(void *param)
|
||||
{
|
||||
#if defined(BUZZER_PIN) && (BUZZER_PIN != -1)
|
||||
|
||||
NoteSequence sequence;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (xQueueReceive(noteQueue, &sequence, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
playing = true;
|
||||
|
||||
ledcAttachPin(BUZZER_PIN, BUZZER_CHANNEL);
|
||||
|
||||
if (sequence.repeat == 0)
|
||||
{
|
||||
sequence.repeat = 1;
|
||||
}
|
||||
|
||||
for (int r = 0; r < sequence.repeat; r++)
|
||||
{
|
||||
for (int n = 0; n < sequence.count; n++)
|
||||
{
|
||||
if (forceInterrupt)
|
||||
{
|
||||
forceInterrupt = false;
|
||||
break;
|
||||
}
|
||||
|
||||
int pitch = sequence.notes[n].pitch;
|
||||
int duration = sequence.notes[n].duration;
|
||||
|
||||
if (pitch > 0)
|
||||
{
|
||||
ledcWriteTone(BUZZER_CHANNEL, pitch);
|
||||
}
|
||||
else
|
||||
{
|
||||
ledcWriteTone(BUZZER_CHANNEL, 0); // Rest
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(duration));
|
||||
}
|
||||
}
|
||||
|
||||
ledcDetachPin(BUZZER_PIN);
|
||||
|
||||
playing = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void vibrationTask(void *param)
|
||||
{
|
||||
#if defined(VIBRATION_PIN) && (VIBRATION_PIN != -1)
|
||||
#ifndef ELECROW_C3
|
||||
pinMode(VIBRATION_PIN, OUTPUT);
|
||||
#endif
|
||||
VibPattern pattern;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (xQueueReceive(vibQueue, &pattern, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
vibrating = true;
|
||||
|
||||
#ifdef ELECROW_C3
|
||||
vibratePin(true);
|
||||
for (int i = 0; i < pattern.count; i++)
|
||||
{
|
||||
delay(pattern.steps[i].duration);
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < pattern.count; i++)
|
||||
{
|
||||
vibratePin(pattern.steps[i].on);
|
||||
delay(pattern.steps[i].duration);
|
||||
}
|
||||
#endif
|
||||
|
||||
vibratePin(false);
|
||||
vibrating = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void startToneSystem()
|
||||
{
|
||||
#if defined(BUZZER_PIN) && (BUZZER_PIN != -1)
|
||||
|
||||
if (!noteQueue)
|
||||
{
|
||||
noteQueue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(NoteSequence));
|
||||
}
|
||||
if (!toneTaskHandle)
|
||||
{
|
||||
xTaskCreatePinnedToCore(toneTask, "toneTask", 2048, nullptr, 1, &toneTaskHandle, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void startVibrationSystem()
|
||||
{
|
||||
#if defined(VIBRATION_PIN) && (VIBRATION_PIN != -1)
|
||||
if (!vibQueue)
|
||||
{
|
||||
vibQueue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(VibPattern));
|
||||
}
|
||||
if (!vibTaskHandle)
|
||||
{
|
||||
xTaskCreatePinnedToCore(vibrationTask, "vibrationTask", 2048, nullptr, 1, &vibTaskHandle, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void feedbackTone(Note *notes, int count, ToneType type, int repeat)
|
||||
{
|
||||
#if defined(BUZZER_PIN) && (BUZZER_PIN != -1)
|
||||
if (check_alert_state(ALERT_SOUND))
|
||||
{
|
||||
if (!noteQueue)
|
||||
startToneSystem();
|
||||
|
||||
if (count > MAX_NOTES_PER_SEQUENCE)
|
||||
count = MAX_NOTES_PER_SEQUENCE;
|
||||
|
||||
if (playing && currentToneType >= type)
|
||||
{
|
||||
// If the current tone is of the same or higher priority, reset the queue
|
||||
forceInterrupt = true;
|
||||
xQueueReset(noteQueue);
|
||||
}
|
||||
|
||||
NoteSequence sequence;
|
||||
sequence.count = count;
|
||||
sequence.repeat = repeat;
|
||||
memcpy(sequence.notes, notes, count * sizeof(Note));
|
||||
|
||||
xQueueSend(noteQueue, &sequence, 0);
|
||||
currentToneType = type;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void feedbackVibrate(Vibration *steps, int count, bool force)
|
||||
{
|
||||
#if defined(VIBRATION_PIN) && (VIBRATION_PIN != -1)
|
||||
if (check_alert_state(ALERT_VIBRATE))
|
||||
{
|
||||
if (!vibQueue)
|
||||
startVibrationSystem();
|
||||
|
||||
if (count > MAX_VIB_PATTERN_LENGTH)
|
||||
count = MAX_VIB_PATTERN_LENGTH;
|
||||
|
||||
if (force && vibrating)
|
||||
{
|
||||
xQueueReset(vibQueue);
|
||||
}
|
||||
|
||||
VibPattern pattern;
|
||||
pattern.count = count;
|
||||
memcpy(pattern.steps, steps, count * sizeof(Vibration));
|
||||
|
||||
xQueueSend(vibQueue, &pattern, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void feedbackRun(ToneType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case T_CALLS:
|
||||
feedbackTone(tone_call, 8, T_CALLS, 3);
|
||||
feedbackVibrate(pattern, 4, true);
|
||||
break;
|
||||
case T_NOTIFICATION:
|
||||
feedbackTone(tone_notification, 3, T_NOTIFICATION, 2);
|
||||
feedbackVibrate(v_notif, 2, true);
|
||||
break;
|
||||
case T_TIMER:
|
||||
feedbackTone(tone_alarm, 7, T_TIMER);
|
||||
feedbackVibrate(pattern, 4, true);
|
||||
break;
|
||||
case T_ALARM:
|
||||
feedbackTone(tone_timer, 6, T_TIMER, 3);
|
||||
feedbackVibrate(pattern, 4, true);
|
||||
break;
|
||||
case T_SYSTEM:
|
||||
feedbackTone(tone_button, 1, T_SYSTEM);
|
||||
feedbackVibrate(pattern, 2, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (check_alert_state(ALERT_SCREEN))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case T_CALLS:
|
||||
screen_on(50);
|
||||
break;
|
||||
default:
|
||||
screen_on();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
hal/esp32/feedback.h
Normal file
82
hal/esp32/feedback.h
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
|
||||
#ifndef FEEDBACK_H
|
||||
#define FEEDBACK_H
|
||||
|
||||
#define TONE_AN 220 // 440 Hz
|
||||
#define TONE_AS 233 // 466 Hz
|
||||
#define TONE_BN 247 // 493 Hz
|
||||
#define TONE_CN 261 // 523 Hz
|
||||
#define TONE_CS 277 // 554 Hz
|
||||
#define TONE_DN 294 // 588 Hz
|
||||
#define TONE_DS 311 // 622 Hz
|
||||
#define TONE_EN 330 // 658 Hz
|
||||
#define TONE_FN 349 // 698 Hz
|
||||
#define TONE_FS 370 // 740 Hz
|
||||
#define TONE_GN 392 // 784 Hz
|
||||
#define TONE_GS 415 // 830 Hz
|
||||
|
||||
#define BUZZER_CHANNEL 0
|
||||
|
||||
#define MAX_QUEUE_SIZE 8
|
||||
#define MAX_NOTES_PER_SEQUENCE 16
|
||||
|
||||
#define MAX_VIB_PATTERN_LENGTH 16
|
||||
|
||||
enum ToneType
|
||||
{
|
||||
T_ALARM = 0,
|
||||
T_TIMER,
|
||||
T_CALLS,
|
||||
T_NOTIFICATION,
|
||||
T_SYSTEM,
|
||||
T_USER
|
||||
};
|
||||
|
||||
struct Note
|
||||
{
|
||||
int pitch;
|
||||
int duration;
|
||||
};
|
||||
|
||||
struct Vibration
|
||||
{
|
||||
bool on;
|
||||
int duration;
|
||||
};
|
||||
|
||||
enum AlertType
|
||||
{
|
||||
ALERT_POPUP = 0x01,
|
||||
ALERT_SCREEN = 0x02,
|
||||
ALERT_SOUND = 0x04,
|
||||
ALERT_VIBRATE = 0x08
|
||||
};
|
||||
|
||||
extern Vibration pattern[];
|
||||
extern Vibration v_notif[];
|
||||
|
||||
extern Note tone_startup[];
|
||||
extern Note tone_off[];
|
||||
extern Note tone_notification[];
|
||||
extern Note tone_call[];
|
||||
extern Note tone_alarm[];
|
||||
extern Note tone_timer[];
|
||||
extern Note tone_button[];
|
||||
|
||||
extern Note tone_simonsays_intro[];
|
||||
extern Note tone_simonsays_gameover[];
|
||||
|
||||
void startToneSystem();
|
||||
void startVibrationSystem();
|
||||
|
||||
void feedbackTone(Note *notes, int count, ToneType type, int repeat = 0);
|
||||
void feedbackVibrate(Vibration *steps, int count, bool force = false);
|
||||
|
||||
void screen_on(long extra = 0);
|
||||
|
||||
void feedbackRun(ToneType type);
|
||||
|
||||
bool check_alert_state(AlertType type);
|
||||
|
||||
#endif
|
||||
355
hal/esp32/wifi_server.cpp
Normal file
355
hal/esp32/wifi_server.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* @file wifi_server.cpp
|
||||
* @brief WiFi Access Point + HTTP WebServer for ESP32 Watch
|
||||
* Provides time sync and notes management via web interface
|
||||
*/
|
||||
|
||||
#include "app_hal.h"
|
||||
|
||||
#ifdef ENABLE_WIFI_SERVER
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <ChronosESP32.h>
|
||||
#include "wifi_server.h"
|
||||
#include "../src/apps/notes/notes_storage.h"
|
||||
|
||||
/* WiFi AP Configuration */
|
||||
#define WIFI_SSID "ESP32-Watch"
|
||||
#define WIFI_PASS "12345678"
|
||||
|
||||
/* External references */
|
||||
extern ChronosESP32 watch;
|
||||
|
||||
static WebServer server(80);
|
||||
static bool serverRunning = false;
|
||||
|
||||
/* ──────────────────────────────────────────────
|
||||
* Embedded HTML Page (PROGMEM)
|
||||
* ────────────────────────────────────────────── */
|
||||
|
||||
static const char index_html[] PROGMEM = R"rawliteral(
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ESP32 Watch Manager</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:'Segoe UI',system-ui,sans-serif;background:#0a0a1a;color:#e0e0e0;min-height:100vh;padding:16px}
|
||||
.container{max-width:600px;margin:0 auto}
|
||||
h1{text-align:center;color:#ffcc00;margin-bottom:24px;font-size:1.5em}
|
||||
h2{color:#ffcc00;margin-bottom:12px;font-size:1.1em;border-bottom:1px solid #333;padding-bottom:6px}
|
||||
.card{background:#1a1a2e;border-radius:12px;padding:16px;margin-bottom:16px}
|
||||
.btn{background:#ffcc00;color:#0a0a1a;border:none;padding:10px 20px;border-radius:8px;cursor:pointer;font-weight:600;font-size:0.95em;transition:background 0.2s}
|
||||
.btn:hover{background:#ffd633}
|
||||
.btn-danger{background:#cc3333;color:#fff}
|
||||
.btn-danger:hover{background:#ff4444}
|
||||
.btn-sm{padding:6px 12px;font-size:0.85em}
|
||||
input,textarea{width:100%;padding:10px;border-radius:8px;border:1px solid #333;background:#0d0d20;color:#e0e0e0;font-size:0.95em;margin-bottom:8px;font-family:inherit}
|
||||
input:focus,textarea:focus{outline:none;border-color:#ffcc00}
|
||||
textarea{resize:vertical;min-height:80px}
|
||||
.note-item{background:#0d0d20;border-radius:8px;padding:12px;margin-bottom:8px;position:relative}
|
||||
.note-item h3{color:#ffcc00;font-size:0.95em;margin-bottom:4px}
|
||||
.note-item p{color:#aaa;font-size:0.9em;white-space:pre-wrap;word-break:break-word}
|
||||
.note-item .del-btn{position:absolute;top:8px;right:8px}
|
||||
.status{text-align:center;padding:8px;color:#88ff88;font-size:0.9em;min-height:28px}
|
||||
.status.error{color:#ff8888}
|
||||
.info{display:flex;justify-content:space-between;flex-wrap:wrap;gap:8px;font-size:0.9em;color:#888;margin-bottom:8px}
|
||||
.sync-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
|
||||
.sync-row .btn{flex-shrink:0}
|
||||
#clock{font-size:1.2em;color:#ffcc00;font-weight:600}
|
||||
.note-count{color:#888;font-size:0.85em;margin-bottom:8px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>ESP32 Watch Manager</h1>
|
||||
|
||||
<div class="card">
|
||||
<h2>Czas</h2>
|
||||
<div class="sync-row">
|
||||
<span id="clock">--:--:--</span>
|
||||
<button class="btn" onclick="syncTime()">Synchronizuj czas</button>
|
||||
</div>
|
||||
<div class="status" id="timeStatus"></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Notatki</h2>
|
||||
<div class="note-count" id="noteCount"></div>
|
||||
<div id="notesList"></div>
|
||||
<hr style="border-color:#333;margin:12px 0">
|
||||
<h3 style="color:#ccc;font-size:0.95em;margin-bottom:8px">Dodaj notatke</h3>
|
||||
<input type="text" id="newTitle" placeholder="Tytul" maxlength="63">
|
||||
<textarea id="newContent" placeholder="Tresc notatki..." maxlength="511"></textarea>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
||||
<button class="btn" onclick="addNote()">Dodaj</button>
|
||||
<button class="btn btn-danger" onclick="clearAll()">Usun wszystkie</button>
|
||||
</div>
|
||||
<div class="status" id="notesStatus"></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Status</h2>
|
||||
<div class="info">
|
||||
<span>IP: 192.168.4.1</span>
|
||||
<span id="batteryInfo">Bateria: --</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let notes = [];
|
||||
|
||||
async function fetchJson(url, opts) {
|
||||
try {
|
||||
const r = await fetch(url, opts);
|
||||
return await r.json();
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadNotes() {
|
||||
const data = await fetchJson('/api/notes');
|
||||
if (data) {
|
||||
notes = data;
|
||||
renderNotes();
|
||||
}
|
||||
}
|
||||
|
||||
function renderNotes() {
|
||||
const el = document.getElementById('notesList');
|
||||
const cnt = document.getElementById('noteCount');
|
||||
cnt.textContent = notes.length + ' notatek';
|
||||
if (notes.length === 0) {
|
||||
el.innerHTML = '<p style="color:#666;text-align:center;padding:12px">Brak notatek</p>';
|
||||
return;
|
||||
}
|
||||
el.innerHTML = notes.map((n, i) =>
|
||||
'<div class="note-item"><h3>' + esc(n.title) + '</h3><p>' + esc(n.content) + '</p>' +
|
||||
'<button class="btn btn-danger btn-sm del-btn" onclick="delNote(' + i + ')">X</button></div>'
|
||||
).join('');
|
||||
}
|
||||
|
||||
function esc(s) {
|
||||
const d = document.createElement('div');
|
||||
d.textContent = s;
|
||||
return d.innerHTML;
|
||||
}
|
||||
|
||||
async function saveNotes() {
|
||||
const r = await fetch('/api/notes', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(notes)
|
||||
});
|
||||
const j = await r.json();
|
||||
showStatus('notesStatus', j.ok ? 'Zapisano!' : 'Blad zapisu', !j.ok);
|
||||
}
|
||||
|
||||
async function addNote() {
|
||||
const t = document.getElementById('newTitle').value.trim();
|
||||
const c = document.getElementById('newContent').value.trim();
|
||||
if (!t && !c) { showStatus('notesStatus', 'Wpisz tytul lub tresc', true); return; }
|
||||
notes.push({title: t || 'Notatka', content: c});
|
||||
await saveNotes();
|
||||
loadNotes();
|
||||
document.getElementById('newTitle').value = '';
|
||||
document.getElementById('newContent').value = '';
|
||||
}
|
||||
|
||||
async function delNote(i) {
|
||||
notes.splice(i, 1);
|
||||
await saveNotes();
|
||||
renderNotes();
|
||||
}
|
||||
|
||||
async function clearAll() {
|
||||
if (!confirm('Usunac wszystkie notatki?')) return;
|
||||
notes = [];
|
||||
await saveNotes();
|
||||
renderNotes();
|
||||
}
|
||||
|
||||
async function syncTime() {
|
||||
const now = new Date();
|
||||
const body = {
|
||||
h: now.getHours(), m: now.getMinutes(), s: now.getSeconds(),
|
||||
d: now.getDate(), mo: now.getMonth() + 1, y: now.getFullYear()
|
||||
};
|
||||
const r = await fetch('/api/time', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
const j = await r.json();
|
||||
showStatus('timeStatus', j.ok ? 'Czas zsynchronizowany!' : 'Blad synchronizacji', !j.ok);
|
||||
if (j.ok) updateClock();
|
||||
}
|
||||
|
||||
function showStatus(id, msg, isErr) {
|
||||
const el = document.getElementById(id);
|
||||
el.textContent = msg;
|
||||
el.className = 'status' + (isErr ? ' error' : '');
|
||||
setTimeout(() => { el.textContent = ''; }, 3000);
|
||||
}
|
||||
|
||||
async function updateClock() {
|
||||
const data = await fetchJson('/api/status');
|
||||
if (data) {
|
||||
document.getElementById('clock').textContent =
|
||||
String(data.h).padStart(2,'0') + ':' +
|
||||
String(data.m).padStart(2,'0') + ':' +
|
||||
String(data.s).padStart(2,'0');
|
||||
document.getElementById('batteryInfo').textContent = 'Bateria: ' + data.bat + '%';
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(updateClock, 2000);
|
||||
updateClock();
|
||||
loadNotes();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)rawliteral";
|
||||
|
||||
/* ──────────────────────────────────────────────
|
||||
* API Handlers
|
||||
* ────────────────────────────────────────────── */
|
||||
|
||||
static void handleRoot()
|
||||
{
|
||||
server.send(200, "text/html", index_html);
|
||||
}
|
||||
|
||||
static void handleGetNotes()
|
||||
{
|
||||
char *json = notes_storage_get_json();
|
||||
if (json) {
|
||||
server.send(200, "application/json", json);
|
||||
free(json);
|
||||
} else {
|
||||
server.send(200, "application/json", "[]");
|
||||
}
|
||||
}
|
||||
|
||||
static void handlePostNotes()
|
||||
{
|
||||
if (!server.hasArg("plain")) {
|
||||
server.send(400, "application/json", "{\"ok\":false,\"error\":\"no body\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
String body = server.arg("plain");
|
||||
bool ok = notes_storage_save(body.c_str());
|
||||
|
||||
if (ok) {
|
||||
server.send(200, "application/json", "{\"ok\":true}");
|
||||
} else {
|
||||
server.send(500, "application/json", "{\"ok\":false,\"error\":\"write failed\"}");
|
||||
}
|
||||
}
|
||||
|
||||
static void handlePostTime()
|
||||
{
|
||||
if (!server.hasArg("plain")) {
|
||||
server.send(400, "application/json", "{\"ok\":false,\"error\":\"no body\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
String body = server.arg("plain");
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeJson(doc, body);
|
||||
|
||||
if (error) {
|
||||
server.send(400, "application/json", "{\"ok\":false,\"error\":\"invalid json\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
int h = doc["h"] | 0;
|
||||
int m = doc["m"] | 0;
|
||||
int s = doc["s"] | 0;
|
||||
int d = doc["d"] | 1;
|
||||
int mo = doc["mo"] | 1;
|
||||
int y = doc["y"] | 2025;
|
||||
|
||||
watch.setTime(s, m, h, d, mo, y);
|
||||
|
||||
server.send(200, "application/json", "{\"ok\":true}");
|
||||
}
|
||||
|
||||
static void handleGetStatus()
|
||||
{
|
||||
JsonDocument doc;
|
||||
doc["h"] = watch.getHour(true);
|
||||
doc["m"] = watch.getMinute();
|
||||
doc["s"] = watch.getSecond();
|
||||
doc["d"] = watch.getDay();
|
||||
doc["mo"] = watch.getMonth() + 1;
|
||||
doc["y"] = watch.getYear();
|
||||
doc["bat"] = watch.getPhoneBattery();
|
||||
|
||||
String output;
|
||||
serializeJson(doc, output);
|
||||
server.send(200, "application/json", output);
|
||||
}
|
||||
|
||||
static void handleNotFound()
|
||||
{
|
||||
server.send(404, "text/plain", "Not Found");
|
||||
}
|
||||
|
||||
/* ──────────────────────────────────────────────
|
||||
* Public API
|
||||
* ────────────────────────────────────────────── */
|
||||
|
||||
extern "C" {
|
||||
|
||||
void wifi_server_start(void)
|
||||
{
|
||||
if (serverRunning) return;
|
||||
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAP(WIFI_SSID, WIFI_PASS);
|
||||
|
||||
/* Register endpoints */
|
||||
server.on("/", HTTP_GET, handleRoot);
|
||||
server.on("/api/notes", HTTP_GET, handleGetNotes);
|
||||
server.on("/api/notes", HTTP_POST, handlePostNotes);
|
||||
server.on("/api/time", HTTP_POST, handlePostTime);
|
||||
server.on("/api/status", HTTP_GET, handleGetStatus);
|
||||
server.onNotFound(handleNotFound);
|
||||
|
||||
server.begin();
|
||||
serverRunning = true;
|
||||
}
|
||||
|
||||
void wifi_server_stop(void)
|
||||
{
|
||||
if (!serverRunning) return;
|
||||
|
||||
server.stop();
|
||||
WiFi.softAPdisconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
serverRunning = false;
|
||||
}
|
||||
|
||||
void wifi_server_handle(void)
|
||||
{
|
||||
if (serverRunning) {
|
||||
server.handleClient();
|
||||
}
|
||||
}
|
||||
|
||||
bool wifi_server_is_running(void)
|
||||
{
|
||||
return serverRunning;
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
|
||||
#endif /* ENABLE_WIFI_SERVER */
|
||||
22
hal/esp32/wifi_server.h
Normal file
22
hal/esp32/wifi_server.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @file wifi_server.h
|
||||
* @brief WiFi Access Point + WebServer for time sync and notes management
|
||||
*/
|
||||
|
||||
#ifndef WIFI_SERVER_H
|
||||
#define WIFI_SERVER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void wifi_server_start(void);
|
||||
void wifi_server_stop(void);
|
||||
void wifi_server_handle(void);
|
||||
bool wifi_server_is_running(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* WIFI_SERVER_H */
|
||||
822
hal/pico/app_hal.cpp
Normal file
822
hal/pico/app_hal.cpp
Normal file
@@ -0,0 +1,822 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Felix Biego
|
||||
|
||||
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.
|
||||
|
||||
______________ _____
|
||||
___ __/___ /_ ___(_)_____ _______ _______
|
||||
__ /_ __ __ \__ / _ _ \__ __ `/_ __ \
|
||||
_ __/ _ /_/ /_ / / __/_ /_/ / / /_/ /
|
||||
/_/ /_.___/ /_/ \___/ _\__, / \____/
|
||||
/____/
|
||||
|
||||
*/
|
||||
|
||||
#define LGFX_USE_V1
|
||||
#include "Arduino.h"
|
||||
#include <LovyanGFX.hpp>
|
||||
#include <Timber.h>
|
||||
#include "app_hal.h"
|
||||
|
||||
#include <lvgl.h>
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include "ui/custom_face.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "pins.h"
|
||||
#include "splash.h"
|
||||
|
||||
#ifdef ENABLE_APP_QMI8658C
|
||||
#include "FastIMU.h"
|
||||
#define QMI_ADDRESS 0x6B
|
||||
#endif
|
||||
|
||||
#define buf_size 20
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
public:
|
||||
lgfx::Panel_GC9A01 _panel_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
lgfx::Touch_CST816S _touch_instance;
|
||||
|
||||
|
||||
LGFX(void)
|
||||
{
|
||||
{
|
||||
auto cfg = _bus_instance.config();
|
||||
|
||||
// SPI bus settings
|
||||
// cfg.spi_host = 1; // Select the SPI to use ESP32-S2,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
|
||||
// * Due to the ESP-IDF version upgrade, VSPI_HOST, The HSPI_HOST description is deprecated, so if an error occurs, use SPI2_HOST or SPI3_HOST instead.
|
||||
cfg.spi_mode = 0; // Set SPI communication mode (0 ~ 3)
|
||||
// cfg.freq_write = 10000000; // Transferred SPI clock (maximum 80MHz, 40MHz is an integer value excluding 80MHz)
|
||||
cfg.pin_sclk = SCLK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = MOSI; // Set SPI CLK pin number
|
||||
cfg.pin_miso = MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = DC; // Set SPI D/C pin number (-1 = disable)
|
||||
_bus_instance.config(cfg); // Reflect the setting value to the bus.
|
||||
_panel_instance.setBus(&_bus_instance); // Set the bus to the panel.
|
||||
}
|
||||
|
||||
{ // Set the display panel control.
|
||||
auto cfg = _panel_instance.config(); // Get the structure for display panel settings.
|
||||
|
||||
cfg.pin_cs = CS; // Pin number to which CS is connected (-1 = disable)
|
||||
cfg.pin_rst = RST; // Pin number to which RST is connected (-1 = disable)
|
||||
cfg.pin_busy = -1; // Pin number to which BUSY is connected (-1 = disable)
|
||||
|
||||
// * The following settings are set to general initial values for each panel, so try commenting out any unknown items.
|
||||
|
||||
cfg.memory_width = WIDTH; // Maximum width supported by driver IC
|
||||
cfg.memory_height = HEIGHT; // Maximum height supported by driver IC
|
||||
cfg.panel_width = WIDTH; // Actual displayable width
|
||||
cfg.panel_height = HEIGHT; // Actual displayable height
|
||||
cfg.offset_x = OFFSET_X; // Panel offset in X direction
|
||||
cfg.offset_y = OFFSET_Y; // Panel offset in Y direction
|
||||
cfg.offset_rotation = 0; // Value 0~7 in rotation direction (4~7 is inverted)
|
||||
cfg.dummy_read_pixel = 8; // Virtual number of positions read before reading image
|
||||
cfg.dummy_read_bits = 1; // The number of imaginary words other than the image element
|
||||
cfg.readable = false; // As long as the number of acquisitions is as high as possible, the setting is true
|
||||
cfg.invert = true; // As a result, the brightness and darkness of the face plate is reversed, and the setting is true
|
||||
cfg.rgb_order = RGB_ORDER; // As a result, the red color and the blue color are replaced on the face plate, and the setting is true
|
||||
cfg.dlen_16bit = false; // From 16th position to 16th position, the length of the number of transfers is set to true
|
||||
cfg.bus_shared = false; // How to use drawJpgFile (e.g. summary control)
|
||||
|
||||
_panel_instance.config(cfg);
|
||||
}
|
||||
|
||||
{ // Set backlight control. (delete if not necessary)
|
||||
auto cfg = _light_instance.config(); // Get the structure for backlight configuration.
|
||||
cfg.pin_bl = BL; // pin number to which the backlight is connected
|
||||
cfg.invert = false; // true to invert backlight brightness
|
||||
cfg.freq = 44100; // backlight PWM frequency
|
||||
cfg.pwm_channel = 1; // PWM channel number to use
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance); // Sets the backlight to the panel.
|
||||
}
|
||||
|
||||
{ // Sets touchscreen control. (Delete if not needed)
|
||||
|
||||
auto cfg = _touch_instance.config();
|
||||
|
||||
cfg.x_min = 0; // Minimum X value obtained from touch screen (raw value)
|
||||
cfg.x_max = WIDTH; // Maximum X value obtained from touch screen (raw value)
|
||||
cfg.y_min = 0; // Minimum Y value obtained from touch screen (raw value)
|
||||
cfg.y_max = HEIGHT; // Maximum Y value obtained from touch screen (raw value)
|
||||
|
||||
cfg.pin_int = TP_INT; // Pin number to which INT is connected
|
||||
cfg.pin_rst = TP_RST;
|
||||
cfg.bus_shared = true; // Set true if using a bus shared with the screen
|
||||
|
||||
cfg.offset_rotation = 0; // Adjust if display and touch orientation do not match. Set to a value between 0 and 7
|
||||
|
||||
cfg.i2c_port = 1; // Select the I2C to use (0 or 1)
|
||||
cfg.i2c_addr = 0x15; // I2C device address number
|
||||
cfg.pin_sda = I2C_SDA; // Pin number to which SDA is connected
|
||||
cfg.pin_scl = I2C_SCL; // Pin number to which SCL is connected
|
||||
cfg.freq = 100000; // Set the I2C clock
|
||||
_touch_instance.config(cfg);
|
||||
_panel_instance.setTouch(&_touch_instance); // Set the touch screen to the panel.
|
||||
}
|
||||
|
||||
setPanel(&_panel_instance); // Set the panel to use.
|
||||
}
|
||||
};
|
||||
|
||||
LGFX tft;
|
||||
|
||||
#ifdef ENABLE_APP_QMI8658C
|
||||
QMI8658 qmi8658c;
|
||||
calData calib = {0};
|
||||
AccelData acc;
|
||||
GyroData gyro;
|
||||
#endif
|
||||
|
||||
static const uint32_t screenWidth = WIDTH;
|
||||
static const uint32_t screenHeight = HEIGHT;
|
||||
|
||||
const unsigned int lvBufferSize = screenWidth * buf_size;
|
||||
static uint8_t *lvBuffer; // [lvBufferSize];
|
||||
static uint8_t *lvBuffer2;
|
||||
|
||||
static lv_display_t *lvDisplay;
|
||||
static lv_indev_t *lvInput;
|
||||
|
||||
struct ChronosTimer
|
||||
{
|
||||
unsigned long time;
|
||||
long duration = 5000;
|
||||
bool active;
|
||||
};
|
||||
|
||||
struct Notification
|
||||
{
|
||||
int icon;
|
||||
const char *app;
|
||||
const char *time;
|
||||
const char *message;
|
||||
};
|
||||
|
||||
struct Weather
|
||||
{
|
||||
int icon;
|
||||
int day;
|
||||
int temp;
|
||||
int high;
|
||||
int low;
|
||||
};
|
||||
|
||||
struct HourlyForecast
|
||||
{
|
||||
int day; // day of forecast
|
||||
int hour; // hour of the forecast
|
||||
int icon; // (0-7) // 0 - sun + cloud // 1 - sun // 2 - snow // 3 - rain // 4 - clouds // 5 - tornado // 6 - wind // 7 - sun + haze
|
||||
int temp; //
|
||||
int uv; // uv index
|
||||
int humidity; // %
|
||||
int wind; // wind speed km/h
|
||||
};
|
||||
|
||||
void update_faces();
|
||||
void setupContacts();
|
||||
void setupWeather();
|
||||
|
||||
// some pre-generated data just for preview
|
||||
Notification notifications[10] = {
|
||||
{.icon = 0xC0, .app = "Chronos", .time = "10:27", .message = "Chronos v3.7.5 is live! Enjoy enhanced notifications for finding your watch and viewing activity status, plus more. Upgrade now for an improved experience"},
|
||||
{.icon = 0x08, .app = "Skype", .time = "09:30", .message = "Hey there! Just reminding you about our meeting at 10:00 AM. Please make sure to prepare the presentation slides and gather all necessary documents beforehand. Looking forward to a productive discussion!"},
|
||||
{.icon = 0x10, .app = "Facebook", .time = "14:20", .message = "You've got 3 new friend requests. Check them out now! Don't forget to catch up with your old friends and see what they've been up to lately. It's always nice to reconnect and expand your social circle."},
|
||||
{.icon = 0x18, .app = "Telegram", .time = "16:45", .message = "New message from John: 'Hey, have you seen the latest news?' Let's catch up later today and discuss the latest updates together. It's always interesting to exchange ideas and opinions on current events."},
|
||||
{.icon = 0x11, .app = "Messenger", .time = "19:10", .message = "Sarah sent you a photo. Tap to view it! Sarah has always been good at capturing moments. Let's see what memorable snapshot she has shared this time. It might bring back some fond memories or inspire us for our next adventure."},
|
||||
{.icon = 0x12, .app = "Instagram", .time = "11:55", .message = "Your post got 50 likes! Keep up the good work. Your creativity and unique perspective are truly appreciated by your followers. Let's continue to share meaningful content and inspire others along the way."},
|
||||
{.icon = 0x13, .app = "Weibo", .time = "07:30", .message = "Trending topic: #TravelTuesday. Share your latest adventures! Whether it's a breathtaking landscape, a delicious local dish, or an unforgettable cultural experience, your travel stories never fail to captivate your audience. Let's share another exciting chapter of your journey!"},
|
||||
{.icon = 0x09, .app = "Wechat", .time = "22:15", .message = "New message from Mom: 'Don't forget to buy milk on your way home!' Mom always has our best interests at heart. Let's make sure to pick up the milk and any other groceries she needs. It's a small gesture of appreciation for all her love and care."},
|
||||
{.icon = 0x0F, .app = "Twitter", .time = "18:00", .message = "Breaking news: SpaceX launches its latest satellite into orbit. The advancements in space exploration never cease to amaze us. Let's stay updated on the latest developments and continue to support the incredible work being done in the field of aerospace engineering."},
|
||||
{.icon = 0x07, .app = "Tencent", .time = "13:40", .message = "Your gaming buddy is online. Ready for a match? It's time to put our skills to the test and embark on another thrilling gaming adventure together. Let's strategize, communicate, and emerge victorious as a team!"}};
|
||||
|
||||
Weather weather[7] = {
|
||||
{.icon = 0, .day = 0, .temp = 21, .high = 22, .low = 18},
|
||||
{.icon = 4, .day = 1, .temp = 25, .high = 26, .low = 24},
|
||||
{.icon = 5, .day = 2, .temp = 23, .high = 24, .low = 17},
|
||||
{.icon = 2, .day = 3, .temp = 20, .high = 23, .low = 12},
|
||||
{.icon = 0, .day = 4, .temp = 27, .high = 27, .low = 23},
|
||||
{.icon = 3, .day = 5, .temp = 22, .high = 25, .low = 18},
|
||||
{.icon = 2, .day = 6, .temp = 24, .high = 26, .low = 19},
|
||||
};
|
||||
|
||||
HourlyForecast hourly[24] = {
|
||||
{1, 0, 0, 25, 5, 70, 15}, // Day 1, 00:00, Partly Cloudy, 25°C, UV 5, 70% humidity, 15 km/h wind
|
||||
{1, 1, 1, 23, 4, 65, 10}, // Day 1, 01:00, Sunny, 23°C, UV 4, 65% humidity, 10 km/h wind
|
||||
{1, 2, 3, 20, 2, 85, 12}, // Day 1, 02:00, Rain, 20°C, UV 2, 85% humidity, 12 km/h wind
|
||||
{1, 3, 0, 21, 1, 75, 14}, // Day 1, 03:00, Partly Cloudy, 21°C, UV 1, 75% humidity, 14 km/h wind
|
||||
{1, 4, 4, 19, 0, 90, 8}, // Day 1, 04:00, Cloudy, 19°C, UV 0, 90% humidity, 8 km/h wind
|
||||
{1, 5, 1, 22, 3, 60, 20}, // Day 1, 05:00, Sunny, 22°C, UV 3, 60% humidity, 20 km/h wind
|
||||
{1, 6, 0, 26, 6, 50, 18}, // Day 1, 06:00, Partly Cloudy, 26°C, UV 6, 50% humidity, 18 km/h wind
|
||||
{1, 7, 1, 28, 7, 45, 22}, // Day 1, 07:00, Sunny, 28°C, UV 7, 45% humidity, 22 km/h wind
|
||||
{1, 8, 2, 16, 1, 85, 5}, // Day 1, 08:00, Snow, 16°C, UV 1, 85% humidity, 5 km/h wind
|
||||
{1, 9, 6, 30, 8, 35, 25}, // Day 1, 09:00, Windy, 30°C, UV 8, 35% humidity, 25 km/h wind
|
||||
{1, 10, 0, 32, 9, 40, 30}, // Day 1, 10:00, Partly Cloudy, 32°C, UV 9, 40% humidity, 30 km/h wind
|
||||
{1, 11, 5, 27, 4, 65, 18}, // Day 1, 11:00, Tornado, 27°C, UV 4, 65% humidity, 18 km/h wind
|
||||
{1, 12, 7, 35, 10, 20, 12}, // Day 1, 12:00, Sun + Haze, 35°C, UV 10, 20% humidity, 12 km/h wind
|
||||
{1, 13, 1, 34, 9, 25, 28}, // Day 1, 13:00, Sunny, 34°C, UV 9, 25% humidity, 28 km/h wind
|
||||
{1, 14, 4, 29, 8, 50, 24}, // Day 1, 14:00, Cloudy, 29°C, UV 8, 50% humidity, 24 km/h wind
|
||||
{1, 15, 3, 22, 6, 85, 14}, // Day 1, 15:00, Rain, 22°C, UV 6, 85% humidity, 14 km/h wind
|
||||
{1, 16, 0, 25, 5, 70, 19}, // Day 1, 16:00, Partly Cloudy, 25°C, UV 5, 70% humidity, 19 km/h wind
|
||||
{1, 17, 1, 26, 5, 65, 20}, // Day 1, 17:00, Sunny, 26°C, UV 5, 65% humidity, 20 km/h wind
|
||||
{1, 18, 6, 30, 7, 45, 17}, // Day 1, 18:00, Windy, 30°C, UV 7, 45% humidity, 17 km/h wind
|
||||
{1, 19, 0, 24, 4, 75, 22}, // Day 1, 19:00, Partly Cloudy, 24°C, UV 4, 75% humidity, 22 km/h wind
|
||||
{1, 20, 7, 28, 3, 80, 10}, // Day 1, 20:00, Sun + Haze, 28°C, UV 3, 80% humidity, 10 km/h wind
|
||||
{1, 21, 4, 22, 1, 85, 12}, // Day 1, 21:00, Cloudy, 22°C, UV 1, 85% humidity, 12 km/h wind
|
||||
{1, 22, 3, 20, 2, 90, 16}, // Day 1, 22:00, Rain, 20°C, UV 2, 90% humidity, 16 km/h wind
|
||||
{1, 23, 0, 18, 0, 95, 8} // Day 1, 23:00, Partly Cloudy, 18°C, UV 0, 95% humidity, 8 km/h wind
|
||||
};
|
||||
|
||||
ChronosTimer screenTimer;
|
||||
|
||||
const char *daysWk[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
|
||||
void my_disp_flush(lv_display_t *display, const lv_area_t *area, unsigned char *data)
|
||||
{
|
||||
|
||||
uint32_t w = lv_area_get_width(area);
|
||||
uint32_t h = lv_area_get_height(area);
|
||||
lv_draw_sw_rgb565_swap(data, w * h);
|
||||
|
||||
if (tft.getStartCount() == 0)
|
||||
{
|
||||
tft.endWrite();
|
||||
}
|
||||
|
||||
tft.pushImageDMA(area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1, (uint16_t *)data);
|
||||
|
||||
lv_display_flush_ready(display); /* tell lvgl that flushing is done */
|
||||
}
|
||||
|
||||
/*Read the touchpad*/
|
||||
void my_touchpad_read(lv_indev_t *indev_driver, lv_indev_data_t *data)
|
||||
{
|
||||
bool touched;
|
||||
uint16_t touchX, touchY;
|
||||
|
||||
touched = tft.getTouch(&touchX, &touchY);
|
||||
|
||||
if (!touched)
|
||||
{
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
|
||||
/*Set the coordinates*/
|
||||
data->point.x = touchX;
|
||||
data->point.y = touchY;
|
||||
|
||||
screenTimer.time = millis();
|
||||
screenTimer.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
void screenBrightness(uint8_t value)
|
||||
{
|
||||
tft.setBrightness(value);
|
||||
}
|
||||
|
||||
void setTimeout(int i)
|
||||
{
|
||||
if (i == 4)
|
||||
{
|
||||
screenTimer.duration = -1; // always on
|
||||
}
|
||||
else if (i == 0)
|
||||
{
|
||||
screenTimer.duration = 5000; // 5 seconds
|
||||
screenTimer.active = true;
|
||||
}
|
||||
else if (i < 4)
|
||||
{
|
||||
screenTimer.duration = 10000 * i; // 10, 20, 30 seconds
|
||||
screenTimer.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
void onLoadHome(lv_event_t *e) {}
|
||||
|
||||
void onClickAlert(lv_event_t *e) {}
|
||||
|
||||
void onForecastOpen(lv_event_t *e) {}
|
||||
|
||||
void onWeatherLoad(lv_event_t *e)
|
||||
{
|
||||
setupWeather();
|
||||
}
|
||||
|
||||
void onNotificationsOpen(lv_event_t *e) {}
|
||||
|
||||
void onBrightnessChange(lv_event_t *e)
|
||||
{
|
||||
lv_obj_t *slider = (lv_obj_t *)lv_event_get_target(e);
|
||||
int v = lv_slider_get_value(slider);
|
||||
screenBrightness(v);
|
||||
}
|
||||
|
||||
void onScrollMode(lv_event_t *e) {}
|
||||
|
||||
void onTimeoutChange(lv_event_t *e) {
|
||||
lv_obj_t *obj = (lv_obj_t *)lv_event_get_target(e);
|
||||
uint16_t sel = lv_dropdown_get_selected(obj);
|
||||
setTimeout(sel);
|
||||
}
|
||||
|
||||
void onRotateChange(lv_event_t *e)
|
||||
{
|
||||
lv_obj_t *obj = (lv_obj_t *)lv_event_get_target(e);
|
||||
uint16_t sel = lv_dropdown_get_selected(obj);
|
||||
tft.setRotation(sel);
|
||||
// screen rotation has changed, invalidate to redraw
|
||||
lv_obj_invalidate(lv_screen_active());
|
||||
}
|
||||
|
||||
void onBatteryChange(lv_event_t *e) {}
|
||||
|
||||
void onMusicPlay(lv_event_t *e)
|
||||
{
|
||||
showError("Error", "This is a test error message\nClick the button below to close this window");
|
||||
}
|
||||
|
||||
void onMusicPrevious(lv_event_t *e)
|
||||
{
|
||||
lv_label_set_text(ui_callName, "World");
|
||||
lv_screen_load_anim(ui_callScreen, LV_SCR_LOAD_ANIM_FADE_IN, 500, 0, false);
|
||||
}
|
||||
|
||||
void onMusicNext(lv_event_t *e)
|
||||
{
|
||||
lv_label_set_text(ui_cameraLabel, "Click capture to close to close");
|
||||
lv_screen_load_anim(ui_cameraScreen, LV_SCR_LOAD_ANIM_FADE_IN, 500, 0, false);
|
||||
}
|
||||
|
||||
void onStartSearch(lv_event_t *e) {}
|
||||
|
||||
void onEndSearch(lv_event_t *e) {}
|
||||
|
||||
void onVolumeUp(lv_event_t *e)
|
||||
{
|
||||
clearContactList();
|
||||
setupContacts();
|
||||
}
|
||||
|
||||
void onVolumeDown(lv_event_t *e)
|
||||
{
|
||||
setNoContacts();
|
||||
}
|
||||
|
||||
void onAutoNavigation(lv_event_t *e) {}
|
||||
|
||||
void onAlertState(lv_event_t *e) {}
|
||||
|
||||
void on_alert_state_change(int32_t states) {}
|
||||
|
||||
void onNavState(lv_event_t *e) {}
|
||||
|
||||
void onLanguageChange(lv_event_t *e)
|
||||
{
|
||||
}
|
||||
|
||||
void onWatchfaceChange(lv_event_t *e) {}
|
||||
|
||||
void onFaceSelected(lv_event_t *e) {}
|
||||
|
||||
void on_watchface_list_open() {}
|
||||
|
||||
void onCustomFaceSelected(int pathIndex) {}
|
||||
|
||||
void onRTWState(bool state)
|
||||
{
|
||||
}
|
||||
|
||||
void savePrefInt(const char *key, int value) {}
|
||||
|
||||
int getPrefInt(const char *key, int def_value)
|
||||
{
|
||||
return def_value;
|
||||
}
|
||||
|
||||
void toneOut(int pitch, int duration) {}
|
||||
|
||||
void onGameOpened() {}
|
||||
|
||||
void onGameClosed() {}
|
||||
|
||||
bool loadCustomFace(const char *file)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void onMessageClick(lv_event_t *e)
|
||||
{
|
||||
// Your code here
|
||||
// int index = (int)lv_event_get_user_data(e);
|
||||
intptr_t index = (intptr_t)lv_event_get_user_data(e);
|
||||
|
||||
index %= 10;
|
||||
|
||||
lv_label_set_text(ui_messageTime, notifications[index].time);
|
||||
lv_label_set_text(ui_messageContent, notifications[index].message);
|
||||
setNotificationIcon(ui_messageIcon, notifications[index].icon);
|
||||
|
||||
lv_obj_scroll_to_y(ui_messagePanel, 0, LV_ANIM_ON);
|
||||
lv_obj_add_flag(ui_messageList, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_remove_flag(ui_messagePanel, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
void onCaptureClick(lv_event_t *e)
|
||||
{
|
||||
lv_screen_load_anim(ui_home, LV_SCR_LOAD_ANIM_FADE_IN, 500, 0, false);
|
||||
}
|
||||
|
||||
void addFaceList(lv_obj_t *parent, Face face) {}
|
||||
|
||||
void timerEnded(int x){}
|
||||
|
||||
void simonTone(int type, int pitch){}
|
||||
|
||||
void setupWeather()
|
||||
{
|
||||
// lv_obj_set_style_bg_image_src(ui_weatherScreen, &ui_img_753022056, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
|
||||
lv_obj_remove_flag(ui_weatherPanel, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(ui_forecastList, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
const char *updateTime = "Updated at\n10:47";
|
||||
lv_label_set_text(ui_weatherCity, "Nairobi");
|
||||
lv_label_set_text(ui_weatherUpdateTime, updateTime);
|
||||
lv_label_set_text_fmt(ui_weatherCurrentTemp, "%d°C", weather[0].temp);
|
||||
|
||||
setWeatherIcon(ui_weatherCurrentIcon, weather[0].icon, true);
|
||||
|
||||
lv_label_set_text_fmt(ui_weatherTemp, "%d°C", weather[0].temp);
|
||||
setWeatherIcon(ui_weatherIcon, weather[0].icon, true);
|
||||
|
||||
lv_obj_clean(ui_forecastList);
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
addForecast(weather[i].day, weather[i].temp, weather[i].icon);
|
||||
}
|
||||
|
||||
lv_obj_clean(ui_hourlyList);
|
||||
addHourlyWeather(0, 1, 0, 0, 0, 0, true);
|
||||
for (int h = 0; h < 4; h++)
|
||||
{
|
||||
addHourlyWeather(hourly[h].hour, hourly[h].icon, hourly[h].temp, hourly[h].humidity, hourly[h].wind, hourly[h].uv, false);
|
||||
}
|
||||
}
|
||||
|
||||
void setupNotifications()
|
||||
{
|
||||
lv_obj_clean(ui_messageList);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
addNotificationList(notifications[i].icon, notifications[i].message, i);
|
||||
}
|
||||
|
||||
lv_obj_scroll_to_y(ui_messageList, 1, LV_ANIM_ON);
|
||||
lv_obj_remove_flag(ui_messageList, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(ui_messagePanel, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
void setupFiles()
|
||||
{
|
||||
|
||||
// addListDrive("C:/", 16777216, 8456213);
|
||||
// addListDrive("D:/", 6456326, 456213);
|
||||
|
||||
addListDir("watchface");
|
||||
addListDir("extracted");
|
||||
addListDir("bluetooth");
|
||||
|
||||
addListFile("kenya.bin", 152453);
|
||||
addListFile("kenya.wf", 453);
|
||||
addListFile("list.txt", 2453);
|
||||
|
||||
lv_obj_scroll_to_y(ui_fileManagerPanel, 1, LV_ANIM_ON);
|
||||
}
|
||||
|
||||
void setupContacts()
|
||||
{
|
||||
|
||||
clearContactList();
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
addContact("fbiego Chronos", "1234567890", i == 2);
|
||||
}
|
||||
}
|
||||
|
||||
void imu_init()
|
||||
{
|
||||
#ifdef ENABLE_APP_QMI8658C
|
||||
int err = qmi8658c.init(calib, QMI_ADDRESS);
|
||||
if (err != 0)
|
||||
{
|
||||
showError("IMU State", "Failed to init");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
imu_data_t get_imu_data()
|
||||
{
|
||||
imu_data_t qmi;
|
||||
#ifdef ENABLE_APP_QMI8658C
|
||||
|
||||
qmi8658c.update();
|
||||
qmi8658c.getAccel(&acc);
|
||||
qmi8658c.getGyro(&gyro);
|
||||
|
||||
qmi.ax = acc.accelX;
|
||||
qmi.ay = acc.accelY;
|
||||
qmi.az = acc.accelZ;
|
||||
qmi.gx = gyro.gyroX;
|
||||
qmi.gy = gyro.gyroY;
|
||||
qmi.gz = gyro.gyroZ;
|
||||
qmi.temp = qmi8658c.getTemp();
|
||||
qmi.success = true;
|
||||
#else
|
||||
qmi.success = false;
|
||||
#endif
|
||||
return qmi;
|
||||
}
|
||||
|
||||
void imu_close()
|
||||
{
|
||||
#ifdef ENABLE_APP_QMI8658C
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void my_log_cb(const char *buf)
|
||||
{
|
||||
Serial.write(buf, strlen(buf));
|
||||
}
|
||||
|
||||
void loadSplash()
|
||||
{
|
||||
int w = 122;
|
||||
int h = 130;
|
||||
int xOffset = 63;
|
||||
int yOffset = 55;
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
screenBrightness(200);
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
tft.writePixel(x + xOffset, y + yOffset, uint16_t(splash[(((y * w) + x) * 2)] << 8 | splash[(((y * w) + x) * 2) + 1]));
|
||||
}
|
||||
}
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
static uint32_t my_tick(void)
|
||||
{
|
||||
return millis();
|
||||
}
|
||||
|
||||
void logCallback(Level level, unsigned long time, String message)
|
||||
{
|
||||
// Serial.print(message);
|
||||
}
|
||||
|
||||
int putchar(int ch)
|
||||
{
|
||||
// Serial.write(ch); // Send character to Serial
|
||||
return ch;
|
||||
}
|
||||
|
||||
void my_log_cb(lv_log_level_t level, const char *buf)
|
||||
{
|
||||
// Serial.write(buf, strlen(buf));
|
||||
}
|
||||
|
||||
void hal_setup()
|
||||
{
|
||||
|
||||
Serial.begin(115200); /* prepare for possible serial debug */
|
||||
|
||||
Timber.setLogCallback(logCallback);
|
||||
|
||||
Timber.i("Starting up device");
|
||||
|
||||
tft.init();
|
||||
tft.initDMA();
|
||||
tft.startWrite();
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
|
||||
|
||||
|
||||
// tft.setRotation(rt);
|
||||
loadSplash();
|
||||
|
||||
printf("Hello from printf!\n");
|
||||
|
||||
lv_init();
|
||||
|
||||
// lv_log_register_print_cb(my_log_cb);
|
||||
|
||||
lv_tick_set_cb(my_tick);
|
||||
|
||||
lvBuffer = (uint8_t *)malloc(lvBufferSize);
|
||||
if (lvBuffer == NULL)
|
||||
{
|
||||
// Handle memory allocation failure
|
||||
Timber.e("Failed to allocate memory %d", lvBufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
Timber.i("Memory allocated %d", lvBufferSize);
|
||||
}
|
||||
|
||||
lvBuffer2 = (uint8_t *)malloc(lvBufferSize);
|
||||
if (lvBuffer2 == NULL)
|
||||
{
|
||||
// Handle memory allocation failure
|
||||
Timber.e("Failed to allocate buffer2 %d", lvBufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
Timber.i("Buffer2 allocated %d", lvBufferSize);
|
||||
}
|
||||
|
||||
lvDisplay = lv_display_create(screenWidth, screenHeight);
|
||||
lv_display_set_color_format(lvDisplay, LV_COLOR_FORMAT_RGB565);
|
||||
lv_display_set_flush_cb(lvDisplay, my_disp_flush);
|
||||
lv_display_set_buffers(lvDisplay, lvBuffer, lvBuffer2, lvBufferSize, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
lvInput = lv_indev_create();
|
||||
lv_indev_set_type(lvInput, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(lvInput, my_touchpad_read);
|
||||
|
||||
ui_init();
|
||||
|
||||
screenTimer.active = true;
|
||||
screenTimer.time = millis();
|
||||
|
||||
setTimeout(0);
|
||||
|
||||
imu_init();
|
||||
|
||||
setupNotifications();
|
||||
setupWeather();
|
||||
|
||||
setupFiles();
|
||||
setupContacts();
|
||||
|
||||
circular = true;
|
||||
|
||||
lv_obj_scroll_to_y(ui_settingsList, 1, LV_ANIM_ON);
|
||||
lv_obj_scroll_to_y(ui_appList, 1, LV_ANIM_ON);
|
||||
lv_obj_scroll_to_y(ui_appInfoPanel, 1, LV_ANIM_ON);
|
||||
lv_obj_scroll_to_y(ui_gameList, 1, LV_ANIM_ON);
|
||||
lv_obj_add_state(ui_Switch2, LV_STATE_CHECKED);
|
||||
|
||||
lv_label_set_text_fmt(ui_aboutText, "%s\nPico RP2040\nA1:B2:C3:D4:E5:F6", ui_info_text);
|
||||
|
||||
ui_setup();
|
||||
|
||||
Timber.i("Setup done");
|
||||
}
|
||||
|
||||
void hal_loop()
|
||||
{
|
||||
|
||||
lv_timer_handler(); /* let the GUI do its work */
|
||||
delay(5); /* let this time pass */
|
||||
|
||||
if (ui_home == ui_clockScreen)
|
||||
{
|
||||
time_t now = time(0);
|
||||
tm *ltm = localtime(&now);
|
||||
|
||||
int second = ltm->tm_sec;
|
||||
int minute = ltm->tm_min;
|
||||
int hour = ltm->tm_hour;
|
||||
bool am = hour < 12;
|
||||
int day = ltm->tm_mday;
|
||||
int month = 1 + ltm->tm_mon; // Month starts from 0
|
||||
int year = 1900 + ltm->tm_year; // Year is since 1900
|
||||
int weekday = ltm->tm_wday;
|
||||
|
||||
lv_label_set_text_fmt(ui_hourLabel, "%02d", hour);
|
||||
lv_label_set_text_fmt(ui_dayLabel, "%s", daysWk[weekday]);
|
||||
lv_label_set_text_fmt(ui_minuteLabel, "%02d", minute);
|
||||
lv_label_set_text_fmt(ui_dateLabel, "%02d\n%s", day, months[month - 1]);
|
||||
lv_label_set_text(ui_amPmLabel, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
update_faces();
|
||||
}
|
||||
|
||||
if (screenTimer.active)
|
||||
{
|
||||
uint8_t lvl = lv_slider_get_value(ui_brightnessSlider);
|
||||
screenBrightness(lvl);
|
||||
|
||||
if (screenTimer.duration < 0)
|
||||
{
|
||||
screenTimer.active = false;
|
||||
}
|
||||
else if (screenTimer.time + screenTimer.duration < millis())
|
||||
{
|
||||
screenTimer.active = false;
|
||||
|
||||
screenBrightness(0);
|
||||
lv_screen_load(ui_home);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void contacts_app_launched()
|
||||
{
|
||||
setupContacts();
|
||||
}
|
||||
|
||||
void calendar_app_launched(void)
|
||||
{
|
||||
time_t now = time(0);
|
||||
tm *ltm = localtime(&now);
|
||||
int day = ltm->tm_mday;
|
||||
int month = 1 + ltm->tm_mon; // Month starts from 0
|
||||
int year = 1900 + ltm->tm_year; // Year is since 1900
|
||||
calendar_set_today(year, month, day);
|
||||
}
|
||||
|
||||
int32_t read_encoder_position()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void update_faces()
|
||||
{
|
||||
time_t now = time(0);
|
||||
tm *ltm = localtime(&now);
|
||||
|
||||
// Extract time fields
|
||||
int second = ltm->tm_sec;
|
||||
int minute = ltm->tm_min;
|
||||
int hour = ltm->tm_hour;
|
||||
bool am = hour < 12;
|
||||
int day = ltm->tm_mday;
|
||||
int month = 1 + ltm->tm_mon; // Month starts from 0
|
||||
int year = 1900 + ltm->tm_year; // Year is since 1900
|
||||
int weekday = ltm->tm_wday;
|
||||
|
||||
bool mode = true;
|
||||
|
||||
int temp = 22;
|
||||
int icon = 1;
|
||||
|
||||
int battery = 75; // rand() % 100;
|
||||
bool connection = true;
|
||||
|
||||
int steps = 2735;
|
||||
int distance = 17;
|
||||
int kcal = 348;
|
||||
int bpm = 76;
|
||||
int oxygen = 97;
|
||||
|
||||
if (ui_home == face_custom_root)
|
||||
{
|
||||
update_time_custom(second, minute, hour, mode, am, day, month, year, weekday);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
ui_update_watchfaces(second, minute, hour, mode, am, day, month, year, weekday,
|
||||
temp, icon, battery, connection, steps, distance, kcal, bpm, oxygen);
|
||||
}
|
||||
}
|
||||
65
hal/pico/app_hal.h
Normal file
65
hal/pico/app_hal.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef DRIVER_H
|
||||
#define DRIVER_H
|
||||
|
||||
#ifdef NO_WATCHFACES
|
||||
|
||||
#elif PICO_1_69
|
||||
// 240x280 watchfaces
|
||||
|
||||
#define ENABLE_FACE_174 // (174)
|
||||
#define ENABLE_FACE_228 // (228)
|
||||
#define ENABLE_FACE_1041 // (1041)
|
||||
#define ENABLE_FACE_1167 // (1167)
|
||||
#define ENABLE_FACE_1169 // (1169)
|
||||
#define ENABLE_FACE_2051 // (2051)
|
||||
#define ENABLE_FACE_2151 // (2151)
|
||||
#define ENABLE_FACE_3589 // (3589)
|
||||
|
||||
#else
|
||||
// 240x240 watchfaces
|
||||
|
||||
#define ENABLE_FACE_ELECROW // elecrow analog
|
||||
#define ENABLE_FACE_34_2 // (Shadow)
|
||||
#define ENABLE_FACE_75_2 // (Analog)
|
||||
#define ENABLE_FACE_79_2 // (Blue)
|
||||
#define ENABLE_FACE_116_2 // (Outline)
|
||||
#define ENABLE_FACE_756_2 // (Red)
|
||||
#define ENABLE_FACE_B_W_RESIZED // (B & W)
|
||||
#define ENABLE_FACE_KENYA // (Kenya)
|
||||
#define ENABLE_FACE_PIXEL_RESIZED // (Pixel)
|
||||
#define ENABLE_FACE_RADAR // (Radar)
|
||||
#define ENABLE_FACE_SMART_RESIZED // (Smart)
|
||||
#define ENABLE_FACE_TIX_RESIZED // (Tix)
|
||||
#define ENABLE_FACE_WFB_RESIZED // (WFB)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(PICO_1_69) || defined(PICO_1_28)
|
||||
// #define ENABLE_APP_QMI8658C
|
||||
// #define ENABLE_APP_ATTITUDE
|
||||
#endif
|
||||
|
||||
#define ENABLE_APP_CALENDAR
|
||||
#define ENABLE_APP_SAMPLE
|
||||
// #define ENABLE_GAME_RACING
|
||||
#define ENABLE_GAME_SIMON
|
||||
|
||||
// #define ENABLE_APP_NAVIGATION
|
||||
// #define ENABLE_APP_CONTACTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
void hal_setup(void);
|
||||
void hal_loop(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*DRIVER_H*/
|
||||
130
hal/pico/pins.h
Normal file
130
hal/pico/pins.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Felix Biego
|
||||
|
||||
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.
|
||||
|
||||
______________ _____
|
||||
___ __/___ /_ ___(_)_____ _______ _______
|
||||
__ /_ __ __ \__ / _ _ \__ __ `/_ __ \
|
||||
_ __/ _ /_/ /_ / / __/_ /_/ / / /_/ /
|
||||
/_/ /_.___/ /_/ \___/ _\__, / \____/
|
||||
/____/
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef PICO_1_28
|
||||
|
||||
// screen configs
|
||||
#define WIDTH 240
|
||||
#define HEIGHT 240
|
||||
#define OFFSET_X 0
|
||||
#define OFFSET_Y 0
|
||||
#define RGB_ORDER false
|
||||
|
||||
// touch
|
||||
#define I2C_SDA 6
|
||||
#define I2C_SCL 7
|
||||
#define TP_INT 21
|
||||
#define TP_RST 22
|
||||
|
||||
// display
|
||||
#define SPI 0
|
||||
|
||||
#define SCLK 10
|
||||
#define MOSI 11
|
||||
#define MISO 12
|
||||
#define DC 8
|
||||
#define CS 9
|
||||
#define RST 13
|
||||
|
||||
#define BL 25
|
||||
|
||||
#define BUZZER -1
|
||||
|
||||
#define MAX_FILE_OPEN 50
|
||||
|
||||
#elif PICO_1_69
|
||||
|
||||
// screen configs
|
||||
#define WIDTH 240
|
||||
#define HEIGHT 280
|
||||
#define OFFSET_X 0
|
||||
#define OFFSET_Y 20
|
||||
#define RGB_ORDER true
|
||||
|
||||
// touch
|
||||
#define I2C_SDA 6
|
||||
#define I2C_SCL 7
|
||||
#define TP_INT 21
|
||||
#define TP_RST 22
|
||||
|
||||
// display
|
||||
#define SPI 0
|
||||
|
||||
#define SCLK 10
|
||||
#define MOSI 11
|
||||
#define MISO -1
|
||||
#define DC 8
|
||||
#define CS 9
|
||||
#define RST 13
|
||||
|
||||
#define BL 25
|
||||
|
||||
#define BUZZER 2
|
||||
|
||||
#define MAX_FILE_OPEN 20
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
// screen configs
|
||||
#define WIDTH 240
|
||||
#define HEIGHT 240
|
||||
#define OFFSET_X 0
|
||||
#define OFFSET_Y 0
|
||||
#define RGB_ORDER false
|
||||
|
||||
// touch
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
#define TP_INT 14
|
||||
#define TP_RST 5
|
||||
|
||||
// display
|
||||
#define SPI VSPI_HOST
|
||||
|
||||
#define SCLK 18
|
||||
#define MOSI 23
|
||||
#define MISO -1
|
||||
#define DC 4
|
||||
#define CS 15
|
||||
#define RST 13
|
||||
|
||||
#define BL 2
|
||||
|
||||
#define BUZZER -1
|
||||
|
||||
#define MAX_FILE_OPEN 10
|
||||
|
||||
#endif
|
||||
472
hal/sdl2/app_hal.cpp
Normal file
472
hal/sdl2/app_hal.cpp
Normal file
@@ -0,0 +1,472 @@
|
||||
#include <unistd.h>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/
|
||||
#include SDL_INCLUDE_PATH
|
||||
#include "drivers/sdl/lv_sdl_mouse.h"
|
||||
#include "drivers/sdl/lv_sdl_mousewheel.h"
|
||||
#include "drivers/sdl/lv_sdl_keyboard.h"
|
||||
|
||||
#include "app_hal.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
static lv_display_t *lvDisplay;
|
||||
static lv_indev_t *lvMouse;
|
||||
static lv_indev_t *lvMousewheel;
|
||||
static lv_indev_t *lvKeyboard;
|
||||
|
||||
struct Notification
|
||||
{
|
||||
int icon;
|
||||
const char *app;
|
||||
const char *time;
|
||||
const char *message;
|
||||
};
|
||||
|
||||
struct Weather
|
||||
{
|
||||
int icon;
|
||||
int day;
|
||||
int temp;
|
||||
int high;
|
||||
int low;
|
||||
};
|
||||
|
||||
struct HourlyForecast
|
||||
{
|
||||
int day; // day of forecast
|
||||
int hour; // hour of the forecast
|
||||
int icon; // (0-7) // 0 - sun + cloud // 1 - sun // 2 - snow // 3 - rain // 4 - clouds // 5 - tornado // 6 - wind // 7 - sun + haze
|
||||
int temp; //
|
||||
int uv; // uv index
|
||||
int humidity; // %
|
||||
int wind; // wind speed km/h
|
||||
};
|
||||
|
||||
void hal_setup(void);
|
||||
void hal_loop(void);
|
||||
|
||||
void update_faces();
|
||||
void setupContacts();
|
||||
void setupWeather();
|
||||
|
||||
// some pre-generated data just for preview
|
||||
Notification notifications[10] = {
|
||||
{.icon = 0xC0, .app = "Chronos", .time = "10:27", .message = "Chronos v3.7.5 is live! Enjoy enhanced notifications for finding your watch and viewing activity status, plus more. Upgrade now for an improved experience"},
|
||||
{.icon = 0x08, .app = "Skype", .time = "09:30", .message = "Hey there! Just reminding you about our meeting at 10:00 AM. Please make sure to prepare the presentation slides and gather all necessary documents beforehand. Looking forward to a productive discussion!"},
|
||||
{.icon = 0x10, .app = "Facebook", .time = "14:20", .message = "You've got 3 new friend requests. Check them out now! Don't forget to catch up with your old friends and see what they've been up to lately. It's always nice to reconnect and expand your social circle."},
|
||||
{.icon = 0x18, .app = "Telegram", .time = "16:45", .message = "New message from John: 'Hey, have you seen the latest news?' Let's catch up later today and discuss the latest updates together. It's always interesting to exchange ideas and opinions on current events."},
|
||||
{.icon = 0x11, .app = "Messenger", .time = "19:10", .message = "Sarah sent you a photo. Tap to view it! Sarah has always been good at capturing moments. Let's see what memorable snapshot she has shared this time. It might bring back some fond memories or inspire us for our next adventure."},
|
||||
{.icon = 0x12, .app = "Instagram", .time = "11:55", .message = "Your post got 50 likes! Keep up the good work. Your creativity and unique perspective are truly appreciated by your followers. Let's continue to share meaningful content and inspire others along the way."},
|
||||
{.icon = 0x13, .app = "Weibo", .time = "07:30", .message = "Trending topic: #TravelTuesday. Share your latest adventures! Whether it's a breathtaking landscape, a delicious local dish, or an unforgettable cultural experience, your travel stories never fail to captivate your audience. Let's share another exciting chapter of your journey!"},
|
||||
{.icon = 0x09, .app = "Wechat", .time = "22:15", .message = "New message from Mom: 'Don't forget to buy milk on your way home!' Mom always has our best interests at heart. Let's make sure to pick up the milk and any other groceries she needs. It's a small gesture of appreciation for all her love and care."},
|
||||
{.icon = 0x0F, .app = "Twitter", .time = "18:00", .message = "Breaking news: SpaceX launches its latest satellite into orbit. The advancements in space exploration never cease to amaze us. Let's stay updated on the latest developments and continue to support the incredible work being done in the field of aerospace engineering."},
|
||||
{.icon = 0x07, .app = "Tencent", .time = "13:40", .message = "Your gaming buddy is online. Ready for a match? It's time to put our skills to the test and embark on another thrilling gaming adventure together. Let's strategize, communicate, and emerge victorious as a team!"}};
|
||||
|
||||
Weather weather[7] = {
|
||||
{.icon = 0, .day = 0, .temp = 21, .high = 22, .low = 18},
|
||||
{.icon = 4, .day = 1, .temp = 25, .high = 26, .low = 24},
|
||||
{.icon = 5, .day = 2, .temp = 23, .high = 24, .low = 17},
|
||||
{.icon = 2, .day = 3, .temp = 20, .high = 23, .low = 12},
|
||||
{.icon = 0, .day = 4, .temp = 27, .high = 27, .low = 23},
|
||||
{.icon = 3, .day = 5, .temp = 22, .high = 25, .low = 18},
|
||||
{.icon = 2, .day = 6, .temp = 24, .high = 26, .low = 19},
|
||||
};
|
||||
|
||||
HourlyForecast hourly[24] = {
|
||||
{1, 0, 0, 25, 5, 70, 15}, // Day 1, 00:00, Partly Cloudy, 25°C, UV 5, 70% humidity, 15 km/h wind
|
||||
{1, 1, 1, 23, 4, 65, 10}, // Day 1, 01:00, Sunny, 23°C, UV 4, 65% humidity, 10 km/h wind
|
||||
{1, 2, 3, 20, 2, 85, 12}, // Day 1, 02:00, Rain, 20°C, UV 2, 85% humidity, 12 km/h wind
|
||||
{1, 3, 0, 21, 1, 75, 14}, // Day 1, 03:00, Partly Cloudy, 21°C, UV 1, 75% humidity, 14 km/h wind
|
||||
{1, 4, 4, 19, 0, 90, 8}, // Day 1, 04:00, Cloudy, 19°C, UV 0, 90% humidity, 8 km/h wind
|
||||
{1, 5, 1, 22, 3, 60, 20}, // Day 1, 05:00, Sunny, 22°C, UV 3, 60% humidity, 20 km/h wind
|
||||
{1, 6, 0, 26, 6, 50, 18}, // Day 1, 06:00, Partly Cloudy, 26°C, UV 6, 50% humidity, 18 km/h wind
|
||||
{1, 7, 1, 28, 7, 45, 22}, // Day 1, 07:00, Sunny, 28°C, UV 7, 45% humidity, 22 km/h wind
|
||||
{1, 8, 2, 16, 1, 85, 5}, // Day 1, 08:00, Snow, 16°C, UV 1, 85% humidity, 5 km/h wind
|
||||
{1, 9, 6, 30, 8, 35, 25}, // Day 1, 09:00, Windy, 30°C, UV 8, 35% humidity, 25 km/h wind
|
||||
{1, 10, 0, 32, 9, 40, 30}, // Day 1, 10:00, Partly Cloudy, 32°C, UV 9, 40% humidity, 30 km/h wind
|
||||
{1, 11, 5, 27, 4, 65, 18}, // Day 1, 11:00, Tornado, 27°C, UV 4, 65% humidity, 18 km/h wind
|
||||
{1, 12, 7, 35, 10, 20, 12}, // Day 1, 12:00, Sun + Haze, 35°C, UV 10, 20% humidity, 12 km/h wind
|
||||
{1, 13, 1, 34, 9, 25, 28}, // Day 1, 13:00, Sunny, 34°C, UV 9, 25% humidity, 28 km/h wind
|
||||
{1, 14, 4, 29, 8, 50, 24}, // Day 1, 14:00, Cloudy, 29°C, UV 8, 50% humidity, 24 km/h wind
|
||||
{1, 15, 3, 22, 6, 85, 14}, // Day 1, 15:00, Rain, 22°C, UV 6, 85% humidity, 14 km/h wind
|
||||
{1, 16, 0, 25, 5, 70, 19}, // Day 1, 16:00, Partly Cloudy, 25°C, UV 5, 70% humidity, 19 km/h wind
|
||||
{1, 17, 1, 26, 5, 65, 20}, // Day 1, 17:00, Sunny, 26°C, UV 5, 65% humidity, 20 km/h wind
|
||||
{1, 18, 6, 30, 7, 45, 17}, // Day 1, 18:00, Windy, 30°C, UV 7, 45% humidity, 17 km/h wind
|
||||
{1, 19, 0, 24, 4, 75, 22}, // Day 1, 19:00, Partly Cloudy, 24°C, UV 4, 75% humidity, 22 km/h wind
|
||||
{1, 20, 7, 28, 3, 80, 10}, // Day 1, 20:00, Sun + Haze, 28°C, UV 3, 80% humidity, 10 km/h wind
|
||||
{1, 21, 4, 22, 1, 85, 12}, // Day 1, 21:00, Cloudy, 22°C, UV 1, 85% humidity, 12 km/h wind
|
||||
{1, 22, 3, 20, 2, 90, 16}, // Day 1, 22:00, Rain, 20°C, UV 2, 90% humidity, 16 km/h wind
|
||||
{1, 23, 0, 18, 0, 95, 8} // Day 1, 23:00, Partly Cloudy, 18°C, UV 0, 95% humidity, 8 km/h wind
|
||||
};
|
||||
|
||||
const char *daysWk[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
/**
|
||||
* A task to measure the elapsed time for LittlevGL
|
||||
* @param data unused
|
||||
* @return never return
|
||||
*/
|
||||
static int tick_thread(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
while (1)
|
||||
{
|
||||
SDL_Delay(5); /*Sleep for 5 millisecond*/
|
||||
lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void onLoadHome(lv_event_t *e) {}
|
||||
|
||||
void onClickAlert(lv_event_t *e) {}
|
||||
|
||||
void onForecastOpen(lv_event_t *e) {}
|
||||
|
||||
void onWeatherLoad(lv_event_t *e)
|
||||
{
|
||||
setupWeather();
|
||||
}
|
||||
|
||||
void onNotificationsOpen(lv_event_t *e) {}
|
||||
|
||||
void onBrightnessChange(lv_event_t *e) {}
|
||||
|
||||
void onScrollMode(lv_event_t *e) {}
|
||||
|
||||
void onTimeoutChange(lv_event_t *e) {}
|
||||
|
||||
void onRotateChange(lv_event_t *e) {}
|
||||
|
||||
void onBatteryChange(lv_event_t *e) {}
|
||||
|
||||
void onMusicPlay(lv_event_t *e)
|
||||
{
|
||||
showError("Error", "This is a test error message\nClick the button below to close this window");
|
||||
}
|
||||
|
||||
void onMusicPrevious(lv_event_t *e)
|
||||
{
|
||||
lv_label_set_text(ui_callName, "World");
|
||||
lv_screen_load_anim(ui_callScreen, LV_SCR_LOAD_ANIM_FADE_IN, 500, 0, false);
|
||||
}
|
||||
|
||||
void onMusicNext(lv_event_t *e)
|
||||
{
|
||||
lv_label_set_text(ui_cameraLabel, "Click capture to close to close");
|
||||
lv_screen_load_anim(ui_cameraScreen, LV_SCR_LOAD_ANIM_FADE_IN, 500, 0, false);
|
||||
}
|
||||
|
||||
void onStartSearch(lv_event_t *e) {}
|
||||
|
||||
void onEndSearch(lv_event_t *e) {}
|
||||
|
||||
void onVolumeUp(lv_event_t *e)
|
||||
{
|
||||
clearContactList();
|
||||
setupContacts();
|
||||
}
|
||||
|
||||
void onVolumeDown(lv_event_t *e)
|
||||
{
|
||||
setNoContacts();
|
||||
}
|
||||
|
||||
void onAutoNavigation(lv_event_t *e) {}
|
||||
|
||||
void onAlertState(lv_event_t *e) {}
|
||||
|
||||
void on_alert_state_change(int32_t states) {}
|
||||
|
||||
void onNavState(lv_event_t *e) {}
|
||||
|
||||
void onLanguageChange(lv_event_t *e)
|
||||
{
|
||||
}
|
||||
|
||||
void onWatchfaceChange(lv_event_t *e) {}
|
||||
|
||||
void onFaceSelected(lv_event_t *e) {}
|
||||
|
||||
void on_watchface_list_open() {}
|
||||
|
||||
void onCustomFaceSelected(int pathIndex) {}
|
||||
|
||||
void onRTWState(bool state)
|
||||
{
|
||||
}
|
||||
|
||||
void savePrefInt(const char *key, int value) {}
|
||||
|
||||
int getPrefInt(const char *key, int def_value)
|
||||
{
|
||||
return def_value;
|
||||
}
|
||||
|
||||
void toneOut(int pitch, int duration) {}
|
||||
|
||||
void onGameOpened() {}
|
||||
|
||||
void onGameClosed() {}
|
||||
|
||||
bool loadCustomFace(const char *file)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void onMessageClick(lv_event_t *e)
|
||||
{
|
||||
// Your code here
|
||||
// int index = (int)lv_event_get_user_data(e);
|
||||
intptr_t index = (intptr_t)lv_event_get_user_data(e);
|
||||
|
||||
index %= 10;
|
||||
|
||||
lv_label_set_text(ui_messageTime, notifications[index].time);
|
||||
lv_label_set_text(ui_messageContent, notifications[index].message);
|
||||
setNotificationIcon(ui_messageIcon, notifications[index].icon);
|
||||
|
||||
lv_obj_scroll_to_y(ui_messagePanel, 0, LV_ANIM_ON);
|
||||
lv_obj_add_flag(ui_messageList, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_remove_flag(ui_messagePanel, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
void onCaptureClick(lv_event_t *e)
|
||||
{
|
||||
lv_screen_load_anim(ui_home, LV_SCR_LOAD_ANIM_FADE_IN, 500, 0, false);
|
||||
}
|
||||
|
||||
void addFaceList(lv_obj_t *parent, Face face) {}
|
||||
|
||||
void timerEnded(int x){}
|
||||
|
||||
void simonTone(int type, int pitch){}
|
||||
|
||||
void setupWeather()
|
||||
{
|
||||
// lv_obj_set_style_bg_image_src(ui_weatherScreen, &ui_img_753022056, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
|
||||
lv_obj_remove_flag(ui_weatherPanel, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(ui_forecastList, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
const char *updateTime = "Updated at\n10:47";
|
||||
lv_label_set_text(ui_weatherCity, "Nairobi");
|
||||
lv_label_set_text(ui_weatherUpdateTime, updateTime);
|
||||
lv_label_set_text_fmt(ui_weatherCurrentTemp, "%d°C", weather[0].temp);
|
||||
|
||||
setWeatherIcon(ui_weatherCurrentIcon, weather[0].icon, true);
|
||||
|
||||
lv_label_set_text_fmt(ui_weatherTemp, "%d°C", weather[0].temp);
|
||||
setWeatherIcon(ui_weatherIcon, weather[0].icon, true);
|
||||
|
||||
lv_obj_clean(ui_forecastList);
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
addForecast(weather[i].day, weather[i].temp, weather[i].icon);
|
||||
}
|
||||
|
||||
lv_obj_clean(ui_hourlyList);
|
||||
addHourlyWeather(0, 1, 0, 0, 0, 0, true);
|
||||
for (int h = 0; h < 24; h++){
|
||||
addHourlyWeather(hourly[h].hour, hourly[h].icon, hourly[h].temp, hourly[h].humidity, hourly[h].wind, hourly[h].uv, false);
|
||||
}
|
||||
}
|
||||
|
||||
void setupNotifications()
|
||||
{
|
||||
lv_obj_clean(ui_messageList);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
addNotificationList(notifications[i].icon, notifications[i].message, i);
|
||||
}
|
||||
|
||||
lv_obj_scroll_to_y(ui_messageList, 1, LV_ANIM_ON);
|
||||
lv_obj_remove_flag(ui_messageList, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(ui_messagePanel, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
void setupFiles()
|
||||
{
|
||||
|
||||
// addListDrive("C:/", 16777216, 8456213);
|
||||
// addListDrive("D:/", 6456326, 456213);
|
||||
|
||||
addListDir("watchface");
|
||||
addListDir("extracted");
|
||||
addListDir("bluetooth");
|
||||
|
||||
addListFile("kenya.bin", 152453);
|
||||
addListFile("kenya.wf", 453);
|
||||
addListFile("list.txt", 2453);
|
||||
|
||||
lv_obj_scroll_to_y(ui_fileManagerPanel, 1, LV_ANIM_ON);
|
||||
}
|
||||
|
||||
void setupContacts()
|
||||
{
|
||||
|
||||
clearContactList();
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
addContact("fbiego Chronos", "1234567890", i == 2);
|
||||
}
|
||||
}
|
||||
|
||||
void hal_setup(void)
|
||||
{
|
||||
// Workaround for sdl2 `-m32` crash
|
||||
// https://bugs.launchpad.net/ubuntu/+source/libsdl2/+bug/1775067/comments/7
|
||||
#ifndef WIN32
|
||||
setenv("DBUS_FATAL_WARNINGS", "0", 1);
|
||||
#endif
|
||||
|
||||
lv_init();
|
||||
|
||||
lvDisplay = lv_sdl_window_create(SDL_HOR_RES, SDL_VER_RES);
|
||||
lv_sdl_window_set_title(lvDisplay, "C3 Mini");
|
||||
lvMouse = lv_sdl_mouse_create();
|
||||
lvMousewheel = lv_sdl_mousewheel_create();
|
||||
lvKeyboard = lv_sdl_keyboard_create();
|
||||
|
||||
ui_init();
|
||||
|
||||
setupNotifications();
|
||||
// setupWeather();
|
||||
|
||||
setupFiles();
|
||||
setupContacts();
|
||||
|
||||
circular = true;
|
||||
|
||||
lv_obj_scroll_to_y(ui_settingsList, 1, LV_ANIM_ON);
|
||||
lv_obj_scroll_to_y(ui_appList, 1, LV_ANIM_ON);
|
||||
lv_obj_scroll_to_y(ui_appInfoPanel, 1, LV_ANIM_ON);
|
||||
lv_obj_scroll_to_y(ui_gameList, 1, LV_ANIM_ON);
|
||||
lv_obj_add_state(ui_Switch2, LV_STATE_CHECKED);
|
||||
|
||||
set_alert_states(3);
|
||||
|
||||
lv_label_set_text_fmt(ui_aboutText, "%s\nLVGL Simulator\nA1:B2:C3:D4:E5:F6", ui_info_text);
|
||||
|
||||
time_t now = time(0);
|
||||
tm *ltm = localtime(&now);
|
||||
ui_update_seconds(ltm->tm_sec);
|
||||
|
||||
lv_rand_set_seed(ltm->tm_sec);
|
||||
|
||||
ui_setup();
|
||||
|
||||
/* Tick init.
|
||||
* You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed
|
||||
* Create an SDL thread to do this*/
|
||||
SDL_CreateThread(tick_thread, "tick", NULL);
|
||||
}
|
||||
|
||||
void hal_loop(void)
|
||||
{
|
||||
uint32_t lastTick = SDL_GetTicks();
|
||||
while (1)
|
||||
{
|
||||
SDL_Delay(5);
|
||||
uint32_t current = SDL_GetTicks();
|
||||
lv_tick_inc(current - lastTick);
|
||||
lastTick = current;
|
||||
lv_timer_handler();
|
||||
|
||||
if (ui_home == ui_clockScreen)
|
||||
{
|
||||
time_t now = time(0);
|
||||
tm *ltm = localtime(&now);
|
||||
|
||||
int second = ltm->tm_sec;
|
||||
int minute = ltm->tm_min;
|
||||
int hour = ltm->tm_hour;
|
||||
bool am = hour < 12;
|
||||
int day = ltm->tm_mday;
|
||||
int month = 1 + ltm->tm_mon; // Month starts from 0
|
||||
int year = 1900 + ltm->tm_year; // Year is since 1900
|
||||
int weekday = ltm->tm_wday;
|
||||
|
||||
lv_label_set_text_fmt(ui_hourLabel, "%02d", hour);
|
||||
lv_label_set_text_fmt(ui_dayLabel, "%s", daysWk[weekday]);
|
||||
lv_label_set_text_fmt(ui_minuteLabel, "%02d", minute);
|
||||
lv_label_set_text_fmt(ui_dateLabel, "%02d\n%s", day, months[month - 1]);
|
||||
lv_label_set_text(ui_amPmLabel, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
update_faces();
|
||||
}
|
||||
|
||||
// this works just okay on native, esp32 implementation is different
|
||||
ui_games_update();
|
||||
}
|
||||
}
|
||||
|
||||
void contacts_app_launched()
|
||||
{
|
||||
setupContacts();
|
||||
}
|
||||
|
||||
void calendar_app_launched(void)
|
||||
{
|
||||
time_t now = time(0);
|
||||
tm *ltm = localtime(&now);
|
||||
int day = ltm->tm_mday;
|
||||
int month = 1 + ltm->tm_mon; // Month starts from 0
|
||||
int year = 1900 + ltm->tm_year; // Year is since 1900
|
||||
calendar_set_today(year, month, day);
|
||||
}
|
||||
|
||||
int32_t read_encoder_position()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void update_faces()
|
||||
{
|
||||
time_t now = time(0);
|
||||
tm *ltm = localtime(&now);
|
||||
|
||||
// Extract time fields
|
||||
int second = ltm->tm_sec;
|
||||
int minute = ltm->tm_min;
|
||||
int hour = ltm->tm_hour;
|
||||
bool am = hour < 12;
|
||||
int day = ltm->tm_mday;
|
||||
int month = 1 + ltm->tm_mon; // Month starts from 0
|
||||
int year = 1900 + ltm->tm_year; // Year is since 1900
|
||||
int weekday = ltm->tm_wday;
|
||||
|
||||
// int second = rand() % 60;
|
||||
// int minute = rand() % 60;
|
||||
// int hour = rand() % 24;
|
||||
// bool am = hour < 12;
|
||||
// int day = 11;
|
||||
// int month = 5;
|
||||
// int year = 2024;
|
||||
// int weekday = rand() % 7;
|
||||
|
||||
bool mode = true;
|
||||
|
||||
int temp = 22;
|
||||
int icon = 1;
|
||||
|
||||
int battery = 75; // rand() % 100;
|
||||
bool connection = true;
|
||||
|
||||
int steps = 2735;
|
||||
int distance = 17;
|
||||
int kcal = 348;
|
||||
int bpm = 76;
|
||||
int oxygen = 97;
|
||||
|
||||
ui_update_watchfaces(second, minute, hour, mode, am, day, month, year, weekday,
|
||||
temp, icon, battery, connection, steps, distance, kcal, bpm, oxygen);
|
||||
}
|
||||
64
hal/sdl2/app_hal.h
Normal file
64
hal/sdl2/app_hal.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef DRIVER_H
|
||||
#define DRIVER_H
|
||||
|
||||
#if SDL_VER_RES == 240
|
||||
|
||||
#define ENABLE_FACE_ELECROW // elecrow analog
|
||||
#define ENABLE_FACE_34_2 // (Shadow)
|
||||
#define ENABLE_FACE_75_2 // (Analog)
|
||||
#define ENABLE_FACE_79_2 // (Blue)
|
||||
#define ENABLE_FACE_116_ // (Outline)
|
||||
#define ENABLE_FACE_756_2 // (Red)
|
||||
#define ENABLE_FACE_B_W_RESIZED // (B & W)
|
||||
#define ENABLE_FACE_KENYA // (Kenya)
|
||||
#define ENABLE_FACE_PIXEL_RESIZED // (Pixel)
|
||||
#define ENABLE_FACE_RADAR // (Radar)
|
||||
#define ENABLE_FACE_SMART_RESIZED // (Smart)
|
||||
#define ENABLE_FACE_TIX_RESIZED // (Tix)
|
||||
#define ENABLE_FACE_WFB_RESIZED // (WFB)
|
||||
|
||||
#endif
|
||||
|
||||
#if SDL_VER_RES == 280
|
||||
|
||||
#define ENABLE_FACE_174 // (174)
|
||||
#define ENABLE_FACE_228 // (228)
|
||||
#define ENABLE_FACE_1041 // (1041)
|
||||
#define ENABLE_FACE_1167 // (1167)
|
||||
#define ENABLE_FACE_1169 // (1169)
|
||||
#define ENABLE_FACE_2051 // (2051)
|
||||
#define ENABLE_FACE_2151 // (2151)
|
||||
#define ENABLE_FACE_3589 // (3589)
|
||||
|
||||
#endif
|
||||
|
||||
#if SDL_VER_RES == 466
|
||||
#define ENABLE_FACE_756_2_466 // (Red)
|
||||
#define ENABLE_FACE_RADAR_466 // (Radar)
|
||||
|
||||
#endif
|
||||
|
||||
#define ENABLE_GAME_RACING
|
||||
#define ENABLE_GAME_SIMON
|
||||
|
||||
#define ENABLE_APP_CALENDAR
|
||||
#define ENABLE_APP_SAMPLE
|
||||
// #define ENABLE_APP_QMI8658C
|
||||
#define ENABLE_APP_NAVIGATION
|
||||
#define ENABLE_APP_CONTACTS
|
||||
#define ENABLE_APP_TIMER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
void hal_setup(void);
|
||||
void hal_loop(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*DRIVER_H*/
|
||||
Reference in New Issue
Block a user