Merge remote-tracking branch 'upstream/development' into development

This commit is contained in:
Lovett1991 2021-04-14 10:13:46 +01:00
commit a10095217c
246 changed files with 6365 additions and 960 deletions

6
.gitignore vendored
View File

@ -1,7 +1,13 @@
## OS specific ######## ## OS specific ########
.DS_Store .DS_Store
.fuse_hidden* .fuse_hidden*
## Compilation artefacts ########
*.pyc *.pyc
*.d
*.o
*.gcno
*.gcda
## Project files ###### ## Project files ######
.platformio .platformio

View File

@ -17,6 +17,8 @@ All notable changes to this project will be documented in this file.
- Berry add ``gpio`` module - Berry add ``gpio`` module
- Berry add ``light`` module - Berry add ``light`` module
- Support for dummy energy monitor using user values set by commands ``VoltageSet``, ``CurrentSet``, ``PowerSet`` and ``FrequencySet``. Enable by selecting any GPIO as ``Option A2`` (#10640) - Support for dummy energy monitor using user values set by commands ``VoltageSet``, ``CurrentSet``, ``PowerSet`` and ``FrequencySet``. Enable by selecting any GPIO as ``Option A2`` (#10640)
- Command ``Backlog0`` to allow execution of following commands without delay
- Tasmota discovery as alternative to Home Assistant discovery using define ``USE_TASMOTA_DISCOVERY``
### Changed ### Changed
- PubSubClient library from EspEasy v2.7.12 to Tasmota v2.8.12 - PubSubClient library from EspEasy v2.7.12 to Tasmota v2.8.12
@ -25,6 +27,7 @@ All notable changes to this project will be documented in this file.
- Limit number of relay/button columns in GUI to 8 (#11546) - Limit number of relay/button columns in GUI to 8 (#11546)
- ADC range result from int to float using command ``FreqRes`` for decimal resolution selection (#11545) - ADC range result from int to float using command ``FreqRes`` for decimal resolution selection (#11545)
- Teleinfo, if raw mode selected also return telemety values in SENSOR data - Teleinfo, if raw mode selected also return telemety values in SENSOR data
- Removed overtemp detection on external energy monitoring devices (#11628)
### Fixed ### Fixed
- HC-SR04 on ESP32 release serial interface if not used (#11507) - HC-SR04 on ESP32 release serial interface if not used (#11507)

View File

@ -83,6 +83,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- Command ``Sensor80 1 <0..7>`` to control MFRC522 RFID antenna gain from 18dB (0) to 48dB (7) [#11073](https://github.com/arendst/Tasmota/issues/11073) - Command ``Sensor80 1 <0..7>`` to control MFRC522 RFID antenna gain from 18dB (0) to 48dB (7) [#11073](https://github.com/arendst/Tasmota/issues/11073)
- Command ``SerialBuffer 256..520`` to change hardware serial receive buffer size from default (256) to max local buffer size (520) [#11448](https://github.com/arendst/Tasmota/issues/11448) - Command ``SerialBuffer 256..520`` to change hardware serial receive buffer size from default (256) to max local buffer size (520) [#11448](https://github.com/arendst/Tasmota/issues/11448)
- Command ``SetOption126 1`` to enable DS18x20 arithmetic mean over teleperiod for JSON temperature based on [#11472](https://github.com/arendst/Tasmota/issues/11472) - Command ``SetOption126 1`` to enable DS18x20 arithmetic mean over teleperiod for JSON temperature based on [#11472](https://github.com/arendst/Tasmota/issues/11472)
- Command ``Backlog0`` to allow execution of following commands without delay
- Commands ``MqttKeepAlive 1..100`` to set Mqtt Keep Alive timer (default 30) and ``MqttTimeout 1..100`` to set Mqtt Socket Timeout (default 4) [#5341](https://github.com/arendst/Tasmota/issues/5341) - Commands ``MqttKeepAlive 1..100`` to set Mqtt Keep Alive timer (default 30) and ``MqttTimeout 1..100`` to set Mqtt Socket Timeout (default 4) [#5341](https://github.com/arendst/Tasmota/issues/5341)
- Commands ``DisplayType`` to select sub-modules where implemented and ``DisplayInvert`` to select inverted display where implemented - Commands ``DisplayType`` to select sub-modules where implemented and ``DisplayInvert`` to select inverted display where implemented
- Support for SML VBUS [#11125](https://github.com/arendst/Tasmota/issues/11125) - Support for SML VBUS [#11125](https://github.com/arendst/Tasmota/issues/11125)
@ -103,6 +104,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- ESP32 support for WS2812 hardware driver via RMT or I2S - ESP32 support for WS2812 hardware driver via RMT or I2S
- ESP32 support for secondary I2C controller - ESP32 support for secondary I2C controller
- ESP32 support for internal Hall Effect sensor connected to both GPIO36 and GPIO39 only - ESP32 support for internal Hall Effect sensor connected to both GPIO36 and GPIO39 only
- Tasmota discovery as alternative to Home Assistant discovery using define ``USE_TASMOTA_DISCOVERY``
### Changed ### Changed
- TasmotaSerial library from v3.2.0 to v3.3.0 - TasmotaSerial library from v3.2.0 to v3.3.0
@ -114,6 +116,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- DeepSleep announcement topic [#11223](https://github.com/arendst/Tasmota/issues/11223) - DeepSleep announcement topic [#11223](https://github.com/arendst/Tasmota/issues/11223)
- Limit number of relay/button columns in GUI to 8 [#11546](https://github.com/arendst/Tasmota/issues/11546) - Limit number of relay/button columns in GUI to 8 [#11546](https://github.com/arendst/Tasmota/issues/11546)
- ADC range result from int to float using command ``FreqRes`` for decimal resolution selection [#11545](https://github.com/arendst/Tasmota/issues/11545) - ADC range result from int to float using command ``FreqRes`` for decimal resolution selection [#11545](https://github.com/arendst/Tasmota/issues/11545)
- Removed overtemp detection on external energy monitoring devices [#11628](https://github.com/arendst/Tasmota/issues/11628)
### Fixed ### Fixed
- PN532 on ESP32 Serial flush both Tx and Rx buffers [#10910](https://github.com/arendst/Tasmota/issues/10910) - PN532 on ESP32 Serial flush both Tx and Rx buffers [#10910](https://github.com/arendst/Tasmota/issues/10910)

View File

@ -1243,6 +1243,16 @@ void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) {
textsize_y = (s_y > 0) ? s_y : 1; textsize_y = (s_y > 0) ? s_y : 1;
} }
void Adafruit_GFX::setwidth(uint16_t w) {
WIDTH = w;
_width = w;
}
void Adafruit_GFX::setheight(uint16_t h) {
HEIGHT = h;
_height = h;
}
/**************************************************************************/ /**************************************************************************/
/*! /*!
@brief Set rotation setting for display @brief Set rotation setting for display

View File

@ -187,6 +187,10 @@ virtual void
/************************************************************************/ /************************************************************************/
int16_t height(void) const { return _height; } int16_t height(void) const { return _height; }
void setwidth(uint16_t w);
void setheight(uint16_t h);
/************************************************************************/ /************************************************************************/
/*! /*!
@brief Get rotation setting for display @brief Get rotation setting for display

View File

@ -0,0 +1,30 @@
#######################################
# Syntax Coloring Map
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
ST7789 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
setRotation KEYWORD2
setAddrWindow KEYWORD2
pushColor KEYWORD2
drawPixel KEYWORD2
drawFastVLine KEYWORD2
drawFastHLine KEYWORD2
fillRect KEYWORD2
setRotation KEYWORD2
setRotation KEYWORD2
height KEYWORD2
width KEYWORD2
invertDisplay KEYWORD2
drawImage KEYWORD2
setScrollArea KEYWORD2
scroll KEYWORD2

View File

@ -0,0 +1,9 @@
name=universal display Library
version=0.1
author=Gerhard Mutz
maintainer=Gerhard Mutz
sentence=This is a library a couple of displays.
paragraph=This is a library a couple of displays.
category=Display
url=https://github.com/arendst/Tasmota
architectures=*

View File

@ -0,0 +1,607 @@
/*
uDisplay.cpp - universal display driver support for Tasmota
Copyright (C) 2021 Gerhard Mutz and Theo Arends
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/>.
*/
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include "uDisplay.h"
const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\
UDISP_YELLOW,UDISP_NAVY,UDISP_DARKGREEN,UDISP_DARKCYAN,UDISP_MAROON,UDISP_PURPLE,UDISP_OLIVE,\
UDISP_LIGHTGREY,UDISP_DARKGREY,UDISP_ORANGE,UDISP_GREENYELLOW,UDISP_PINK};
uint16_t uDisplay::GetColorFromIndex(uint8_t index) {
if (index >= sizeof(udisp_colors) / 2) index = 0;
return udisp_colors[index];
}
extern uint8_t *buffer;
uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
// analyse decriptor
uint8_t section = 0;
dsp_ncmds = 0;
char linebuff[128];
while (*lp) {
uint16_t llen = strlen_ln(lp);
strncpy(linebuff, lp, llen);
linebuff[llen] = 0;
lp += llen;
char *lp1 = linebuff;
if (*lp1 == '#') break;
if (*lp1 == '\n') lp1++;
while (*lp1 == ' ') lp1++;
//Serial.printf(">> %s\n",lp1);
if (*lp1 != ';') {
// check ids:
if (*lp1 == ':') {
// id line
lp1++;
section = *lp1++;
} else {
switch (section) {
case 'H':
// header line
// SD1306,128,64,1,I2C,5a,*,*,*
str2c(&lp1, dname, sizeof(dname));
char ibuff[16];
gxs = next_val(&lp1);
setwidth(gxs);
gys = next_val(&lp1);
setheight(gys);
bpp = next_val(&lp1);
str2c(&lp1, ibuff, sizeof(ibuff));
if (!strncmp(ibuff, "I2C", 3)) {
interface = _UDSP_I2C;
i2caddr = next_hex(&lp1);
i2c_scl = next_val(&lp1);
i2c_sda = next_val(&lp1);
reset = next_val(&lp1);
section = 0;
} else if (!strncmp(ibuff, "SPI", 3)) {
interface = _UDSP_SPI;
spi_nr = next_val(&lp1);
spi_cs = next_val(&lp1);
spi_clk = next_val(&lp1);
spi_mosi = next_val(&lp1);
spi_dc = next_val(&lp1);
bpanel = next_val(&lp1);
reset = next_val(&lp1);
spi_miso = next_val(&lp1);
spi_speed = next_val(&lp1);
section = 0;
Serial.printf("%d %d %d %d %d %d %d %d\n", spi_cs, spi_clk, spi_mosi, spi_dc, bpanel, reset, spi_miso, spi_speed);
}
break;
case 'S':
splash_font = next_val(&lp1);
splash_size = next_val(&lp1);
fg_col = next_val(&lp1);
if (bpp == 16) {
fg_col = GetColorFromIndex(fg_col);
}
bg_col = next_val(&lp1);
if (bpp == 16) {
bg_col = GetColorFromIndex(bg_col);
}
splash_xp = next_val(&lp1);
splash_yp = next_val(&lp1);
break;
case 'I':
// init data
if (interface == _UDSP_I2C) {
dsp_cmds[dsp_ncmds++] = next_hex(&lp1);
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
}
} else {
while (1) {
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
} else {
break;
}
if (dsp_ncmds >= sizeof(dsp_cmds)) break;
}
}
break;
case 'o':
str2c(&lp1, ibuff, sizeof(ibuff));
dsp_off = strtol(ibuff, 0, 16);
break;
case 'O':
str2c(&lp1, ibuff, sizeof(ibuff));
dsp_on = strtol(ibuff, 0, 16);
break;
case '0':
rot_0 = next_hex(&lp1);
break;
case '1':
rot_1 = next_hex(&lp1);
break;
case '2':
rot_2 = next_hex(&lp1);
break;
case '3':
rot_3 = next_hex(&lp1);
break;
case 'A':
saw_1 = next_hex(&lp1);
saw_2 = next_hex(&lp1);
saw_3 = next_hex(&lp1);
break;
}
}
}
if (*lp == '\n') {
lp++;
} else {
lp = strchr(lp, '\n');
if (!lp) break;
lp++;
}
}
}
Renderer *uDisplay::Init(void) {
if (reset >= 0) {
pinMode(reset, OUTPUT);
digitalWrite(reset, HIGH);
delay(50);
digitalWrite(reset, LOW);
delay(50);
digitalWrite(reset, HIGH);
delay(200);
}
if (interface == _UDSP_I2C) {
Wire.begin(i2c_sda, i2c_scl);
if (bpp < 16) {
if (buffer) free(buffer);
buffer = (uint8_t*)calloc((width()*height()*bpp)/8, 1);
for (uint32_t cnt = 0; cnt < dsp_ncmds; cnt++) {
i2c_command(dsp_cmds[cnt]);
}
}
}
if (interface == _UDSP_SPI) {
if (bpanel >= 0) {
#ifdef ESP32
ledcSetup(ESP32_PWM_CHANNEL, 4000, 8);
ledcAttachPin(bpanel, ESP32_PWM_CHANNEL);
ledcWrite(ESP32_PWM_CHANNEL, 128);
#else
pinMode(bpanel, OUTPUT);
digitalWrite(bpanel, HIGH);
#endif // ESP32
}
if (spi_dc >= 0) {
pinMode(spi_dc, OUTPUT);
digitalWrite(spi_dc, HIGH);
}
if (spi_cs >= 0) {
pinMode(spi_cs, OUTPUT);
digitalWrite(spi_cs, HIGH);
}
spiSettings = SPISettings(spi_speed, MSBFIRST, SPI_MODE3);
#ifdef ESP8266
SPI.begin();
uspi = &SPI;
#else
if (spi_nr != 1) {
uspi = new SPIClass(HSPI);
} else {
uspi = &SPI;
}
uspi->begin(spi_clk, spi_miso, spi_mosi, -1);
#endif
uint16_t index = 0;
SPI_BEGIN_TRANSACTION
while (1) {
uint8_t iob;
SPI_CS_LOW
SPI_DC_LOW
iob = dsp_cmds[index++];
uspi->write(iob);
SPI_DC_HIGH
uint8_t args = dsp_cmds[index++];
//Serial.printf("cmd, args %x, %d ", iob, args&0x7f);
for (uint32_t cnt = 0; cnt < (args & 0x7f); cnt++) {
iob = dsp_cmds[index++];
//Serial.printf("%02x ", iob );
uspi->write(iob);
}
SPI_CS_HIGH
//Serial.printf("\n");
if (args & 0x80) delay(120);
if (index >= dsp_ncmds) break;
}
SPI_END_TRANSACTION
}
return this;
}
void uDisplay::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
setRotation(rot);
invertDisplay(false);
setTextWrap(false);
cp437(true);
setTextFont(font);
setTextSize(size);
setTextColor(fg_col, bg_col);
setCursor(0,0);
fillScreen(bg_col);
Updateframe();
}
void uDisplay::spi_command(uint8_t val) {
SPI_BEGIN_TRANSACTION
SPI_DC_LOW
SPI_CS_LOW
uspi->write(val);
SPI_CS_HIGH
SPI_DC_HIGH
SPI_END_TRANSACTION
}
void uDisplay::i2c_command(uint8_t val) {
//Serial.printf("%02x\n",val );
Wire.beginTransmission(i2caddr);
Wire.write(0);
Wire.write(val);
Wire.endTransmission();
}
#define SH1106_SETLOWCOLUMN 0
#define SH1106_SETHIGHCOLUMN 0x10
#define SH1106_SETSTARTLINE 0x40
void uDisplay::Updateframe(void) {
if (interface == _UDSP_I2C) {
i2c_command(SH1106_SETLOWCOLUMN | 0x0); // low col = 0
i2c_command(SH1106_SETHIGHCOLUMN | 0x0); // hi col = 0
i2c_command(SH1106_SETSTARTLINE | 0x0); // line #0
uint8_t ys = gys >> 3;
uint8_t xs = gxs >> 3;
//uint8_t xs = 132 >> 3;
uint8_t m_row = 0;
uint8_t m_col = 2;
uint16_t p = 0;
uint8_t i, j, k = 0;
for ( i = 0; i < ys; i++) {
// send a bunch of data in one xmission
i2c_command(0xB0 + i + m_row);//set page address
i2c_command(m_col & 0xf);//set lower column address
i2c_command(0x10 | (m_col >> 4));//set higher column address
for( j = 0; j < 8; j++){
Wire.beginTransmission(i2caddr);
Wire.write(0x40);
for ( k = 0; k < xs; k++, p++) {
Wire.write(buffer[p]);
}
Wire.endTransmission();
}
}
}
}
void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
if (interface != _UDSP_SPI) {
Renderer::drawFastVLine(x, y, h, color);
return;
}
// Rudimentary clipping
if ((x >= _width) || (y >= _height)) return;
if ((y + h - 1) >= _height) h = _height - y;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, 1, h);
while (h--) {
uspi->write16(color);
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
if (interface != _UDSP_SPI) {
Renderer::drawFastHLine(x, y, w, color);
return;
}
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((x+w-1) >= _width) w = _width-x;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, w, 1);
while (w--) {
uspi->write16(color);
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::fillScreen(uint16_t color) {
fillRect(0, 0, gxs, gys, color);
}
// fill a rectangle
void uDisplay::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
if (interface != _UDSP_SPI) {
Renderer::fillRect(x, y, w, h, color);
return;
}
// rudimentary clipping (drawChar w/big text requires this)
if((x >= gxs) || (y >= gys)) return;
if((x + w - 1) >= gxs) w = gxs - x;
if((y + h - 1) >= gys) h = gys - y;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, w, h);
for (y = h; y > 0; y--) {
for (x = w; x > 0; x--) {
uspi->write16(color);
}
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::Splash(void) {
setTextFont(splash_font);
setTextSize(splash_size);
DrawStringAt(splash_xp, splash_yp, dname, fg_col, 0);
Updateframe();
}
void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
if (!x0 && !y0 && !x1 && !y1) {
SPI_CS_HIGH
SPI_END_TRANSACTION
} else {
SPI_CS_LOW
SPI_BEGIN_TRANSACTION
setAddrWindow_int(x0, y0, x1 - x0, y1 - y0 );
}
}
void uDisplay::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
uint32_t xa = ((uint32_t)x << 16) | (x+w-1);
uint32_t ya = ((uint32_t)y << 16) | (y+h-1);
SPI_DC_LOW
uspi->write(saw_1);
SPI_DC_HIGH
uspi->write32(xa);
SPI_DC_LOW
uspi->write(saw_2);
SPI_DC_HIGH
uspi->write32(ya);
SPI_DC_LOW
uspi->write(saw_3); // write to RAM
SPI_DC_HIGH
}
void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean first) {
uint16_t color;
while (len--) {
color = *data++;
uspi->write16(color);
}
}
void uDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) {
if (interface != _UDSP_SPI) {
Renderer::drawPixel(x, y, color);
return;
}
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, 1, 1);
uspi->write16(color);
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::setRotation(uint8_t m) {
if (interface != _UDSP_SPI) {
Renderer::setRotation(m);
return;
}
switch (rotation) {
case 0:
if (interface == _UDSP_SPI) spi_command(rot_0);
_width = gxs;
_height = gys;
break;
case 1:
if (interface == _UDSP_SPI) spi_command(rot_1);
_width = gys;
_height = gxs;
break;
case 2:
if (interface == _UDSP_SPI) spi_command(rot_2);
_width = gxs;
_height = gys;
break;
case 3:
if (interface == _UDSP_SPI) spi_command(rot_3);
_width = gys;
_height = gxs;
break;
}
}
void uDisplay::DisplayOnff(int8_t on) {
if (interface == _UDSP_I2C) {
if (on) {
i2c_command(dsp_on);
} else {
i2c_command(dsp_off);
}
} else {
if (on) {
spi_command(dsp_on);
if (bpanel >= 0) {
#ifdef ESP32
ledcWrite(ESP32_PWM_CHANNEL, dimmer);
#else
digitalWrite(bpanel, HIGH);
#endif
}
} else {
spi_command(dsp_off);
if (bpanel >= 0) {
#ifdef ESP32
ledcWrite(ESP32_PWM_CHANNEL, 0);
#else
digitalWrite(bpanel, LOW);
#endif
}
}
}
}
void uDisplay::dim(uint8_t dim) {
dimmer = dim;
if (dimmer > 15) dimmer = 15;
dimmer = ((float)dimmer / 15.0) * 255.0;
#ifdef ESP32
ledcWrite(ESP32_PWM_CHANNEL, dimmer);
#endif
}
uint8_t uDisplay::strlen_ln(char *str) {
for (uint32_t cnt = 0; cnt < 256; cnt++) {
if (!str[cnt] || str[cnt] == '\n') return cnt;
}
return 0;
}
char *uDisplay::devname(void) {
return dname;
}
uint32_t uDisplay::str2c(char **sp, char *vp, uint32_t len) {
char *lp = *sp;
if (len) len--;
char *cp = strchr(lp, ',');
if (cp) {
while (1) {
if (*lp == ',') {
*vp = 0;
*sp = lp + 1;
return 0;
}
if (len) {
*vp++ = *lp++;
len--;
} else {
lp++;
}
}
} else {
uint8_t slen = strlen(lp);
if (slen) {
strlcpy(vp, *sp, len);
*sp = lp + slen;
return 0;
}
}
return 1;
}
int32_t uDisplay::next_val(char **sp) {
char ibuff[16];
str2c(sp, ibuff, sizeof(ibuff));
return atoi(ibuff);
}
uint32_t uDisplay::next_hex(char **sp) {
char ibuff[16];
str2c(sp, ibuff, sizeof(ibuff));
return strtol(ibuff, 0, 16);
}

View File

@ -0,0 +1,114 @@
#ifndef _UDISP_
#define _UDISP_
#include <Adafruit_GFX.h>
#include <renderer.h>
#define _UDSP_I2C 1
#define _UDSP_SPI 2
#define UDISP1_WHITE 1
#define UDISP1_BLACK 0
// Color definitions
#define UDISP_BLACK 0x0000 /* 0, 0, 0 */
#define UDISP_NAVY 0x000F /* 0, 0, 128 */
#define UDISP_DARKGREEN 0x03E0 /* 0, 128, 0 */
#define UDISP_DARKCYAN 0x03EF /* 0, 128, 128 */
#define UDISP_MAROON 0x7800 /* 128, 0, 0 */
#define UDISP_PURPLE 0x780F /* 128, 0, 128 */
#define UDISP_OLIVE 0x7BE0 /* 128, 128, 0 */
#define UDISP_LIGHTGREY 0xC618 /* 192, 192, 192 */
#define UDISP_DARKGREY 0x7BEF /* 128, 128, 128 */
#define UDISP_BLUE 0x001F /* 0, 0, 255 */
#define UDISP_GREEN 0x07E0 /* 0, 255, 0 */
#define UDISP_CYAN 0x07FF /* 0, 255, 255 */
#define UDISP_RED 0xF800 /* 255, 0, 0 */
#define UDISP_MAGENTA 0xF81F /* 255, 0, 255 */
#define UDISP_YELLOW 0xFFE0 /* 255, 255, 0 */
#define UDISP_WHITE 0xFFFF /* 255, 255, 255 */
#define UDISP_ORANGE 0xFD20 /* 255, 165, 0 */
#define UDISP_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
#define UDISP_PINK 0xF81F
#define SPI_BEGIN_TRANSACTION uspi->beginTransaction(spiSettings);
#define SPI_END_TRANSACTION uspi->endTransaction();
#define SPI_CS_LOW if (spi_cs >= 0) digitalWrite(spi_cs, LOW);
#define SPI_CS_HIGH if (spi_cs >= 0) digitalWrite(spi_cs, HIGH);
#define SPI_DC_LOW if (spi_dc >= 0) digitalWrite(spi_dc, LOW);
#define SPI_DC_HIGH if (spi_dc >= 0) digitalWrite(spi_dc, HIGH);
#define ESP32_PWM_CHANNEL 1
class uDisplay : public Renderer {
public:
uDisplay(char *);
Renderer *Init(void);
void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font);
void Updateframe();
void DisplayOnff(int8_t on);
void Splash(void);
char *devname(void);
uint16_t fgcol(void) const { return fg_col; };
uint16_t bgcol(void) const { return bg_col; };
void dim(uint8_t dim);
uint16_t GetColorFromIndex(uint8_t index);
void setRotation(uint8_t m);
void fillScreen(uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void pushColors(uint16_t *data, uint16_t len, boolean first);
private:
void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
uint32_t str2c(char **sp, char *vp, uint32_t len);
void i2c_command(uint8_t val);
void spi_command(uint8_t val);
uint8_t strlen_ln(char *str);
int32_t next_val(char **sp);
uint32_t next_hex(char **sp);
void setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
char dname[16];
int8_t bpp;
uint8_t interface;
uint8_t i2caddr;
int8_t i2c_scl;
int8_t i2c_sda;
int8_t reset;
uint8_t dsp_cmds[128];
uint8_t dsp_ncmds;
uint8_t dsp_on;
uint8_t dsp_off;
uint16_t splash_font;
uint16_t splash_size;
uint16_t splash_xp;
uint16_t splash_yp;
uint16_t fg_col;
uint16_t bg_col;
uint16_t gxs;
uint16_t gys;
int8_t spi_cs;
int8_t spi_clk;
int8_t spi_mosi;
int8_t spi_dc;
int8_t bpanel;
int8_t spi_miso;
uint8_t dimmer;
SPIClass *uspi;
SPISettings spiSettings;
uint32_t spi_speed;
uint8_t spi_nr = 1;
uint8_t rot_0;
uint8_t rot_1;
uint8_t rot_2;
uint8_t rot_3;
uint8_t saw_1;
uint8_t saw_2;
uint8_t saw_3;
uint8_t flags;
};
#endif // _UDISP_

View File

@ -1,7 +0,0 @@
name=Berry
version=0.1.10
author=Guan Wenliang <skiars@qq.com>,
maintainer=Stephan Hadinger <stephan.hadinger@gmail.com>
sentence=Berry scripting language for Tasmota32
paragraph=Berry is a ultra-lightweight dynamically typed embedded scripting language.
architectures=esp32

View File

@ -1 +0,0 @@
#include "port/berry_conf.h"

View File

@ -1,34 +0,0 @@
/********************************************************************
* Tasmota lib
*
* To use: `d = Driver()`
*
*******************************************************************/
#include "be_object.h"
// #if !BE_USE_PRECOMPILED_OBJECT
#if 1 // TODO we will do pre-compiled later
void be_load_driverlib(bvm *vm)
{
static const bnfuncinfo members[] = {
{ "every_second", NULL },
{ "every_100ms", NULL },
{ "web_add_button", NULL },
{ "web_add_main_button", NULL },
{ "save_before_restart", NULL },
{ "web_sensor", NULL },
{ "json_append", NULL },
{ "button_pressed", NULL },
{ NULL, NULL }
};
be_regclass(vm, "Driver", members);
}
#else
/* @const_object_info_begin
module tasmota (scope: global, depend: 1) {
get_free_heap, func(l_getFreeHeap)
}
@const_object_info_end */
#include "../generate/be_fixed_tasmota.h"
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,110 @@
/********************************************************************
* Tasmota lib
*
* To use: `d = Driver()`
*
*******************************************************************/
#include "be_object.h"
#include "be_string.h"
#include "be_gc.h"
extern int d_getTasmotaGlob(bvm *vm);
/********************************************************************
"class Driver2 : Driver "
"def add_cmd(c, f) "
"var tasmota = self.get_tasmota() "
"tasmota.add_cmd(c, / cmd, idx, payload, payload_json -> f(self, cmd, idx, payload, payload_json)) "
"end "
"end "
"Driver = Driver2 "
********************************************************************/
/********************************************************************
** Solidified function: add_cmd
********************************************************************/
/********** Solidified proto: add_cmd_0 */
static const bupvaldesc add_cmd_0_upvals[2] = {
be_local_const_upval(1, 2),
be_local_const_upval(1, 0),
};
be_define_local_const_str(add_cmd_0_str_name, "add_cmd_0", 607256038, 0, 8, 0);
be_define_local_const_str(add_cmd_0_str_source, "input", -103256197, 0, 5, 0);
static const uint32_t add_cmd_0_code[8] = {
0x68100000, // 0000 GETUPV R4 U0
0x68140001, // 0001 GETUPV R5 U1
0x5C180000, // 0002 MOVE R6 R0
0x5C1C0200, // 0003 MOVE R7 R1
0x5C200400, // 0004 MOVE R8 R2
0x5C240600, // 0005 MOVE R9 R3
0x7C100A00, // 0006 CALL R4 5
0x80040800, // 0007 RET 1 R4
};
be_define_local_proto(add_cmd_0, 10, 4, 0, 0, 1);
/********** Solidified proto: add_cmd */
static const bproto *add_cmd_subproto[1] = {
&add_cmd_0_proto,
};
be_define_local_const_str(add_cmd_str_name, "add_cmd", -933336417, 0, 7, 0);
be_define_local_const_str(add_cmd_str_source, "input", -103256197, 0, 5, 0);
be_define_local_const_str(add_cmd_str_0, "get_tasmota", 334356779, 0, 11, 0);
be_define_local_const_str(add_cmd_str_1, "add_cmd", -933336417, 0, 7, 0);
static const bvalue add_cmd_ktab[2] = {
{ { .s=be_local_const_str(add_cmd_str_0) }, BE_STRING},
{ { .s=be_local_const_str(add_cmd_str_1) }, BE_STRING},
};
static const uint32_t add_cmd_code[8] = {
0x8C0C0100, // 0000 GETMET R3 R0 R256
0x7C0C0200, // 0001 CALL R3 1
0x8C100701, // 0002 GETMET R4 R3 R257
0x5C180200, // 0003 MOVE R6 R1
0x841C0000, // 0004 CLOSURE R7 P0
0x7C100600, // 0005 CALL R4 3
0xA0000000, // 0006 CLOSE 0
0x80000000, // 0007 RET 0 R0
};
be_define_local_proto(add_cmd, 8, 3, 1, 1, 0);
be_define_local_closure(add_cmd);
/*******************************************************************/
// #if !BE_USE_PRECOMPILED_OBJECT
#if 1 // TODO we will do pre-compiled later
void be_load_driverlib(bvm *vm)
{
static const bnfuncinfo members[] = {
{ "every_second", NULL },
{ "every_100ms", NULL },
{ "web_add_button", NULL },
{ "web_add_main_button", NULL },
{ "save_before_restart", NULL },
{ "web_sensor", NULL },
{ "json_append", NULL },
{ "button_pressed", NULL },
{ "get_tasmota", d_getTasmotaGlob },
{ NULL, (bntvfunc) BE_CLOSURE }, /* mark section for berry closures */
{ "add_cmd", (bntvfunc) &add_cmd_closure },
{ NULL, NULL }
};
be_regclass(vm, "Driver", members);
}
#else
/* @const_object_info_begin
module tasmota (scope: global, depend: 1) {
get_free_heap, func(l_getFreeHeap)
}
@const_object_info_end */
#include "../generate/be_fixed_tasmota.h"
#endif

View File

@ -0,0 +1,20 @@
# anonymous function and closure
def count(x)
var arr = []
for i : 0 .. x
arr.push(
def (n) # loop variable cannot be used directly as free variable
return def ()
return n * n
end
end (i) # define and call anonymous function
)
end
return arr
end
for xx : count(6)
print(xx()) # 0, 1, 4 ... n * n
end
return count

View File

@ -0,0 +1,15 @@
import time
c = time.clock()
do
i = 0
while i < 100000000
i += 1
end
end
print('while iteration 100000000 times', time.clock() - c, 's')
c = time.clock()
for i : 1 .. 100000000
end
print('for iteration 100000000 times', time.clock() - c, 's')

View File

@ -0,0 +1,60 @@
# Reference from https://github.com/BerryMathDevelopmentTeam/BerryMath/blob/master/testscript/BinaryTree.bm
class node
var v, l, r
def init(v, l, r)
self.v = v
self.l = l
self.r = r
end
def insert(v)
if v < self.v
if self.l
self.l.insert(v)
else
self.l = node(v)
end
else
if self.r
self.r.insert(v)
else
self.r = node (v)
end
end
end
def sort(l)
if (self.l) self.l.sort(l) end
l.push(self.v)
if (self.r) self.r.sort(l) end
end
end
class btree
var root
def insert(v)
if self.root
self.root.insert(v)
else
self.root = node(v)
end
end
def sort()
var l = []
if self.root
self.root.sort(l)
end
return l
end
end
var tree = btree()
tree.insert(-100)
tree.insert(5);
tree.insert(3);
tree.insert(9);
tree.insert(10);
tree.insert(10000000);
tree.insert(1);
tree.insert(-1);
tree.insert(-10);
print(tree.sort());

View File

@ -0,0 +1,16 @@
def cpi(n)
i = 2
pi = 3
while i <= n
term = 4.0 / (i * (i + 1) * (i + 2))
if i % 4
pi = pi + term
else
pi = pi - term
end
i = i + 2
end
return pi
end
print("pi =", cpi(100))

View File

@ -0,0 +1,12 @@
import debug
def test_func()
try
compile('def +() end')()
except .. as e, v
print('catch execption:', str(e) + ' >>>\n ' + str(v))
debug.traceback()
end
end
test_func()

View File

@ -0,0 +1,12 @@
import time
def fib(x)
if x <= 2
return 1
end
return fib(x - 1) + fib(x - 2)
end
c = time.clock()
print("fib:", fib(38)) # minimum stack size: 78!!
print("time:", time.clock() - c, 's')

View File

@ -0,0 +1,26 @@
import time
import math
math.srand(time.time())
res = math.rand() % 100
max_test = 7
test = -1
idx = 1
print('Guess a number between 0 and 99. You have', max_test, 'chances.')
while test != res && idx <= max_test
test = number(input(str(idx) + ': enter the number you guessed: '))
if type(test) != 'int'
print('This is not an integer. Continue!')
continue
elif test > res
print('This number is too large.')
elif test < res
print('This number is too small.')
end
idx = idx + 1
end
if test == res
print('You win!')
else
print('You failed, the correct answer is', res)
end

View File

@ -0,0 +1,4 @@
import json
print(json.load('{"key": "value"}'))
print(json.dump({'test key': nil}))
print(json.dump({'key1': nil, 45: true}, 'format'))

View File

@ -0,0 +1,8 @@
# simple lambda example
print((/a b c-> a * b + c)(2, 3, 4))
# Y-Combinator and factorial functions
Y = /f-> (/x-> f(/n-> x(x)(n)))(/x-> f(/n-> x(x)(n)))
F = /f-> /x-> x ? f(x - 1) * x : 1
fact = Y(F)
print('fact(10) == ' .. fact(10))

View File

@ -0,0 +1,16 @@
import os
def scandir(path)
print('path: ' + path)
for name : os.listdir(path)
var fullname = os.path.join(path, name)
if os.path.isfile(fullname)
print('file: ' + fullname)
else
print('path: ' + fullname)
scandir(fullname)
end
end
end
scandir('.')

View File

@ -0,0 +1,42 @@
def qsort(data)
# do once sort
def once(left, right)
var pivot = data[left] # use the 0th value as the pivot
while left < right # check if sort is complete
# put the value less than the pivot to the left
while left < right && data[right] >= pivot
right -= 1 # skip values greater than pivot
end
data[left] = data[right]
# put the value greater than the pivot on the right
while left < right && data[left] <= pivot
left += 1 # skip values less than pivot
end
data[right] = data[left]
end
# now we have the index of the pivot, store it
data[left] = pivot
return left # return the index of the pivot
end
# recursive quick sort algorithm
def _sort(left, right)
if left < right # executed when the array is not empty
var index = once(left, right) # get index of pivot for divide and conquer
_sort(left, index - 1) # sort the data on the left
_sort(index + 1, right) # sort the data on the right
end
end
# start quick sort
_sort(0, data.size() - 1)
return data
end
import time, math
math.srand(time.time()) # sse system time as a random seed
data = []
# put 20 random numbers into the array
for i : 1 .. 20
data.push(math.rand() % 100)
end
# sort and print
print(qsort(data))

View File

@ -0,0 +1,61 @@
do
def ismult(msg)
import string
return string.split(msg, -5)[1] == '\'EOS\''
end
def multline(src, msg)
if !ismult(msg)
print('syntax_error: ' + msg)
return
end
while true
try
src += '\n' + input('>> ')
return compile(src)
except 'syntax_error' as e, m
if !ismult(m)
print('syntax_error: ' + m)
return
end
end
end
end
def parse()
var fun, src = input('> ')
try
fun = compile('return (' + src + ')')
except 'syntax_error' as e, m
try
fun = compile(src)
except 'syntax_error' as e, m
fun = multline(src, m)
end
end
return fun
end
def run(fun)
try
var res = fun()
if res print(res) end
except .. as e, m
import debug
print(e .. ': ' .. m)
debug.traceback()
end
end
def repl()
while true
var fun = parse()
if fun != nil
run(fun)
end
end
end
print("Berry Berry REPL!")
repl()
end

View File

@ -0,0 +1,32 @@
s = "This is a long string test. 0123456789 abcdefg ABCDEFG"
print(s)
a = .5
print(a)
import string as s
print(s.hex(0x45678ABCD, 16))
def bin(x, num)
assert(type(x) == 'int', 'the type of \'x\' must be integer')
# test the 'x' bits
var bits = 1
for i : 0 .. 62
if x & (1 << 63 - i)
bits = 64 - i
break
end
end
if type(num) == 'int' && num > 0 && num <= 64
bits = bits < num ? num : bits
end
var result = ''
bits -= 1
for i : 0 .. bits
result += x & (1 << (bits - i)) ? '1' : '0'
end
return result
end
print(bin(33))

View File

@ -0,0 +1,7 @@
import string
print(string.format('%.3d', 12))
print(string.format('%.3f', 12))
print(string.format('%20.7f', 14.5))
print(string.format('-- %-40s ---', 'this is a string format test'))
print(string.format('-- %40s ---', 'this is a string format test'))

View File

@ -0,0 +1,29 @@
{
"name":"Berry",
"description":"Berry scripting language for Tasmota32",
"keywords":"berry, script",
"authors":
{
"name": "Guan Wenliang <skiars@qq.com>, ",
"maintainer": true
},
"repository":
{
"type": "git",
"url": "https://github.com/Skiars/berry"
},
"version": "7.0",
"license": "MIT License",
"frameworks": "*",
"platforms": "*",
"build": {
"srcFilter": [
"+<*.c>",
"+<../default/*.c>",
"+<../default/*.cpp>",
"+<../default/*.hpp>",
"+<*.cpp>",
"+<*.h>"
]
}
}

Some files were not shown because too many files have changed in this diff Show More