mirror of https://github.com/arendst/Tasmota.git
Merge branch 'arendst:development' into development
This commit is contained in:
commit
878d6ef02f
|
@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Command ``SspmScan`` to rescan Sonoff SPM modbus
|
||||
- Support for MQ analog sensor for air quality by Francesco Adriani (#14581)
|
||||
- Command ``SetOption134 1`` to disable PWM auto-phasing for lights by default (new behavior) (#14590)
|
||||
- Increase PWM channels to 16 (Esp32 only)
|
||||
|
||||
### Changed
|
||||
- BME68x-Sensor-API library from v3.5.9 to v4.4.7
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# I2C devices
|
||||
|
||||
Tasmota supports several I2C devices but to use them they mostly need to be enabled at compile time to solve possible address conflicts.
|
||||
Tasmota supports several I2C devices. To use them I2C and the device need to be enabled at compile time. I2C and some devices are supported also in the official releases. Devices can be de/-actived on runtime to solve possible address conflicts. (e.g. address 0x27 is used by multiple devices)
|
||||
|
||||
Using command ``I2cDriver`` individual drivers can be enabled or disabled at runtime allowing duplicate I2C addresses at compile time. Use the Index from the table below to control I2C drivers like ``I2cDriver10 0`` for disabling BMP support.
|
||||
|
||||
|
@ -41,7 +40,7 @@ Index | Define | Driver | Device | Address(es) | Description
|
|||
19 | USE_SI1145 | xsns_24 | SI1147 | 0x60 | Ultra violet index and light sensor
|
||||
20 | USE_LM75AD | xsns_26 | LM75AD | 0x48 - 0x4F | Temperature sensor
|
||||
21 | USE_APDS9960 | xsns_27 | APDS9960 | 0x39 | Proximity ambient light RGB and gesture sensor
|
||||
22 | USE_MCP230xx | xsns_29 | MCP23008 | 0x20 - 0x26 | 16-bit I/O expander
|
||||
22 | USE_MCP230xx | xsns_29 | MCP23008 | 0x20 - 0x26 | 8-bit I/O expander
|
||||
22 | USE_MCP230xx | xsns_29 | MCP23017 | 0x20 - 0x26 | 16-bit I/O expander
|
||||
23 | USE_MPR121 | xsns_30 | MPR121 | 0x5A - 0x5D | Proximity capacitive touch sensor
|
||||
24 | USE_CCS811 | xsns_31 | CCS811 | 0x5A | Gas (TVOC) and air quality sensor
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"build": {
|
||||
"arduino":{
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": "-DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3",
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "dout",
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3",
|
||||
"partitions": "esp32_partition_app1856k_spiffs320k.csv"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"espidf",
|
||||
"arduino"
|
||||
],
|
||||
"name": "Espressif Generic ESP32-S3 4M Flash, Tasmota 1856k Code/OTA, 320k FS",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
|
||||
"vendor": "Espressif"
|
||||
}
|
|
@ -52,6 +52,13 @@
|
|||
#define HSPI_HOST SPI3_HOST
|
||||
#define VSPI_HOST SPI3_HOST
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
// SPI_HOST (SPI1_HOST) is not supported by the SPI Master and SPI Slave driver on ESP32-S2 and later
|
||||
#define SPI_HOST SPI1_HOST
|
||||
#define FSPI_HOST SPI2_HOST
|
||||
#define HSPI_HOST SPI3_HOST
|
||||
#define VSPI_HOST SPI3_HOST
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define SPI_HOST SPI1_HOST
|
||||
#define HSPI_HOST SPI2_HOST
|
||||
|
|
|
@ -18,6 +18,7 @@ const uint16_t ST7789_colors[]={ST7789_BLACK,ST7789_WHITE,ST7789_RED,ST7789_GREE
|
|||
ST7789_LIGHTGREY,ST7789_DARKGREY,ST7789_ORANGE,ST7789_GREENYELLOW,ST7789_PINK};
|
||||
|
||||
#ifdef ESP32
|
||||
#include "esp8266toEsp32.h"
|
||||
#define ST7789_DIMMER
|
||||
#endif
|
||||
|
||||
|
@ -258,11 +259,9 @@ void Arduino_ST7789::commonInit(const uint8_t *cmdList) {
|
|||
}
|
||||
|
||||
if (_bp>=0) {
|
||||
#define ESP32_PWM_CHANNEL 1
|
||||
// #define ESP32_PWM_CHANNEL 1
|
||||
#ifdef ST7789_DIMMER
|
||||
ledcSetup(ESP32_PWM_CHANNEL,4000,8);
|
||||
ledcAttachPin(_bp,ESP32_PWM_CHANNEL);
|
||||
ledcWrite(ESP32_PWM_CHANNEL,128);
|
||||
analogWrite(_bp, 128);
|
||||
#else
|
||||
pinMode(_bp, OUTPUT);
|
||||
#endif
|
||||
|
@ -575,7 +574,8 @@ void Arduino_ST7789::DisplayOnff(int8_t on) {
|
|||
writecommand(ST7789_DISPON); //Display on
|
||||
if (_bp>=0) {
|
||||
#ifdef ST7789_DIMMER
|
||||
ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
analogWrite(_bp, dimmer);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
#else
|
||||
digitalWrite(_bp,HIGH);
|
||||
#endif
|
||||
|
@ -584,7 +584,8 @@ void Arduino_ST7789::DisplayOnff(int8_t on) {
|
|||
writecommand(ST7789_DISPOFF);
|
||||
if (_bp>=0) {
|
||||
#ifdef ST7789_DIMMER
|
||||
ledcWrite(ESP32_PWM_CHANNEL,0);
|
||||
analogWrite(_bp, 0);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL,0);
|
||||
#else
|
||||
digitalWrite(_bp,LOW);
|
||||
#endif
|
||||
|
@ -598,7 +599,8 @@ void Arduino_ST7789::dim(uint8_t dim) {
|
|||
if (dimmer>15) dimmer=15;
|
||||
dimmer=((float)dimmer/15.0)*255.0;
|
||||
#ifdef ESP32
|
||||
ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
analogWrite(_bp, dimmer);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -59,10 +59,10 @@ uint16_t Renderer::GetColorFromIndex(uint8_t index) {
|
|||
|
||||
void Renderer::dim(uint8_t contrast) {
|
||||
uint8_t contrast8 = ((uint32_t)contrast * 255) / 15;
|
||||
dim8(contrast8, contrast8);
|
||||
dim10(contrast8, contrast8 * 4);
|
||||
}
|
||||
|
||||
void Renderer::dim8(uint8_t contrast, uint8_t contrast_gamma) {
|
||||
void Renderer::dim10(uint8_t contrast, uint16_t contrast_gamma) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
virtual void Begin(int16_t p1,int16_t p2,int16_t p3);
|
||||
virtual void Updateframe();
|
||||
virtual void dim(uint8_t contrast); // input has range 0..15
|
||||
virtual void dim8(uint8_t contrast, uint8_t contrast_gamma); // input has range 0..255, second arg has gamma correction for PWM
|
||||
virtual void dim10(uint8_t contrast, uint16_t contrast_gamma); // input has range 0..255, second arg has gamma correction for PWM with 10 bits resolution
|
||||
virtual void pushColors(uint16_t *data, uint16_t len, boolean first);
|
||||
virtual void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
|
||||
virtual void invertDisplay(boolean i);
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
// ESP32 uses 2. SPI BUS, ESP8266 uses software spi
|
||||
#ifdef ESP32
|
||||
#include "esp8266toEsp32.h"
|
||||
#undef ILI9341_2_DIMMER
|
||||
#define ILI9341_2_DIMMER
|
||||
#undef ESP32_PWM_CHANNEL
|
||||
|
@ -248,9 +249,7 @@ void ILI9341_2::init(uint16_t width, uint16_t height) {
|
|||
|
||||
if (_bp >= 0) {
|
||||
#ifdef ILI9341_2_DIMMER
|
||||
ledcSetup(ESP32_PWM_CHANNEL, 4000, 8);
|
||||
ledcAttachPin(_bp, ESP32_PWM_CHANNEL);
|
||||
ledcWrite(ESP32_PWM_CHANNEL, 128);
|
||||
analogWrite(_bp, 511);
|
||||
#else
|
||||
pinMode(_bp, OUTPUT);
|
||||
#endif
|
||||
|
@ -544,7 +543,8 @@ void ILI9341_2::DisplayOnff(int8_t on) {
|
|||
SPI_END_TRANSACTION();
|
||||
if (_bp >= 0) {
|
||||
#ifdef ILI9341_2_DIMMER
|
||||
ledcWrite(ESP32_PWM_CHANNEL, dimmer);
|
||||
analogWrite(_bp, dimmer * 4);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, dimmer);
|
||||
#else
|
||||
digitalWrite(_bp, HIGH);
|
||||
#endif
|
||||
|
@ -557,7 +557,8 @@ void ILI9341_2::DisplayOnff(int8_t on) {
|
|||
SPI_END_TRANSACTION();
|
||||
if (_bp >= 0) {
|
||||
#ifdef ILI9341_2_DIMMER
|
||||
ledcWrite(ESP32_PWM_CHANNEL, 0);
|
||||
analogWrite(_bp, 0);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, 0);
|
||||
#else
|
||||
digitalWrite(_bp, LOW);
|
||||
#endif
|
||||
|
@ -604,7 +605,8 @@ void ILI9341_2::dim(uint8_t dim) {
|
|||
dimmer=((float)dimmer/15.0)*255.0;
|
||||
#ifdef ESP32
|
||||
if (_bp>=0) {
|
||||
ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
analogWrite(_bp, dimmer * 4);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
} else {
|
||||
if (_hwspi>=2) {
|
||||
//ili9342_dimm(dim);
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include <Arduino.h>
|
||||
#include "uDisplay.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#include "esp8266toEsp32.h"
|
||||
#endif
|
||||
|
||||
// #define UDSP_DEBUG
|
||||
|
||||
const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\
|
||||
|
@ -428,9 +432,7 @@ Renderer *uDisplay::Init(void) {
|
|||
|
||||
if (bpanel >= 0) {
|
||||
#ifdef ESP32
|
||||
ledcSetup(ESP32_PWM_CHANNEL, 977, 8); // use 10 bits resolution like in Light
|
||||
ledcAttachPin(bpanel, ESP32_PWM_CHANNEL);
|
||||
ledcWrite(ESP32_PWM_CHANNEL, 8); // 38/255 correspond roughly to 50% visual brighness (with Gamma)
|
||||
analogWrite(bpanel, 32);
|
||||
#else
|
||||
pinMode(bpanel, OUTPUT);
|
||||
digitalWrite(bpanel, HIGH);
|
||||
|
@ -1353,7 +1355,8 @@ void uDisplay::DisplayOnff(int8_t on) {
|
|||
if (dsp_on != 0xff) spi_command_one(dsp_on);
|
||||
if (bpanel >= 0) {
|
||||
#ifdef ESP32
|
||||
ledcWrite(ESP32_PWM_CHANNEL, dimmer8_gamma);
|
||||
analogWrite(bpanel, dimmer10_gamma);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, dimmer8_gamma);
|
||||
#else
|
||||
digitalWrite(bpanel, HIGH);
|
||||
#endif
|
||||
|
@ -1363,7 +1366,8 @@ void uDisplay::DisplayOnff(int8_t on) {
|
|||
if (dsp_off != 0xff) spi_command_one(dsp_off);
|
||||
if (bpanel >= 0) {
|
||||
#ifdef ESP32
|
||||
ledcWrite(ESP32_PWM_CHANNEL, 0);
|
||||
analogWrite(bpanel, 0);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, 0);
|
||||
#else
|
||||
digitalWrite(bpanel, LOW);
|
||||
#endif
|
||||
|
@ -1402,16 +1406,17 @@ void udisp_dimm(uint8_t dim);
|
|||
// }
|
||||
|
||||
// dim is 0..255
|
||||
void uDisplay::dim8(uint8_t dim, uint8_t dim_gamma) { // dimmer with 8 bits resolution, 0..255. Gamma correction must be done by caller
|
||||
void uDisplay::dim10(uint8_t dim, uint16_t dim_gamma) { // dimmer with 8 bits resolution, 0..255. Gamma correction must be done by caller
|
||||
dimmer8 = dim;
|
||||
dimmer8_gamma = dim_gamma;
|
||||
dimmer10_gamma = dim_gamma;
|
||||
if (ep_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ESP32 // TODO should we also add a ESP8266 version for bpanel?
|
||||
if (bpanel >= 0) { // is the BaclPanel GPIO configured
|
||||
ledcWrite(ESP32_PWM_CHANNEL, dimmer8_gamma);
|
||||
analogWrite(bpanel, dimmer10_gamma);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, dimmer8_gamma);
|
||||
} else if (dim_cbp) {
|
||||
dim_cbp(dim);
|
||||
}
|
||||
|
|
|
@ -74,9 +74,6 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
|
|||
#define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR_SLOW(spi_dc);
|
||||
#define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc);
|
||||
|
||||
|
||||
#define ESP32_PWM_CHANNEL 1
|
||||
|
||||
#define LUTMAXSIZE 64
|
||||
|
||||
class uDisplay : public Renderer {
|
||||
|
@ -93,7 +90,7 @@ class uDisplay : public Renderer {
|
|||
uint16_t bgcol(void);
|
||||
int8_t color_type(void);
|
||||
// void dim(uint8_t dim); // original version with 4 bits resolution 0..15
|
||||
virtual void dim8(uint8_t dim, uint8_t dim_gamma); // dimmer with 8 bits resolution, 0..255. Gamma correction must be done by caller
|
||||
virtual void dim10(uint8_t dim, uint16_t dim_gamma); // dimmer with 8 bits resolution, 0..255. Gamma correction must be done by caller with 10 bits resolution
|
||||
uint16_t GetColorFromIndex(uint8_t index);
|
||||
void setRotation(uint8_t m);
|
||||
void fillScreen(uint16_t color);
|
||||
|
@ -186,7 +183,7 @@ class uDisplay : public Renderer {
|
|||
int8_t bpanel; // backbanel GPIO, -1 if none
|
||||
int8_t spi_miso;
|
||||
uint8_t dimmer8; // 8 bits resolution, 0..255
|
||||
uint8_t dimmer8_gamma; // 8 bits resolution, 0..255, gamma corrected
|
||||
uint16_t dimmer10_gamma; // 10 bits resolution, 0..1023, gamma corrected
|
||||
SPIClass *uspi;
|
||||
uint8_t sspi;
|
||||
SPISettings spiSettings;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
Attention when updating library. Changes in lib needed!!
|
||||
All OpenTherm constants shall be prepended with `OPTH_` to avoid conflicts with other libs.
|
||||
|
||||
See commit https://github.com/arendst/Tasmota/commit/960291729ccc7cb4da50108e5299d44a79cb06de
|
||||
|
||||
As of OpenTherm-0.9.0, hte list is:
|
||||
OPTH_NONE
|
||||
OPTH_SUCCESS
|
||||
OPTH_INVALID
|
||||
OPTH_TIMEOUT
|
||||
OPTH_READ_DATA
|
||||
OPTH_READ
|
||||
OPTH_WRITE_DATA
|
||||
OPTH_WRITE
|
||||
OPTH_INVALID_DATA
|
||||
OPTH_RESERVED
|
||||
OPTH_READ_ACK
|
||||
OPTH_WRITE_ACK
|
||||
OPTH_DATA_INVALID
|
||||
OPTH_UNKNOWN_DATA_ID
|
||||
OPTH_NOT_INITIALIZED
|
||||
OPTH_READY
|
||||
OPTH_DELAY
|
||||
OPTH_REQUEST_SENDING
|
||||
OPTH_RESPONSE_WAITING
|
||||
OPTH_RESPONSE_START_BIT
|
||||
OPTH_RESPONSE_RECEIVING
|
||||
OPTH_RESPONSE_READY
|
||||
OPTH_RESPONSE_INVALID
|
|
@ -50,7 +50,9 @@ extern "C"
|
|||
#include <lwip/inet.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <include/ClientContext.h>
|
||||
#include <c_types.h>
|
||||
#ifdef ESP8266
|
||||
#include <c_types.h>
|
||||
#endif
|
||||
#include <coredecls.h>
|
||||
|
||||
#if !CORE_MOCK
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
#include "lwip/netif.h"
|
||||
#ifdef ESP8266
|
||||
#include <include/ClientContext.h>
|
||||
#include "c_types.h"
|
||||
#endif
|
||||
#include "c_types.h"
|
||||
|
||||
#include <core_version.h>
|
||||
#undef DEBUG_TLS
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
/**/
|
||||
#include <stdint.h>
|
||||
#ifndef ICACHE_FLASH_ATTR
|
||||
#define ICACHE_FLASH_ATTR
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
//
|
||||
// Compat with ESP32
|
||||
//
|
|
@ -13,58 +13,66 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
//
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
#include "Arduino.h"
|
||||
//#include "lwip/apps/sntp.h"
|
||||
#include <nvs.h>
|
||||
|
||||
// See libraries\ESP32\examples\ResetReason.ino
|
||||
#if ESP_IDF_VERSION_MAJOR > 3 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
|
||||
#include "esp32c3/rom/rtc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/rtc.h"
|
||||
#endif
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "esp8266toEsp32.h"
|
||||
#include "driver/ledc.h"
|
||||
|
||||
// Tasmota Logging
|
||||
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
||||
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
|
||||
|
||||
// ESP Stuff
|
||||
|
||||
// replicated from `tasmota.h`
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
const uint8_t MAX_PWMS = 16; // ESP32: 16 ledc PWM channels in total - TODO for now
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
const uint8_t MAX_PWMS = 8; // ESP32S2: 8 ledc PWM channels in total
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
const uint8_t MAX_PWMS = 8; // ESP32S2: 8 ledc PWM channels in total
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
const uint8_t MAX_PWMS = 6; // ESP32C3: 6 ledc PWM channels in total
|
||||
#else
|
||||
const uint8_t MAX_PWMS = 5; // Unknown - revert to 5 PWM max
|
||||
#endif
|
||||
|
||||
// channel mapping
|
||||
static uint8_t pwm_channel[MAX_PWMS];
|
||||
static uint32_t pwm_frequency = 977; // Default 977Hz
|
||||
static uint8_t pwm_bit_num = 10; // Default 1023
|
||||
static bool pwm_impl_inited = false; // trigger initialization
|
||||
|
||||
/*********************************************************************************************\
|
||||
* ESP32 analogWrite emulation support
|
||||
\*********************************************************************************************/
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
uint8_t _pwm_channel[PWM_SUPPORTED_CHANNELS] = { 99, 99, 99, 99, 99, 99 };
|
||||
uint32_t _pwm_frequency = 977; // Default 977Hz
|
||||
uint8_t _pwm_bit_num = 10; // Default 1023
|
||||
#else // other ESP32
|
||||
uint8_t _pwm_channel[PWM_SUPPORTED_CHANNELS] = { 99, 99, 99, 99, 99, 99, 99, 99 };
|
||||
uint32_t _pwm_frequency = 977; // Default 977Hz
|
||||
uint8_t _pwm_bit_num = 10; // Default 1023
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3 vs ESP32
|
||||
void _analogInit(void) {
|
||||
if (pwm_impl_inited) return;
|
||||
// set all channels to unaffected (255)
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
pwm_channel[i] = 255;
|
||||
}
|
||||
pwm_impl_inited = true;
|
||||
}
|
||||
|
||||
uint32_t _analog_pin2chan(uint32_t pin) {
|
||||
for (uint32_t channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) {
|
||||
if ((_pwm_channel[channel] < 99) && (_pwm_channel[channel] == pin)) {
|
||||
int32_t _analog_pin2chan(uint32_t pin) { // returns -1 if uallocated
|
||||
_analogInit(); // make sure the mapping array is initialized
|
||||
for (uint32_t channel = 0; channel < MAX_PWMS; channel++) {
|
||||
if ((pwm_channel[channel] < 255) && (pwm_channel[channel] == pin)) {
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void _analogWriteFreqRange(void) {
|
||||
for (uint32_t channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) {
|
||||
if (_pwm_channel[channel] < 99) {
|
||||
ledcSetup(channel + PWM_CHANNEL_OFFSET, _pwm_frequency, _pwm_bit_num);
|
||||
_analogInit(); // make sure the mapping array is initialized
|
||||
for (uint32_t channel = 0; channel < MAX_PWMS; channel++) {
|
||||
if (pwm_channel[channel] < 255) {
|
||||
ledcSetup(channel, pwm_frequency, pwm_bit_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,50 +88,43 @@ uint32_t _analogGetResolution(uint32_t x) {
|
|||
}
|
||||
|
||||
void analogWriteRange(uint32_t range) {
|
||||
_pwm_bit_num = _analogGetResolution(range);
|
||||
pwm_bit_num = _analogGetResolution(range);
|
||||
_analogWriteFreqRange();
|
||||
}
|
||||
|
||||
void analogWriteFreq(uint32_t freq) {
|
||||
_pwm_frequency = freq;
|
||||
pwm_frequency = freq;
|
||||
_analogWriteFreqRange();
|
||||
}
|
||||
|
||||
bool analogAttach(uint32_t pin) {
|
||||
int32_t analogAttach(uint32_t pin) { // returns ledc channel used, or -1 if failed
|
||||
_analogInit(); // make sure the mapping array is initialized
|
||||
// Find if pin is already attached
|
||||
uint32_t channel;
|
||||
for (channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) {
|
||||
if (_pwm_channel[channel] == pin) {
|
||||
// Already attached
|
||||
// Serial.printf("PWM: Already attached pin %d to channel %d\n", pin, channel);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
int32_t channel = _analog_pin2chan(pin);
|
||||
if (channel >= 0) { return channel; }
|
||||
// Find an empty channel
|
||||
for (channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) {
|
||||
if (99 == _pwm_channel[channel]) {
|
||||
_pwm_channel[channel] = pin;
|
||||
ledcAttachPin(pin, channel + PWM_CHANNEL_OFFSET);
|
||||
ledcSetup(channel + PWM_CHANNEL_OFFSET, _pwm_frequency, _pwm_bit_num);
|
||||
for (channel = 0; channel < MAX_PWMS; channel++) {
|
||||
if (255 == pwm_channel[channel]) {
|
||||
pwm_channel[channel] = pin;
|
||||
ledcAttachPin(pin, channel);
|
||||
ledcSetup(channel, pwm_frequency, pwm_bit_num);
|
||||
// Serial.printf("PWM: New attach pin %d to channel %d\n", pin, channel);
|
||||
return true;
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
// No more channels available
|
||||
return false;
|
||||
AddLog(LOG_LEVEL_INFO, "PWM: no more PWM (ledc) channel for GPIO %i", pin);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// void analogWrite(uint8_t pin, int val);
|
||||
extern "C" void __wrap__Z11analogWritehi(uint8_t pin, int val)
|
||||
{
|
||||
uint32_t channel = _analog_pin2chan(pin);
|
||||
if ( val >> (_pwm_bit_num-1) ) ++val;
|
||||
ledcWrite(channel + PWM_CHANNEL_OFFSET, val);
|
||||
// Serial.printf("write %d - %d\n",channel,val);
|
||||
extern "C" void __wrap__Z11analogWritehi(uint8_t pin, int val) {
|
||||
analogWritePhase(pin, val, 0); // if unspecified, use phase = 0
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The primary goal of this library is to add phase control to PWM ledc
|
||||
The primary goal of this function is to add phase control to PWM ledc
|
||||
functions.
|
||||
|
||||
Phase control allows to stress less the power supply of LED lights.
|
||||
|
@ -142,35 +143,28 @@ extern "C" void __wrap__Z11analogWritehi(uint8_t pin, int val)
|
|||
implementation changes.
|
||||
*/
|
||||
|
||||
#include "driver/ledc.h"
|
||||
|
||||
#ifdef SOC_LEDC_SUPPORT_HS_MODE
|
||||
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1)
|
||||
#else
|
||||
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM)
|
||||
#endif
|
||||
|
||||
// exported from Arduno Core
|
||||
extern uint8_t channels_resolution[LEDC_CHANNELS];
|
||||
extern uint8_t channels_resolution[MAX_PWMS];
|
||||
|
||||
void analogWritePhase(uint8_t pin, uint32_t duty, uint32_t phase)
|
||||
{
|
||||
uint32_t chan = _analog_pin2chan(pin) + PWM_CHANNEL_OFFSET;
|
||||
if (duty >> (_pwm_bit_num-1) ) ++duty;
|
||||
|
||||
if(chan >= LEDC_CHANNELS){
|
||||
return;
|
||||
int32_t chan = _analog_pin2chan(pin);
|
||||
if (chan < 0) { // not yet allocated, try to allocate
|
||||
chan = analogAttach(pin);
|
||||
if (chan < 0) { return; } // failed
|
||||
}
|
||||
|
||||
if (duty >> (pwm_bit_num-1) ) ++duty; // input is 0..1023 but PWM takes 0..1024 - so we skip at mid-range. It creates a small non-linearity
|
||||
if (phase >> (pwm_bit_num-1) ) ++phase;
|
||||
|
||||
uint8_t group=(chan/8), channel=(chan%8);
|
||||
|
||||
//Fixing if all bits in resolution is set = LEDC FULL ON
|
||||
uint32_t max_duty = (1 << channels_resolution[chan]) - 1;
|
||||
phase = phase % max_duty;
|
||||
|
||||
if(duty == max_duty){ // no sure whether this is needed anymore TODO
|
||||
duty = max_duty + 1;
|
||||
}
|
||||
phase = phase & max_duty;
|
||||
|
||||
ledc_set_duty_with_hpoint((ledc_mode_t)group, (ledc_channel_t)channel, duty, phase);
|
||||
ledc_update_duty((ledc_mode_t)group, (ledc_channel_t)channel);
|
||||
}
|
||||
|
||||
#endif // ESP32
|
||||
|
|
|
@ -13,39 +13,21 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef __ESP8266TOESP32_H__
|
||||
#define __ESP8266TOESP32_H__
|
||||
|
||||
#ifdef ESP32
|
||||
// my debug Stuff
|
||||
#define Serial_Debug1(p) Serial.printf p
|
||||
#define Serial_DebugX(p)
|
||||
|
||||
//
|
||||
// basics
|
||||
//
|
||||
// dummy defines
|
||||
//#define SPIFFS_END (SPI_FLASH_SEC_SIZE * 200)
|
||||
//#define SETTINGS_LOCATION SPIFFS_END
|
||||
|
||||
#include <Esp.h>
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
#define PWM_SUPPORTED_CHANNELS 6
|
||||
#define PWM_CHANNEL_OFFSET 1 // Webcam uses channel 0, so we offset standard PWM
|
||||
#else // other ESP32
|
||||
#define PWM_SUPPORTED_CHANNELS 8
|
||||
#define PWM_CHANNEL_OFFSET 2 // Webcam uses channel 0, so we offset standard PWM
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3 vs ESP32
|
||||
|
||||
extern uint8_t _pwm_channel[PWM_SUPPORTED_CHANNELS];
|
||||
extern uint32_t _pwm_frequency;
|
||||
extern uint8_t _pwm_bit_num;
|
||||
|
||||
void _analogWriteFreqRange(void);
|
||||
// input range is in full range, ledc needs bits
|
||||
uint32_t _analogGetResolution(uint32_t x);
|
||||
void analogWriteRange(uint32_t range);
|
||||
void analogWriteFreq(uint32_t freq);
|
||||
bool analogAttach(uint32_t pin);
|
||||
int32_t analogAttach(uint32_t pin); // returns the ledc channel, or -1 if failed. This is implicitly called by analogWrite if the channel was not already allocated
|
||||
void analogWrite(uint8_t pin, int val);
|
||||
|
||||
// Extended version that also allows to change phase
|
||||
|
@ -56,8 +38,6 @@ extern void analogWritePhase(uint8_t pin, uint32_t duty, uint32_t phase = 0);
|
|||
|
||||
#define INPUT_PULLDOWN_16 INPUT_PULLUP
|
||||
|
||||
typedef double real64_t;
|
||||
|
||||
//
|
||||
// Time and Timer
|
||||
//
|
||||
|
@ -71,7 +51,6 @@ typedef double real64_t;
|
|||
// Serial minimal type to hold the config
|
||||
typedef int SerConfu8;
|
||||
typedef int SerialConfig;
|
||||
//#define analogWrite(a, b)
|
||||
|
||||
//
|
||||
// UDP
|
||||
|
@ -79,9 +58,6 @@ typedef int SerialConfig;
|
|||
//#define PortUdp_writestr(log_data) PortUdp.write((const uint8_t *)(log_data), strlen(log_data))
|
||||
#define PortUdp_write(log_data, n) PortUdp.write((const uint8_t *)(log_data), n)
|
||||
|
||||
//
|
||||
#define wifi_forceSleepBegin()
|
||||
|
||||
#undef LWIP_IPV6
|
||||
|
||||
#define REASON_DEFAULT_RST 0 // "Power on" normal startup by power on
|
||||
|
@ -106,4 +82,5 @@ typedef int SerialConfig;
|
|||
|
||||
#define STATION_IF 0
|
||||
|
||||
#endif
|
||||
#endif // ESP32
|
||||
#endif // __ESP8266TOESP32_H__
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#pragma once
|
||||
/**/
|
||||
#include <lwip/ip_addr.h>
|
||||
/*
|
||||
#ifndef ICACHE_FLASH_ATTR
|
||||
#define ICACHE_FLASH_ATTR
|
||||
#endif
|
||||
*/
|
|
@ -41,6 +41,7 @@ be_extern_native_module(webserver);
|
|||
be_extern_native_module(flash);
|
||||
be_extern_native_module(path);
|
||||
be_extern_native_module(unishox);
|
||||
be_extern_native_module(uuid);
|
||||
be_extern_native_module(animate);
|
||||
#ifdef USE_LVGL
|
||||
be_extern_native_module(lv);
|
||||
|
@ -118,6 +119,7 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = {
|
|||
&be_native_module(light),
|
||||
#endif
|
||||
|
||||
&be_native_module(uuid),
|
||||
#ifdef USE_UNISHOX_COMPRESSION
|
||||
&be_native_module(unishox),
|
||||
#endif // USE_UNISHOX_COMPRESSION
|
||||
|
|
|
@ -41,12 +41,15 @@ extern const bcstring be_const_str_EVENT_DELETE;
|
|||
extern const bcstring be_const_str_EVENT_DRAW_MAIN;
|
||||
extern const bcstring be_const_str_EVENT_DRAW_PART_BEGIN;
|
||||
extern const bcstring be_const_str_EVENT_DRAW_PART_END;
|
||||
extern const bcstring be_const_str_EXTERNAL_I2S;
|
||||
extern const bcstring be_const_str_False;
|
||||
extern const bcstring be_const_str_GET;
|
||||
extern const bcstring be_const_str_HTTP_GET;
|
||||
extern const bcstring be_const_str_HTTP_POST;
|
||||
extern const bcstring be_const_str_I2C_Driver;
|
||||
extern const bcstring be_const_str_I2C_X3A;
|
||||
extern const bcstring be_const_str_INTERNAL_DAC;
|
||||
extern const bcstring be_const_str_INTERNAL_PDM;
|
||||
extern const bcstring be_const_str_LVG_X3A_X20call_X20to_X20unsupported_X20callback;
|
||||
extern const bcstring be_const_str_LVG_X3A_X20object_X3A;
|
||||
extern const bcstring be_const_str_Leds;
|
||||
|
@ -108,6 +111,7 @@ extern const bcstring be_const_str__X23init_X2Ebat;
|
|||
extern const bcstring be_const_str__X23preinit_X2Ebe;
|
||||
extern const bcstring be_const_str__X2502d_X25s_X2502d;
|
||||
extern const bcstring be_const_str__X2504d_X2D_X2502d_X2D_X2502dT_X2502d_X3A_X2502d_X3A_X2502d;
|
||||
extern const bcstring be_const_str__X2508x_X2D_X2504x_X2D_X2504x_X2D_X2504x_X2D_X2504x_X2508x;
|
||||
extern const bcstring be_const_str__X25s_X2Eautoconf;
|
||||
extern const bcstring be_const_str__X26lt_X3BError_X3A_X20apply_X20new_X20or_X20remove_X26gt_X3B;
|
||||
extern const bcstring be_const_str__X26lt_X3BNone_X26gt_X3B;
|
||||
|
@ -149,7 +153,7 @@ extern const bcstring be_const_str__X3Coption_X20value_X3D_X27reset_X27_X3E_X26l
|
|||
extern const bcstring be_const_str__X3Cp_X20style_X3D_X27width_X3A340px_X3B_X27_X3E_X3Cb_X3EException_X3A_X3C_X2Fb_X3E_X3Cbr_X3E_X27_X25s_X27_X3Cbr_X3E_X25s_X3C_X2Fp_X3E;
|
||||
extern const bcstring be_const_str__X3Cp_X3ECurrent_X20configuration_X3A_X20_X3C_X2Fp_X3E_X3Cp_X3E_X3Cb_X3E_X25s_X3C_X2Fb_X3E_X3C_X2Fp_X3E;
|
||||
extern const bcstring be_const_str__X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E;
|
||||
extern const bcstring be_const_str__X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27ac_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3E_X26_X23129668_X3B_X20Auto_X2Dconfiguration_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E;
|
||||
extern const bcstring be_const_str__X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27ac_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3EAuto_X2Dconfiguration_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E;
|
||||
extern const bcstring be_const_str__X3Cp_X3E_X3Cform_X20id_X3Dreapply_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20action_X3D_X27_X2Fac_X27_X20method_X3D_X27post_X27_X20;
|
||||
extern const bcstring be_const_str__X3Cp_X3E_X3Cform_X20id_X3Dzip_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20action_X3D_X27_X2Fac_X27_X20method_X3D_X27post_X27_X20;
|
||||
extern const bcstring be_const_str__X3Cp_X3E_X3Csmall_X3E_X26nbsp_X3B_X28This_X20feature_X20requires_X20an_X20internet_X20connection_X29_X3C_X2Fsmall_X3E_X3C_X2Fp_X3E;
|
||||
|
@ -333,6 +337,7 @@ extern const bcstring be_const_str_detect;
|
|||
extern const bcstring be_const_str_detected_X20on_X20bus;
|
||||
extern const bcstring be_const_str_digital_read;
|
||||
extern const bcstring be_const_str_digital_write;
|
||||
extern const bcstring be_const_str_dimmer;
|
||||
extern const bcstring be_const_str_dirty;
|
||||
extern const bcstring be_const_str_display;
|
||||
extern const bcstring be_const_str_display_X2Eini;
|
||||
|
@ -652,6 +657,7 @@ extern const bcstring be_const_str_set_channels;
|
|||
extern const bcstring be_const_str_set_chg_current;
|
||||
extern const bcstring be_const_str_set_dc_voltage;
|
||||
extern const bcstring be_const_str_set_dcdc_enable;
|
||||
extern const bcstring be_const_str_set_exten;
|
||||
extern const bcstring be_const_str_set_first_time;
|
||||
extern const bcstring be_const_str_set_gain;
|
||||
extern const bcstring be_const_str_set_height;
|
||||
|
@ -740,6 +746,7 @@ extern const bcstring be_const_str_unknown_X20instruction;
|
|||
extern const bcstring be_const_str_update;
|
||||
extern const bcstring be_const_str_upper;
|
||||
extern const bcstring be_const_str_url_encode;
|
||||
extern const bcstring be_const_str_uuid4;
|
||||
extern const bcstring be_const_str_v;
|
||||
extern const bcstring be_const_str_value;
|
||||
extern const bcstring be_const_str_value_error;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,14 +1,17 @@
|
|||
#include "be_constobj.h"
|
||||
|
||||
static be_define_const_map_slots(be_class_audio_output_i2s_map) {
|
||||
{ be_const_key(INTERNAL_PDM, -1), be_const_int(AudioOutputI2S::INTERNAL_PDM) },
|
||||
{ be_const_key(INTERNAL_DAC, 2), be_const_int(AudioOutputI2S::INTERNAL_DAC) },
|
||||
{ be_const_key(init, -1), be_const_func(i2s_output_i2s_init) },
|
||||
{ be_const_key(EXTERNAL_I2S, 1), be_const_int(AudioOutputI2S::EXTERNAL_I2S) },
|
||||
{ be_const_key(deinit, -1), be_const_func(i2s_output_i2s_deinit) },
|
||||
{ be_const_key(stop, -1), be_const_func(i2s_output_i2s_stop) },
|
||||
};
|
||||
|
||||
static be_define_const_map(
|
||||
be_class_audio_output_i2s_map,
|
||||
3
|
||||
6
|
||||
);
|
||||
|
||||
BE_EXPORT_VARIABLE be_define_const_class(
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#include "be_constobj.h"
|
||||
|
||||
static be_define_const_map_slots(m_libdisplay_map) {
|
||||
{ be_const_key(dimmer, -1), be_const_func(be_ntv_display_dimmer) },
|
||||
{ be_const_key(start, 0), be_const_func(be_ntv_display_start) },
|
||||
};
|
||||
|
||||
static be_define_const_map(
|
||||
m_libdisplay_map,
|
||||
2
|
||||
);
|
||||
|
||||
static be_define_const_module(
|
||||
m_libdisplay,
|
||||
"display"
|
||||
);
|
||||
|
||||
BE_EXPORT_VARIABLE be_define_const_native_module(display);
|
|
@ -46,19 +46,29 @@ int32_t be_audio_opus_decoder_deinit(struct bvm *vm) {
|
|||
// decode(payload:bytes) -> pcm:bytes()
|
||||
int32_t be_audio_opus_decoder_decode(struct bvm *vm) {
|
||||
int32_t argc = be_top(vm);
|
||||
be_call_c_func(vm, NULL, NULL, ".(bytes)");
|
||||
be_call_c_func(vm, NULL, NULL, ".(bytes)[ii]");
|
||||
|
||||
OpusDecoder* st = (OpusDecoder*) be_convert_single_elt(vm, 1, NULL, NULL); // get value of '.p'
|
||||
size_t frames_len;
|
||||
const uint8_t * opus_frame = be_tobytes(vm, 2, &frames_len);
|
||||
size_t bytes_len;
|
||||
const uint8_t * opus_frame = be_tobytes(vm, 2, &bytes_len);
|
||||
int32_t frame_start = 0;
|
||||
int32_t frame_len = bytes_len;
|
||||
if (argc >= 3) { frame_start = be_toint(vm, 3); if (frame_start < 0) frame_start = 0; }
|
||||
if (argc >= 4) { frame_len = be_toint(vm, 4); }
|
||||
|
||||
int samples = opus_decoder_get_nb_samples(st, opus_frame, frames_len);
|
||||
if (frame_start >= bytes_len) { frame_len = 0; } // send empty packet
|
||||
else if (frame_len < 0) { frame_len = bytes_len - frame_start; } // send all packet, adjust len
|
||||
else if (frame_start + frame_len > bytes_len) { frame_len = bytes_len - frame_start; } // len is too long, adjust
|
||||
// adjust start
|
||||
opus_frame = opus_frame + frame_start;
|
||||
|
||||
int samples = opus_decoder_get_nb_samples(st, opus_frame, frame_len);
|
||||
// tasmota_log_C(LOG_LEVEL_DEBUG, "AUD: frame contains %i samples", samples);
|
||||
|
||||
// allocate a buffer for the content
|
||||
void * pcm = be_pushbytes(vm, NULL, samples * 2);
|
||||
|
||||
int ret = opus_decode(st, opus_frame, frames_len, pcm, samples, 0);
|
||||
int ret = opus_decode(st, opus_frame, frame_len, pcm, samples, 0);
|
||||
if (ret != samples) { be_raisef(vm, "internal_error", "wrong number of frames %i (supposed to be %i", ret, samples); }
|
||||
|
||||
be_return(vm);
|
||||
|
|
|
@ -897,7 +897,7 @@ be_local_closure(Autoconf_web_add_config_button, /* name */
|
|||
( &(const bvalue[ 3]) { /* constants */
|
||||
/* K0 */ be_nested_str(webserver),
|
||||
/* K1 */ be_nested_str(content_send),
|
||||
/* K2 */ be_nested_str(_X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27ac_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3E_X26_X23129668_X3B_X20Auto_X2Dconfiguration_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E),
|
||||
/* K2 */ be_nested_str(_X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27ac_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3EAuto_X2Dconfiguration_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E),
|
||||
}),
|
||||
&be_const_str_web_add_config_button,
|
||||
&be_const_str_solidified,
|
||||
|
|
|
@ -9,21 +9,15 @@
|
|||
|
||||
#ifdef USE_DISPLAY
|
||||
|
||||
// Tasmota specific
|
||||
|
||||
extern int be_ntv_display_start(bvm *vm);
|
||||
extern int be_ntv_display_dimmer(bvm *vm);
|
||||
|
||||
/********************************************************************
|
||||
** Solidified module: display
|
||||
********************************************************************/
|
||||
be_local_module(display,
|
||||
"display",
|
||||
be_nested_map(1,
|
||||
( (struct bmapnode*) &(const bmapnode[]) {
|
||||
{ be_const_key(start, -1), be_const_func(be_ntv_display_start) },
|
||||
}))
|
||||
);
|
||||
BE_EXPORT_VARIABLE be_define_const_native_module(display);
|
||||
/********************************************************************/
|
||||
/* @const_object_info_begin
|
||||
module display (scope: global) {
|
||||
start, func(be_ntv_display_start)
|
||||
dimmer, func(be_ntv_display_dimmer)
|
||||
}
|
||||
@const_object_info_end */
|
||||
#include "be_fixed_display.h"
|
||||
|
||||
#endif // USE_DISPLAY
|
||||
#endif // USE_DISPLAY
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -147,6 +147,8 @@ int32_t be_audio_output_consume_silence(struct bvm *vm) {
|
|||
return be_call_c_func(vm, (void*) &be_audio_output_consume_silence_ntv, "i", ".");
|
||||
}
|
||||
|
||||
#include "AudioOutputI2S.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include "be_fixed_be_class_audio_output.h"
|
||||
|
@ -211,6 +213,10 @@ class be_class_audio_file_source (scope: global, name: AudioFileSource) {
|
|||
}
|
||||
|
||||
class be_class_audio_output_i2s (scope: global, name: AudioOutputI2S, super: be_class_audio_output) {
|
||||
EXTERNAL_I2S, int(AudioOutputI2S::EXTERNAL_I2S)
|
||||
INTERNAL_DAC, int(AudioOutputI2S::INTERNAL_DAC)
|
||||
INTERNAL_PDM, int(AudioOutputI2S::INTERNAL_PDM)
|
||||
|
||||
init, func(i2s_output_i2s_init)
|
||||
deinit, func(i2s_output_i2s_deinit)
|
||||
stop, func(i2s_output_i2s_stop)
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/********************************************************************
|
||||
* uuid module
|
||||
*
|
||||
*******************************************************************/
|
||||
#include "be_constobj.h"
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: _anonymous_
|
||||
********************************************************************/
|
||||
be_local_closure(uuid__anonymous_, /* name */
|
||||
be_nested_proto(
|
||||
12, /* nstack */
|
||||
0, /* argc */
|
||||
0, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 5]) { /* constants */
|
||||
/* K0 */ be_nested_str(string),
|
||||
/* K1 */ be_nested_str(math),
|
||||
/* K2 */ be_nested_str(format),
|
||||
/* K3 */ be_nested_str(_X2508x_X2D_X2504x_X2D_X2504x_X2D_X2504x_X2D_X2504x_X2508x),
|
||||
/* K4 */ be_nested_str(rand),
|
||||
}),
|
||||
&be_const_str__anonymous_,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[30]) { /* code */
|
||||
0xA4020000, // 0000 IMPORT R0 K0
|
||||
0xA4060200, // 0001 IMPORT R1 K1
|
||||
0x8C080102, // 0002 GETMET R2 R0 K2
|
||||
0x58100003, // 0003 LDCONST R4 K3
|
||||
0x8C140304, // 0004 GETMET R5 R1 K4
|
||||
0x7C140200, // 0005 CALL R5 1
|
||||
0x8C180304, // 0006 GETMET R6 R1 K4
|
||||
0x7C180200, // 0007 CALL R6 1
|
||||
0x541EFFFE, // 0008 LDINT R7 65535
|
||||
0x2C180C07, // 0009 AND R6 R6 R7
|
||||
0x8C1C0304, // 000A GETMET R7 R1 K4
|
||||
0x7C1C0200, // 000B CALL R7 1
|
||||
0x54220FFE, // 000C LDINT R8 4095
|
||||
0x2C1C0E08, // 000D AND R7 R7 R8
|
||||
0x54223FFF, // 000E LDINT R8 16384
|
||||
0x301C0E08, // 000F OR R7 R7 R8
|
||||
0x8C200304, // 0010 GETMET R8 R1 K4
|
||||
0x7C200200, // 0011 CALL R8 1
|
||||
0x54263FFE, // 0012 LDINT R9 16383
|
||||
0x2C201009, // 0013 AND R8 R8 R9
|
||||
0x54267FFF, // 0014 LDINT R9 32768
|
||||
0x30201009, // 0015 OR R8 R8 R9
|
||||
0x8C240304, // 0016 GETMET R9 R1 K4
|
||||
0x7C240200, // 0017 CALL R9 1
|
||||
0x542AFFFE, // 0018 LDINT R10 65535
|
||||
0x2C24120A, // 0019 AND R9 R9 R10
|
||||
0x8C280304, // 001A GETMET R10 R1 K4
|
||||
0x7C280200, // 001B CALL R10 1
|
||||
0x7C081000, // 001C CALL R2 8
|
||||
0x80040400, // 001D RET 1 R2
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified module: uuid
|
||||
********************************************************************/
|
||||
be_local_module(uuid,
|
||||
"uuid",
|
||||
be_nested_map(1,
|
||||
( (struct bmapnode*) &(const bmapnode[]) {
|
||||
{ be_const_key(uuid4, -1), be_const_closure(uuid__anonymous__closure) },
|
||||
}))
|
||||
);
|
||||
BE_EXPORT_VARIABLE be_define_const_native_module(uuid);
|
||||
/********************************************************************/
|
|
@ -141,7 +141,7 @@ autoconf_module.init = def (m)
|
|||
# Displays a "Autocong" button on the configuration page
|
||||
def web_add_config_button()
|
||||
import webserver
|
||||
webserver.content_send("<p><form id=ac action='ac' style='display: block;' method='get'><button>🪄 Auto-configuration</button></form></p>")
|
||||
webserver.content_send("<p><form id=ac action='ac' style='display: block;' method='get'><button>Auto-configuration</button></form></p>")
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -67,6 +67,11 @@ class AXP192 : I2C_Driver
|
|||
end
|
||||
end
|
||||
|
||||
# set EXTEN which enables external power on M5Stack, powering Hat with 5V
|
||||
def set_exten(state)
|
||||
self.write_bit(0x12, 6, state)
|
||||
end
|
||||
|
||||
# set DCDC enable, 1/2/3
|
||||
def set_dcdc_enable(dcdc, state)
|
||||
if dcdc == 1 self.write_bit(0x12, 0, state) end
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
uuid = module("uuid")
|
||||
uuid.uuid4 = def ()
|
||||
import string
|
||||
import math
|
||||
return string.format("%08x-%04x-%04x-%04x-%04x%08x",
|
||||
math.rand(),
|
||||
math.rand() & 0xFFFF,
|
||||
math.rand() & 0x0FFF | 0x4000,
|
||||
math.rand() & 0x3FFF | 0x8000,
|
||||
math.rand() & 0xFFFF,
|
||||
math.rand() )
|
||||
end
|
||||
|
||||
return uuid
|
|
@ -26,12 +26,21 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
#define LOG_LEVEL_DEBUG (0)
|
||||
#define LOG_LEVEL_INFO (1)
|
||||
#define LOG_LEVEL_WARN (2)
|
||||
#define LOG_LEVEL_ERROR (3)
|
||||
#define LOG_LEVEL_CRITICAL (4)
|
||||
#define LOG_LEVEL_NONE (5)
|
||||
*/
|
||||
#define LOG_LEVEL_DEBUG (3)
|
||||
#define LOG_LEVEL_INFO (2)
|
||||
#define LOG_LEVEL_WARN (4)
|
||||
#define LOG_LEVEL_ERROR (1)
|
||||
#define LOG_LEVEL_CRITICAL (5)
|
||||
#define LOG_LEVEL_NONE (0)
|
||||
|
||||
/* Up to 7 custom log levels. */
|
||||
#define LOG_LEVEL_MAX (15)
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Attention when updating library. Changes in lib needed!!
|
||||
See https://github.com/arendst/Tasmota/commit/497d8218f9f92d9db4664fa519bbafbf78711db7
|
File diff suppressed because it is too large
Load Diff
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
THIS EXAMPLE IS REALLY JUST DOCUMENTATION TO GUIDE YOU THROUGH CHANGES IN
|
||||
Adafruit_LvGL_Glue 2.0.
|
||||
|
||||
If you’re coming to Adafruit_LvGL_Glue for the first time as a current user
|
||||
of LittlevGL on other platforms, you're fine, there are no surprises here,
|
||||
have a look at the other examples to see how to set up an Adafruit display
|
||||
for your LittlevGL application.
|
||||
|
||||
BUT...if you've used a prior version of Adafruit_LvGL_Glue, and had written
|
||||
Arduino sketches around it, you're unfortunately in for some extra work.
|
||||
The "glue" hasn't changed at all, but LittlevGL has seen repeated overhauls,
|
||||
and projects using earlier versions of Adafruit_LvGL_Glue will no longer
|
||||
compile in the new system without substantial changes. Many function names,
|
||||
constants, and styles in particular, will require updating. Many LittlevGL
|
||||
projects are too much to fit on M0 (SAMD21) boards now -- it's best to work
|
||||
with a device with more RAM -- M4 (SAMD51), nRF52 and ESP32 are currently
|
||||
supported.
|
||||
|
||||
If desperate to get old code working, you can downgrade to lv_arduino 2.1.5
|
||||
and Adafruit_LvGL_Glue 1.0.2, but this is NOT recommended when developing
|
||||
for the long haul -- lv_arduino is altogether deprecated now and won't be
|
||||
staging a comeback.
|
||||
|
||||
For starters, LittlevGL has moved to an entirely different Arduino library.
|
||||
"lv_arduino" should be UNINSTALLED, and in its place, "lvgl" should be
|
||||
INSTALLED. The latter is at version 7.11.0 as this is being written...if
|
||||
there's a newer release, and if you find our glue examples failing to
|
||||
compile, it's recommended to install that version until this library can be
|
||||
updated. The LittlevGL developers' preference favors structural and
|
||||
consistency upgrades over backwards compatibility -- and that's fine, their
|
||||
project, their rules -- just explaining why this overhaul is necessary.
|
||||
|
||||
To repeat: in the Arduino Library Manager, uninstall lv_arduino, install
|
||||
lvgl.
|
||||
|
||||
Also in the Arduino Library Manager, you'll see a related library called
|
||||
"lv_examples" from the same developer. You can install that if you want, but
|
||||
understand that this is not actually a library, nor will any of the examples
|
||||
there compile in the Arduino IDE! But if you pick through these files
|
||||
manually, there's C code you can dissect for insights in creating interfaces
|
||||
with LittlevGL, and might create mash-ups with Adafruit_LvGL_Glue examples.
|
||||
|
||||
Adafruit_LvGL_Glue includes a lv_conf.file (LittlevGL configuration) that
|
||||
should "just work" and enables some settings for best compatibility with
|
||||
Adafruit displays. The only "gotcha" here is that user sketches MUST
|
||||
#include Adafruit_LvGL_Glue.h BEFORE including lvgl.h, in order for
|
||||
LittlevGL to pick up on the location of this header file.
|
||||
|
||||
BELOW IS A HYPOTHETICAL AND MINIMAL BUT ESSENTIALLY VALID ADAFRUIT_LVGL_GLUE
|
||||
ARDUINO SKETCH. Please see the other examples for more realistic use. Actual
|
||||
projects will have different display interfacing, backlight control, a set
|
||||
of UI widgets and so forth.
|
||||
*/
|
||||
|
||||
#include <Adafruit_LvGL_Glue.h> // Glue library header INCLUDE THIS FIRST!
|
||||
#include <lvgl.h> // LittlevGL header
|
||||
#include <Adafruit_ST7789.h> // Display-specific header
|
||||
|
||||
#define TFT_CS 1 // Display chip-select pin
|
||||
#define TFT_DC 2 // Display data/command pin
|
||||
#define TFT_RST 3 // Display reset pin
|
||||
|
||||
Adafruit_ST7789 tft(TFT_CS, TFT_DC, TFT_RST); // TFT on default SPI port
|
||||
Adafruit_LvGL_Glue glue;
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
tft.init(240, 240); // Initialize display
|
||||
|
||||
// Initialize glue, passing in address of display
|
||||
LvGLStatus status = glue.begin(&tft);
|
||||
if(status != LVGL_OK) {
|
||||
Serial.printf("Glue error %d\r\n", (int)status);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
// Create simple label centered on screen
|
||||
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_text(label, "Hello Arduino!");
|
||||
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
lv_task_handler(); // Call LittleVGL task handler periodically
|
||||
delay(5);
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
// Minimal "Hello" example for LittlevGL on Adafruit CLUE. Requires
|
||||
// LittlevGL, Adafruit_LvGL_Glue, Adafruit_GFX and Adafruit_ST7735
|
||||
// libraries.
|
||||
|
||||
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
|
||||
|
||||
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
|
||||
#include <lvgl.h>
|
||||
#include <Adafruit_ST7789.h>
|
||||
|
||||
#define TFT_ROTATION 1 // Landscape orientation on CLUE
|
||||
#define TFT_SPI SPI1 // CLUE display peripheral & pins
|
||||
#define TFT_CS 31
|
||||
#define TFT_DC 32
|
||||
#define TFT_RST 33
|
||||
#define TFT_BACKLIGHT 34
|
||||
|
||||
Adafruit_ST7789 tft(&TFT_SPI, TFT_CS, TFT_DC, TFT_RST);
|
||||
Adafruit_LvGL_Glue glue;
|
||||
|
||||
// This example sketch's LittlevGL UI-building calls are all in this
|
||||
// function rather than in setup(), so simple programs can just
|
||||
// copy-and-paste this sketch as a starting point, then embellish here:
|
||||
void lvgl_setup(void) {
|
||||
// Create simple label centered on screen
|
||||
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_text(label, "Hello Arduino!");
|
||||
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize display BEFORE glue setup
|
||||
tft.init(240, 240);
|
||||
tft.setRotation(TFT_ROTATION);
|
||||
pinMode(TFT_BACKLIGHT, OUTPUT);
|
||||
digitalWrite(TFT_BACKLIGHT, HIGH);
|
||||
|
||||
// Initialize glue, passing in address of display
|
||||
LvGLStatus status = glue.begin(&tft);
|
||||
if(status != LVGL_OK) {
|
||||
Serial.printf("Glue error %d\r\n", (int)status);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
lvgl_setup(); // Call UI-building function above
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
lv_task_handler(); // Call LittleVGL task handler periodically
|
||||
delay(5);
|
||||
}
|
||||
|
||||
// NOTE TO FUTURE SELF: this sketch is essentially the same as the Gizmo
|
||||
// widgets example. If updating one sketch, make sure the other is kept
|
||||
// in sync. Aside from screen setup, differences include backlight control
|
||||
// and A/B button setup & read (CPX is active high, CLUE is active low).
|
|
@ -1,74 +0,0 @@
|
|||
// Minimal "Hello" example for LittlevGL on Adafruit TFT FeatherWings.
|
||||
// Requires LittlevGL, Adafruit_LvGL_Glue, Adafruit_STMPE610, Adafruit_GFX
|
||||
// and Adafruit_ILI9341 (2.4" TFT) or Adafruit_HX8357 (3.5") libraries.
|
||||
// This example doesn't use any touchscreen input, but it's declared anyway
|
||||
// so this sketch can be copied-and-pasted to serve as a starting point for
|
||||
// other projects. If display is scrambled, check that correct FeatherWing
|
||||
// type is selected below (set BIG_FEATHERWING to 0 or 1 as needed).
|
||||
|
||||
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
|
||||
|
||||
#define BIG_FEATHERWING 0 // Set this to 1 for 3.5" (480x320) FeatherWing!
|
||||
|
||||
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
|
||||
#include <lvgl.h>
|
||||
#include <Adafruit_STMPE610.h>
|
||||
|
||||
#ifdef ESP32
|
||||
#define TFT_CS 15
|
||||
#define TFT_DC 33
|
||||
#define STMPE_CS 32
|
||||
#else
|
||||
#define TFT_CS 9
|
||||
#define TFT_DC 10
|
||||
#define STMPE_CS 6
|
||||
#endif
|
||||
#define TFT_ROTATION 1 // Landscape orientation on FeatherWing
|
||||
#define TFT_RST -1
|
||||
|
||||
#if BIG_FEATHERWING
|
||||
#include <Adafruit_HX8357.h>
|
||||
Adafruit_HX8357 tft(TFT_CS, TFT_DC, TFT_RST);
|
||||
#else
|
||||
#include <Adafruit_ILI9341.h>
|
||||
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
|
||||
#endif
|
||||
|
||||
Adafruit_STMPE610 ts(STMPE_CS);
|
||||
Adafruit_LvGL_Glue glue;
|
||||
|
||||
// This example sketch's LittlevGL UI-building calls are all in this
|
||||
// function rather than in setup(), so simple programs can just
|
||||
// copy-and-paste this sketch as a starting point, then embellish here:
|
||||
void lvgl_setup(void) {
|
||||
// Create simple label centered on screen
|
||||
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_text(label, "Hello Arduino!");
|
||||
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize display and touchscreen BEFORE glue setup
|
||||
tft.begin();
|
||||
tft.setRotation(TFT_ROTATION);
|
||||
if(!ts.begin()) {
|
||||
Serial.println("Couldn't start touchscreen controller");
|
||||
for(;;);
|
||||
}
|
||||
|
||||
// Initialize glue, passing in address of display & touchscreen
|
||||
LvGLStatus status = glue.begin(&tft, &ts);
|
||||
if(status != LVGL_OK) {
|
||||
Serial.printf("Glue error %d\r\n", (int)status);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
lvgl_setup(); // Call UI-building function above
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
lv_task_handler(); // Call LittleVGL task handler periodically
|
||||
delay(5);
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
// Minimal "Hello" example for LittlevGL on TFT Gizmo display for Adafruit
|
||||
// Circuit Playground Express or Circuit Playground Bluefruit. Requires
|
||||
// LittlevGL, Adafruit_LvGL_Glue, Adafruit_GFX and Adafruit_ST7735 libraries.
|
||||
|
||||
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
|
||||
|
||||
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
|
||||
#include <lvgl.h>
|
||||
#include <Adafruit_ST7789.h>
|
||||
|
||||
#define TFT_ROTATION 2
|
||||
#define TFT_CS A6
|
||||
#define TFT_DC A7
|
||||
#define TFT_RST -1
|
||||
#define TFT_BACKLIGHT A3
|
||||
#if defined(NRF52_SERIES) // Circuit Playground Bluefruit
|
||||
#define TFT_SPI SPI
|
||||
#else // Circuit Playground Express
|
||||
#define TFT_SPI SPI1
|
||||
#endif
|
||||
|
||||
Adafruit_ST7789 tft(&TFT_SPI, TFT_CS, TFT_DC, TFT_RST);
|
||||
Adafruit_LvGL_Glue glue;
|
||||
|
||||
// This example sketch's LittlevGL UI-building calls are all in this
|
||||
// function rather than in setup(), so simple programs can just
|
||||
// copy-and-paste this sketch as a starting point, then embellish here:
|
||||
void lvgl_setup(void) {
|
||||
// Create simple label centered on screen
|
||||
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_text(label, "Hello Arduino!");
|
||||
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize display BEFORE glue setup
|
||||
tft.init(240, 240);
|
||||
tft.setRotation(TFT_ROTATION);
|
||||
pinMode(TFT_BACKLIGHT, OUTPUT);
|
||||
analogWrite(TFT_BACKLIGHT, 255); // USE analogWrite() FOR GIZMO BACKLIGHT!
|
||||
|
||||
// Initialize glue, passing in address of display
|
||||
LvGLStatus status = glue.begin(&tft);
|
||||
if(status != LVGL_OK) {
|
||||
Serial.printf("Glue error %d\r\n", (int)status);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
lvgl_setup(); // Call UI-building function above
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
lv_task_handler(); // Call LittleVGL task handler periodically
|
||||
delay(5);
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
// Minimal "Hello" example for LittlevGL on Adafruit PyPortal. Requires
|
||||
// LittlevGL, Adafruit_LvGL_Glue, Adafruit Touchscreen, Adafruit_GFX and
|
||||
// Adafruit_ILI9341 (PyPortal, PyPortal Pynt) or Adafruit_HX8357 (PyPortal
|
||||
// Titano) libraries. This example doesn't use any touchscreen input, but
|
||||
// it's declared anyway so this sketch can be copied-and-pasted to serve
|
||||
// as a starting point for other projects. If display is scrambled, check
|
||||
// that the correct board is selected -- PyPortal vs PyPortal Titano.
|
||||
|
||||
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
|
||||
|
||||
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
|
||||
#include <lvgl.h>
|
||||
#include <TouchScreen.h>
|
||||
|
||||
#define TFT_ROTATION 3 // Landscape orientation on PyPortal
|
||||
#define TFT_D0 34 // PyPortal TFT pins
|
||||
#define TFT_WR 26
|
||||
#define TFT_DC 10
|
||||
#define TFT_CS 11
|
||||
#define TFT_RST 24
|
||||
#define TFT_RD 9
|
||||
#define TFT_BACKLIGHT 25
|
||||
#define YP A4 // PyPortal touchscreen pins
|
||||
#define XP A5
|
||||
#define YM A6
|
||||
#define XM A7
|
||||
|
||||
#if defined(ADAFRUIT_PYPORTAL_M4_TITANO)
|
||||
#include <Adafruit_HX8357.h>
|
||||
Adafruit_HX8357 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST,
|
||||
TFT_RD);
|
||||
#else
|
||||
#include <Adafruit_ILI9341.h>
|
||||
Adafruit_ILI9341 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST,
|
||||
TFT_RD);
|
||||
#endif
|
||||
TouchScreen ts(XP, YP, XM, YM, 300);
|
||||
Adafruit_LvGL_Glue glue;
|
||||
|
||||
// This example sketch's LittlevGL UI-building calls are all in this
|
||||
// function rather than in setup(), so simple programs can just
|
||||
// copy-and-paste this sketch as a starting point, then embellish here:
|
||||
void lvgl_setup(void) {
|
||||
// Create simple label centered on screen
|
||||
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_text(label, "Hello Arduino!");
|
||||
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize display BEFORE glue setup
|
||||
tft.begin();
|
||||
tft.setRotation(TFT_ROTATION);
|
||||
pinMode(TFT_BACKLIGHT, OUTPUT);
|
||||
digitalWrite(TFT_BACKLIGHT, HIGH);
|
||||
|
||||
// PyPortal touchscreen needs no init
|
||||
|
||||
// Initialize glue, passing in address of display & touchscreen
|
||||
LvGLStatus status = glue.begin(&tft, &ts);
|
||||
if(status != LVGL_OK) {
|
||||
Serial.printf("Glue error %d\r\n", (int)status);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
lvgl_setup(); // Call UI-building function above
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
lv_task_handler(); // Call LittleVGL task handler periodically
|
||||
delay(5);
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
// A more functional example for LittlevGL on Adafruit CLUE. Lacking
|
||||
// touchscreen input, interaction options are limited (but not impossible).
|
||||
// In this case we'll pretend like it's a status display for something --
|
||||
// the left and right buttons switch between three different tabs, each
|
||||
// displaying different information. The code's a bit more complex than
|
||||
// the hello_clue example, so best get that working before trying this.
|
||||
|
||||
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
|
||||
|
||||
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
|
||||
#include <lvgl.h>
|
||||
#include <Adafruit_ST7789.h>
|
||||
|
||||
#define TFT_ROTATION 1 // Landscape orientation on CLUE
|
||||
#define TFT_SPI SPI1 // CLUE display peripheral & pins
|
||||
#define TFT_CS 31
|
||||
#define TFT_DC 32
|
||||
#define TFT_RST 33
|
||||
#define TFT_BACKLIGHT 34
|
||||
|
||||
Adafruit_ST7789 tft(&TFT_SPI, TFT_CS, TFT_DC, TFT_RST);
|
||||
Adafruit_LvGL_Glue glue;
|
||||
|
||||
lv_obj_t *tabview, // LittlevGL tabview object
|
||||
*gauge, // Gauge object (on first of three tabs)
|
||||
*chart, // Chart object (second tab)
|
||||
*canvas; // Canvas object (third tab)
|
||||
uint8_t active_tab = 0, // Index of currently-active tab (0-2)
|
||||
prev_tab = 0; // Index of previously-active tab
|
||||
lv_chart_series_t *series; // 'Series' data for the bar chart
|
||||
|
||||
// Canvas object is an image in memory. Although LittlevGL supports several
|
||||
// internal image formats, only the TRUE_COLOR variety allows drawing
|
||||
// operations. Fortunately nRF52840 has gobs of RAM for this. The canvas
|
||||
// buffer is global because it's referenced both in the setup and main loop.
|
||||
#define CANVAS_WIDTH 200 // Dimensions in pixels
|
||||
#define CANVAS_HEIGHT 150
|
||||
lv_color_t canvas_buffer[
|
||||
LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
|
||||
lv_draw_line_dsc_t draw_dsc; // Drawing style (for canvas) is similarly global
|
||||
|
||||
void lvgl_setup(void) {
|
||||
// Create a tabview object, by default this covers the full display.
|
||||
tabview = lv_tabview_create(lv_disp_get_scr_act(NULL), NULL);
|
||||
// The CLUE display has a lot of pixels and can't refresh very fast.
|
||||
// To show off the tabview animation, let's slow it down to 1 second.
|
||||
lv_tabview_set_anim_time(tabview, 1000);
|
||||
|
||||
// Because they're referenced any time an object is drawn, styles need
|
||||
// to be permanent in scope; either declared globally (outside all
|
||||
// functions), or static. The styles used on tabs are never modified after
|
||||
// they're used here, so let's use static on those...
|
||||
static lv_style_t tab_style, tab_background_style, indicator_style;
|
||||
|
||||
// This is the background style "behind" the tabs. This is what shows
|
||||
// through for "off" (inactive) tabs -- a vertical green gradient,
|
||||
// minimal padding around edges (zero at bottom).
|
||||
lv_style_init(&tab_background_style);
|
||||
lv_style_set_bg_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x408040));
|
||||
lv_style_set_bg_grad_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x304030));
|
||||
lv_style_set_bg_grad_dir(&tab_background_style, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
|
||||
lv_style_set_pad_top(&tab_background_style, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_pad_left(&tab_background_style, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_pad_right(&tab_background_style, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_pad_bottom(&tab_background_style, LV_STATE_DEFAULT, 0);
|
||||
lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BG, &tab_background_style);
|
||||
|
||||
// Style for tabs. Active tab is white with opaque background, inactive
|
||||
// tabs are transparent so the background shows through (only the white
|
||||
// text is seen). A little top & bottom padding reduces scrunchyness.
|
||||
lv_style_init(&tab_style);
|
||||
lv_style_set_pad_top(&tab_style, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_pad_bottom(&tab_style, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_bg_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_WHITE);
|
||||
lv_style_set_bg_opa(&tab_style, LV_STATE_CHECKED, LV_OPA_100);
|
||||
lv_style_set_text_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_GRAY);
|
||||
lv_style_set_bg_opa(&tab_style, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
lv_style_set_text_color(&tab_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BTN, &tab_style);
|
||||
|
||||
// Style for the small indicator bar that appears below the active tab.
|
||||
lv_style_init(&indicator_style);
|
||||
lv_style_set_bg_color(&indicator_style, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_style_set_size(&indicator_style, LV_STATE_DEFAULT, 5);
|
||||
lv_obj_add_style(tabview, LV_TABVIEW_PART_INDIC, &indicator_style);
|
||||
|
||||
// Back to creating widgets...
|
||||
|
||||
// Add three tabs to the tabview
|
||||
lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Gauge");
|
||||
lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Chart");
|
||||
lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Canvas");
|
||||
|
||||
// And then add stuff in each tab...
|
||||
|
||||
// The first tab holds a gauge. To keep the demo simple, let's just use
|
||||
// the default style and range (0-100). See LittlevGL docs for options.
|
||||
gauge = lv_gauge_create(tab1, NULL);
|
||||
lv_obj_set_size(gauge, 186, 186);
|
||||
lv_obj_align(gauge, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
// Second tab, make a chart...
|
||||
chart = lv_chart_create(tab2, NULL);
|
||||
lv_obj_set_size(chart, 200, 180);
|
||||
lv_obj_align(chart, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_chart_set_type(chart, LV_CHART_TYPE_COLUMN);
|
||||
// For simplicity, we'll stick with the chart's default 10 data points:
|
||||
series = lv_chart_add_series(chart, LV_COLOR_RED);
|
||||
lv_chart_init_points(chart, series, 0);
|
||||
// Make each column shift left as new values enter on right:
|
||||
lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT);
|
||||
|
||||
// Third tab is a canvas, which we'll fill with random colored lines.
|
||||
// LittlevGL draw functions only work on TRUE_COLOR canvas.
|
||||
canvas = lv_canvas_create(tab3, NULL);
|
||||
lv_canvas_set_buffer(canvas, canvas_buffer,
|
||||
CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
|
||||
lv_obj_align(canvas, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_canvas_fill_bg(canvas, LV_COLOR_WHITE, LV_OPA_100);
|
||||
|
||||
// Set up canvas line-drawing style based on defaults.
|
||||
// Later we'll change color settings when drawing each line.
|
||||
lv_draw_line_dsc_init(&draw_dsc);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize display BEFORE glue setup
|
||||
tft.init(240, 240);
|
||||
tft.setRotation(TFT_ROTATION);
|
||||
pinMode(TFT_BACKLIGHT, OUTPUT);
|
||||
digitalWrite(TFT_BACKLIGHT, HIGH);
|
||||
|
||||
// Initialize glue, passing in address of display
|
||||
LvGLStatus status = glue.begin(&tft);
|
||||
if(status != LVGL_OK) {
|
||||
Serial.printf("Glue error %d\r\n", (int)status);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
lvgl_setup(); // Call UI-building function above
|
||||
|
||||
// Enable "A" and "B" buttons as inputs
|
||||
pinMode(PIN_BUTTON1, INPUT_PULLUP);
|
||||
pinMode(PIN_BUTTON2, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
uint32_t prev_time = -1;
|
||||
|
||||
void loop(void) {
|
||||
|
||||
// Read left/right button inputs. Debouncing could be done better,
|
||||
// but this'll do for a quick simple demo...
|
||||
if(digitalRead(PIN_BUTTON1) == LOW) {
|
||||
if(active_tab > 0) {
|
||||
active_tab--;
|
||||
}
|
||||
while(digitalRead(PIN_BUTTON1) == LOW); // Wait for button release
|
||||
} else if(digitalRead(PIN_BUTTON2) == LOW) {
|
||||
if(active_tab < 2) {
|
||||
active_tab++;
|
||||
}
|
||||
while(digitalRead(PIN_BUTTON2) == LOW); // Wait for button release
|
||||
}
|
||||
|
||||
// Change active tab if button pressings happened
|
||||
if(active_tab != prev_tab) {
|
||||
lv_tabview_set_tab_act(tabview, active_tab, true);
|
||||
prev_tab = active_tab;
|
||||
}
|
||||
|
||||
// Make the gauge sweep a full sine wave over time
|
||||
lv_gauge_set_value(gauge, 0, (int)(50.5 + sin(millis() / 1000.0) * 50.0));
|
||||
|
||||
// About 2X a second, things happen on the other two tabs...
|
||||
uint32_t new_time = millis() / 500; // Current half-second
|
||||
if(new_time != prev_time) { // freshly elapsed
|
||||
prev_time = new_time;
|
||||
|
||||
// Add a new random item to the bar chart (old value shift left)
|
||||
lv_chart_set_next(chart, series, random(100));
|
||||
lv_chart_refresh(chart);
|
||||
|
||||
// Add a random line to the canvas
|
||||
lv_point_t points[2];
|
||||
points[0].x = random(CANVAS_WIDTH);
|
||||
points[0].y = random(CANVAS_HEIGHT);
|
||||
points[1].x = random(CANVAS_WIDTH);
|
||||
points[1].y = random(CANVAS_HEIGHT);
|
||||
draw_dsc.color.ch.red = random();
|
||||
draw_dsc.color.ch.green = random();
|
||||
draw_dsc.color.ch.blue = random();
|
||||
lv_canvas_draw_line(canvas, points, 2, &draw_dsc);
|
||||
// This forces the canvas to update (otherwise changes aren't
|
||||
// seen unless leaving and returning to the canvas tab):
|
||||
lv_canvas_set_buffer(canvas, canvas_buffer,
|
||||
CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
|
||||
}
|
||||
|
||||
lv_task_handler(); // Call LittleVGL task handler periodically
|
||||
delay(5);
|
||||
}
|
|
@ -1,261 +0,0 @@
|
|||
// A more interesting example for LittlevGL on Adafruit TFT FeatherWings,
|
||||
// showing use of the touchscreen. Code's a little more complex than the
|
||||
// hello_featherwing example, so best get that working before trying this.
|
||||
// By default, as written, on a 320x240 TFT FeatherWing the example is a
|
||||
// pretend calculator keypad, while 480x320 TFT has a whole keyboard
|
||||
// (though you'll probably need a stylus). These just seemed the right
|
||||
// level of detail for their respective screens, but feel free to override
|
||||
// and try either for yourself. If display is scrambled, check that
|
||||
// correct FeatherWing type is selected below (set BIG_FEATHERWING to 0
|
||||
// or 1 as needed).
|
||||
|
||||
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
|
||||
|
||||
// Feather M0 is no longer recommended for LittlevGL use. The calculator
|
||||
// almost works (hangs after a few button presses) and keyboard won't run
|
||||
// at all. A Feather M4 or other >32K RAM device is recommended.
|
||||
|
||||
#define BIG_FEATHERWING 0 // Set this to 1 for 3.5" (480x320) FeatherWing!
|
||||
|
||||
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
|
||||
#include <lvgl.h>
|
||||
#include <Adafruit_STMPE610.h>
|
||||
|
||||
#define DEMO_CALC 0
|
||||
#define DEMO_TEXT 1
|
||||
|
||||
#ifdef ESP32
|
||||
#define TFT_CS 15
|
||||
#define TFT_DC 33
|
||||
#define STMPE_CS 32
|
||||
#else
|
||||
#define TFT_CS 9
|
||||
#define TFT_DC 10
|
||||
#define STMPE_CS 6
|
||||
#endif
|
||||
#define TFT_RST -1
|
||||
|
||||
#if BIG_FEATHERWING
|
||||
#include <Adafruit_HX8357.h>
|
||||
Adafruit_HX8357 tft(TFT_CS, TFT_DC, TFT_RST);
|
||||
#define DEMO DEMO_TEXT // On big TFT, do text/keyboard example
|
||||
#else
|
||||
#include <Adafruit_ILI9341.h>
|
||||
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
|
||||
#define DEMO DEMO_CALC // Smaller TFT, do keypad example
|
||||
#endif
|
||||
|
||||
Adafruit_STMPE610 ts(STMPE_CS);
|
||||
Adafruit_LvGL_Glue glue;
|
||||
|
||||
#if DEMO == DEMO_CALC
|
||||
|
||||
// "Pretend" calculator example. Please, PLEASE...do NOT implement the whole
|
||||
// calculator and submit as a pull request, because it will NOT be merged!
|
||||
// This sketch is meant only to be illustrative and not functional, just
|
||||
// showing LittlevGL + Adafruit display/touch tied together with a modest
|
||||
// amount of code. Even a simple but working calc would require WAY more
|
||||
// code, distracting from that core idea (and is a waste of hardware).
|
||||
// Daiso has better calculators for $1.50.
|
||||
|
||||
#define TFT_ROTATION 0 // Portrait orientation
|
||||
|
||||
lv_obj_t *digits_label = NULL; // LittlevGL label object showing digits
|
||||
String digits = "0"; // Current digits string value
|
||||
bool hasDecimal = false; // Only allow one decimal point
|
||||
const char *buttons[] = { // Button matrix labels
|
||||
"7", "8", "9", "/", "\n",
|
||||
"4", "5", "6", "x", "\n",
|
||||
"1", "2", "3", "-", "\n",
|
||||
"0", ".", "=", "+", "" };
|
||||
|
||||
// This function processes events from the button matrix
|
||||
void button_event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
if(event == LV_EVENT_VALUE_CHANGED) {
|
||||
const char *txt = lv_btnmatrix_get_active_btn_text(obj);
|
||||
if(txt) { // NULL if pressed in frame area outside buttons
|
||||
if(txt[0] == '.') {
|
||||
// Decimal button pressed. Add decimal point to "digits" string
|
||||
// if it's not too long and there's no decimal present yet...
|
||||
if((digits.length() < 15) && !hasDecimal) {
|
||||
digits += '.';
|
||||
hasDecimal = true;
|
||||
}
|
||||
} else if((txt[0] >= '0') && (txt[0] <= '9')) {
|
||||
// Number button (0-9) pressed. If there's nothing currently
|
||||
// being displayed, take the digit literally. Otherwise, append
|
||||
// the new digit if the "digits" string is not too long.
|
||||
if(digits.equals("0")) {
|
||||
digits = txt[0];
|
||||
} else if(digits.length() < 15) {
|
||||
digits += txt[0];
|
||||
}
|
||||
} else {
|
||||
// Any other button, just reset the calculator display.
|
||||
// It's all just pretend.
|
||||
digits = "0";
|
||||
hasDecimal = false;
|
||||
}
|
||||
if(digits_label != NULL) {
|
||||
lv_label_set_text(digits_label, digits.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lvgl_setup(void) {
|
||||
|
||||
// Just using the default styles for everything here, keeping
|
||||
// it basic. See the official LittlevGL docs and examples for
|
||||
// insights on applying styles.
|
||||
|
||||
// The calculator digits are held inside a LvGL container object
|
||||
// as this gives us a little more control over positioning.
|
||||
lv_obj_t *container = lv_cont_create(lv_scr_act(), NULL);
|
||||
lv_cont_set_fit(container, LV_FIT_NONE); // Don't auto fit
|
||||
lv_obj_set_size(container, tft.width(), 50); // Full width x 50 px
|
||||
|
||||
// Calculator digits are just a text label inside the container,
|
||||
// refreshed whenever the global "digits" string changes.
|
||||
digits_label = lv_label_create(container, NULL);
|
||||
lv_label_set_text(digits_label, digits.c_str());
|
||||
lv_obj_align(digits_label, NULL, LV_ALIGN_IN_TOP_LEFT, 20, 10);
|
||||
lv_label_set_long_mode(digits_label, LV_LABEL_LONG_CROP);
|
||||
lv_obj_set_size(digits_label, tft.width() - 40, 30);
|
||||
lv_label_set_align(digits_label, LV_LABEL_ALIGN_RIGHT);
|
||||
|
||||
// Fill the remaining space with the button matrix.
|
||||
lv_obj_t *button_matrix = lv_btnmatrix_create(lv_scr_act(), NULL);
|
||||
lv_btnmatrix_set_map(button_matrix, buttons);
|
||||
lv_obj_align(button_matrix, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 50);
|
||||
lv_obj_set_size(button_matrix, tft.width(), tft.height() - 50);
|
||||
lv_obj_set_event_cb(button_matrix, button_event_handler);
|
||||
}
|
||||
|
||||
#else // Keyboard demo
|
||||
|
||||
// Keyboard example, lets you enter and edit text in a field. Even on a
|
||||
// 480x320 TFT it requires a stylus to be even half useful (fingertip
|
||||
// is possible if very patient), but having the option of a keyboard at
|
||||
// all on this device is pretty nifty!
|
||||
|
||||
#define TFT_ROTATION 1 // Landscape orientation
|
||||
|
||||
lv_obj_t *textarea,
|
||||
*keyboard = NULL; // Created/deleted as needed
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
// Called after keyboard slides closed - deletes keyboard object
|
||||
void delete_keyboard(lv_anim_t * a) {
|
||||
lv_obj_del((lv_obj_t *)a->var);
|
||||
keyboard = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Called when the close or ok button is pressed on the keyboard
|
||||
void keyboard_event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
lv_keyboard_def_event_cb(keyboard, event);
|
||||
|
||||
if(event == LV_EVENT_APPLY || event == LV_EVENT_CANCEL) {
|
||||
#if LV_USE_ANIMATION
|
||||
// If animation is enabled, make keyboard slide away
|
||||
lv_anim_path_t path;
|
||||
lv_anim_path_init(&path);
|
||||
lv_anim_path_set_cb(&path, lv_anim_path_ease_in_out);
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
|
||||
lv_anim_set_var(&a, keyboard);
|
||||
lv_anim_set_time(&a, 300);
|
||||
lv_anim_set_values(&a, lv_obj_get_y(keyboard), LV_VER_RES); // start, end
|
||||
lv_anim_set_path(&a, &path);
|
||||
lv_anim_set_ready_cb(&a, delete_keyboard);
|
||||
lv_anim_start(&a);
|
||||
#else
|
||||
lv_obj_del(keyboard);
|
||||
keyboard = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Other clicks in the text area
|
||||
void text_area_event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
if(event == LV_EVENT_CLICKED) {
|
||||
|
||||
// Unsure why, but text area has an initial clicked event on
|
||||
// creation, causing the keyboard to appear. This is a hacky
|
||||
// workaround that just ignores the first click event, so
|
||||
// subsequent actual clicks bring up the keyboard.
|
||||
static bool first = true;
|
||||
if(first) {
|
||||
first = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(keyboard == NULL) {
|
||||
// If not present, create keyboard object at bottom of screen
|
||||
keyboard = lv_keyboard_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_size(keyboard, tft.width(), tft.height() * 7 / 16);
|
||||
lv_obj_align(keyboard, textarea, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
lv_keyboard_set_textarea(keyboard, textarea);
|
||||
lv_keyboard_set_cursor_manage(keyboard, true);
|
||||
lv_obj_set_event_cb(keyboard, keyboard_event_handler);
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
// If animation is enabled, make keyboard slide into place
|
||||
lv_anim_path_t path;
|
||||
lv_anim_path_init(&path);
|
||||
lv_anim_path_set_cb(&path, lv_anim_path_ease_in_out);
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
|
||||
lv_anim_set_var(&a, keyboard);
|
||||
lv_anim_set_time(&a, 300);
|
||||
lv_anim_set_values(&a, LV_VER_RES, lv_obj_get_y(keyboard)); // start, end
|
||||
lv_anim_set_path(&a, &path);
|
||||
lv_anim_start(&a);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lvgl_setup(void) {
|
||||
textarea = lv_textarea_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_size(textarea, LV_HOR_RES, LV_VER_RES); // Whole screen
|
||||
lv_obj_align(textarea, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_textarea_set_text(textarea, "This text is editable.");
|
||||
lv_obj_set_event_cb(textarea, text_area_event_handler);
|
||||
lv_textarea_set_cursor_pos(textarea, LV_TEXTAREA_CURSOR_LAST);
|
||||
}
|
||||
|
||||
#endif // end calculator / keyboard examples
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize display and touchscreen BEFORE glue setup
|
||||
tft.begin();
|
||||
tft.setRotation(TFT_ROTATION);
|
||||
if(!ts.begin()) {
|
||||
Serial.println("Couldn't start touchscreen controller");
|
||||
for(;;);
|
||||
}
|
||||
|
||||
// Initialize glue, passing in address of display & touchscreen
|
||||
LvGLStatus status = glue.begin(&tft, &ts);
|
||||
if(status != LVGL_OK) {
|
||||
Serial.printf("Glue error %d\r\n", (int)status);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
lvgl_setup(); // Call UI-building function above
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
lv_task_handler(); // Call LittleVGL task handler periodically
|
||||
delay(5);
|
||||
}
|
||||
|
||||
// NOTE TO FUTURE SELF: this sketch is largely similar to the PyPortal
|
||||
// widgets example. If updating/bugfixing one sketch, make sure the other
|
||||
// is kept in sync.
|
|
@ -1,225 +0,0 @@
|
|||
// A more functional example for LittlevGL on Adafruit Circuit Playground
|
||||
// Bluefruit (NOT Express!) with TFT Gizmo display. Lacking touchscreen
|
||||
// input, interaction options are limited (but not impossible). In this
|
||||
// case we'll pretend like it's a status display for something -- the left
|
||||
// and right buttons (on the back if looking at the screen) switch between
|
||||
// three different tabs, each displaying different information. The code's
|
||||
// a bit more complex than the hello_gizmo example, so best get that
|
||||
// working before trying this. This example is a bit too much for the
|
||||
// Circuit Playground Express to handle now, but simpler LittlevGL
|
||||
// programs should be possible.
|
||||
|
||||
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
|
||||
|
||||
#if !defined(NRF52_SERIES) // Circuit Playground Bluefruit
|
||||
#error "This example is for Circuit Playground Bluefruit only."
|
||||
#endif
|
||||
|
||||
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
|
||||
#include <lvgl.h>
|
||||
#include <Adafruit_ST7789.h>
|
||||
|
||||
#define TFT_ROTATION 2
|
||||
#define TFT_CS A6
|
||||
#define TFT_DC A7
|
||||
#define TFT_RST -1
|
||||
#define TFT_BACKLIGHT A3
|
||||
#if defined(NRF52_SERIES) // Circuit Playground Bluefruit
|
||||
#define TFT_SPI SPI
|
||||
#else // Circuit Playground Express
|
||||
#define TFT_SPI SPI1
|
||||
// Though this example won't work on CP Express, including this
|
||||
// here anyway for reference, if copying over to a simpler sketch.
|
||||
#endif
|
||||
|
||||
Adafruit_ST7789 tft(&TFT_SPI, TFT_CS, TFT_DC, TFT_RST);
|
||||
Adafruit_LvGL_Glue glue;
|
||||
|
||||
lv_obj_t *tabview, // LittlevGL tabview object
|
||||
*gauge, // Gauge object (on first of three tabs)
|
||||
*chart, // Chart object (second tab)
|
||||
*canvas; // Canvas object (third tab)
|
||||
uint8_t active_tab = 0, // Index of currently-active tab (0-2)
|
||||
prev_tab = 0; // Index of previously-active tab
|
||||
lv_chart_series_t *series; // 'Series' data for the bar chart
|
||||
|
||||
// Canvas object is an image in memory. Although LittlevGL supports several
|
||||
// internal image formats, only the TRUE_COLOR variety allows drawing
|
||||
// operations. Fortunately nRF52840 has gobs of RAM for this. The canvas
|
||||
// buffer is global because it's referenced both in the setup and main loop.
|
||||
// Circuit Playground Express (M0) doesn't have enough RAM for this.
|
||||
#define CANVAS_WIDTH 200 // Dimensions in pixels
|
||||
#define CANVAS_HEIGHT 150
|
||||
lv_color_t canvas_buffer[
|
||||
LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
|
||||
lv_draw_line_dsc_t draw_dsc; // Drawing style (for canvas) is similarly global
|
||||
|
||||
void lvgl_setup(void) {
|
||||
// Create a tabview object, by default this covers the full display.
|
||||
tabview = lv_tabview_create(lv_disp_get_scr_act(NULL), NULL);
|
||||
// The Gizmo display has a lot of pixels and can't refresh very fast.
|
||||
// To show off the tabview animation, let's slow it down to 1 second.
|
||||
lv_tabview_set_anim_time(tabview, 1000);
|
||||
|
||||
// Because they're referenced any time an object is drawn, styles need
|
||||
// to be permanent in scope; either declared globally (outside all
|
||||
// functions), or static. The styles used on tabs are never modified after
|
||||
// they're used here, so let's use static on those...
|
||||
static lv_style_t tab_style, tab_background_style, indicator_style;
|
||||
|
||||
// This is the background style "behind" the tabs. This is what shows
|
||||
// through for "off" (inactive) tabs -- a vertical green gradient,
|
||||
// minimal padding around edges (zero at bottom).
|
||||
lv_style_init(&tab_background_style);
|
||||
lv_style_set_bg_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x408040));
|
||||
lv_style_set_bg_grad_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x304030));
|
||||
lv_style_set_bg_grad_dir(&tab_background_style, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
|
||||
lv_style_set_pad_top(&tab_background_style, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_pad_left(&tab_background_style, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_pad_right(&tab_background_style, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_pad_bottom(&tab_background_style, LV_STATE_DEFAULT, 0);
|
||||
lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BG, &tab_background_style);
|
||||
|
||||
// Style for tabs. Active tab is white with opaque background, inactive
|
||||
// tabs are transparent so the background shows through (only the white
|
||||
// text is seen). A little top & bottom padding reduces scrunchyness.
|
||||
lv_style_init(&tab_style);
|
||||
lv_style_set_pad_top(&tab_style, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_pad_bottom(&tab_style, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_bg_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_WHITE);
|
||||
lv_style_set_bg_opa(&tab_style, LV_STATE_CHECKED, LV_OPA_100);
|
||||
lv_style_set_text_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_GRAY);
|
||||
lv_style_set_bg_opa(&tab_style, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
lv_style_set_text_color(&tab_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BTN, &tab_style);
|
||||
|
||||
// Style for the small indicator bar that appears below the active tab.
|
||||
lv_style_init(&indicator_style);
|
||||
lv_style_set_bg_color(&indicator_style, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_style_set_size(&indicator_style, LV_STATE_DEFAULT, 5);
|
||||
lv_obj_add_style(tabview, LV_TABVIEW_PART_INDIC, &indicator_style);
|
||||
|
||||
// Back to creating widgets...
|
||||
|
||||
// Add three tabs to the tabview
|
||||
lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Gauge");
|
||||
lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Chart");
|
||||
lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Canvas");
|
||||
|
||||
// And then add stuff in each tab...
|
||||
|
||||
// The first tab holds a gauge. To keep the demo simple, let's just use
|
||||
// the default style and range (0-100). See LittlevGL docs for options.
|
||||
gauge = lv_gauge_create(tab1, NULL);
|
||||
lv_obj_set_size(gauge, 186, 186);
|
||||
lv_obj_align(gauge, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
// Second tab, make a chart...
|
||||
chart = lv_chart_create(tab2, NULL);
|
||||
lv_obj_set_size(chart, 200, 180);
|
||||
lv_obj_align(chart, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_chart_set_type(chart, LV_CHART_TYPE_COLUMN);
|
||||
// For simplicity, we'll stick with the chart's default 10 data points:
|
||||
series = lv_chart_add_series(chart, LV_COLOR_RED);
|
||||
lv_chart_init_points(chart, series, 0);
|
||||
// Make each column shift left as new values enter on right:
|
||||
lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT);
|
||||
|
||||
// Third tab is a canvas, which we'll fill with random colored lines.
|
||||
// LittlevGL draw functions only work on TRUE_COLOR canvas.
|
||||
canvas = lv_canvas_create(tab3, NULL);
|
||||
lv_canvas_set_buffer(canvas, canvas_buffer,
|
||||
CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
|
||||
lv_obj_align(canvas, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_canvas_fill_bg(canvas, LV_COLOR_WHITE, LV_OPA_100);
|
||||
|
||||
// Set up canvas line-drawing style based on defaults.
|
||||
// Later we'll change color settings when drawing each line.
|
||||
lv_draw_line_dsc_init(&draw_dsc);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize display BEFORE glue setup
|
||||
tft.init(240, 240);
|
||||
tft.setRotation(TFT_ROTATION);
|
||||
analogWrite(TFT_BACKLIGHT, 255); // USE analogWrite() FOR GIZMO BACKLIGHT!
|
||||
|
||||
// Initialize glue, passing in address of display
|
||||
LvGLStatus status = glue.begin(&tft);
|
||||
if(status != LVGL_OK) {
|
||||
Serial.printf("Glue error %d\r\n", (int)status);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
lvgl_setup(); // Call UI-building function above
|
||||
|
||||
// Enable "A" and "B" buttons as inputs
|
||||
pinMode(4, INPUT_PULLDOWN); // Left (A) button
|
||||
pinMode(5, INPUT_PULLDOWN); // Right (B) button
|
||||
}
|
||||
|
||||
uint32_t prev_time = -1;
|
||||
|
||||
void loop(void) {
|
||||
|
||||
// Read left/right button inputs. Debouncing could be done better,
|
||||
// but this'll do for a quick simple demo. The arrangements of the
|
||||
// buttons is intentionally flipped here (pin 5, the "right" button,
|
||||
// moves one tab left, pin 4 the opposite) so the button placements
|
||||
// make sense while looking at the screen on the reverse side.
|
||||
if(digitalRead(5) == HIGH) {
|
||||
if(active_tab > 0) {
|
||||
active_tab--;
|
||||
}
|
||||
while(digitalRead(5) == HIGH); // Wait for button release
|
||||
} else if(digitalRead(4) == HIGH) {
|
||||
if(active_tab < 2) {
|
||||
active_tab++;
|
||||
}
|
||||
while(digitalRead(4) == HIGH); // Wait for button release
|
||||
}
|
||||
|
||||
// Change active tab if button pressings happened
|
||||
if(active_tab != prev_tab) {
|
||||
lv_tabview_set_tab_act(tabview, active_tab, true);
|
||||
prev_tab = active_tab;
|
||||
}
|
||||
|
||||
// Make the gauge sweep a full sine wave over timeCLUE
|
||||
lv_gauge_set_value(gauge, 0, (int)(50.5 + sin(millis() / 1000.0) * 50.0));
|
||||
|
||||
// About 2X a second, things happen on the other two tabs...
|
||||
uint32_t new_time = millis() / 500; // Current half-second
|
||||
if(new_time != prev_time) { // freshly elapsed
|
||||
prev_time = new_time;
|
||||
|
||||
// Add a new random item to the bar chart (old value shift left)
|
||||
lv_chart_set_next(chart, series, random(100));
|
||||
lv_chart_refresh(chart);
|
||||
|
||||
// Add a random line to the canvas
|
||||
lv_point_t points[2];
|
||||
points[0].x = random(CANVAS_WIDTH);
|
||||
points[0].y = random(CANVAS_HEIGHT);
|
||||
points[1].x = random(CANVAS_WIDTH);
|
||||
points[1].y = random(CANVAS_HEIGHT);
|
||||
draw_dsc.color.ch.red = random();
|
||||
draw_dsc.color.ch.green = random();
|
||||
draw_dsc.color.ch.blue = random();
|
||||
lv_canvas_draw_line(canvas, points, 2, &draw_dsc);
|
||||
// This forces the canvas to update (otherwise changes aren't
|
||||
// seen unless leaving and returning to the canvas tab):
|
||||
lv_canvas_set_buffer(canvas, canvas_buffer,
|
||||
CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
|
||||
}
|
||||
|
||||
lv_task_handler(); // Call LittleVGL task handler periodically
|
||||
delay(5);
|
||||
}
|
||||
|
||||
// NOTE TO FUTURE SELF: this sketch is essentially the same as the CLUE
|
||||
// widgets example. If updating one sketch, make sure the other is kept
|
||||
// in sync. Aside from screen setup, differences include backlight control
|
||||
// and A/B button setup & read (CPX is active high, CLUE is active low).
|
|
@ -1,255 +0,0 @@
|
|||
// A more interesting example for LittlevGL on Adafruit PyPortal, showing
|
||||
// use of the touchscreen. Code's a little more complex than the
|
||||
// hello_pyportal example, so best get that working before trying this.
|
||||
// By default, as written, on regular (320x240) PyPortal the example is a
|
||||
// pretend calculator keypad, while PyPortal Titano (480x320) has a whole
|
||||
// keyboard (though you'll probably need a stylus). These just seemed the
|
||||
// right level of detail for their respective screens, but feel free to
|
||||
// override and try either for yourself.
|
||||
|
||||
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
|
||||
|
||||
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
|
||||
#include <lvgl.h>
|
||||
#include <TouchScreen.h>
|
||||
|
||||
#define DEMO_CALC 0
|
||||
#define DEMO_TEXT 1
|
||||
|
||||
#define TFT_D0 34 // PyPortal TFT pins
|
||||
#define TFT_WR 26
|
||||
#define TFT_DC 10
|
||||
#define TFT_CS 11
|
||||
#define TFT_RST 24
|
||||
#define TFT_RD 9
|
||||
#define TFT_BACKLIGHT 25
|
||||
#define YP A4 // PyPortal touchscreen pins
|
||||
#define XP A5
|
||||
#define YM A6
|
||||
#define XM A7
|
||||
|
||||
#if defined(ADAFRUIT_PYPORTAL_M4_TITANO)
|
||||
#include <Adafruit_HX8357.h>
|
||||
Adafruit_HX8357 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST,
|
||||
TFT_RD);
|
||||
#define DEMO DEMO_TEXT // On Titano, do text/keyboard example
|
||||
#else
|
||||
#include <Adafruit_ILI9341.h>
|
||||
Adafruit_ILI9341 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST,
|
||||
TFT_RD);
|
||||
#define DEMO DEMO_CALC // Smaller PyPortal, do keypad example
|
||||
#endif
|
||||
TouchScreen ts(XP, YP, XM, YM, 300);
|
||||
Adafruit_LvGL_Glue glue;
|
||||
|
||||
#if DEMO == DEMO_CALC
|
||||
|
||||
// "Pretend" calculator example. Please, PLEASE...do NOT implement the whole
|
||||
// calculator and submit as a pull request, because it will NOT be merged!
|
||||
// This sketch is meant only to be illustrative and not functional, just
|
||||
// showing LittlevGL + Adafruit display/touch tied together with a modest
|
||||
// amount of code. Even a simple but working calc would require WAY more
|
||||
// code, distracting from that core idea (and is a waste of PyPortal).
|
||||
// Daiso has better calculators for $1.50.
|
||||
|
||||
#define TFT_ROTATION 0 // Portrait orientation on PyPortal (USB top)
|
||||
|
||||
lv_obj_t *digits_label = NULL; // LittlevGL label object showing digits
|
||||
String digits = "0"; // Current digits string value
|
||||
bool hasDecimal = false; // Only allow one decimal point
|
||||
const char *buttons[] = { // Button matrix labels
|
||||
"7", "8", "9", "/", "\n",
|
||||
"4", "5", "6", "x", "\n",
|
||||
"1", "2", "3", "-", "\n",
|
||||
"0", ".", "=", "+", "" };
|
||||
|
||||
// This function processes events from the button matrix
|
||||
void button_event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
if(event == LV_EVENT_VALUE_CHANGED) {
|
||||
const char *txt = lv_btnmatrix_get_active_btn_text(obj);
|
||||
if(txt) { // NULL if pressed in frame area outside buttons
|
||||
if(txt[0] == '.') {
|
||||
// Decimal button pressed. Add decimal point to "digits" string
|
||||
// if it's not too long and there's no decimal present yet...
|
||||
if((digits.length() < 15) && !hasDecimal) {
|
||||
digits += '.';
|
||||
hasDecimal = true;
|
||||
}
|
||||
} else if((txt[0] >= '0') && (txt[0] <= '9')) {
|
||||
// Number button (0-9) pressed. If there's nothing currently
|
||||
// being displayed, take the digit literally. Otherwise, append
|
||||
// the new digit if the "digits" string is not too long.
|
||||
if(digits.equals("0")) {
|
||||
digits = txt[0];
|
||||
} else if(digits.length() < 15) {
|
||||
digits += txt[0];
|
||||
}
|
||||
} else {
|
||||
// Any other button, just reset the calculator display.
|
||||
// It's all just pretend.
|
||||
digits = "0";
|
||||
hasDecimal = false;
|
||||
}
|
||||
if(digits_label != NULL) {
|
||||
lv_label_set_text(digits_label, digits.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lvgl_setup(void) {
|
||||
|
||||
// Just using the default styles for everything here, keeping
|
||||
// it basic. See the official LittlevGL docs and examples for
|
||||
// insights on applying styles.
|
||||
|
||||
// The calculator digits are held inside a LvGL container object
|
||||
// as this gives us a little more control over positioning.
|
||||
lv_obj_t *container = lv_cont_create(lv_scr_act(), NULL);
|
||||
lv_cont_set_fit(container, LV_FIT_NONE); // Don't auto fit
|
||||
lv_obj_set_size(container, tft.width(), 50); // Full width x 50 px
|
||||
|
||||
// Calculator digits are just a text label inside the container,
|
||||
// refreshed whenever the global "digits" string changes.
|
||||
digits_label = lv_label_create(container, NULL);
|
||||
lv_label_set_text(digits_label, digits.c_str());
|
||||
lv_obj_align(digits_label, NULL, LV_ALIGN_IN_TOP_LEFT, 20, 10);
|
||||
lv_label_set_long_mode(digits_label, LV_LABEL_LONG_CROP);
|
||||
lv_obj_set_size(digits_label, tft.width() - 40, 30);
|
||||
lv_label_set_align(digits_label, LV_LABEL_ALIGN_RIGHT);
|
||||
|
||||
// Fill the remaining space with the button matrix.
|
||||
lv_obj_t *button_matrix = lv_btnmatrix_create(lv_scr_act(), NULL);
|
||||
lv_btnmatrix_set_map(button_matrix, buttons);
|
||||
lv_obj_align(button_matrix, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 50);
|
||||
lv_obj_set_size(button_matrix, tft.width(), tft.height() - 50);
|
||||
lv_obj_set_event_cb(button_matrix, button_event_handler);
|
||||
}
|
||||
|
||||
#else // Keyboard demo
|
||||
|
||||
// Keyboard example, lets you enter and edit text in a field. Even on a
|
||||
// PyPortal Titano it requires a stylus to be even half useful (fingertip
|
||||
// is possible if very patient), but having the option of a keyboard at
|
||||
// all on this device is pretty nifty!
|
||||
|
||||
#define TFT_ROTATION 3 // Landscape orientation on PyPortal (USB right)
|
||||
|
||||
lv_obj_t *textarea,
|
||||
*keyboard = NULL; // Created/deleted as needed
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
// Called after keyboard slides closed - deletes keyboard object
|
||||
void delete_keyboard(lv_anim_t * a) {
|
||||
lv_obj_del((lv_obj_t *)a->var);
|
||||
keyboard = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Called when the close or ok button is pressed on the keyboard
|
||||
void keyboard_event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
lv_keyboard_def_event_cb(keyboard, event);
|
||||
|
||||
if(event == LV_EVENT_APPLY || event == LV_EVENT_CANCEL) {
|
||||
#if LV_USE_ANIMATION
|
||||
// If animation is enabled, make keyboard slide away
|
||||
lv_anim_path_t path;
|
||||
lv_anim_path_init(&path);
|
||||
lv_anim_path_set_cb(&path, lv_anim_path_ease_in_out);
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
|
||||
lv_anim_set_var(&a, keyboard);
|
||||
lv_anim_set_time(&a, 300);
|
||||
lv_anim_set_values(&a, lv_obj_get_y(keyboard), LV_VER_RES); // start, end
|
||||
lv_anim_set_path(&a, &path);
|
||||
lv_anim_set_ready_cb(&a, delete_keyboard);
|
||||
lv_anim_start(&a);
|
||||
#else
|
||||
lv_obj_del(keyboard);
|
||||
keyboard = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Other clicks in the text area
|
||||
void text_area_event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
if(event == LV_EVENT_CLICKED) {
|
||||
|
||||
// Unsure why, but text area has an initial clicked event on
|
||||
// creation, causing the keyboard to appear. This is a hacky
|
||||
// workaround that just ignores the first click event, so
|
||||
// subsequent actual clicks bring up the keyboard.
|
||||
static bool first = true;
|
||||
if(first) {
|
||||
first = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(keyboard == NULL) {
|
||||
// If not present, create keyboard object at bottom of screen
|
||||
keyboard = lv_keyboard_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_size(keyboard, tft.width(), tft.height() * 7 / 16);
|
||||
lv_obj_align(keyboard, textarea, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
lv_keyboard_set_textarea(keyboard, textarea);
|
||||
lv_keyboard_set_cursor_manage(keyboard, true);
|
||||
lv_obj_set_event_cb(keyboard, keyboard_event_handler);
|
||||
|
||||
#if LV_USE_ANIMATION
|
||||
// If animation is enabled, make keyboard slide into place
|
||||
lv_anim_path_t path;
|
||||
lv_anim_path_init(&path);
|
||||
lv_anim_path_set_cb(&path, lv_anim_path_ease_in_out);
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
|
||||
lv_anim_set_var(&a, keyboard);
|
||||
lv_anim_set_time(&a, 300);
|
||||
lv_anim_set_values(&a, LV_VER_RES, lv_obj_get_y(keyboard)); // start, end
|
||||
lv_anim_set_path(&a, &path);
|
||||
lv_anim_start(&a);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lvgl_setup(void) {
|
||||
textarea = lv_textarea_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_size(textarea, LV_HOR_RES, LV_VER_RES); // Whole screen
|
||||
lv_obj_align(textarea, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_textarea_set_text(textarea, "This text is editable.");
|
||||
lv_obj_set_event_cb(textarea, text_area_event_handler);
|
||||
lv_textarea_set_cursor_pos(textarea, LV_TEXTAREA_CURSOR_LAST);
|
||||
}
|
||||
|
||||
#endif // end calculator / keyboard examples
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize display BEFORE glue setup
|
||||
tft.begin();
|
||||
tft.setRotation(TFT_ROTATION);
|
||||
pinMode(TFT_BACKLIGHT, OUTPUT);
|
||||
digitalWrite(TFT_BACKLIGHT, HIGH);
|
||||
|
||||
// PyPortal touchscreen needs no init
|
||||
|
||||
// Initialize glue, passing in address of display & touchscreen
|
||||
LvGLStatus status = glue.begin(&tft, &ts);
|
||||
if(status != LVGL_OK) {
|
||||
Serial.printf("Glue error %d\r\n", (int)status);
|
||||
for(;;);
|
||||
}
|
||||
|
||||
lvgl_setup(); // Call UI-building function above
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
lv_task_handler(); // Call LittleVGL task handler periodically
|
||||
delay(5);
|
||||
}
|
||||
|
||||
// NOTE TO FUTURE SELF: this sketch is largely similar to the FeatherWing
|
||||
// widgets example. If updating/bugfixing one sketch, make sure the other
|
||||
// is kept in sync.
|
|
@ -43,7 +43,7 @@ int lv0_init(bvm *vm);
|
|||
int lv0_init(bvm *vm) {
|
||||
// "+_p" indicates that there must be an non NULL argument, either passed as comptr or returned by the function
|
||||
// Here, there is no function, so calling the constructor without a non-null comptr argument is rejected
|
||||
return be_call_c_func(vm, NULL, "+_p", NULL);
|
||||
return be_call_c_func(vm, NULL, "=_p", NULL);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
|
|
@ -52,3 +52,23 @@ debug_init_break = tbreak setup
|
|||
build_unflags = ${core32solo1.build_unflags}
|
||||
build_flags = ${core32solo1.build_flags}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
; *** pre alpha S3 Version
|
||||
[env:tasmota32s3]
|
||||
extends = env:tasmota32_base
|
||||
platform = https://github.com/Jason2866/platform-espressif32.git#IDF44/ESP32-S3
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/617/framework-arduinoespressif32-v4.4_dev-3cfa267e25.tar.gz
|
||||
board = esp32s3
|
||||
build_flags = ${env:tasmota32_base.build_flags}
|
||||
lib_extra_dirs =
|
||||
lib/lib_basic
|
||||
lib/lib_ssl
|
||||
lib/libesp32
|
||||
lib_ignore =
|
||||
TTGO TWatch Library
|
||||
NimBLE-Arduino
|
||||
Micro-RTSP
|
||||
epdiy
|
||||
NeoPixelBus
|
||||
SPI
|
||||
SD
|
||||
|
|
|
@ -22,6 +22,7 @@ lib_ignore =
|
|||
ESP RainMaker
|
||||
WiFiProv
|
||||
USB
|
||||
SD_MMC
|
||||
ESP32 Azure IoT Arduino
|
||||
ESP32 Async UDP
|
||||
ESP32 BLE Arduino
|
||||
|
|
|
@ -41,6 +41,9 @@ class AXP192_M5StickC : AXP192
|
|||
self.set_dcdc_enable(1, true)
|
||||
self.set_dcdc_enable(3, true)
|
||||
|
||||
# enable external power on HAT connector (5V)
|
||||
self.set_exten(true)
|
||||
|
||||
# Set temperature protection
|
||||
self.write8(0x39, 0xFC)
|
||||
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,52 @@
|
|||
var antiburn = module('antiburn')
|
||||
|
||||
antiburn.init = def (m)
|
||||
class Antiburn
|
||||
var scr_original
|
||||
var scr_antiburn
|
||||
var running
|
||||
static colors = [
|
||||
0x000000,
|
||||
0xff0000,
|
||||
0x00ff00,
|
||||
0x0000ff,
|
||||
0xffffff
|
||||
]
|
||||
def init()
|
||||
self.running = false
|
||||
end
|
||||
def start()
|
||||
if self.running
|
||||
return
|
||||
else
|
||||
lv.start()
|
||||
self.scr_original = lv.scr_act()
|
||||
self.scr_antiburn = lv.obj(0)
|
||||
lv.scr_load(self.scr_antiburn)
|
||||
self.scr_antiburn.add_event_cb(/->self.stop(), lv.EVENT_PRESSED, 0)
|
||||
self.running = true
|
||||
self.cycle(0)
|
||||
end
|
||||
end
|
||||
def cycle(i)
|
||||
if !self.running return end
|
||||
if i < 30
|
||||
self.scr_antiburn.set_style_bg_color(lv.color_hex(self.colors[i % 5]), 0)
|
||||
tasmota.set_timer(1000, /->self.cycle(i+1))
|
||||
else
|
||||
self.stop()
|
||||
end
|
||||
end
|
||||
def stop()
|
||||
if self.running && self.scr_antiburn != nil
|
||||
lv.scr_load(self.scr_original)
|
||||
self.running = false
|
||||
self.scr_antiburn.del()
|
||||
self.scr_antiburn = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
return Antiburn()
|
||||
end
|
||||
|
||||
return antiburn
|
|
@ -0,0 +1,20 @@
|
|||
# Register the command 'Antiburn'
|
||||
# Module loaded in memory only when the command is first used
|
||||
|
||||
var wd = tasmota.wd
|
||||
|
||||
lv.antiburn = def()
|
||||
import sys
|
||||
var path = sys.path()
|
||||
path.push(wd)
|
||||
import antiburn
|
||||
path.pop()
|
||||
antiburn.start()
|
||||
end
|
||||
|
||||
tasmota.add_cmd("Antiburn",
|
||||
def ()
|
||||
lv.antiburn()
|
||||
tasmota.resp_cmnd_done()
|
||||
end
|
||||
)
|
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# H_bridge class in Berry to pilot a H-bridge device
|
||||
#
|
||||
|
||||
class H_bridge
|
||||
var gpio1, gpio2
|
||||
var max
|
||||
|
||||
# init(phy_gpio1, phy_gpio2) - intialize H-bridge with the 2 GPIOs used to control it
|
||||
def init(gpio1, gpio2)
|
||||
self.gpio1 = gpio1
|
||||
self.gpio2 = gpio2
|
||||
self.max = 1023 # max value of duty
|
||||
end
|
||||
|
||||
# set the value of both PWM values
|
||||
def set(v1, v2)
|
||||
if v1 < 0 v1 = 0 end
|
||||
if v2 < 0 v2 = 0 end
|
||||
if v1 + v2 > self.max
|
||||
raise "value_error", "the sum of duties must not exceed 100%"
|
||||
end
|
||||
|
||||
import gpio
|
||||
gpio.set_pwm(self.gpio1, v1, 0)
|
||||
gpio.set_pwm(self.gpio2, v2, v1) # dephase by value v1
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
:H,WT32-SC01,480,320,16,SPI,1,*,*,*,*,*,*,*,80
|
||||
:S,2,1,1,0,40,20
|
||||
:I
|
||||
01,80
|
||||
F0,1,C3
|
||||
F0,1,96
|
||||
C5,1,1C
|
||||
36,1,48
|
||||
3A,1,55
|
||||
B0,1,80
|
||||
B4,1,01
|
||||
B6,3,80,02,3B
|
||||
B7,1,C6
|
||||
F0,1,69
|
||||
F0,1,3C
|
||||
11,80
|
||||
29,80
|
||||
:o,28
|
||||
:O,29
|
||||
:R,36
|
||||
:0,28,00,00,01
|
||||
:1,88,00,00,02
|
||||
:2,E8,00,00,03
|
||||
:3,48,00,00,00
|
||||
:i,20,21
|
||||
:A,2A,2B,2C
|
||||
:TI1,38,*,*
|
||||
#
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 - RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 - OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 - SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "А"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "А"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -852,6 +852,8 @@
|
|||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "安培"
|
||||
|
|
|
@ -724,6 +724,7 @@
|
|||
// -- Serial sensors ------------------------------
|
||||
//#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code)
|
||||
//#define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code)
|
||||
//#define USE_CM110x // Add support for CM110x CO2 sensors (+2k7code)
|
||||
#define CO2_LOW 800 // Below this CO2 value show green light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
|
||||
#define CO2_HIGH 1200 // Above this CO2 value show red light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
|
||||
//#define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code)
|
||||
|
@ -747,7 +748,7 @@
|
|||
//#define USE_IBEACON // Add support for bluetooth LE passive scan of ibeacon devices (uses HM17 module)
|
||||
//#define USE_GPS // Add support for GPS and NTP Server for becoming Stratus 1 Time Source (+3k1 code, +132 bytes RAM)
|
||||
// #define USE_FLOG // Add support for GPS logging in OTA's Flash (Experimental) (+2k9 code, +8 bytes RAM)
|
||||
//#define USE_HM10 // (ESP8266 only) Add support for HM-10 as a BLE-bridge (+9k3 code)
|
||||
//#define USE_HM10 // (ESP8266 only) Add support for HM-10 as a BLE-bridge (+17k code)
|
||||
//#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
|
||||
//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k6 code, 64 mem)
|
||||
#define USE_TASMOTA_CLIENT_FLASH_SPEED 57600 // Usually 57600 for 3.3V variants and 115200 for 5V variants
|
||||
|
@ -793,7 +794,7 @@
|
|||
#define DDSU666_SPEED 9600 // Chint DDSU666 Modbus RS485 serial speed (default: 9600 baud)
|
||||
//#define USE_SOLAX_X1 // Add support for Solax X1 series Modbus log info (+3k1 code)
|
||||
#define SOLAXX1_SPEED 9600 // Solax X1 Modbus RS485 serial speed (default: 9600 baud)
|
||||
#define SOLAXX1_PV2 // Solax X1 using second PV
|
||||
// #define SOLAXX1_PV2 // Solax X1 using second PV
|
||||
//#define USE_LE01MR // Add support for F&F LE-01MR Modbus energy monitor (+1k code)
|
||||
#define LE01MR_SPEED 9600 // LE-01MR modbus baudrate (default: 9600)
|
||||
#define LE01MR_ADDR 1 // LE-01MR modbus address (default: 0x01)
|
||||
|
|
|
@ -474,7 +474,7 @@ typedef struct {
|
|||
TimeRule tflag[2]; // 2E2
|
||||
uint16_t pwm_frequency; // 2E6
|
||||
power_t power; // 2E8
|
||||
uint16_t pwm_value[MAX_PWMS]; // 2EC
|
||||
uint16_t pwm_value[MAX_PWMS_LEGACY];// 2EC
|
||||
int16_t altitude; // 2F6
|
||||
uint16_t tele_period; // 2F8
|
||||
uint8_t display_rotate; // 2FA
|
||||
|
@ -579,7 +579,7 @@ typedef struct {
|
|||
uint8_t ex_my_adc0; // 495 Free since 9.0.0.1
|
||||
|
||||
uint16_t light_pixels; // 496
|
||||
uint8_t light_color[5]; // 498
|
||||
uint8_t light_color[LST_MAX]; // 498 LST_MAX = 5
|
||||
uint8_t light_correction; // 49D
|
||||
uint8_t light_dimmer; // 49E
|
||||
uint8_t rule_enabled; // 49F
|
||||
|
@ -614,7 +614,8 @@ typedef struct {
|
|||
uint32_t ipv4_rgx_address; // 558
|
||||
uint32_t ipv4_rgx_subnetmask; // 55C
|
||||
|
||||
uint8_t free_560[92]; // 560
|
||||
uint16_t pwm_value_ext[16-5]; // 560 Extension to pwm_value to store up to 16 PWM for ESP32. This array stores values 5..15
|
||||
uint8_t free_560[70]; // 576
|
||||
|
||||
SysMBitfield1 flag2; // 5BC
|
||||
uint32_t pulse_counter[MAX_COUNTERS]; // 5C0
|
||||
|
|
|
@ -184,10 +184,11 @@ bool RtcRebootValid(void) {
|
|||
extern "C" {
|
||||
#include "spi_flash.h"
|
||||
}
|
||||
#include "eboot_command.h"
|
||||
|
||||
#ifdef ESP8266
|
||||
|
||||
#include "eboot_command.h"
|
||||
|
||||
extern "C" uint32_t _FS_start; // 1M = 0x402fb000, 2M = 0x40300000, 4M = 0x40300000
|
||||
const uint32_t FLASH_FS_START = (((uint32_t)&_FS_start - 0x40200000) / SPI_FLASH_SEC_SIZE);
|
||||
uint32_t SETTINGS_LOCATION = FLASH_FS_START -1; // 0xFA, 0x0FF or 0x0FF
|
||||
|
@ -1094,7 +1095,7 @@ void SettingsDefaultSet2(void) {
|
|||
|
||||
Settings->pwm_frequency = PWM_FREQ;
|
||||
Settings->pwm_range = PWM_RANGE;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
for (uint32_t i = 0; i < LST_MAX; i++) {
|
||||
Settings->light_color[i] = DEFAULT_LIGHT_COMPONENT;
|
||||
// Settings->pwm_value[i] = 0;
|
||||
}
|
||||
|
|
|
@ -1523,56 +1523,6 @@ void CmndTemplate(void)
|
|||
if (!error) { TemplateJson(); }
|
||||
}
|
||||
|
||||
void CmndPwm(void)
|
||||
{
|
||||
if (TasmotaGlobal.pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings->pwm_range) && PinUsed(GPIO_PWM1, XdrvMailbox.index -1)) {
|
||||
Settings->pwm_value[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
||||
analogWrite(Pin(GPIO_PWM1, XdrvMailbox.index -1), bitRead(TasmotaGlobal.pwm_inverted, XdrvMailbox.index -1) ? Settings->pwm_range - XdrvMailbox.payload : XdrvMailbox.payload);
|
||||
}
|
||||
Response_P(PSTR("{"));
|
||||
MqttShowPWMState(); // Render the PWM status to MQTT
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void CmndPwmfrequency(void)
|
||||
{
|
||||
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload >= PWM_MIN) && (XdrvMailbox.payload <= PWM_MAX))) {
|
||||
Settings->pwm_frequency = (1 == XdrvMailbox.payload) ? PWM_FREQ : XdrvMailbox.payload;
|
||||
analogWriteFreq(Settings->pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
|
||||
#ifdef USE_LIGHT
|
||||
LightReapplyColor();
|
||||
LightAnimate();
|
||||
#endif // USE_LIGHT
|
||||
}
|
||||
ResponseCmndNumber(Settings->pwm_frequency);
|
||||
}
|
||||
|
||||
void CmndPwmrange(void) {
|
||||
// Support only 8 (=255), 9 (=511) and 10 (=1023) bits resolution
|
||||
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload > 254) && (XdrvMailbox.payload < 1024))) {
|
||||
uint32_t pwm_range = XdrvMailbox.payload;
|
||||
uint32_t pwm_resolution = 0;
|
||||
while (pwm_range) {
|
||||
pwm_resolution++;
|
||||
pwm_range >>= 1;
|
||||
}
|
||||
pwm_range = (1 << pwm_resolution) - 1;
|
||||
uint32_t old_pwm_range = Settings->pwm_range;
|
||||
Settings->pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : pwm_range;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (Settings->pwm_value[i] > Settings->pwm_range) {
|
||||
Settings->pwm_value[i] = Settings->pwm_range;
|
||||
}
|
||||
}
|
||||
if (Settings->pwm_range != old_pwm_range) { // On ESP32 this prevents loss of duty state
|
||||
analogWriteRange(Settings->pwm_range); // Default is 1023 (Arduino.h)
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber(Settings->pwm_range);
|
||||
}
|
||||
|
||||
void CmndButtonDebounce(void)
|
||||
{
|
||||
if ((XdrvMailbox.payload > 39) && (XdrvMailbox.payload < 1001)) {
|
||||
|
|
|
@ -144,7 +144,7 @@ void CrashDumpClear(void)
|
|||
}
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
/**
|
||||
* Save crash information in RTC memory
|
||||
* This function is called automatically if ESP8266 suffers an exception
|
||||
|
|
|
@ -126,6 +126,8 @@ String GetDeviceHardware(void) {
|
|||
#include "esp32/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
|
||||
#include "esp32s3/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
|
||||
#include "esp32c3/rom/rtc.h"
|
||||
#else
|
||||
|
@ -277,6 +279,8 @@ extern "C" {
|
|||
#include "esp32/rom/spi_flash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
|
||||
#include "esp32s2/rom/spi_flash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
|
||||
#include "esp32s3/rom/spi_flash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
|
||||
#include "esp32c3/rom/spi_flash.h"
|
||||
#else
|
||||
|
@ -524,12 +528,14 @@ float CpuTemperature(void) {
|
|||
return t;
|
||||
*/
|
||||
#else
|
||||
// Currently (20210801) repeated calls to temperatureRead() on ESP32C3 and ESP32S2 result in IDF error messages
|
||||
static float t = NAN;
|
||||
if (isnan(t)) {
|
||||
t = (float)temperatureRead(); // In Celsius
|
||||
}
|
||||
return t;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S3
|
||||
// Currently (20210801) repeated calls to temperatureRead() on ESP32C3 and ESP32S2 result in IDF error messages
|
||||
static float t = NAN;
|
||||
if (isnan(t)) {
|
||||
t = (float)temperatureRead(); // In Celsius
|
||||
}
|
||||
return t;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -788,7 +788,9 @@ void ResponseAppendFeatures(void)
|
|||
#ifdef USE_SDM230
|
||||
feature8 |= 0x00100000; // xnrg_21_sdm230.ino
|
||||
#endif
|
||||
// feature8 |= 0x00200000;
|
||||
#ifdef USE_CM110x
|
||||
feature8 |= 0x00200000; // xsns_95_cm110x.ino
|
||||
#endif
|
||||
// feature8 |= 0x00400000;
|
||||
// feature8 |= 0x00800000;
|
||||
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
support_pwm.ino - command support for Tasmota
|
||||
|
||||
Copyright (C) 2021 Theo Arends & Stephan Hadinger
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/***********************************************************************\
|
||||
* PWM Control for ESP32
|
||||
\***********************************************************************/
|
||||
#ifdef ESP32
|
||||
|
||||
// All changes in PWM have been applied, rearm all change indicators
|
||||
void PwmRearmChanges(void) {
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
// Init expected changes
|
||||
TasmotaGlobal.pwm_value[i] = -1; // no change wanted
|
||||
TasmotaGlobal.pwm_phase[i] = -1; // no change wanted
|
||||
}
|
||||
}
|
||||
|
||||
// Load PWM values from settings and intiliaze values
|
||||
// void PwmLoadFromSettings(void) {
|
||||
// for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
// if (i < MAX_PWMS_LEGACY) {
|
||||
// TasmotaGlobal.pwm_cur_value[i] = Settings->pwm_value[i]; // retrieve in Legacy pool for 0..4
|
||||
// } else {
|
||||
// TasmotaGlobal.pwm_cur_value[i] = Settings->pwm_value_ext[i - MAX_PWMS_LEGACY]; // retrieve in Legacy pool for 5..15
|
||||
// }
|
||||
// TasmotaGlobal.pwm_cur_phase[i] = 0; // no phase shift for now, will be recomputed at first push to GPIOs
|
||||
// }
|
||||
// PwmRearmChanges(); // reset expected changes
|
||||
// }
|
||||
|
||||
// Copy current values to Settings
|
||||
void PwmSaveToSettings(void) {
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (i < MAX_PWMS_LEGACY) {
|
||||
Settings->pwm_value[i] = TasmotaGlobal.pwm_cur_value[i]; // store in Legacy pool for 0..4
|
||||
} else {
|
||||
Settings->pwm_value_ext[i - MAX_PWMS_LEGACY] = TasmotaGlobal.pwm_cur_value[i]; // retrieve in Legacy pool for 5..15
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************\
|
||||
* PWM Control for ESP32
|
||||
\***********************************************************************/
|
||||
// Apply PWM expected values to actual GPIO PWM
|
||||
// As input, `TasmotaGlobal.pwm_value[]` and `TasmotaGlobal.pwm_phase[]` contain the new expected values
|
||||
// or `-1` if no change.
|
||||
// Auto-phasing is recomputed, and changes are applied to GPIO if there is a physical GPIO configured and an actual change needed
|
||||
//
|
||||
void PwmApplyGPIO(void) {
|
||||
uint32_t pwm_phase_accumulator = 0; // dephase each PWM channel with the value of the previous
|
||||
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
// compute `pwm_val`, the virtual value of PWM (not taking into account inverted)
|
||||
uint32_t pwm_val = TasmotaGlobal.pwm_cur_value[i]; // logical value of PWM, 0..1023
|
||||
if (TasmotaGlobal.pwm_value[i] >= 0) { pwm_val = TasmotaGlobal.pwm_value[i]; } // new value explicitly specified
|
||||
if (pwm_val > Settings->pwm_range) { pwm_val = Settings->pwm_range; } // prevent overflow
|
||||
|
||||
// gpio_val : actual value of GPIO, taking into account inversion
|
||||
uint32_t gpio_val = bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - pwm_val : pwm_val;
|
||||
|
||||
// compute phase
|
||||
uint32_t pwm_phase = TasmotaGlobal.pwm_cur_phase[i]; // pwm_phase is the logical phase of the active pulse, ignoring inverted
|
||||
uint32_t gpio_phase = pwm_phase; // gpio is the physical phase taking into account inverted
|
||||
if (TasmotaGlobal.pwm_phase[i] >= 0) {
|
||||
pwm_phase = TasmotaGlobal.pwm_phase[i]; // if explicit set explicitly,
|
||||
} else if (Settings->flag5.pwm_force_same_phase) {
|
||||
pwm_phase = 0; // if auto-phase is off
|
||||
} else {
|
||||
// compute auto-phase
|
||||
pwm_phase = pwm_phase_accumulator;
|
||||
uint32_t pwm_phase_invert = bitRead(TasmotaGlobal.pwm_inverted, i) ? pwm_val : 0; // move phase if inverted
|
||||
gpio_phase = (pwm_phase + pwm_phase_invert) & Settings->pwm_range;
|
||||
// accumulate phase for next GPIO
|
||||
pwm_phase_accumulator = (pwm_phase + pwm_val) & Settings->pwm_range;
|
||||
}
|
||||
|
||||
// apply new values to GPIO if GPIO is set
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
if ((pwm_val != TasmotaGlobal.pwm_cur_value[i]) || (pwm_phase != TasmotaGlobal.pwm_cur_phase[i])) {
|
||||
// GPIO has PWM and there is a chnage to apply, apply it
|
||||
analogWritePhase(Pin(GPIO_PWM1, i), gpio_val, gpio_phase);
|
||||
}
|
||||
}
|
||||
|
||||
// set new current values
|
||||
TasmotaGlobal.pwm_cur_value[i] = pwm_val;
|
||||
TasmotaGlobal.pwm_cur_phase[i] = pwm_phase;
|
||||
}
|
||||
// AddLog(LOG_LEVEL_INFO, "PWM: Val=%03X-%03X-%03X-%03X-%03X Phase=%03X-%03X-%03X-%03X-%03X Range=%03X",
|
||||
// TasmotaGlobal.pwm_cur_value[0], TasmotaGlobal.pwm_cur_value[1], TasmotaGlobal.pwm_cur_value[2], TasmotaGlobal.pwm_cur_value[3],
|
||||
// TasmotaGlobal.pwm_cur_value[4],
|
||||
// TasmotaGlobal.pwm_cur_phase[0], TasmotaGlobal.pwm_cur_phase[1], TasmotaGlobal.pwm_cur_phase[2], TasmotaGlobal.pwm_cur_phase[3],
|
||||
// TasmotaGlobal.pwm_cur_phase[4],
|
||||
// Settings->pwm_range
|
||||
// );
|
||||
PwmSaveToSettings(); // copy to Settings
|
||||
PwmRearmChanges(); // reset expected changes
|
||||
}
|
||||
|
||||
void CmndPwm(void)
|
||||
{
|
||||
if (TasmotaGlobal.pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings->pwm_range) && PinUsed(GPIO_PWM1, XdrvMailbox.index -1)) {
|
||||
TasmotaGlobal.pwm_value[XdrvMailbox.index - 1] = XdrvMailbox.payload;
|
||||
PwmApplyGPIO();
|
||||
}
|
||||
Response_P(PSTR("{"));
|
||||
MqttShowPWMState(); // Render the PWM status to MQTT
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void GpioInitPwm(void) {
|
||||
PwmRearmChanges();
|
||||
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
analogAttach(Pin(GPIO_PWM1, i));
|
||||
if (i < TasmotaGlobal.light_type) {
|
||||
// force PWM GPIOs to black
|
||||
TasmotaGlobal.pwm_value[i] = 0;
|
||||
} else {
|
||||
TasmotaGlobal.pwm_present = true;
|
||||
if (i < MAX_PWMS_LEGACY) {
|
||||
TasmotaGlobal.pwm_value[i] = Settings->pwm_value[i];
|
||||
} else {
|
||||
TasmotaGlobal.pwm_value[i] = Settings->pwm_value_ext[i - MAX_PWMS_LEGACY];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PwmApplyGPIO(); // apply all changes
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void ResetPwm(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
TasmotaGlobal.pwm_value[i] = 0;
|
||||
}
|
||||
PwmApplyGPIO();
|
||||
}
|
||||
|
||||
#else // now for ESP8266
|
||||
|
||||
void PwmRearmChanges(void) {}
|
||||
|
||||
void CmndPwm(void)
|
||||
{
|
||||
if (TasmotaGlobal.pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings->pwm_range) && PinUsed(GPIO_PWM1, XdrvMailbox.index -1)) {
|
||||
uint32_t pwm_index = XdrvMailbox.index - 1;
|
||||
if (pwm_index < MAX_PWMS_LEGACY) { // write in the appropriate settings pool
|
||||
Settings->pwm_value[pwm_index] = XdrvMailbox.payload;
|
||||
} else {
|
||||
Settings->pwm_value_ext[pwm_index - MAX_PWMS_LEGACY] = XdrvMailbox.payload;
|
||||
}
|
||||
analogWrite(Pin(GPIO_PWM1, pwm_index), bitRead(TasmotaGlobal.pwm_inverted, pwm_index) ? Settings->pwm_range - XdrvMailbox.payload : XdrvMailbox.payload);
|
||||
}
|
||||
Response_P(PSTR("{"));
|
||||
MqttShowPWMState(); // Render the PWM status to MQTT
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void GpioInitPwm(void) {
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
pinMode(Pin(GPIO_PWM1, i), OUTPUT);
|
||||
if (i < TasmotaGlobal.light_type) {
|
||||
// force PWM GPIOs to low or high mode if belongs to the light (always <5), see #7165
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range : 0);
|
||||
} else {
|
||||
TasmotaGlobal.pwm_present = true;
|
||||
if (i < MAX_PWMS_LEGACY) {
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value[i] : Settings->pwm_value[i]);
|
||||
} else {
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value_ext[i] : Settings->pwm_value_ext[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void ResetPwm(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range : 0);
|
||||
// analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value[i] : Settings->pwm_value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ESP8266
|
||||
|
||||
void CmndPwmfrequency(void)
|
||||
{
|
||||
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload >= PWM_MIN) && (XdrvMailbox.payload <= PWM_MAX))) {
|
||||
Settings->pwm_frequency = (1 == XdrvMailbox.payload) ? PWM_FREQ : XdrvMailbox.payload;
|
||||
analogWriteFreq(Settings->pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
|
||||
#ifdef USE_LIGHT
|
||||
LightReapplyColor();
|
||||
LightAnimate();
|
||||
#endif // USE_LIGHT
|
||||
}
|
||||
ResponseCmndNumber(Settings->pwm_frequency);
|
||||
}
|
||||
|
||||
void CmndPwmrange(void) {
|
||||
// Support only 8 (=255), 9 (=511) and 10 (=1023) bits resolution
|
||||
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload > 254) && (XdrvMailbox.payload < 1024))) {
|
||||
uint32_t pwm_range = XdrvMailbox.payload;
|
||||
uint32_t pwm_resolution = 0;
|
||||
while (pwm_range) {
|
||||
pwm_resolution++;
|
||||
pwm_range >>= 1;
|
||||
}
|
||||
pwm_range = (1 << pwm_resolution) - 1;
|
||||
uint32_t old_pwm_range = Settings->pwm_range;
|
||||
Settings->pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : pwm_range;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (i < MAX_PWMS_LEGACY) {
|
||||
if (Settings->pwm_value[i] > Settings->pwm_range) {
|
||||
Settings->pwm_value[i] = Settings->pwm_range;
|
||||
}
|
||||
} else {
|
||||
if (Settings->pwm_value_ext[i - MAX_PWMS_LEGACY] > Settings->pwm_range) {
|
||||
Settings->pwm_value_ext[i - MAX_PWMS_LEGACY] = Settings->pwm_range;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Settings->pwm_range != old_pwm_range) { // On ESP32 this prevents loss of duty state
|
||||
analogWriteRange(Settings->pwm_range); // Default is 1023 (Arduino.h)
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber(Settings->pwm_range);
|
||||
}
|
||||
|
||||
void MqttShowPWMState(void)
|
||||
{
|
||||
ResponseAppend_P(PSTR("\"" D_CMND_PWM "\":{"));
|
||||
bool first = true;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // TODO
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
uint32_t pwm_val = (i < MAX_PWMS_LEGACY) ? Settings->pwm_value[i] : Settings->pwm_value_ext[i - MAX_PWMS_LEGACY];
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_PWM "%d\":%d"), first ? "" : ",", i+1, pwm_val);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
ResponseJsonEnd();
|
||||
}
|
|
@ -444,7 +444,7 @@ void SetLedPowerIdx(uint32_t led, uint32_t state)
|
|||
pwm = changeUIntScale((uint16_t)(state ? Settings->ledpwm_on : Settings->ledpwm_off), 0, 255, 0, Settings->pwm_range); // linear
|
||||
#endif //USE_LIGHT
|
||||
#ifdef ESP32
|
||||
if (analogAttach(Pin(GPIO_LED1, led)))
|
||||
if (analogAttach(Pin(GPIO_LED1, led)) >= 0)
|
||||
#endif
|
||||
analogWrite(Pin(GPIO_LED1, led), bitRead(TasmotaGlobal.led_inverted, led) ? Settings->pwm_range - pwm : pwm);
|
||||
} else {
|
||||
|
@ -735,19 +735,6 @@ void StopAllPowerBlink(void)
|
|||
}
|
||||
}
|
||||
|
||||
void MqttShowPWMState(void)
|
||||
{
|
||||
ResponseAppend_P(PSTR("\"" D_CMND_PWM "\":{"));
|
||||
bool first = true;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_PWM "%d\":%d"), first ? "" : ",", i+1, Settings->pwm_value[i]);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
|
||||
void MqttShowState(void)
|
||||
{
|
||||
char stemp1[TOPSZ];
|
||||
|
@ -1670,17 +1657,6 @@ void SerialInput(void)
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void ResetPwm(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range : 0);
|
||||
// analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value[i] : Settings->pwm_value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
@ -1825,7 +1801,7 @@ void GpioInit(void)
|
|||
mpin -= (AGPIO(GPIO_HEARTBEAT_INV) - AGPIO(GPIO_HEARTBEAT));
|
||||
}
|
||||
else if ((mpin >= AGPIO(GPIO_PWM1_INV)) && (mpin < (AGPIO(GPIO_PWM1_INV) + MAX_PWMS))) {
|
||||
bitSet(TasmotaGlobal.pwm_inverted, mpin - AGPIO(GPIO_PWM1_INV));
|
||||
bitSet(TasmotaGlobal.pwm_inverted, mpin - AGPIO(GPIO_PWM1_INV)); // PWMi are later converted to PMW, but marked as inverted in TasmotaGlobal.pwm_inverted
|
||||
mpin -= (AGPIO(GPIO_PWM1_INV) - AGPIO(GPIO_PWM1));
|
||||
}
|
||||
else if (XdrvCall(FUNC_PIN_STATE)) {
|
||||
|
@ -2002,23 +1978,7 @@ void GpioInit(void)
|
|||
#endif // USE_SONOFF_SC
|
||||
#endif // ESP8266
|
||||
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
#ifdef ESP8266
|
||||
pinMode(Pin(GPIO_PWM1, i), OUTPUT);
|
||||
#endif // ESP8266
|
||||
#ifdef ESP32
|
||||
analogAttach(Pin(GPIO_PWM1, i));
|
||||
#endif // ESP32
|
||||
if (TasmotaGlobal.light_type) {
|
||||
// force PWM GPIOs to low or high mode, see #7165
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range : 0);
|
||||
} else {
|
||||
TasmotaGlobal.pwm_present = true;
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value[i] : Settings->pwm_value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
GpioInitPwm();
|
||||
|
||||
for (uint32_t i = 0; i < MAX_RELAYS; i++) {
|
||||
if (PinUsed(GPIO_REL1, i)) {
|
||||
|
|
|
@ -60,7 +60,23 @@ const uint8_t MAX_KEYS = 8; // Max number of keys or buttons (up
|
|||
const uint8_t MAX_INTERLOCKS_SET = 14; // Max number of interlock groups (MAX_RELAYS / 2)
|
||||
const uint8_t MAX_SWITCHES_SET = 28; // Max number of switches
|
||||
const uint8_t MAX_LEDS = 4; // Max number of leds
|
||||
const uint8_t MAX_PWMS = 5; // Max number of PWM channels
|
||||
const uint8_t MAX_PWMS_LEGACY = 5; // Max number of PWM channels in first settings block - Legacy limit for ESP8266, but extended for ESP32 (see below)
|
||||
#ifdef ESP32
|
||||
// Max number of PWM channels (total including extended) - ESP32 only
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
const uint8_t MAX_PWMS = 16; // ESP32: 16 ledc PWM channels in total - TODO for now
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
const uint8_t MAX_PWMS = 8; // ESP32S2: 8 ledc PWM channels in total
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
const uint8_t MAX_PWMS = 8; // ESP32S3: 8 ledc PWM channels in total
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
const uint8_t MAX_PWMS = 6; // ESP32C3: 6 ledc PWM channels in total
|
||||
#else
|
||||
const uint8_t MAX_PWMS = 5; // Unknown - revert to 5 PWM max
|
||||
#endif
|
||||
#else
|
||||
const uint8_t MAX_PWMS = 5; // (not used on ESP8266)
|
||||
#endif
|
||||
const uint8_t MAX_COUNTERS = 4; // Max number of counter sensors
|
||||
const uint8_t MAX_TIMERS = 16; // Max number of Timers
|
||||
const uint8_t MAX_PULSETIMERS = 8; // Max number of supported pulse timers
|
||||
|
@ -88,6 +104,8 @@ const uint8_t MAX_I2S = 2; // Max number of Hardware I2S contro
|
|||
const uint8_t MAX_RMT = 8; // Max number or RMT channels (ESP32 only)
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
const uint8_t MAX_RMT = 4; // Max number or RMT channels (ESP32S2 only)
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
const uint8_t MAX_RMT = 1; // Max number or RMT channels (ESP32S3 only)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
const uint8_t MAX_RMT = 2; // Max number or RMT channels (ESP32C3 only)
|
||||
#else
|
||||
|
|
|
@ -154,6 +154,13 @@ struct TasmotaGlobal_t {
|
|||
bool enable_logging; // Enable logging
|
||||
|
||||
StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits)
|
||||
uint16_t pwm_inverted; // PWM inverted flag (1 = inverted) - extended to 16 bits for ESP32
|
||||
#ifdef ESP32
|
||||
int16_t pwm_cur_value[MAX_PWMS]; // Current effective values of PWMs as applied to GPIOs
|
||||
int16_t pwm_cur_phase[MAX_PWMS]; // Current phase values of PWMs as applied to GPIOs
|
||||
int16_t pwm_value[MAX_PWMS]; // Wanted values of PWMs after update - -1 means no change
|
||||
int16_t pwm_phase[MAX_PWMS]; // Wanted phase of PWMs after update - -1 means no change
|
||||
#endif // ESP32
|
||||
uint8_t init_state; // Tasmota init state
|
||||
uint8_t heartbeat_inverted; // Heartbeat pulse inverted flag
|
||||
uint8_t spi_enabled; // SPI configured
|
||||
|
@ -172,7 +179,7 @@ struct TasmotaGlobal_t {
|
|||
uint8_t led_inverted; // LED inverted flag (1 = (0 = On, 1 = Off))
|
||||
uint8_t led_power; // LED power state
|
||||
uint8_t ledlnk_inverted; // Link LED inverted flag (1 = (0 = On, 1 = Off))
|
||||
uint8_t pwm_inverted; // PWM inverted flag (1 = inverted)
|
||||
// uint8_t pwm_inverted; // PWM inverted flag (1 = inverted) -- TODO
|
||||
uint8_t energy_driver; // Energy monitor configured
|
||||
uint8_t light_driver; // Light module configured
|
||||
uint8_t light_type; // Light types
|
||||
|
|
|
@ -340,6 +340,7 @@
|
|||
|
||||
//#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code)
|
||||
//#define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code)
|
||||
//#define USE_CM110x // Add support for CM110x CO2 sensors (+2k7 code)
|
||||
#ifndef CO2_LOW
|
||||
#define CO2_LOW 800 // Below this CO2 value show green light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
|
||||
#endif
|
||||
|
@ -476,6 +477,7 @@
|
|||
|
||||
#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code)
|
||||
#define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code)
|
||||
#define USE_CM110x // Add support for CM110x CO2 sensors (+2k7 code)
|
||||
#ifndef CO2_LOW
|
||||
#define CO2_LOW 800 // Below this CO2 value show green light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
|
||||
#endif
|
||||
|
|
|
@ -181,6 +181,7 @@ enum UserSelectablePins {
|
|||
GPIO_OPTION_E, // Emulated module
|
||||
GPIO_SDM230_TX, GPIO_SDM230_RX, // SDM230 Serial interface
|
||||
GPIO_ADC_MQ, // Analog MQ Sensor
|
||||
GPIO_CM11_TXD, GPIO_CM11_RXD, // CM11 Serial interface
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
enum ProgramSelectablePins {
|
||||
|
@ -400,7 +401,8 @@ const char kSensorNames[] PROGMEM =
|
|||
D_SENSOR_SOLAXX1_RTS "|"
|
||||
D_SENSOR_OPTION " E|"
|
||||
D_SENSOR_SDM230_TX "|" D_SENSOR_SDM230_RX "|"
|
||||
D_SENSOR_ADC_MQ
|
||||
D_SENSOR_ADC_MQ "|"
|
||||
D_SENSOR_CM11_TX "|" D_SENSOR_CM11_RX "|"
|
||||
;
|
||||
|
||||
const char kSensorNamesFixed[] PROGMEM =
|
||||
|
@ -448,8 +450,8 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||
AGPIO(GPIO_CNTR1) + MAX_COUNTERS, // Counters
|
||||
AGPIO(GPIO_CNTR1_NP) + MAX_COUNTERS,
|
||||
#endif
|
||||
AGPIO(GPIO_PWM1) + MAX_PWMS, // RGB Red or C Cold White
|
||||
AGPIO(GPIO_PWM1_INV) + MAX_PWMS,
|
||||
AGPIO(GPIO_PWM1) + MAX_PWMS, // RGB Red or C Cold White
|
||||
AGPIO(GPIO_PWM1_INV) + MAX_PWMS, // or extended PWM for ESP32
|
||||
#ifdef USE_BUZZER
|
||||
AGPIO(GPIO_BUZZER), // Buzzer
|
||||
AGPIO(GPIO_BUZZER_INV), // Inverted buzzer
|
||||
|
@ -934,6 +936,10 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||
AGPIO(GPIO_MAX7219CS),
|
||||
#endif // USE_DISPLAY_MAX7219
|
||||
|
||||
#ifdef USE_CM110x
|
||||
AGPIO(GPIO_CM11_TXD), // CM110x Serial interface
|
||||
AGPIO(GPIO_CM11_RXD), // CM110x Serial interface
|
||||
#endif
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
* ESP32 specifics
|
||||
\*-------------------------------------------------------------------------------------------*/
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue