Resolved conflicts and merged with development

This commit is contained in:
Ajith Vasudevan 2021-03-01 18:19:47 +05:30
commit 0eb634a315
87 changed files with 2552 additions and 1424 deletions

View File

@ -172,6 +172,7 @@
| USE_TASMOTA_CLIENT | - | - | - | - | - | - | - |
| USE_OPENTHERM | - | - | - | - | - | - | - |
| USE_MIEL_HVAC | - | - | - | - | - | - | - |
| USE_PROJECTOR_CTRL | - | - | - | - | - | - | - |
| USE_AS608 | - | - | - | - | - | - | - |
| USE_TCP_BRIDGE | - | - | - | - | - | - | - | zbbridge
| | | | | | | | |

View File

@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
- Allow MCP230xx pinmode from output to input (#11104)
- SML VBUS support (#11125)
- Command ``Sensor80 1 <0..7>`` to control MFRC522 RFID antenna gain from 18dB (0) to 48dB (7) (#11073)
- Support for NEC and OPTOMA LCD/DLP Projector serial power control by Jan Bubík (#11145)
### Changed
- TuyaMcu dimmer timeout (#11121)
@ -18,6 +19,7 @@ All notable changes to this project will be documented in this file.
- Timer loop when console is scrolled up regression from v9.3.0 (#11108)
- Display exception when no file system is present (#11125)
- PN532 on ESP32 Serial flush both Tx and Rx buffers (#10910)
- Light scheme related color changes (#11041)
## [Released]

View File

@ -80,9 +80,10 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
## Changelog v9.3.1.1
### Added
- Allow MCP230xx pinmode from output to input [#11104](https://github.com/arendst/Tasmota/issues/11104)
- SML VBUS support [#11125](https://github.com/arendst/Tasmota/issues/11125)
- 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)
- Support for SML VBUS [#11125](https://github.com/arendst/Tasmota/issues/11125)
- Support for NEC and OPTOMA LCD/DLP Projector serial power control by Jan Bubík [#11145](https://github.com/arendst/Tasmota/issues/11145)
- Allow MCP230xx pinmode from output to input [#11104](https://github.com/arendst/Tasmota/issues/11104)
### Changed
- TuyaMcu dimmer timeout [#11121](https://github.com/arendst/Tasmota/issues/11121)
@ -93,3 +94,4 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- Timer loop when console is scrolled up regression from v9.3.0 [#11108](https://github.com/arendst/Tasmota/issues/11108)
- Display exception when no file system is present [#11125](https://github.com/arendst/Tasmota/issues/11125)
- PN532 on ESP32 Serial flush both Tx and Rx buffers [#10910](https://github.com/arendst/Tasmota/issues/10910)
- Light scheme related color changes [#11041](https://github.com/arendst/Tasmota/issues/11041)

View File

@ -22,11 +22,12 @@ const uint16_t ssd1351_colors[]={SSD1351_BLACK,SSD1351_WHITE,SSD1351_RED,SSD1351
SSD1351_LIGHTGREY,SSD1351_DARKGREY,SSD1351_ORANGE,SSD1351_GREENYELLOW,SSD1351_PINK};
// Constructor when using software SPI. All output pins are configurable.
SSD1351::SSD1351(int8_t cs,int8_t mosi,int8_t sclk) : Renderer(SSD1351_WIDTH, SSD1351_HEIGHT) {
SSD1351::SSD1351(int8_t cs,int8_t mosi,int8_t sclk, int8_t dc) : Renderer(SSD1351_WIDTH, SSD1351_HEIGHT) {
_cs = cs;
_mosi = mosi;
_sclk = sclk;
_hwspi = 0;
_dc = dc;
}
#ifndef ESP32
@ -70,27 +71,30 @@ uint32_t ssd1351_mtdo_prev;
void SSD1351::spi_lcd_mode_init(void) {
uint32 regvalue;
ssd1351_clock_prev=SPI1CLK;
ssd1351_usr_prev=SPI1U;
ssd1351_usr1_prev=SPI1U1;
ssd1351_usr2_prev=SPI1U2;
ssd1351_spi1c_prev=SPI1C;
ssd1351_spi1p_prev=SPI1P;
//ssd1351_gpmux_prev=GPMUX;
ssd1351_mtdo_prev=READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U);
if (_dc >= 0) {
spis = SPISettings(40000000, MSBFIRST, SPI_MODE0);
} else {
ssd1351_clock_prev=SPI1CLK;
ssd1351_usr_prev=SPI1U;
ssd1351_usr1_prev=SPI1U1;
ssd1351_usr2_prev=SPI1U2;
ssd1351_spi1c_prev=SPI1C;
ssd1351_spi1p_prev=SPI1P;
//ssd1351_gpmux_prev=GPMUX;
ssd1351_mtdo_prev=READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U);
SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE;
SPI1U1=0;
SPI1C = 0;
SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE;
SPI1U1=0;
SPI1C = 0;
//bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock
//bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock
//bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock
//bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9
//PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure miso to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure mosi to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure sclk to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure cs to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure mosi to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure sclk to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure cs to spi mode
// the current implementation leaves about 1 us between transfers ????
// due to lack of documentation i could not find the reason
@ -98,9 +102,9 @@ void SSD1351::spi_lcd_mode_init(void) {
//SET_PERI_REG_MASK(SPI_USER(1), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND);
SET_PERI_REG_MASK(SPI_USER(1), SPI_USR_COMMAND);
SET_PERI_REG_MASK(SPI_USER(1), SPI_USR_COMMAND);
CLEAR_PERI_REG_MASK(SPI_USER(1), SPI_FLASH_MODE);
CLEAR_PERI_REG_MASK(SPI_USER(1), SPI_FLASH_MODE);
// SPI clock=CPU clock/8 => 10 Mhz
/*
WRITE_PERI_REG(SPI_CLOCK(1),
@ -110,47 +114,58 @@ void SSD1351::spi_lcd_mode_init(void) {
((3&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
*/
// will result in 80/18 = 4,4 Mhz
SPI.setFrequency(4500000);
SPI.setFrequency(4500000);
ssd1351_clock=SPI1CLK;
ssd1351_usr=SPI1U;
ssd1351_usr1=SPI1U1;
ssd1351_usr2=SPI1U2;
ssd1351_spi1c=SPI1C;
ssd1351_spi1p=SPI1P;
//ssd1351_gpmux=GPMUX;
ssd1351_mtdo=READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U);
ssd131_start=0;
ssd1351_clock=SPI1CLK;
ssd1351_usr=SPI1U;
ssd1351_usr1=SPI1U1;
ssd1351_usr2=SPI1U2;
ssd1351_spi1c=SPI1C;
ssd1351_spi1p=SPI1P;
//ssd1351_gpmux=GPMUX;
ssd1351_mtdo=READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U);
}
ssd131_start = 0;
}
void SSD1351::start(void) {
if (ssd131_start) return;
//while(SPI1CMD & SPIBUSY) {}
while(READ_PERI_REG(SPI_CMD(1))&SPI_USR);
SPI1CLK=ssd1351_clock;
SPI1U=ssd1351_usr;
SPI1U1=ssd1351_usr1;
SPI1U2=ssd1351_usr2;
SPI1C=ssd1351_spi1c;
SPI1P=ssd1351_spi1p;
//GPMUX=ssd1351_gpmux;
WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U,ssd1351_mtdo);
ssd131_start=1;
if (_dc >= 0) {
SPI.beginTransaction(spis);
} else {
while(READ_PERI_REG(SPI_CMD(1))&SPI_USR);
SPI1CLK=ssd1351_clock;
SPI1U=ssd1351_usr;
SPI1U1=ssd1351_usr1;
SPI1U2=ssd1351_usr2;
SPI1C=ssd1351_spi1c;
SPI1P=ssd1351_spi1p;
//GPMUX=ssd1351_gpmux;
WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U,ssd1351_mtdo);
}
ssd131_start = 1;
}
void SSD1351::stop(void) {
if (!ssd131_start) return;
//while(SPI1CMD & SPIBUSY) {}
while(READ_PERI_REG(SPI_CMD(1))&SPI_USR);
SPI1CLK=ssd1351_clock_prev;
SPI1U=ssd1351_usr_prev;
SPI1U1=ssd1351_usr1_prev;
SPI1U2=ssd1351_usr2_prev;
SPI1C=ssd1351_spi1c_prev;
SPI1P=ssd1351_spi1p_prev;
//GPMUX=ssd1351_gpmux_prev;
WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U,ssd1351_mtdo_prev);
ssd131_start=0;
if (_dc >= 0) {
SPI.endTransaction();
} else {
//while(SPI1CMD & SPIBUSY) {}
while(READ_PERI_REG(SPI_CMD(1))&SPI_USR);
SPI1CLK=ssd1351_clock_prev;
SPI1U=ssd1351_usr_prev;
SPI1U1=ssd1351_usr1_prev;
SPI1U2=ssd1351_usr2_prev;
SPI1C=ssd1351_spi1c_prev;
SPI1P=ssd1351_spi1p_prev;
//GPMUX=ssd1351_gpmux_prev;
WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U,ssd1351_mtdo_prev);
}
ssd131_start = 0;
}
// dc = 0
@ -158,19 +173,23 @@ void SSD1351::writecommand(uint8_t c) {
if (_hwspi) {
uint32_t regvalue;
uint8_t bytetemp;
bytetemp=(c>>1)&0x7f;
start();
//#define SPI_USR_COMMAND_BITLEN 0x0000000F
//#define SPI_USR_COMMAND_BITLEN_S 28
regvalue= ((8&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)bytetemp); //configure transmission variable,9bit transmission length and first 8 command bit
if(c&0x01) regvalue|=BIT15; //write the 9th bit
while(READ_PERI_REG(SPI_CMD(1))&SPI_USR); //waiting for spi module available
WRITE_PERI_REG(SPI_USER2(1), regvalue); //write command and command length into spi reg
SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); //transmission start
} else fastSPIwrite(c,0);
if (_dc >= 0) {
digitalWrite(_dc, LOW);
SPI.transfer(c);
} else {
bytetemp = (c >> 1) & 0x7f;
regvalue= ((8&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)bytetemp); //configure transmission variable,9bit transmission length and first 8 command bit
if (c & 0x01) regvalue |= BIT15; //write the 9th bit
while (READ_PERI_REG(SPI_CMD(1)) & SPI_USR); //waiting for spi module available
WRITE_PERI_REG(SPI_USER2(1), regvalue); //write command and command length into spi reg
SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); //transmission start
}
} else {
fastSPIwrite(c, 0);
}
}
// dc = 1
@ -178,47 +197,63 @@ void SSD1351::writedata(uint8_t d) {
if (_hwspi) {
uint32_t regvalue;
uint8_t bytetemp;
bytetemp=(d>>1)|0x80;
start();
regvalue= ((8&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)bytetemp); //configure transmission variable,9bit transmission length and first 8 command bit
if(d&0x01) regvalue|=BIT15; //write the 9th bit
while(READ_PERI_REG(SPI_CMD(1))&SPI_USR); //waiting for spi module available
WRITE_PERI_REG(SPI_USER2(1), regvalue); //write command and command length into spi reg
SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); //transmission start
} else fastSPIwrite(d,1);
if (_dc >= 0) {
digitalWrite(_dc, HIGH);
SPI.transfer(d);
} else {
bytetemp = (d >> 1) | 0x80;
regvalue= ((8&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)bytetemp); //configure transmission variable,9bit transmission length and first 8 command bit
if(d&0x01) regvalue|=BIT15; //write the 9th bit
while(READ_PERI_REG(SPI_CMD(1))&SPI_USR); //waiting for spi module available
WRITE_PERI_REG(SPI_USER2(1), regvalue); //write command and command length into spi reg
SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); //transmission start
}
} else {
fastSPIwrite(d, 1);
}
}
void ICACHE_RAM_ATTR SSD1351::fastSPIwrite(uint8_t d,uint8_t dc) {
void ICACHE_RAM_ATTR SSD1351::fastSPIwrite(uint8_t d, uint8_t dc) {
WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_cs);
WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk);
if(dc) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi);
else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi);
WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk);
WRITE_PERI_REG( PIN_OUT_CLEAR, 1 << _cs);
for(uint8_t bit = 0x80; bit; bit >>= 1) {
if (_dc >= 0) {
digitalWrite(_dc, dc);
WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk);
if(d&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi);
for(uint8_t bit = 0x80; bit; bit >>= 1) {
WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk);
if(d&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi);
else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi);
WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk);
}
} else {
WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk);
if(dc) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi);
else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi);
WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk);
for(uint8_t bit = 0x80; bit; bit >>= 1) {
WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk);
if(d&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi);
else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi);
WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk);
}
}
WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs);
WRITE_PERI_REG( PIN_OUT_SET, 1 << _cs);
}
#else
// ESP32 section
uint8_t ssd131_start;
void SSD1351::writedata(uint8_t d) {
fastSPIwrite(d,1);
fastSPIwrite(d, 1);
}
void SSD1351::writecommand(uint8_t c) {
fastSPIwrite(c,0);
fastSPIwrite(c, 0);
}
#include "soc/spi_reg.h"
@ -227,12 +262,10 @@ void SSD1351::writecommand(uint8_t c) {
#include "esp32-hal.h"
#include "soc/spi_struct.h"
SPISettings oled_spiSettings;
// diconnect from spi
void SSD1351::start(void) {
if (ssd131_start) return;
SPI.beginTransaction(oled_spiSettings);
SPI.beginTransaction(spis);
ssd131_start = 1;
}
@ -245,21 +278,25 @@ void SSD1351::stop(void) {
// since ardunio transferBits ia completely disfunctional
// we use our own hardware driver for 9 bit spi
void SSD1351::fastSPIwrite(uint8_t d,uint8_t dc) {
void SSD1351::fastSPIwrite(uint8_t d, uint8_t dc) {
digitalWrite( _cs, LOW);
if (_dc >= 0) {
digitalWrite(_dc, dc);
SPI.transfer(d);
} else {
uint32_t regvalue = d >> 1;
if (dc) regvalue |= 0x80;
else regvalue &= 0x7f;
if (d & 1) regvalue |= 0x8000;
uint32_t regvalue=d>>1;
if (dc) regvalue|=0x80;
else regvalue&=0x7f;
if (d&1) regvalue|=0x8000;
REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI);
REG_WRITE(SPI_MOSI_DLEN_REG(3), 9 - 1);
uint32_t *dp=(uint32_t*)SPI_W0_REG(3);
*dp=regvalue;
REG_SET_BIT(SPI_CMD_REG(3), SPI_USR);
while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR));
REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI);
REG_WRITE(SPI_MOSI_DLEN_REG(3), 9 - 1);
uint32_t *dp=(uint32_t*)SPI_W0_REG(3);
*dp = regvalue;
REG_SET_BIT(SPI_CMD_REG(3), SPI_USR);
while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR));
}
digitalWrite( _cs, HIGH);
}
@ -312,21 +349,26 @@ void SSD1351::begin(void) {
pinMode(_mosi, OUTPUT);
digitalWrite(_mosi, LOW);
if (_dc >= 0) {
pinMode(_dc, OUTPUT);
digitalWrite(_dc, LOW);
}
#ifndef ESP32
if ((_sclk==14) && (_mosi==13) && (_cs==15)) {
if ((_sclk == 14) && (_mosi == 13) && (_cs == 15)) {
// we use hardware spi
_hwspi=1;
_hwspi = 1;
SPI.begin();
spi_lcd_mode_init();
} else {
// we must use software spi
_hwspi=0;
_hwspi = 0;
}
#else
_hwspi=1;
SPI.begin(_sclk,-1,_mosi, -1);
oled_spiSettings = SPISettings(4500000, MSBFIRST, SPI_MODE3);
_hwspi = 1;
SPI.begin(_sclk, -1, _mosi, -1);
spis = SPISettings(4500000, MSBFIRST, SPI_MODE3);
#endif
const uint8_t *addr = (const uint8_t *)initList;

View File

@ -93,7 +93,7 @@ class SSD1351 : public Renderer {
public:
SSD1351(int8_t cs,int8_t mosi,int8_t sclk);
SSD1351(int8_t cs,int8_t mosi,int8_t sclk, int8_t dc);
void begin(void);
void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font);
@ -119,10 +119,11 @@ class SSD1351 : public Renderer {
private:
uint8_t tabcolor;
SPISettings spis;
void fastSPIwrite(uint8_t d,uint8_t dc);
void start(void);
void stop(void);
int8_t _cs, _mosi, _sclk, _hwspi;
int8_t _cs, _mosi, _sclk, _hwspi, _dc;
};

View File

@ -1,128 +1,111 @@
extern const bcstring be_const_str_calldepth;
extern const bcstring be_const_str_clock;
extern const bcstring be_const_str_size;
extern const bcstring be_const_str_system;
extern const bcstring be_const_str_type;
extern const bcstring be_const_str_if;
extern const bcstring be_const_str_int;
extern const bcstring be_const_str_isfile;
extern const bcstring be_const_str_log;
extern const bcstring be_const_str_raise;
extern const bcstring be_const_str_concat;
extern const bcstring be_const_str_list;
extern const bcstring be_const_str_map;
extern const bcstring be_const_str_for;
extern const bcstring be_const_str_dot_p;
extern const bcstring be_const_str_isdir;
extern const bcstring be_const_str_mkdir;
extern const bcstring be_const_str_remove;
extern const bcstring be_const_str_cosh;
extern const bcstring be_const_str_abs;
extern const bcstring be_const_str_reverse;
extern const bcstring be_const_str_sinh;
extern const bcstring be_const_str_hex;
extern const bcstring be_const_str_tostring;
extern const bcstring be_const_str_opt_add;
extern const bcstring be_const_str_atan;
extern const bcstring be_const_str_real;
extern const bcstring be_const_str_iter;
extern const bcstring be_const_str_top;
extern const bcstring be_const_str_except;
extern const bcstring be_const_str_getcwd;
extern const bcstring be_const_str_listdir;
extern const bcstring be_const_str_log10;
extern const bcstring be_const_str_allocated;
extern const bcstring be_const_str_init;
extern const bcstring be_const_str_module;
extern const bcstring be_const_str_ceil;
extern const bcstring be_const_str_clear;
extern const bcstring be_const_str_collect;
extern const bcstring be_const_str_find;
extern const bcstring be_const_str_item;
extern const bcstring be_const_str_format;
extern const bcstring be_const_str_sqrt;
extern const bcstring be_const_str_classname;
extern const bcstring be_const_str_byte;
extern const bcstring be_const_str_else;
extern const bcstring be_const_str_deinit;
extern const bcstring be_const_str_end;
extern const bcstring be_const_str_true;
extern const bcstring be_const_str___upper__;
extern const bcstring be_const_str_char;
extern const bcstring be_const_str_load;
extern const bcstring be_const_str_resize;
extern const bcstring be_const_str_sethook;
extern const bcstring be_const_str_varname;
extern const bcstring be_const_str_deg;
extern const bcstring be_const_str_srand;
extern const bcstring be_const_str_str;
extern const bcstring be_const_str_range;
extern const bcstring be_const_str_toupper;
extern const bcstring be_const_str_;
extern const bcstring be_const_str_copy;
extern const bcstring be_const_str_exp;
extern const bcstring be_const_str_time;
extern const bcstring be_const_str_break;
extern const bcstring be_const_str_opt_neq;
extern const bcstring be_const_str_assert;
extern const bcstring be_const_str_attrdump;
extern const bcstring be_const_str_chdir;
extern const bcstring be_const_str_isinstance;
extern const bcstring be_const_str_continue;
extern const bcstring be_const_str_do;
extern const bcstring be_const_str_lower;
extern const bcstring be_const_str_pow;
extern const bcstring be_const_str_false;
extern const bcstring be_const_str_count;
extern const bcstring be_const_str_exit;
extern const bcstring be_const_str_print;
extern const bcstring be_const_str_def;
extern const bcstring be_const_str_pop;
extern const bcstring be_const_str_tolower;
extern const bcstring be_const_str_classof;
extern const bcstring be_const_str_cos;
extern const bcstring be_const_str_dump;
extern const bcstring be_const_str_join;
extern const bcstring be_const_str_push;
extern const bcstring be_const_str_sin;
extern const bcstring be_const_str_return;
extern const bcstring be_const_str_path;
extern const bcstring be_const_str_rand;
extern const bcstring be_const_str_class;
extern const bcstring be_const_str_nil;
extern const bcstring be_const_str_input;
extern const bcstring be_const_str_floor;
extern const bcstring be_const_str_keys;
extern const bcstring be_const_str_number;
extern const bcstring be_const_str_rad;
extern const bcstring be_const_str_imin;
extern const bcstring be_const_str_pi;
extern const bcstring be_const_str_splitext;
extern const bcstring be_const_str_compile;
extern const bcstring be_const_str_setrange;
extern const bcstring be_const_str_traceback;
extern const bcstring be_const_str_upper;
extern const bcstring be_const_str_var;
extern const bcstring be_const_str_opt_eq;
extern const bcstring be_const_str_codedump;
extern const bcstring be_const_str_tan;
extern const bcstring be_const_str_setitem;
extern const bcstring be_const_str_tanh;
extern const bcstring be_const_str_as;
extern const bcstring be_const_str_issubclass;
extern const bcstring be_const_str_upvname;
extern const bcstring be_const_str_opt_connect;
extern const bcstring be_const_str_try;
extern const bcstring be_const_str_while;
extern const bcstring be_const_str_import;
extern const bcstring be_const_str___lower__;
extern const bcstring be_const_str_open;
extern const bcstring be_const_str_acos;
extern const bcstring be_const_str_asin;
extern const bcstring be_const_str_imax;
extern const bcstring be_const_str_insert;
extern const bcstring be_const_str_split;
extern const bcstring be_const_str___iterator__;
extern const bcstring be_const_str_exists;
extern const bcstring be_const_str_super;
extern const bcstring be_const_str_list;
extern const bcstring be_const_str_module;
extern const bcstring be_const_str_pop;
extern const bcstring be_const_str_int;
extern const bcstring be_const_str_push;
extern const bcstring be_const_str_setrange;
extern const bcstring be_const_str_sinh;
extern const bcstring be_const_str_elif;
extern const bcstring be_const_str_iter;
extern const bcstring be_const_str_load;
extern const bcstring be_const_str_class;
extern const bcstring be_const_str_if;
extern const bcstring be_const_str_opt_eq;
extern const bcstring be_const_str_ceil;
extern const bcstring be_const_str_floor;
extern const bcstring be_const_str_map;
extern const bcstring be_const_str_print;
extern const bcstring be_const_str_else;
extern const bcstring be_const_str_find;
extern const bcstring be_const_str_str;
extern const bcstring be_const_str___upper__;
extern const bcstring be_const_str_dump;
extern const bcstring be_const_str_atan;
extern const bcstring be_const_str_size;
extern const bcstring be_const_str_tolower;
extern const bcstring be_const_str_opt_add;
extern const bcstring be_const_str_abs;
extern const bcstring be_const_str_lower;
extern const bcstring be_const_str_end;
extern const bcstring be_const_str_import;
extern const bcstring be_const_str_classof;
extern const bcstring be_const_str_concat;
extern const bcstring be_const_str_byte;
extern const bcstring be_const_str_top;
extern const bcstring be_const_str_clear;
extern const bcstring be_const_str_opt_connect;
extern const bcstring be_const_str_collect;
extern const bcstring be_const_str_init;
extern const bcstring be_const_str_log10;
extern const bcstring be_const_str_nil;
extern const bcstring be_const_str_;
extern const bcstring be_const_str_real;
extern const bcstring be_const_str_calldepth;
extern const bcstring be_const_str_format;
extern const bcstring be_const_str_pi;
extern const bcstring be_const_str_do;
extern const bcstring be_const_str___iterator__;
extern const bcstring be_const_str_number;
extern const bcstring be_const_str_type;
extern const bcstring be_const_str_dot_p;
extern const bcstring be_const_str_traceback;
extern const bcstring be_const_str_as;
extern const bcstring be_const_str___lower__;
extern const bcstring be_const_str_exp;
extern const bcstring be_const_str_hex;
extern const bcstring be_const_str_char;
extern const bcstring be_const_str_split;
extern const bcstring be_const_str_toupper;
extern const bcstring be_const_str_deinit;
extern const bcstring be_const_str_tan;
extern const bcstring be_const_str_srand;
extern const bcstring be_const_str_imin;
extern const bcstring be_const_str_input;
extern const bcstring be_const_str_issubclass;
extern const bcstring be_const_str_tostring;
extern const bcstring be_const_str_break;
extern const bcstring be_const_str_insert;
extern const bcstring be_const_str_var;
extern const bcstring be_const_str_open;
extern const bcstring be_const_str_tanh;
extern const bcstring be_const_str_upper;
extern const bcstring be_const_str_allocated;
extern const bcstring be_const_str_rad;
extern const bcstring be_const_str_attrdump;
extern const bcstring be_const_str_copy;
extern const bcstring be_const_str_sqrt;
extern const bcstring be_const_str_for;
extern const bcstring be_const_str_raise;
extern const bcstring be_const_str_opt_neq;
extern const bcstring be_const_str_assert;
extern const bcstring be_const_str_item;
extern const bcstring be_const_str_reverse;
extern const bcstring be_const_str_sin;
extern const bcstring be_const_str_super;
extern const bcstring be_const_str_try;
extern const bcstring be_const_str_range;
extern const bcstring be_const_str_return;
extern const bcstring be_const_str_compile;
extern const bcstring be_const_str_false;
extern const bcstring be_const_str_resize;
extern const bcstring be_const_str_continue;
extern const bcstring be_const_str_log;
extern const bcstring be_const_str_true;
extern const bcstring be_const_str_while;
extern const bcstring be_const_str_pow;
extern const bcstring be_const_str_cos;
extern const bcstring be_const_str_count;
extern const bcstring be_const_str_remove;
extern const bcstring be_const_str_imax;
extern const bcstring be_const_str_rand;
extern const bcstring be_const_str_codedump;
extern const bcstring be_const_str_deg;
extern const bcstring be_const_str_keys;
extern const bcstring be_const_str_setitem;
extern const bcstring be_const_str_def;
extern const bcstring be_const_str_except;
extern const bcstring be_const_str_classname;
extern const bcstring be_const_str_isinstance;
extern const bcstring be_const_str_cosh;

View File

@ -1,190 +1,165 @@
be_define_const_str(calldepth, "calldepth", 3122364302u, 0, 9, &be_const_str_clock);
be_define_const_str(clock, "clock", 363073373u, 0, 5, &be_const_str_size);
be_define_const_str(size, "size", 597743964u, 0, 4, &be_const_str_system);
be_define_const_str(system, "system", 1226705564u, 0, 6, &be_const_str_type);
be_define_const_str(type, "type", 1361572173u, 0, 4, &be_const_str_if);
be_define_const_str(if, "if", 959999494u, 50, 2, NULL);
be_define_const_str(int, "int", 2515107422u, 0, 3, &be_const_str_isfile);
be_define_const_str(isfile, "isfile", 3131505107u, 0, 6, &be_const_str_log);
be_define_const_str(log, "log", 1062293841u, 0, 3, &be_const_str_raise);
be_define_const_str(raise, "raise", 1593437475u, 70, 5, NULL);
be_define_const_str(concat, "concat", 4124019837u, 0, 6, &be_const_str_list);
be_define_const_str(list, "list", 217798785u, 0, 4, &be_const_str_map);
be_define_const_str(map, "map", 3751997361u, 0, 3, &be_const_str_for);
be_define_const_str(for, "for", 2901640080u, 54, 3, NULL);
be_define_const_str(dot_p, ".p", 1171526419u, 0, 2, &be_const_str_isdir);
be_define_const_str(isdir, "isdir", 2340917412u, 0, 5, &be_const_str_mkdir);
be_define_const_str(mkdir, "mkdir", 2883839448u, 0, 5, &be_const_str_remove);
be_define_const_str(remove, "remove", 3683784189u, 0, 6, NULL);
be_define_const_str(cosh, "cosh", 4099687964u, 0, 4, NULL);
be_define_const_str(abs, "abs", 709362235u, 0, 3, &be_const_str_reverse);
be_define_const_str(reverse, "reverse", 558918661u, 0, 7, &be_const_str_sinh);
be_define_const_str(sinh, "sinh", 282220607u, 0, 4, NULL);
be_define_const_str(hex, "hex", 4273249610u, 0, 3, NULL);
be_define_const_str(tostring, "tostring", 2299708645u, 0, 8, NULL);
be_define_const_str(opt_add, "+", 772578730u, 0, 1, &be_const_str_atan);
be_define_const_str(atan, "atan", 108579519u, 0, 4, &be_const_str_real);
be_define_const_str(real, "real", 3604983901u, 0, 4, NULL);
be_define_const_str(iter, "iter", 3124256359u, 0, 4, &be_const_str_top);
be_define_const_str(top, "top", 2802900028u, 0, 3, &be_const_str_except);
be_define_const_str(except, "except", 950914032u, 69, 6, NULL);
be_define_const_str(getcwd, "getcwd", 652026575u, 0, 6, &be_const_str_listdir);
be_define_const_str(listdir, "listdir", 2005220720u, 0, 7, &be_const_str_log10);
be_define_const_str(log10, "log10", 2346846000u, 0, 5, NULL);
be_define_const_str(allocated, "allocated", 429986098u, 0, 9, &be_const_str_init);
be_define_const_str(init, "init", 380752755u, 0, 4, &be_const_str_module);
be_define_const_str(module, "module", 3617558685u, 0, 6, NULL);
be_define_const_str(ceil, "ceil", 1659167240u, 0, 4, &be_const_str_clear);
be_define_const_str(clear, "clear", 1550717474u, 0, 5, &be_const_str_collect);
be_define_const_str(collect, "collect", 2399039025u, 0, 7, &be_const_str_find);
be_define_const_str(find, "find", 3186656602u, 0, 4, &be_const_str_item);
be_define_const_str(item, "item", 2671260646u, 0, 4, NULL);
be_define_const_str(format, "format", 3114108242u, 0, 6, &be_const_str_sqrt);
be_define_const_str(sqrt, "sqrt", 2112764879u, 0, 4, NULL);
be_define_const_str(classname, "classname", 1998589948u, 0, 9, NULL);
be_define_const_str(byte, "byte", 1683620383u, 0, 4, NULL);
be_define_const_str(else, "else", 3183434736u, 52, 4, NULL);
be_define_const_str(deinit, "deinit", 2345559592u, 0, 6, &be_const_str_end);
be_define_const_str(end, "end", 1787721130u, 56, 3, &be_const_str_true);
be_define_const_str(true, "true", 1303515621u, 61, 4, NULL);
be_define_const_str(__upper__, "__upper__", 3612202883u, 0, 9, NULL);
be_define_const_str(char, "char", 2823553821u, 0, 4, &be_const_str_load);
be_define_const_str(load, "load", 3859241449u, 0, 4, &be_const_str_resize);
be_define_const_str(resize, "resize", 3514612129u, 0, 6, &be_const_str_sethook);
be_define_const_str(sethook, "sethook", 3963967276u, 0, 7, &be_const_str_varname);
be_define_const_str(varname, "varname", 2273276445u, 0, 7, NULL);
be_define_const_str(deg, "deg", 3327754271u, 0, 3, &be_const_str_srand);
be_define_const_str(srand, "srand", 465518633u, 0, 5, &be_const_str_str);
be_define_const_str(str, "str", 3259748752u, 0, 3, NULL);
be_define_const_str(range, "range", 4208725202u, 0, 5, &be_const_str_toupper);
be_define_const_str(toupper, "toupper", 3691983576u, 0, 7, NULL);
be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str_copy);
be_define_const_str(copy, "copy", 3848464964u, 0, 4, &be_const_str_exp);
be_define_const_str(exp, "exp", 1923516200u, 0, 3, &be_const_str_time);
be_define_const_str(time, "time", 1564253156u, 0, 4, &be_const_str_break);
be_define_const_str(break, "break", 3378807160u, 58, 5, NULL);
be_define_const_str(opt_neq, "!=", 2428715011u, 0, 2, &be_const_str_assert);
be_define_const_str(assert, "assert", 2774883451u, 0, 6, &be_const_str_attrdump);
be_define_const_str(attrdump, "attrdump", 1521571304u, 0, 8, &be_const_str_chdir);
be_define_const_str(chdir, "chdir", 806634853u, 0, 5, &be_const_str_isinstance);
be_define_const_str(isinstance, "isinstance", 3669352738u, 0, 10, &be_const_str_continue);
be_define_const_str(continue, "continue", 2977070660u, 59, 8, &be_const_str_do);
be_define_const_str(do, "do", 1646057492u, 65, 2, NULL);
be_define_const_str(lower, "lower", 3038577850u, 0, 5, &be_const_str_pow);
be_define_const_str(pow, "pow", 1479764693u, 0, 3, &be_const_str_false);
be_define_const_str(false, "false", 184981848u, 62, 5, NULL);
be_define_const_str(count, "count", 967958004u, 0, 5, NULL);
be_define_const_str(exit, "exit", 3454868101u, 0, 4, &be_const_str_print);
be_define_const_str(print, "print", 372738696u, 0, 5, &be_const_str_def);
be_define_const_str(def, "def", 3310976652u, 55, 3, NULL);
be_define_const_str(pop, "pop", 1362321360u, 0, 3, &be_const_str_tolower);
be_define_const_str(tolower, "tolower", 1042520049u, 0, 7, NULL);
be_define_const_str(classof, "classof", 1796577762u, 0, 7, &be_const_str_cos);
be_define_const_str(cos, "cos", 4220379804u, 0, 3, &be_const_str_dump);
be_define_const_str(dump, "dump", 3663001223u, 0, 4, &be_const_str_join);
be_define_const_str(join, "join", 3374496889u, 0, 4, &be_const_str_push);
be_define_const_str(push, "push", 2272264157u, 0, 4, &be_const_str_sin);
be_define_const_str(sin, "sin", 3761252941u, 0, 3, &be_const_str_return);
be_define_const_str(return, "return", 2246981567u, 60, 6, NULL);
be_define_const_str(path, "path", 2223459638u, 0, 4, &be_const_str_rand);
be_define_const_str(rand, "rand", 2711325910u, 0, 4, &be_const_str_class);
be_define_const_str(class, "class", 2872970239u, 57, 5, &be_const_str_nil);
be_define_const_str(nil, "nil", 228849900u, 63, 3, NULL);
be_define_const_str(input, "input", 4191711099u, 0, 5, NULL);
be_define_const_str(floor, "floor", 3102149661u, 0, 5, &be_const_str_keys);
be_define_const_str(keys, "keys", 4182378701u, 0, 4, &be_const_str_number);
be_define_const_str(number, "number", 467038368u, 0, 6, &be_const_str_rad);
be_define_const_str(rad, "rad", 1358899048u, 0, 3, NULL);
be_define_const_str(imin, "imin", 2714127864u, 0, 4, &be_const_str_pi);
be_define_const_str(pi, "pi", 1213090802u, 0, 2, NULL);
be_define_const_str(splitext, "splitext", 2150391934u, 0, 8, NULL);
be_define_const_str(compile, "compile", 1000265118u, 0, 7, &be_const_str_setrange);
be_define_const_str(setrange, "setrange", 3794019032u, 0, 8, &be_const_str_traceback);
be_define_const_str(traceback, "traceback", 3385188109u, 0, 9, &be_const_str_upper);
be_define_const_str(upper, "upper", 176974407u, 0, 5, &be_const_str_var);
be_define_const_str(var, "var", 2317739966u, 64, 3, NULL);
be_define_const_str(opt_eq, "==", 2431966415u, 0, 2, NULL);
be_define_const_str(codedump, "codedump", 1786337906u, 0, 8, &be_const_str_tan);
be_define_const_str(tan, "tan", 2633446552u, 0, 3, NULL);
be_define_const_str(setitem, "setitem", 1554834596u, 0, 7, NULL);
be_define_const_str(tanh, "tanh", 153638352u, 0, 4, &be_const_str_as);
be_define_const_str(as, "as", 1579491469u, 67, 2, NULL);
be_define_const_str(issubclass, "issubclass", 4078395519u, 0, 10, &be_const_str_upvname);
be_define_const_str(upvname, "upvname", 3848760617u, 0, 7, NULL);
be_define_const_str(opt_connect, "..", 2748622605u, 0, 2, NULL);
be_define_const_str(try, "try", 2887626766u, 68, 3, &be_const_str_while);
be_define_const_str(while, "while", 231090382u, 53, 5, NULL);
be_define_const_str(import, "import", 288002260u, 66, 6, NULL);
be_define_const_str(__lower__, "__lower__", 123855590u, 0, 9, &be_const_str_open);
be_define_const_str(open, "open", 3546203337u, 0, 4, NULL);
be_define_const_str(acos, "acos", 1006755615u, 0, 4, &be_const_str_asin);
be_define_const_str(asin, "asin", 4272848550u, 0, 4, &be_const_str_imax);
be_define_const_str(imax, "imax", 3084515410u, 0, 4, &be_const_str_insert);
be_define_const_str(insert, "insert", 3332609576u, 0, 6, &be_const_str_split);
be_define_const_str(split, "split", 2276994531u, 0, 5, NULL);
be_define_const_str(__iterator__, "__iterator__", 3884039703u, 0, 12, &be_const_str_exists);
be_define_const_str(exists, "exists", 1002329533u, 0, 6, &be_const_str_super);
be_define_const_str(super, "super", 4152230356u, 0, 5, &be_const_str_elif);
be_define_const_str(asin, "asin", 4272848550u, 0, 4, &be_const_str_list);
be_define_const_str(list, "list", 217798785u, 0, 4, &be_const_str_module);
be_define_const_str(module, "module", 3617558685u, 0, 6, &be_const_str_pop);
be_define_const_str(pop, "pop", 1362321360u, 0, 3, NULL);
be_define_const_str(int, "int", 2515107422u, 0, 3, &be_const_str_push);
be_define_const_str(push, "push", 2272264157u, 0, 4, &be_const_str_setrange);
be_define_const_str(setrange, "setrange", 3794019032u, 0, 8, &be_const_str_sinh);
be_define_const_str(sinh, "sinh", 282220607u, 0, 4, &be_const_str_elif);
be_define_const_str(elif, "elif", 3232090307u, 51, 4, NULL);
be_define_const_str(iter, "iter", 3124256359u, 0, 4, &be_const_str_load);
be_define_const_str(load, "load", 3859241449u, 0, 4, &be_const_str_class);
be_define_const_str(class, "class", 2872970239u, 57, 5, &be_const_str_if);
be_define_const_str(if, "if", 959999494u, 50, 2, NULL);
be_define_const_str(opt_eq, "==", 2431966415u, 0, 2, &be_const_str_ceil);
be_define_const_str(ceil, "ceil", 1659167240u, 0, 4, NULL);
be_define_const_str(floor, "floor", 3102149661u, 0, 5, &be_const_str_map);
be_define_const_str(map, "map", 3751997361u, 0, 3, &be_const_str_print);
be_define_const_str(print, "print", 372738696u, 0, 5, &be_const_str_else);
be_define_const_str(else, "else", 3183434736u, 52, 4, NULL);
be_define_const_str(find, "find", 3186656602u, 0, 4, &be_const_str_str);
be_define_const_str(str, "str", 3259748752u, 0, 3, NULL);
be_define_const_str(__upper__, "__upper__", 3612202883u, 0, 9, &be_const_str_dump);
be_define_const_str(dump, "dump", 3663001223u, 0, 4, NULL);
be_define_const_str(atan, "atan", 108579519u, 0, 4, &be_const_str_size);
be_define_const_str(size, "size", 597743964u, 0, 4, &be_const_str_tolower);
be_define_const_str(tolower, "tolower", 1042520049u, 0, 7, NULL);
be_define_const_str(opt_add, "+", 772578730u, 0, 1, &be_const_str_abs);
be_define_const_str(abs, "abs", 709362235u, 0, 3, &be_const_str_lower);
be_define_const_str(lower, "lower", 3038577850u, 0, 5, &be_const_str_end);
be_define_const_str(end, "end", 1787721130u, 56, 3, &be_const_str_import);
be_define_const_str(import, "import", 288002260u, 66, 6, NULL);
be_define_const_str(classof, "classof", 1796577762u, 0, 7, &be_const_str_concat);
be_define_const_str(concat, "concat", 4124019837u, 0, 6, NULL);
be_define_const_str(byte, "byte", 1683620383u, 0, 4, &be_const_str_top);
be_define_const_str(top, "top", 2802900028u, 0, 3, NULL);
be_define_const_str(clear, "clear", 1550717474u, 0, 5, NULL);
be_define_const_str(opt_connect, "..", 2748622605u, 0, 2, &be_const_str_collect);
be_define_const_str(collect, "collect", 2399039025u, 0, 7, &be_const_str_init);
be_define_const_str(init, "init", 380752755u, 0, 4, &be_const_str_log10);
be_define_const_str(log10, "log10", 2346846000u, 0, 5, &be_const_str_nil);
be_define_const_str(nil, "nil", 228849900u, 63, 3, NULL);
be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str_real);
be_define_const_str(real, "real", 3604983901u, 0, 4, NULL);
be_define_const_str(calldepth, "calldepth", 3122364302u, 0, 9, &be_const_str_format);
be_define_const_str(format, "format", 3114108242u, 0, 6, &be_const_str_pi);
be_define_const_str(pi, "pi", 1213090802u, 0, 2, &be_const_str_do);
be_define_const_str(do, "do", 1646057492u, 65, 2, NULL);
be_define_const_str(__iterator__, "__iterator__", 3884039703u, 0, 12, &be_const_str_number);
be_define_const_str(number, "number", 467038368u, 0, 6, &be_const_str_type);
be_define_const_str(type, "type", 1361572173u, 0, 4, NULL);
be_define_const_str(dot_p, ".p", 1171526419u, 0, 2, &be_const_str_traceback);
be_define_const_str(traceback, "traceback", 3385188109u, 0, 9, &be_const_str_as);
be_define_const_str(as, "as", 1579491469u, 67, 2, NULL);
be_define_const_str(__lower__, "__lower__", 123855590u, 0, 9, &be_const_str_exp);
be_define_const_str(exp, "exp", 1923516200u, 0, 3, &be_const_str_hex);
be_define_const_str(hex, "hex", 4273249610u, 0, 3, NULL);
be_define_const_str(char, "char", 2823553821u, 0, 4, &be_const_str_split);
be_define_const_str(split, "split", 2276994531u, 0, 5, &be_const_str_toupper);
be_define_const_str(toupper, "toupper", 3691983576u, 0, 7, NULL);
be_define_const_str(deinit, "deinit", 2345559592u, 0, 6, &be_const_str_tan);
be_define_const_str(tan, "tan", 2633446552u, 0, 3, NULL);
be_define_const_str(srand, "srand", 465518633u, 0, 5, NULL);
be_define_const_str(imin, "imin", 2714127864u, 0, 4, &be_const_str_input);
be_define_const_str(input, "input", 4191711099u, 0, 5, &be_const_str_issubclass);
be_define_const_str(issubclass, "issubclass", 4078395519u, 0, 10, NULL);
be_define_const_str(tostring, "tostring", 2299708645u, 0, 8, &be_const_str_break);
be_define_const_str(break, "break", 3378807160u, 58, 5, NULL);
be_define_const_str(insert, "insert", 3332609576u, 0, 6, &be_const_str_var);
be_define_const_str(var, "var", 2317739966u, 64, 3, NULL);
be_define_const_str(open, "open", 3546203337u, 0, 4, &be_const_str_tanh);
be_define_const_str(tanh, "tanh", 153638352u, 0, 4, &be_const_str_upper);
be_define_const_str(upper, "upper", 176974407u, 0, 5, NULL);
be_define_const_str(allocated, "allocated", 429986098u, 0, 9, &be_const_str_rad);
be_define_const_str(rad, "rad", 1358899048u, 0, 3, NULL);
be_define_const_str(attrdump, "attrdump", 1521571304u, 0, 8, &be_const_str_copy);
be_define_const_str(copy, "copy", 3848464964u, 0, 4, &be_const_str_sqrt);
be_define_const_str(sqrt, "sqrt", 2112764879u, 0, 4, NULL);
be_define_const_str(for, "for", 2901640080u, 54, 3, &be_const_str_raise);
be_define_const_str(raise, "raise", 1593437475u, 70, 5, NULL);
be_define_const_str(opt_neq, "!=", 2428715011u, 0, 2, &be_const_str_assert);
be_define_const_str(assert, "assert", 2774883451u, 0, 6, &be_const_str_item);
be_define_const_str(item, "item", 2671260646u, 0, 4, &be_const_str_reverse);
be_define_const_str(reverse, "reverse", 558918661u, 0, 7, &be_const_str_sin);
be_define_const_str(sin, "sin", 3761252941u, 0, 3, &be_const_str_super);
be_define_const_str(super, "super", 4152230356u, 0, 5, &be_const_str_try);
be_define_const_str(try, "try", 2887626766u, 68, 3, NULL);
be_define_const_str(range, "range", 4208725202u, 0, 5, &be_const_str_return);
be_define_const_str(return, "return", 2246981567u, 60, 6, NULL);
be_define_const_str(compile, "compile", 1000265118u, 0, 7, &be_const_str_false);
be_define_const_str(false, "false", 184981848u, 62, 5, NULL);
be_define_const_str(resize, "resize", 3514612129u, 0, 6, NULL);
be_define_const_str(continue, "continue", 2977070660u, 59, 8, NULL);
be_define_const_str(log, "log", 1062293841u, 0, 3, &be_const_str_true);
be_define_const_str(true, "true", 1303515621u, 61, 4, NULL);
be_define_const_str(while, "while", 231090382u, 53, 5, NULL);
be_define_const_str(pow, "pow", 1479764693u, 0, 3, NULL);
be_define_const_str(cos, "cos", 4220379804u, 0, 3, &be_const_str_count);
be_define_const_str(count, "count", 967958004u, 0, 5, &be_const_str_remove);
be_define_const_str(remove, "remove", 3683784189u, 0, 6, NULL);
be_define_const_str(imax, "imax", 3084515410u, 0, 4, &be_const_str_rand);
be_define_const_str(rand, "rand", 2711325910u, 0, 4, NULL);
be_define_const_str(codedump, "codedump", 1786337906u, 0, 8, &be_const_str_deg);
be_define_const_str(deg, "deg", 3327754271u, 0, 3, &be_const_str_keys);
be_define_const_str(keys, "keys", 4182378701u, 0, 4, &be_const_str_setitem);
be_define_const_str(setitem, "setitem", 1554834596u, 0, 7, NULL);
be_define_const_str(def, "def", 3310976652u, 55, 3, &be_const_str_except);
be_define_const_str(except, "except", 950914032u, 69, 6, NULL);
be_define_const_str(classname, "classname", 1998589948u, 0, 9, &be_const_str_isinstance);
be_define_const_str(isinstance, "isinstance", 3669352738u, 0, 10, NULL);
be_define_const_str(cosh, "cosh", 4099687964u, 0, 4, NULL);
static const bstring* const m_string_table[] = {
(const bstring *)&be_const_str_calldepth,
(const bstring *)&be_const_str_int,
(const bstring *)&be_const_str_concat,
(const bstring *)&be_const_str_dot_p,
NULL,
(const bstring *)&be_const_str_cosh,
(const bstring *)&be_const_str_abs,
(const bstring *)&be_const_str_hex,
(const bstring *)&be_const_str_tostring,
(const bstring *)&be_const_str_opt_add,
(const bstring *)&be_const_str_iter,
(const bstring *)&be_const_str_getcwd,
NULL,
(const bstring *)&be_const_str_allocated,
(const bstring *)&be_const_str_ceil,
(const bstring *)&be_const_str_format,
(const bstring *)&be_const_str_classname,
(const bstring *)&be_const_str_byte,
(const bstring *)&be_const_str_else,
(const bstring *)&be_const_str_deinit,
(const bstring *)&be_const_str___upper__,
(const bstring *)&be_const_str_char,
NULL,
(const bstring *)&be_const_str_deg,
NULL,
(const bstring *)&be_const_str_range,
(const bstring *)&be_const_str_,
NULL,
(const bstring *)&be_const_str_opt_neq,
(const bstring *)&be_const_str_lower,
(const bstring *)&be_const_str_count,
(const bstring *)&be_const_str_exit,
(const bstring *)&be_const_str_pop,
(const bstring *)&be_const_str_classof,
(const bstring *)&be_const_str_path,
(const bstring *)&be_const_str_input,
(const bstring *)&be_const_str_floor,
(const bstring *)&be_const_str_imin,
(const bstring *)&be_const_str_splitext,
NULL,
(const bstring *)&be_const_str_compile,
(const bstring *)&be_const_str_opt_eq,
(const bstring *)&be_const_str_codedump,
(const bstring *)&be_const_str_setitem,
(const bstring *)&be_const_str_tanh,
(const bstring *)&be_const_str_issubclass,
(const bstring *)&be_const_str_opt_connect,
(const bstring *)&be_const_str_try,
(const bstring *)&be_const_str_import,
(const bstring *)&be_const_str___lower__,
NULL,
(const bstring *)&be_const_str_acos,
(const bstring *)&be_const_str___iterator__
NULL,
(const bstring *)&be_const_str_int,
NULL,
(const bstring *)&be_const_str_iter,
(const bstring *)&be_const_str_opt_eq,
(const bstring *)&be_const_str_floor,
(const bstring *)&be_const_str_find,
(const bstring *)&be_const_str___upper__,
(const bstring *)&be_const_str_atan,
(const bstring *)&be_const_str_opt_add,
NULL,
(const bstring *)&be_const_str_classof,
(const bstring *)&be_const_str_byte,
(const bstring *)&be_const_str_clear,
(const bstring *)&be_const_str_opt_connect,
(const bstring *)&be_const_str_,
(const bstring *)&be_const_str_calldepth,
(const bstring *)&be_const_str___iterator__,
(const bstring *)&be_const_str_dot_p,
(const bstring *)&be_const_str___lower__,
(const bstring *)&be_const_str_char,
(const bstring *)&be_const_str_deinit,
(const bstring *)&be_const_str_srand,
(const bstring *)&be_const_str_imin,
(const bstring *)&be_const_str_tostring,
(const bstring *)&be_const_str_insert,
(const bstring *)&be_const_str_open,
(const bstring *)&be_const_str_allocated,
(const bstring *)&be_const_str_attrdump,
(const bstring *)&be_const_str_for,
(const bstring *)&be_const_str_opt_neq,
(const bstring *)&be_const_str_range,
(const bstring *)&be_const_str_compile,
(const bstring *)&be_const_str_resize,
(const bstring *)&be_const_str_continue,
(const bstring *)&be_const_str_log,
(const bstring *)&be_const_str_while,
(const bstring *)&be_const_str_pow,
(const bstring *)&be_const_str_cos,
(const bstring *)&be_const_str_imax,
(const bstring *)&be_const_str_codedump,
(const bstring *)&be_const_str_def,
(const bstring *)&be_const_str_classname,
(const bstring *)&be_const_str_cosh
};
static const struct bconststrtab m_const_string_table = {
.size = 53,
.count = 107,
.size = 45,
.count = 90,
.table = m_string_table
};

View File

@ -1,19 +1,16 @@
#include "be_constobj.h"
static be_define_const_map_slots(m_libdebug_map) {
{ be_const_key(attrdump, -1), be_const_func(m_attrdump) },
{ be_const_key(upvname, -1), be_const_func(m_upvname) },
{ be_const_key(codedump, -1), be_const_func(m_codedump) },
{ be_const_key(top, -1), be_const_func(m_top) },
{ be_const_key(sethook, 3), be_const_func(m_sethook) },
{ be_const_key(varname, 7), be_const_func(m_varname) },
{ be_const_key(calldepth, -1), be_const_func(m_calldepth) },
{ be_const_key(traceback, -1), be_const_func(m_traceback) },
{ be_const_key(codedump, -1), be_const_func(m_codedump) },
{ be_const_key(calldepth, -1), be_const_func(m_calldepth) },
{ be_const_key(top, -1), be_const_func(m_top) },
{ be_const_key(attrdump, 0), be_const_func(m_attrdump) },
};
static be_define_const_map(
m_libdebug_map,
8
5
);
static be_define_const_module(

View File

@ -1,24 +1,2 @@
#include "be_constobj.h"
static be_define_const_map_slots(m_libos_map) {
{ be_const_key(listdir, 1), be_const_func(m_listdir) },
{ be_const_key(mkdir, -1), be_const_func(m_mkdir) },
{ be_const_key(chdir, -1), be_const_func(m_chdir) },
{ be_const_key(exit, 2), be_const_func(m_exit) },
{ be_const_key(system, -1), be_const_func(m_system) },
{ be_const_key(remove, 3), be_const_func(m_remove) },
{ be_const_key(path, -1), be_const_module(m_libpath) },
{ be_const_key(getcwd, -1), be_const_func(m_getcwd) },
};
static be_define_const_map(
m_libos_map,
8
);
static be_define_const_module(
m_libos,
"os"
);
BE_EXPORT_VARIABLE be_define_const_native_module(os, NULL);

View File

@ -0,0 +1,2 @@
#include "be_constobj.h"

View File

@ -1,17 +1,2 @@
#include "be_constobj.h"
static be_define_const_map_slots(m_libsys_map) {
{ be_const_key(path, -1), be_const_func(m_path) },
};
static be_define_const_map(
m_libsys_map,
1
);
static be_define_const_module(
m_libsys,
"sys"
);
BE_EXPORT_VARIABLE be_define_const_native_module(sys, NULL);

View File

@ -1,19 +1,2 @@
#include "be_constobj.h"
static be_define_const_map_slots(m_libtime_map) {
{ be_const_key(dump, 1), be_const_func(m_dump) },
{ be_const_key(clock, -1), be_const_func(m_clock) },
{ be_const_key(time, 0), be_const_func(m_time) },
};
static be_define_const_map(
m_libtime_map,
3
);
static be_define_const_module(
m_libtime,
"time"
);
BE_EXPORT_VARIABLE be_define_const_native_module(time, NULL);

View File

@ -310,7 +310,7 @@ static void free_ntvclos(bvm *vm, bgcobject *obj)
while (count--) {
be_free(vm, *uv++, sizeof(bupval));
}
be_free(vm, f, sizeof(bntvclos));
be_free(vm, f, sizeof(bntvclos) + sizeof(bupval*) * f->nupvals);
}
}

View File

@ -13,7 +13,7 @@
#define BE_GCOBJECT BE_STRING
#define gc_object(o) cast(bgcobject*, o)
#define gc_cast(o, t, T) ((o) && pgm_read_byte(&(o)->type) == (t) ? (T*)(o) : NULL)
#define gc_cast(o, t, T) ((o) && (o)->type == (t) ? (T*)(o) : NULL)
#define cast_proto(o) gc_cast(o, BE_PROTO, bproto)
#define cast_closure(o) gc_cast(o, BE_CLOSURE, bclosure)
#define cast_ntvclos(o) gc_cast(o, BE_NTVCLOS, bntvclos)
@ -38,11 +38,11 @@ if (!gc_isconst(o)) { \
#define gc_setwhite(o) gc_setmark((o), GC_WHITE)
#define gc_setgray(o) gc_setmark((o), GC_GRAY)
#define gc_setdark(o) gc_setmark((o), GC_DARK)
#define gc_isfixed(o) ((pgm_read_byte(&(o)->marked) & GC_FIXED) != 0)
#define gc_isfixed(o) (((o)->marked & GC_FIXED) != 0)
#define gc_setfixed(o) ((o)->marked |= GC_FIXED)
#define gc_clearfixed(o) ((o)->marked &= ~GC_FIXED)
#define gc_isconst(o) ((pgm_read_byte(&(o)->marked) & GC_CONST) != 0)
#define gc_exmark(o) ((pgm_read_byte(&(o)->marked) >> 4) & 0x0F)
#define gc_isconst(o) (((o)->marked & GC_CONST) != 0)
#define gc_exmark(o) (((o)->marked >> 4) & 0x0F)
#define gc_setexmark(o, k) ((o)->marked |= (k) << 4)
#define be_isgctype(t) ((t) >= BE_GCOBJECT)

View File

@ -105,8 +105,7 @@ static int next(blexer *lexer)
lr->s = s ? s : &eos;
--lr->len;
}
// lexer->cursor = *lr->s++; // SH
lexer->cursor = pgm_read_byte(lr->s++);
lexer->cursor = *lr->s++;
return lexer->cursor;
}

View File

@ -10,37 +10,6 @@
#include "berry.h"
/* support for PROGMEM on ESP8266 and AVR */
#ifdef _PGMSPACE_H_
#define strncmp strncmp_PP
#define strcmp(str1P, str2P) strncmp_PP((str1P), (str2P), SIZE_IRRELEVANT)
#define strncasecmp strncasecmp_P
#define strcasecmp_P(str1, str2P) strncasecmp_P((str1), (str2P), SIZE_IRRELEVANT)
#define strlen strlen_P
#define strchr strchr_P
#define strcat strcat_P
#define strncat strncat_P
#define strcpy strcpy_P
#define strncpy strncpy_P
#define memcpy memcpy_P
#define memccpy memccpy_P
#define memmove memmove_P
#define memcmp memcmp_P
#define memmem memmem_P
#define memchr memchr_P
#define sprintf sprintf_P
#define snprintf snprintf_P
#endif
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const uint8_t*)(addr))
#endif
#ifndef pgm_read_word
#define pgm_read_word(addr) (*(const uint16_t*)(addr))
#endif
/* basic types, do not change value */
#define BE_NONE (-1) /* unknow type */
#define BE_COMPTR (-2) /* common pointer */

View File

@ -31,7 +31,7 @@
#define FUNC_ANONYMOUS 2
/* get binary operator priority */
#define binary_op_prio(op) (pgm_read_byte(&binary_op_prio_tab[cast_int(op) - OptAdd]))
#define binary_op_prio(op) (binary_op_prio_tab[cast_int(op) - OptAdd])
#define scan_next_token(parser) (be_lexer_scan_next(&(parser)->lexer))
#define next_token(parser) ((parser)->lexer.token)

View File

@ -44,9 +44,9 @@ int be_eqstr(bstring *s1, bstring *s2)
if (s1 == s2) { /* short string or the same string */
return 1;
}
slen = pgm_read_byte(&s1->slen);
slen = s1->slen;
/* long string */
if (slen == 255 && slen == pgm_read_byte(&s2->slen)) {
if (slen == 255 && slen == s2->slen) {
blstring *ls1 = cast(blstring*, s1);
blstring *ls2 = cast(blstring*, s2);
return ls1->llen == ls2->llen && !strcmp(lstr(ls1), lstr(ls2));
@ -88,7 +88,7 @@ static void resize(bvm *vm, int size)
static void free_sstring(bvm *vm, bstring *str)
{
be_free(vm, str, sizeof(bsstring) + pgm_read_byte(&str->slen) + 1);
be_free(vm, str, sizeof(bsstring) + str->slen + 1);
}
/* FNV-1a Hash */
@ -97,8 +97,7 @@ static uint32_t str_hash(const char *str, size_t len)
uint32_t hash = 2166136261u;
be_assert(str || len);
while (len--) {
hash = (hash ^ (unsigned char)pgm_read_byte(str)) * 16777619u;
str++;
hash = (hash ^ (unsigned char)*str++) * 16777619u;
}
return hash;
}
@ -150,7 +149,7 @@ static bstring* find_conststr(const char *str, size_t len)
uint32_t hash = str_hash(str, len);
bcstring *s = (bcstring*)tab->table[hash % tab->size];
for (; s != NULL; s = next(s)) {
if (len == pgm_read_byte(&s->slen) && !strncmp(str, s->s, len)) {
if (len == s->slen && !strncmp(str, s->s, len)) {
return (bstring*)s;
}
}
@ -166,7 +165,7 @@ static bstring* newshortstr(bvm *vm, const char *str, size_t len)
bstring **list = vm->strtab.table + (hash & (size - 1));
for (s = *list; s != NULL; s = next(s)) {
if (len == pgm_read_byte(&s->slen) && !strncmp(str, sstr(s), len)) {
if (len == s->slen && !strncmp(str, sstr(s), len)) {
return s;
}
}
@ -253,7 +252,7 @@ uint32_t be_strhash(const bstring *s)
return cast(bcstring*, s)->hash;
}
#if BE_USE_STR_HASH_CACHE
if (pgm_read_byte(&s->slen) != 255) {
if (s->slen != 255) {
return cast(bsstring*, s)->hash;
}
#endif
@ -266,7 +265,7 @@ const char* be_str2cstr(const bstring *s)
if (gc_isconst(s)) {
return cstr(s);
}
if (pgm_read_byte(&s->slen) == 255) {
if (s->slen == 255) {
return lstr(s);
}
return sstr(s);
@ -277,4 +276,4 @@ void be_str_setextra(bstring *s, int extra)
if (!gc_isconst(s)) {
s->extra = cast(bbyte, extra);
}
}
}

View File

@ -33,7 +33,7 @@ typedef struct {
} bcstring;
#define str_len(_s) \
(pgm_read_byte(&(_s)->slen) == 255 ? cast(blstring*, _s)->llen : pgm_read_byte(&(_s)->slen))
((_s)->slen == 255 ? cast(blstring*, _s)->llen : (_s)->slen)
#define str(_s) be_str2cstr(_s)
#define str_extra(_s) ((_s)->extra)

View File

@ -176,7 +176,7 @@ const char* be_pushvfstr(bvm *vm, const char *format, va_list arg)
}
pushstr(vm, format, p - format);
concat2(vm);
switch (pgm_read_byte(&p[1])) {
switch (p[1]) {
case 's': {
const char *s = va_arg(arg, char*);
if (s == NULL) {
@ -339,8 +339,8 @@ bstring* be_strindex(bvm *vm, bstring *str, bvalue *idx)
const char* be_splitpath(const char *path)
{
const char *p;
for (p = path - 1; pgm_read_byte(path) != '\0'; ++path) {
if (pgm_read_byte(path) == '/') {
for (p = path - 1; *path != '\0'; ++path) {
if (*path == '/') {
p = path;
}
}

View File

@ -122,16 +122,16 @@ static int binary_search(int value)
const uint16_t *high = tab + array_count(tab) - 1;
while (low <= high) {
const uint16_t *mid = low + ((high - low) >> 1);
if (pgm_read_word(mid) == value) {
return pgm_read_word(&mid[1]);
if (*mid == value) {
return mid[1];
}
if (pgm_read_word(mid) < value) {
if (*mid < value) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return pgm_read_word(low);
return *low;
}
static int nextpow(int value)

View File

@ -20,7 +20,8 @@ be_extern_native_module(debug);
be_extern_native_module(gc);
/* Tasmota specific */
be_extern_native_module(tasmota);
be_extern_native_module(tasmota_ntv);
be_extern_native_module(wire);
/* user-defined modules declare start */
@ -55,7 +56,8 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = {
#endif
/* user-defined modules register start */
&be_native_module(tasmota),
&be_native_module(tasmota_ntv),
&be_native_module(wire),
/* user-defined modules register end */
NULL /* do not remove */

View File

@ -13,9 +13,16 @@ extern int l_millis(bvm *vm);
extern int l_timereached(bvm *vm);
extern int l_yield(bvm *vm);
extern int l_respCmnd(bvm *vm);
extern int l_respCmndStr(bvm *vm);
extern int l_respCmndDone(bvm *vm);
extern int l_respCmndError(bvm *vm);
extern int l_respCmndFailed(bvm *vm);
// #if !BE_USE_PRECOMPILED_OBJECT
#if 1 // TODO we will do pre-compiled later
be_native_module_attr_table(tasmota) {
be_native_module_attr_table(tasmota_ntv) {
be_native_module_function("getfreeheap", l_getFreeHeap),
be_native_module_function("publish", l_publish),
be_native_module_function("cmd", l_cmd),
@ -23,9 +30,17 @@ be_native_module_attr_table(tasmota) {
be_native_module_function("millis", l_millis),
be_native_module_function("timereached", l_timereached),
be_native_module_function("yield", l_yield),
be_native_module_function("respcmnd", l_respCmnd),
be_native_module_function("respcmndstr", l_respCmndStr),
be_native_module_function("respcmnd_done", l_respCmndDone),
be_native_module_function("respcmnd_error", l_respCmndError),
be_native_module_function("respcmnd_failed", l_respCmndFailed),
be_native_module_str("_operators", "=<>!|"),
};
be_define_native_module(tasmota, NULL);
be_define_native_module(tasmota_ntv, NULL);
#else
/* @const_object_info_begin
module tasmota (scope: global, depend: 1) {

View File

@ -0,0 +1,36 @@
/********************************************************************
* Tasmota lib
*
* To use: `import wire`
*
* 2 wire communication - I2C
*******************************************************************/
#include "be_object.h"
extern int b_wire_begintransmission(bvm *vm);
extern int b_wire_endtransmission(bvm *vm);
extern int b_wire_requestfrom(bvm *vm);
extern int b_wire_available(bvm *vm);
extern int b_wire_write(bvm *vm);
extern int b_wire_read(bvm *vm);
// #if !BE_USE_PRECOMPILED_OBJECT
#if 1 // TODO we will do pre-compiled later
be_native_module_attr_table(wire) {
be_native_module_function("begintransmission", b_wire_begintransmission),
be_native_module_function("endtransmission", b_wire_endtransmission),
be_native_module_function("requestfrom", b_wire_requestfrom),
be_native_module_function("available", b_wire_available),
be_native_module_function("write", b_wire_write),
be_native_module_function("read", b_wire_read),
};
be_define_native_module(wire, NULL);
#else
/* @const_object_info_begin
module tasmota (scope: global, depend: 1) {
getfreeheap, func(l_getFreeHeap)
}
@const_object_info_end */
#include "../generate/be_fixed_tasmota.h"
#endif

View File

@ -8,19 +8,6 @@
#ifndef BERRY_CONF_H
#define BERRY_CONF_H
#include <pgmspace.h>
#ifdef __cplusplus
extern "C" {
#endif
extern int strncmp_PP(const char * str1P, const char * str2P, size_t size);
extern char * strchr_P(const char *s, int c);
#ifdef __cplusplus
}
#endif
#include <assert.h>
/* Macro: BE_DEBUG
@ -53,12 +40,12 @@ extern "C" {
* Use precompiled objects to avoid creating these objects at
* runtime. Enable this macro can greatly optimize RAM usage.
* Default: 1
**/
#ifdef ESP8266
#define BE_USE_PRECOMPILED_OBJECT 0
#else
#define BE_USE_PRECOMPILED_OBJECT 0 // will enable later when stabilized
#endif
// **/
// #ifdef ESP8266
// #define BE_USE_PRECOMPILED_OBJECT 0
// #else
#define BE_USE_PRECOMPILED_OBJECT 1 // will enable later when stabilized
// #endif
/* Macro: BE_DEBUG_RUNTIME_INFO
* Set runtime error debugging information.

View File

@ -20,6 +20,26 @@ def charsinstring(s,c)
return -1
end
###
class Tasmota
var _op, _operators, _rules
def init()
self._operators = "=<>!|"
self._op = [
['==', /s1,s2-> str(s1) == str(s2)],
['!==',/s1,s2-> str(s1) != str(s2)],
['=', /f1,f2-> real(f1) == real(f2)],
['!=', /f1,f2-> real(f1) != real(f2)],
['>=', /f1,f2-> real(f1) >= real(f2)],
['<=', /f1,f2-> real(f1) <= real(f2)],
['>', /f1,f2-> real(f1) > real(f2)],
['<', /f1,f2-> real(f1) < real(f2)],
]
self._rules = {}
end
end
###
tasmota._eqstr=/s1,s2-> str(s1) == str(s2)
tasmota._neqstr=/s1,s2-> str(s1) != str(s2)
tasmota._eq=/f1,f2-> real(f1) == real(f2)

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Herstel"
#define D_SENSOR_RC522_RST "RC522 Herstel"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -768,6 +768,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -780,6 +782,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -765,6 +765,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -777,6 +779,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -1,7 +1,7 @@
/*
it-IT.h - localization for Italian - Italy for Tasmota
Copyright (C) 2021 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 12.02.2021
Copyright (C) 2021 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 27.02.2021
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
@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 - RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC - TX"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC - RX"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP - Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP - Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD - Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD - Reset"
#define D_SENSOR_RC522_RST "RC522 - Reset"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 - CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 - CS"
#define D_SENSOR_SSD1351_CS "SSD1351 - CS"
#define D_SENSOR_SSD1351_DC "SSD1351 - DC"
#define D_SENSOR_RA8876_CS "RA8876 - CS"
#define D_SENSOR_ST7789_CS "ST7789 - CS"
#define D_SENSOR_ST7789_DC "ST7789 - DC"
@ -789,8 +792,8 @@
#define D_SENSOR_SDCARD_CS "Scheda SD - CS"
#define D_SENSOR_WIEGAND_D0 "Wiegand - D0"
#define D_SENSOR_WIEGAND_D1 "Wiegand - D1"
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
#define D_SENSOR_NEOPOOL_TX "NeoPool - TX"
#define D_SENSOR_NEOPOOL_RX "NeoPool - RX"
// Units
#define D_UNIT_AMPERE "A"
@ -998,7 +1001,7 @@
#define D_NEOPOOL_RELAY_FILTRATION "Filtrazione"
#define D_NEOPOOL_RELAY_LIGHT "Luce"
#define D_NEOPOOL_RELAY_PH_ACID "Pompa per acido"
#define D_NEOPOOL_RELAY_PH_BASE "Popa base"
#define D_NEOPOOL_RELAY_PH_BASE "Pompa base"
#define D_NEOPOOL_RELAY_RX "Livello Redox"
#define D_NEOPOOL_RELAY_CL "Pompa cloro"
#define D_NEOPOOL_RELAY_CD "Pompa salamoia"
@ -1010,7 +1013,7 @@
#define D_NEOPOOL_COVER "Copertura"
#define D_NEOPOOL_SHOCK "Shock"
#define D_NEOPOOL_ALARM "! "
#define D_NEOPOOL_LOW "Low"
#define D_NEOPOOL_LOW "Bassa"
#define D_NEOPOOL_FLOW1 "FL1"
#define D_NEOPOOL_FLOW2 "FL2"
#define D_NEOPOOL_PH_HIGH "troppo alto" // ph Alarms

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -769,6 +769,8 @@
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -781,6 +783,7 @@
#define D_SENSOR_EPAPER29_CS "EPaper29 CS"
#define D_SENSOR_EPAPER42_CS "EPaper42 CS"
#define D_SENSOR_SSD1351_CS "SSD1351 CS"
#define D_SENSOR_SSD1351_DC "SSD1351 DC"
#define D_SENSOR_RA8876_CS "RA8876 CS"
#define D_SENSOR_ST7789_CS "ST7789 CS"
#define D_SENSOR_ST7789_DC "ST7789 DC"

View File

@ -677,6 +677,9 @@
#define USE_TASMOTA_CLIENT_SERIAL_SPEED 57600 // Depends on the sketch that is running on the Uno/Pro Mini
//#define USE_OPENTHERM // Add support for OpenTherm (+15k code)
//#define USE_MIEL_HVAC // Add support for Mitsubishi Electric HVAC serial interface (+5k code)
//#define USE_PROJECTOR_CTRL // Add support for LCD/DLP Projector serial control interface (+2k code)
// #define USE_PROJECTOR_CTRL_NEC // Use codes for NEC
// #define USE_PROJECTOR_CTRL_OPTOMA // Use codes for OPTOMA
//#define USE_AS608 // Add support for AS608 optical and R503 capacitive fingerprint sensor (+3k code)
// #define USE_AS608_MESSAGES // Add verbose error messages (+0k4 code)

View File

@ -744,7 +744,7 @@ void SettingsDefaultSet2(void) {
Settings.module = MODULE;
Settings.fallback_module = FALLBACK_MODULE;
ModuleDefault(WEMOS);
// for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) { Settings.my_gp.io[i] = GPIO_NONE; }
// for (uint32_t i = 0; i < nitems(Settings.my_gp.io); i++) { Settings.my_gp.io[i] = GPIO_NONE; }
SettingsUpdateText(SET_FRIENDLYNAME1, PSTR(FRIENDLY_NAME));
SettingsUpdateText(SET_FRIENDLYNAME2, PSTR(FRIENDLY_NAME"2"));
SettingsUpdateText(SET_FRIENDLYNAME3, PSTR(FRIENDLY_NAME"3"));

View File

@ -1237,7 +1237,7 @@ int ResponseJsonEndEnd(void)
#ifdef ESP8266
uint16_t GpioConvert(uint8_t gpio) {
if (gpio >= ARRAY_SIZE(kGpioConvert)) {
if (gpio >= nitems(kGpioConvert)) {
return AGPIO(GPIO_USER);
}
return pgm_read_word(kGpioConvert + gpio);
@ -1285,7 +1285,7 @@ void ConvertGpios(void) {
void DumpConvertTable(void) {
bool jsflg = false;
uint32_t lines = 1;
for (uint32_t i = 0; i < ARRAY_SIZE(kGpioConvert); i++) {
for (uint32_t i = 0; i < nitems(kGpioConvert); i++) {
uint32_t data = pgm_read_word(kGpioConvert + i);
if (!jsflg) {
Response_P(PSTR("{\"GPIOConversion%d\":{"), lines);
@ -1293,14 +1293,14 @@ void DumpConvertTable(void) {
ResponseAppend_P(PSTR(","));
}
jsflg = true;
if ((ResponseAppend_P(PSTR("\"%d\":\"%d\""), i, data) > (MAX_LOGSZ - TOPSZ)) || (i == ARRAY_SIZE(kGpioConvert) -1)) {
if ((ResponseAppend_P(PSTR("\"%d\":\"%d\""), i, data) > (MAX_LOGSZ - TOPSZ)) || (i == nitems(kGpioConvert) -1)) {
ResponseJsonEndEnd();
MqttPublishPrefixTopic_P(RESULT_OR_STAT, XdrvMailbox.command);
jsflg = false;
lines++;
}
}
for (uint32_t i = 0; i < ARRAY_SIZE(kAdcNiceList); i++) {
for (uint32_t i = 0; i < nitems(kAdcNiceList); i++) {
uint32_t data = pgm_read_word(kAdcNiceList + i);
if (!jsflg) {
Response_P(PSTR("{\"ADC0Conversion%d\":{"), lines);
@ -1308,7 +1308,7 @@ void DumpConvertTable(void) {
ResponseAppend_P(PSTR(","));
}
jsflg = true;
if ((ResponseAppend_P(PSTR("\"%d\":\"%d\""), i, data) > (MAX_LOGSZ - TOPSZ)) || (i == ARRAY_SIZE(kAdcNiceList) -1)) {
if ((ResponseAppend_P(PSTR("\"%d\":\"%d\""), i, data) > (MAX_LOGSZ - TOPSZ)) || (i == nitems(kAdcNiceList) -1)) {
ResponseJsonEndEnd();
MqttPublishPrefixTopic_P(RESULT_OR_STAT, XdrvMailbox.command);
jsflg = false;
@ -1328,7 +1328,7 @@ int ICACHE_RAM_ATTR Pin(uint32_t gpio, uint32_t index) {
real_gpio += index;
mask = 0xFFFF;
}
for (uint32_t i = 0; i < ARRAY_SIZE(TasmotaGlobal.gpio_pin); i++) {
for (uint32_t i = 0; i < nitems(TasmotaGlobal.gpio_pin); i++) {
if ((TasmotaGlobal.gpio_pin[i] & mask) == real_gpio) {
return i; // Pin number configured for gpio
}
@ -1342,7 +1342,7 @@ bool PinUsed(uint32_t gpio, uint32_t index) {
}
uint32_t GetPin(uint32_t lpin) {
if (lpin < ARRAY_SIZE(TasmotaGlobal.gpio_pin)) {
if (lpin < nitems(TasmotaGlobal.gpio_pin)) {
return TasmotaGlobal.gpio_pin[lpin];
} else {
return GPIO_NONE;
@ -1466,7 +1466,7 @@ void GetInternalTemplate(void* ptr, uint32_t module, uint32_t option) {
void TemplateGpios(myio *gp)
{
uint16_t *dest = (uint16_t *)gp;
uint16_t src[ARRAY_SIZE(Settings.user_template.gp.io)];
uint16_t src[nitems(Settings.user_template.gp.io)];
memset(dest, GPIO_NONE, sizeof(myio));
if (USER_MODULE == Settings.module) {
@ -1484,7 +1484,7 @@ void TemplateGpios(myio *gp)
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)&src, sizeof(mycfgio));
uint32_t j = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.user_template.gp.io); i++) {
if (6 == i) { j = 9; }
if (8 == i) { j = 12; }
dest[j] = src[i];
@ -1600,7 +1600,7 @@ bool JsonTemplate(char* dataBuf)
uint8_t template8[sizeof(mytmplt8285)] = { GPIO_NONE };
if (13 == arr.size()) { // Possible old template
uint32_t gpio = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(template8) -1; i++) {
for (uint32_t i = 0; i < nitems(template8) -1; i++) {
gpio = arr[i].getUInt();
if (gpio > 255) { // New templates might have values above 255
break;
@ -1615,13 +1615,13 @@ bool JsonTemplate(char* dataBuf)
val = root[PSTR(D_JSON_FLAG)];
if (val) {
template8[ARRAY_SIZE(template8) -1] = val.getUInt() & 0x0F;
template8[nitems(template8) -1] = val.getUInt() & 0x0F;
}
TemplateConvert(template8, Settings.user_template.gp.io);
Settings.user_template.flag.data = 0;
} else {
#endif
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.user_template.gp.io); i++) {
JsonParserToken val = arr[i];
if (!val) { break; }
uint16_t gpio = val.getUInt();
@ -1657,7 +1657,7 @@ void TemplateJson(void)
// AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t*)&Settings.user_template, sizeof(Settings.user_template) / 2, 2);
Response_P(PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), SettingsText(SET_TEMPLATE_NAME));
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.user_template.gp.io); i++) {
uint16_t gpio = Settings.user_template.gp.io[i];
if (gpio == AGPIO(GPIO_USER)) {
gpio = AGPIO(GPIO_NONE) +1;

View File

@ -1156,7 +1156,7 @@ void CmndModule(void)
Settings.module = XdrvMailbox.payload;
SetModuleType();
if (Settings.last_module != XdrvMailbox.payload) {
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.my_gp.io); i++) {
Settings.my_gp.io[i] = GPIO_NONE;
}
}
@ -1200,12 +1200,12 @@ void CmndModules(void)
void CmndGpio(void)
{
if (XdrvMailbox.index < ARRAY_SIZE(Settings.my_gp.io)) {
if (XdrvMailbox.index < nitems(Settings.my_gp.io)) {
myio template_gp;
TemplateGpios(&template_gp);
if (ValidGPIO(XdrvMailbox.index, template_gp.io[XdrvMailbox.index]) && (XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < AGPIO(GPIO_SENSOR_END))) {
bool present = false;
for (uint32_t i = 0; i < ARRAY_SIZE(kGpioNiceList); i++) {
for (uint32_t i = 0; i < nitems(kGpioNiceList); i++) {
uint32_t midx = pgm_read_word(kGpioNiceList + i);
uint32_t max_midx = ((midx & 0x001F) > 0) ? midx : midx +1;
if ((XdrvMailbox.payload >= (midx & 0xFFE0)) && (XdrvMailbox.payload < max_midx)) {
@ -1214,7 +1214,7 @@ void CmndGpio(void)
}
}
if (present) {
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.my_gp.io); i++) {
if (ValidGPIO(i, template_gp.io[i]) && (Settings.my_gp.io[i] == XdrvMailbox.payload)) {
Settings.my_gp.io[i] = GPIO_NONE;
}
@ -1225,7 +1225,7 @@ void CmndGpio(void)
}
bool jsflg = false;
bool jsflg2 = false;
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.my_gp.io); i++) {
if (ValidGPIO(i, template_gp.io[i]) || ((255 == XdrvMailbox.payload) && !FlashPin(i))) {
if (!jsflg) {
Response_P(PSTR("{"));
@ -1243,7 +1243,7 @@ void CmndGpio(void)
char sindex[4] = { 0 };
uint32_t sensor_name_idx = BGPIO(sensor_type);
uint32_t nice_list_search = sensor_type & 0xFFE0;
for (uint32_t j = 0; j < ARRAY_SIZE(kGpioNiceList); j++) {
for (uint32_t j = 0; j < nitems(kGpioNiceList); j++) {
uint32_t nls_idx = pgm_read_word(kGpioNiceList + j);
if (((nls_idx & 0xFFE0) == nice_list_search) && ((nls_idx & 0x001F) > 0)) {
snprintf_P(sindex, sizeof(sindex), PSTR("%d"), (sensor_type & 0x001F) +1);
@ -1310,10 +1310,10 @@ void CmndGpios(void)
// DumpConvertTable();
ShowGpios(nullptr, GPIO_SENSOR_END, 0, lines);
} else {
ShowGpios(kGpioNiceList, ARRAY_SIZE(kGpioNiceList), 0, lines);
ShowGpios(kGpioNiceList, nitems(kGpioNiceList), 0, lines);
#ifdef ESP8266
#ifndef USE_ADC_VCC
ShowGpios(kAdcNiceList, ARRAY_SIZE(kAdcNiceList), 1, lines);
ShowGpios(kAdcNiceList, nitems(kAdcNiceList), 1, lines);
#endif // USE_ADC_VCC
#endif // ESP8266
}
@ -1345,7 +1345,7 @@ void CmndTemplate(void)
}
SettingsUpdateText(SET_TEMPLATE_NAME, PSTR("Merged"));
uint32_t j = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.user_template.gp.io); i++) {
if (6 == i) { j = 9; }
if (8 == i) { j = 12; }
if (TasmotaGlobal.my_module.io[j] > GPIO_NONE) {

View File

@ -718,7 +718,9 @@ void ResponseAppendFeatures(void)
#if defined(USE_DISPLAY) && defined(USE_DISPLAY_TM1637)
feature7 |= 0x40000000;
#endif
// feature7 |= 0x80000000;
#ifdef USE_PROJECTOR_CTRL
feature7 |= 0x80000000; // xdrv_53_projector_ctrl.ino
#endif
}
static uint32_t feature8 = 0x00000000;

View File

@ -1556,7 +1556,7 @@ void GpioInit(void)
ConvertGpios();
#endif // ESP8266
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.user_template.gp.io); i++) {
if ((Settings.user_template.gp.io[i] >= AGPIO(GPIO_SENSOR_END)) && (Settings.user_template.gp.io[i] < AGPIO(GPIO_USER))) {
Settings.user_template.gp.io[i] = AGPIO(GPIO_USER); // Fix not supported sensor ids in template
}
@ -1564,7 +1564,7 @@ void GpioInit(void)
myio template_gp;
TemplateGpios(&template_gp);
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.my_gp.io); i++) {
if ((Settings.my_gp.io[i] >= AGPIO(GPIO_SENSOR_END)) && (Settings.my_gp.io[i] < AGPIO(GPIO_USER))) {
Settings.my_gp.io[i] = GPIO_NONE; // Fix not supported sensor ids in module
}
@ -1576,7 +1576,7 @@ void GpioInit(void)
}
}
for (uint32_t i = 0; i < ARRAY_SIZE(TasmotaGlobal.my_module.io); i++) {
for (uint32_t i = 0; i < nitems(TasmotaGlobal.my_module.io); i++) {
uint32_t mpin = ValidPin(i, TasmotaGlobal.my_module.io[i]);
DEBUG_CORE_LOG(PSTR("INI: gpio pin %d, mpin %d"), i, mpin);
@ -1648,7 +1648,7 @@ void GpioInit(void)
if (mpin) { SetPin(i, mpin); } // Anything above GPIO_NONE and below GPIO_SENSOR_END
}
// AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t*)TasmotaGlobal.gpio_pin, ARRAY_SIZE(TasmotaGlobal.gpio_pin), sizeof(TasmotaGlobal.gpio_pin[0]));
// AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t*)TasmotaGlobal.gpio_pin, nitems(TasmotaGlobal.gpio_pin), sizeof(TasmotaGlobal.gpio_pin[0]));
analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h)
analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
@ -1715,7 +1715,7 @@ void GpioInit(void)
AddLogSpi(1, Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MOSI), Pin(GPIO_SPI_MISO));
#endif // USE_SPI
for (uint32_t i = 0; i < ARRAY_SIZE(TasmotaGlobal.my_module.io); i++) {
for (uint32_t i = 0; i < nitems(TasmotaGlobal.my_module.io); i++) {
uint32_t mpin = ValidPin(i, TasmotaGlobal.my_module.io[i]);
// AddLog(LOG_LEVEL_DEBUG, PSTR("INI: gpio pin %d, mpin %d"), i, mpin);
if (AGPIO(GPIO_OUTPUT_HI) == mpin) {

View File

@ -310,7 +310,7 @@ void setup(void) {
TasmotaGlobal.no_autoexec = true;
}
if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +3) { // Restarted 5 times
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.my_gp.io); i++) {
Settings.my_gp.io[i] = GPIO_NONE; // Reset user defined GPIO disabling sensors
}
}

View File

@ -245,7 +245,7 @@ const br_x509_trust_anchor PROGMEM Tasmota_TA[] = {
}
};
const size_t Tasmota_TA_size = ARRAY_SIZE(Tasmota_TA);
const size_t Tasmota_TA_size = nitems(Tasmota_TA);
// we add a separate CA for telegram
/*********************************************************************************************\

View File

@ -178,6 +178,9 @@
//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
//#define USE_OPENTHERM // Add support for OpenTherm (+15k code)
//#define USE_MIEL_HVAC // Add support for Mitsubishi Electric HVAC serial interface (+5k code)
//#define USE_PROJECTOR_CTRL // Add support for LCD/DLP Projector serial control interface (+2k code)
// #define USE_PROJECTOR_CTRL_NEC // Use codes for NEC
// #define USE_PROJECTOR_CTRL_OPTOMA // Use codes for OPTOMA
//#define USE_AS608 // Add support for AS608 optical and R503 capacitive fingerprint sensor (+3k4 code)
#define USE_ENERGY_SENSOR // Add energy sensors (-14k code)
@ -432,6 +435,7 @@
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
#undef USE_MIEL_HVAC // Disable support for Mitsubishi Electric HVAC serial interface (+5k code)
#undef USE_PROJECTOR_CTRL // Disable support for LCD/DLP Projector serial control interface
#undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
#undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI
@ -561,6 +565,7 @@
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
#undef USE_MIEL_HVAC // Disable support for Mitsubishi Electric HVAC serial interface (+5k code)
#undef USE_PROJECTOR_CTRL // Disable support for LCD/DLP Projector serial control interface
#undef USE_ENERGY_SENSOR // Disable energy sensors
#undef USE_ADE7953 // Disable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5)
@ -700,6 +705,7 @@
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
#undef USE_MIEL_HVAC // Disable support for Mitsubishi Electric HVAC serial interface (+5k code)
#undef USE_PROJECTOR_CTRL // Disable support for LCD/DLP Projector serial control interface
//#undef USE_ENERGY_SENSOR // Disable energy sensors
#undef USE_PZEM004T // Disable PZEM004T energy sensor
@ -841,6 +847,7 @@
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
#undef USE_MIEL_HVAC // Disable support for Mitsubishi Electric HVAC serial interface (+5k code)
#undef USE_PROJECTOR_CTRL // Disable support for LCD/DLP Projector serial control interface
#undef USE_AS608 // Disable support for AS608 optical and R503 capacitive fingerprint sensor (+3k4 code)
#undef USE_ENERGY_SENSOR // Disable energy sensors

View File

@ -461,15 +461,13 @@ const char kWebColors[] PROGMEM =
#define tmin(a,b) ((a)<(b)?(a):(b))
#define tmax(a,b) ((a)>(b)?(a):(b))
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#define STR_HELPER(x) #x
#ifndef STR
#define STR(x) STR_HELPER(x)
#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
#define AGPIO(x) ((x)<<5)
#define BGPIO(x) ((x)>>5)

View File

@ -151,6 +151,8 @@ enum UserSelectablePins {
GPIO_SDM72_TX, GPIO_SDM72_RX, // SDM72 Serial interface
GPIO_TM1637CLK, GPIO_TM1637DIO, // TM1637 interface
GPIO_TM1638CLK, GPIO_TM1638DIO, GPIO_TM1638STB, // TM1638 interface
GPIO_PROJECTOR_CTRL_TX, GPIO_PROJECTOR_CTRL_RX, // LCD/DLP Projector Serial Control
GPIO_SSD1351_DC,
GPIO_SENSOR_END };
enum ProgramSelectablePins {
@ -322,6 +324,8 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_SDM72_TX "|" D_SENSOR_SDM72_RX "|"
D_SENSOR_TM1637_CLK "|" D_SENSOR_TM1637_DIO "|"
D_SENSOR_TM1638_CLK "|" D_SENSOR_TM1638_DIO "|" D_SENSOR_TM1638_STB "|"
D_SENSOR_PROJECTOR_CTRL_TX "|" D_SENSOR_PROJECTOR_CTRL_RX "|"
D_SENSOR_SSD1351_DC "|"
;
const char kSensorNamesFixed[] PROGMEM =
@ -423,6 +427,7 @@ const uint16_t kGpioNiceList[] PROGMEM = {
#endif // USE_DISPLAY_EPAPER_42
#ifdef USE_DISPLAY_SSD1351
AGPIO(GPIO_SSD1351_CS),
AGPIO(GPIO_SSD1351_DC),
#endif // USE_DISPLAY_SSD1351
#ifdef USE_DISPLAY_RA8876
AGPIO(GPIO_RA8876_CS),
@ -765,7 +770,10 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_NEOPOOL_TX), // Sugar Valley RS485 Interface
AGPIO(GPIO_NEOPOOL_RX), // Sugar Valley RS485 Interface
#endif
#ifdef USE_PROJECTOR_CTRL
AGPIO(GPIO_PROJECTOR_CTRL_TX), // LCD/DLP Projector Serial Control
AGPIO(GPIO_PROJECTOR_CTRL_RX), // LCD/DLP Projector Serial Control
#endif
/*-------------------------------------------------------------------------------------------*\
* ESP32 specifics
\*-------------------------------------------------------------------------------------------*/

View File

@ -453,7 +453,7 @@ void StartWebserver(int type, IPAddress ipweb)
if (!Webserver) {
Webserver = new ESP8266WebServer((HTTP_MANAGER == type || HTTP_MANAGER_RESET_ONLY == type) ? 80 : WEB_PORT);
// call `Webserver->on()` on each entry
for (uint32_t i=0; i<ARRAY_SIZE(WebServerDispatch); i++) {
for (uint32_t i=0; i<nitems(WebServerDispatch); i++) {
const WebServerDispatch_t & line = WebServerDispatch[i];
// copy uri in RAM and prefix with '/'
char uri[4];
@ -1325,7 +1325,7 @@ void HandleConfiguration(void)
void WSContentSendNiceLists(uint32_t option) {
char stemp[30]; // Template number and Sensor name
for (uint32_t i = 0; i < ARRAY_SIZE(kGpioNiceList); i++) { // GPIO: }2'0'>None (0)}3}2'17'>Button1 (17)}3...
for (uint32_t i = 0; i < nitems(kGpioNiceList); i++) { // GPIO: }2'0'>None (0)}3}2'17'>Button1 (17)}3...
if (option && (1 == i)) {
WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX, AGPIO(GPIO_USER), PSTR(D_SENSOR_USER)); // }2'255'>User}3
}
@ -1338,7 +1338,7 @@ void WSContentSendNiceLists(uint32_t option) {
WSContentSend_P(PSTR("hs=["));
uint32_t midx;
bool first_done = false;
for (uint32_t i = 0; i < ARRAY_SIZE(kGpioNiceList); i++) { // hs=[36,68,100,132,168,200,232,264,292,324,356,388,421,453];
for (uint32_t i = 0; i < nitems(kGpioNiceList); i++) { // hs=[36,68,100,132,168,200,232,264,292,324,356,388,421,453];
midx = pgm_read_word(kGpioNiceList + i);
if (midx & 0x001F) {
if (first_done) { WSContentSend_P(PSTR(",")); }
@ -1348,7 +1348,7 @@ void WSContentSendNiceLists(uint32_t option) {
}
#ifdef ESP8266
#ifdef USE_ADC
for (uint32_t i = 0; i < ARRAY_SIZE(kAdcNiceList); i++) { // hs=[36,68,100,132,168,200,232,264,292,324,356,388,421,453];
for (uint32_t i = 0; i < nitems(kAdcNiceList); i++) { // hs=[36,68,100,132,168,200,232,264,292,324,356,388,421,453];
midx = pgm_read_word(kAdcNiceList + i);
if (midx & 0x001F) {
if (first_done) { WSContentSend_P(PSTR(",")); }
@ -1366,7 +1366,7 @@ void WSContentSendNiceLists(uint32_t option) {
void WSContentSendAdcNiceList(uint32_t option) {
char stemp[30]; // Template number and Sensor name
WSContentSend_P(PSTR("os=\""));
for (uint32_t i = 0; i < ARRAY_SIZE(kAdcNiceList); i++) { // GPIO: }2'0'>None}3}2'17'>Analog}3...
for (uint32_t i = 0; i < nitems(kAdcNiceList); i++) { // GPIO: }2'0'>None}3}2'17'>Analog}3...
if (option && (1 == i)) {
WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX, AGPIO(GPIO_USER), PSTR(D_SENSOR_USER)); // }2'15'>User}3
}
@ -1404,7 +1404,7 @@ void HandleTemplateConfiguration(void)
WSContentBegin(200, CT_PLAIN);
WSContentSend_P(PSTR("%s}1"), AnyModuleName(module).c_str()); // NAME: Generic
for (uint32_t i = 0; i < ARRAY_SIZE(template_gp.io); i++) { // 17,148,29,149,7,255,255,255,138,255,139,255,255
for (uint32_t i = 0; i < nitems(template_gp.io); i++) { // 17,148,29,149,7,255,255,255,138,255,139,255,255
if (!FlashPin(i)) {
WSContentSend_P(PSTR("%s%d"), (i>0)?",":"", template_gp.io[i]);
}
@ -1490,7 +1490,7 @@ void TemplateSaveSettings(void)
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_TEMPLATE " {\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), tmp);
uint32_t j = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.user_template.gp.io); i++) {
if (6 == i) { j = 9; }
if (8 == i) { j = 12; }
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s%d"), svalue, (i>0)?",":"", WebGetGpioArg(j));
@ -1549,7 +1549,7 @@ void HandleModuleConfiguration(void)
WSContentSendNiceLists(0);
for (uint32_t i = 0; i < ARRAY_SIZE(template_gp.io); i++) {
for (uint32_t i = 0; i < nitems(template_gp.io); i++) {
if (ValidGPIO(i, template_gp.io[i])) {
WSContentSend_P(PSTR("sk(%d,%d);"), TasmotaGlobal.my_module.io[i], i); // g0 - g17
}
@ -1566,7 +1566,7 @@ void HandleModuleConfiguration(void)
WSContentSendStyle();
WSContentSend_P(HTTP_FORM_MODULE, AnyModuleName(MODULE).c_str());
for (uint32_t i = 0; i < ARRAY_SIZE(template_gp.io); i++) {
for (uint32_t i = 0; i < nitems(template_gp.io); i++) {
if (ValidGPIO(i, template_gp.io[i])) {
snprintf_P(stemp, 3, PINS_WEMOS +i*2);
WSContentSend_P(PSTR("<tr><td style='width:116px'>%s <b>" D_GPIO "%d</b></td><td style='width:146px'><select id='g%d' onchange='ot(%d,this.value)'></select></td>"),
@ -1592,7 +1592,7 @@ void ModuleSaveSettings(void)
myio template_gp;
TemplateGpios(&template_gp);
String gpios = "";
for (uint32_t i = 0; i < ARRAY_SIZE(template_gp.io); i++) {
for (uint32_t i = 0; i < nitems(template_gp.io); i++) {
if (Settings.last_module != new_module) {
Settings.my_gp.io[i] = GPIO_NONE;
} else {

View File

@ -33,7 +33,7 @@ WiFiClient EspClient; // Wifi Client - non-TLS
const char kMqttCommands[] PROGMEM = "|" // No prefix
// SetOption synonyms
D_SO_MQTTJSONONLY "|"
D_SO_MQTTJSONONLY "|"
#ifdef USE_MQTT_TLS
D_SO_MQTTTLS "|"
#endif
@ -195,7 +195,7 @@ void MqttInit(void) {
#endif
#ifdef USE_MQTT_TLS_CA_CERT
tlsClient->setTrustAnchor(Tasmota_TA, ARRAY_SIZE(Tasmota_TA));
tlsClient->setTrustAnchor(Tasmota_TA, nitems(Tasmota_TA));
#endif // USE_MQTT_TLS_CA_CERT
MqttClient.setClient(*tlsClient);

View File

@ -1083,6 +1083,13 @@ void LightCalcPWMRange(void) {
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LightCalcPWMRange %d %d - %d %d"), Settings.dimmer_hw_min, Settings.dimmer_hw_max, Light.pwm_min, Light.pwm_max);
}
void LightSetScheme(uint32_t scheme) {
if (!scheme && Settings.light_scheme) {
Light.update = true;
}
Settings.light_scheme = scheme;
}
void LightInit(void)
{
// move white blend mode from deprecated `RGBWWTable` to `SetOption105`
@ -1149,7 +1156,7 @@ void LightInit(void)
max_scheme = LS_POWER;
}
if ((LS_WAKEUP == Settings.light_scheme) || (Settings.light_scheme > max_scheme)) {
Settings.light_scheme = LS_POWER;
LightSetScheme(LS_POWER);
}
Light.power = 0;
Light.update = true;
@ -1308,7 +1315,7 @@ void LightSetSignal(uint16_t lo, uint16_t hi, uint16_t value)
uint16_t signal = changeUIntScale(value, lo, hi, 0, 255); // 0..255
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Light signal %d"), signal);
light_controller.changeRGB(signal, 255 - signal, 0, true); // keep bri
Settings.light_scheme = 0;
LightSetScheme(LS_POWER);
if (0 == light_state.getBri()) {
light_controller.changeBri(50);
}
@ -1668,7 +1675,7 @@ void LightAnimate(void)
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_CMND_WAKEUP));
Light.wakeup_active = 0;
Settings.light_scheme = LS_POWER;
LightSetScheme(LS_POWER);
}
}
break;
@ -2288,7 +2295,7 @@ void LightHandleDevGroupItem(void)
uint32_t old_bri = light_state.getBri();
light_controller.changeChannels(Light.entry_color);
light_controller.changeBri(old_bri);
Settings.light_scheme = 0;
LightSetScheme(LS_POWER);
if (!restore_power && !Light.power) {
Light.old_power = Light.power;
Light.power = 0xff;
@ -2448,7 +2455,7 @@ void CmndSupportColor(void)
#ifdef USE_LIGHT_PALETTE
}
#endif // USE_LIGHT_PALETTE
Settings.light_scheme = 0;
LightSetScheme(LS_POWER);
coldim = true;
} else { // Color3, 4, 5 and 6
for (uint32_t i = 0; i < LST_RGB; i++) {
@ -2617,7 +2624,7 @@ void CmndScheme(void)
Light.wheel--;
#endif // USE_LIGHT_PALETTE
}
Settings.light_scheme = XdrvMailbox.payload;
LightSetScheme(XdrvMailbox.payload);
if (LS_WAKEUP == Settings.light_scheme) {
Light.wakeup_active = 3;
}
@ -2640,7 +2647,7 @@ void CmndWakeup(void)
light_controller.changeDimmer(XdrvMailbox.payload);
}
Light.wakeup_active = 3;
Settings.light_scheme = LS_WAKEUP;
LightSetScheme(LS_WAKEUP);
LightPowerOn();
ResponseCmndChar(PSTR(D_JSON_STARTED));
}

View File

@ -2676,7 +2676,7 @@ chknext:
}
}
*/
if ((gpiopin < ARRAY_SIZE(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) {
if ((gpiopin < nitems(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) {
fvar = TasmotaGlobal.gpio_pin[gpiopin];
// skip ] bracket
len++;

View File

@ -330,11 +330,11 @@ float TuyaAdjustedTemperature(int16_t packetValue, uint8_t res)
break;
case 3:
return (float)packetValue / 1000.0;
break;
break;
default:
return (float)packetValue;
break;
}
}
}
/*********************************************************************************************\
* Internal Functions
@ -622,10 +622,10 @@ void LightSerialDuty(uint16_t duty, char *hex_char, uint8_t TuyaIdx)
dpid = TuyaGetDpId(TUYA_MCU_FUNC_CT);
} else { dpid = TuyaGetDpId(TUYA_MCU_FUNC_DIMMER2); }
}
if (Tuya.ignore_dim && Tuya.ignore_dimmer_cmd_timeout < millis()) {
Tuya.ignore_dim = false;
}
}
if (duty > 0 && !Tuya.ignore_dim && TuyaSerial && dpid > 0) {
if (TuyaIdx == 2 && CTLight) {
@ -955,7 +955,7 @@ void TuyaNormalPowerModePacketProcess(void)
uint8_t key1_gpio = Tuya.buffer[7];
bool key1_set = false;
bool led1_set = false;
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
for (uint32_t i = 0; i < nitems(Settings.my_gp.io); i++) {
if (Settings.my_gp.io[i] == AGPIO(GPIO_LED1)) led1_set = true;
else if (Settings.my_gp.io[i] == AGPIO(GPIO_KEY1)) key1_set = true;
}

View File

@ -100,7 +100,7 @@ Z_Data_Type Z_Data::CharToDataType(char c) {
if (c == '_') {
return Z_Data_Type::Z_Device;
} else {
for (uint32_t i=0; i<ARRAY_SIZE(Z_Data_Type_char); i++) {
for (uint32_t i=0; i<nitems(Z_Data_Type_char); i++) {
if (pgm_read_byte(&Z_Data_Type_char[i]) == c) {
return (Z_Data_Type) i;
}
@ -115,7 +115,7 @@ char Z_Data::DataTypeToChar(Z_Data_Type t) {
return '_';
} else {
uint8_t tt = (uint8_t) t;
if (tt < ARRAY_SIZE(Z_Data_Type_char)) {
if (tt < nitems(Z_Data_Type_char)) {
return pgm_read_byte(&Z_Data_Type_char[tt]);
}
}
@ -418,7 +418,7 @@ public:
inline void setZoneType(uint16_t _zone_type) { zone_type = _zone_type; }
bool update(void) {
for (uint32_t i=0; i<ARRAY_SIZE(Z_Alarm_Types); i++) {
for (uint32_t i=0; i<nitems(Z_Alarm_Types); i++) {
Z_Alarm_Types_t conv_type;
conv_type.i = pgm_read_word(&Z_Alarm_Types[i].i);
if (zone_type == conv_type.t.zcl_type) {
@ -553,7 +553,7 @@ const uint8_t Z_Data_Type_len[] PROGMEM = {
size_t Z_Data::DataTypeToLength(Z_Data_Type t) {
uint32_t tt = (uint32_t) t;
if (tt < ARRAY_SIZE(Z_Data_Type_len)) {
if (tt < nitems(Z_Data_Type_len)) {
return pgm_read_byte(&Z_Data_Type_len[tt]);
}
return 0;

View File

@ -145,7 +145,7 @@ SBuffer hibernateDevicev2(const struct Z_Device &device) {
char *names[3] = { device.modelId, device.manufacturerId, device.friendlyName };
for (uint32_t i=0; i<ARRAY_SIZE(names); i++) {
for (uint32_t i=0; i<nitems(names); i++) {
char *p = names[i];
if (p) {
size_t len = strlen(p);

View File

@ -140,14 +140,14 @@ const uint16_t Cx_cluster[] PROGMEM = {
};
uint16_t CxToCluster(uint8_t cx) {
if (cx < ARRAY_SIZE(Cx_cluster)) {
if (cx < nitems(Cx_cluster)) {
return pgm_read_word(&Cx_cluster[cx]);
}
return 0xFFFF;
}
uint8_t ClusterToCx(uint16_t cluster) {
for (uint32_t i=0; i<ARRAY_SIZE(Cx_cluster); i++) {
for (uint32_t i=0; i<nitems(Cx_cluster); i++) {
if (pgm_read_word(&Cx_cluster[i]) == cluster) {
return i;
}
@ -170,7 +170,7 @@ const int8_t Cm_multiplier[] PROGMEM = {
int8_t CmToMultiplier(uint8_t cm) {
cm = cm & 0x0F; // get only low nibble
if (cm < ARRAY_SIZE(Cm_multiplier)) {
if (cm < nitems(Cm_multiplier)) {
return pgm_read_byte(&Cm_multiplier[cm]);
}
return 1;
@ -668,7 +668,7 @@ typedef union ZCLHeaderFrameControl_t {
const __FlashStringHelper* zigbeeFindAttributeByName(const char *command,
uint16_t *cluster, uint16_t *attribute, int8_t *multiplier,
uint8_t *zigbee_type = nullptr, Z_Data_Type *data_type = nullptr, uint8_t *map_offset = nullptr) {
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
for (uint32_t i = 0; i < nitems(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
if (0 == pgm_read_word(&converter->name_offset)) { continue; } // avoid strcasecmp_P() from crashing
if (0 == strcasecmp_P(command, Z_strings + pgm_read_word(&converter->name_offset))) {
@ -690,7 +690,7 @@ const __FlashStringHelper* zigbeeFindAttributeByName(const char *command,
//
const __FlashStringHelper* zigbeeFindAttributeById(uint16_t cluster, uint16_t attr_id,
uint8_t *attr_type, int8_t *multiplier) {
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
for (uint32_t i = 0; i < nitems(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short));
uint16_t conv_attr_id = pgm_read_word(&converter->attribute);
@ -1458,7 +1458,7 @@ void ZCLFrame::parseReadAttributes(Z_attribute_list& attr_list) {
read_attr_ids[i/2] = attrid;
// find the attribute name
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
for (uint32_t i = 0; i < nitems(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short));
uint16_t conv_attribute = pgm_read_word(&converter->attribute);
@ -1527,7 +1527,7 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) {
// find the attribute name
int8_t multiplier = 1;
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
for (uint32_t i = 0; i < nitems(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short));
uint16_t conv_attribute = pgm_read_word(&converter->attribute);
@ -1997,7 +1997,7 @@ void Z_postProcessAttributes(uint16_t shortaddr, uint16_t src_ep, class Z_attrib
uint8_t map_offset = 0;
uint8_t zigbee_type = Znodata;
int8_t conv_multiplier;
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
for (uint32_t i = 0; i < nitems(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short));
uint16_t conv_attribute = pgm_read_word(&converter->attribute);
@ -2088,7 +2088,7 @@ void Z_postProcessAttributes(uint16_t shortaddr, uint16_t src_ep, class Z_attrib
// Internal search function
void Z_parseAttributeKey_inner(class Z_attribute & attr, uint16_t preferred_cluster) {
// scan attributes to find by name, and retrieve type
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
for (uint32_t i = 0; i < nitems(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
uint16_t local_attr_id = pgm_read_word(&converter->attribute);
uint16_t local_cluster_id = CxToCluster(pgm_read_byte(&converter->cluster_short));
@ -2177,7 +2177,7 @@ bool Z_parseAttributeKey(class Z_attribute & attr, uint16_t preferred_cluster) {
void Z_Data::toAttributes(Z_attribute_list & attr_list) const {
Z_Data_Type type = getType();
// iterate through attributes to see which ones need to be exported
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
for (uint32_t i = 0; i < nitems(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
uint8_t conv_export = pgm_read_byte(&converter->multiplier_idx) & Z_EXPORT_DATA;
uint8_t conv_mapping = pgm_read_byte(&converter->mapping);

View File

@ -438,7 +438,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_SEND(ZBS_PFGK) // check PFGK on ZB1.2
ZI_WAIT_RECV(1000, ZBR_PFGK)
ZI_GOTO(ZIGBEE_LABEL_START_COORD)
ZI_LABEL(ZIGBEE_LABEL_ZB3_INIT)
ZI_SEND(ZBS_PFGK3) // check PFGK on ZB3
ZI_WAIT_RECV(1000, ZBR_PFGK3)
@ -947,7 +947,7 @@ void ZigbeeGotoLabel(uint8_t label) {
uint8_t cur_d8 = 0;
uint8_t cur_instr_len = 1; // size of current instruction in words
for (uint32_t i = 0; i < ARRAY_SIZE(zb_prog); i += cur_instr_len) {
for (uint32_t i = 0; i < nitems(zb_prog); i += cur_instr_len) {
const Zigbee_Instruction *cur_instr_line = &zb_prog[i];
cur_instr = pgm_read_byte(&cur_instr_line->i.i);
cur_d8 = pgm_read_byte(&cur_instr_line->i.d8);
@ -1006,7 +1006,7 @@ void ZigbeeStateMachine_Run(void) {
zigbee.recv_until = false;
zigbee.state_no_timeout = false; // reset the no_timeout for next instruction
if (zigbee.pc > ARRAY_SIZE(zb_prog)) {
if (zigbee.pc > nitems(zb_prog)) {
AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Invalid pc: %d, aborting"), zigbee.pc);
zigbee.pc = -1;
}

View File

@ -207,7 +207,7 @@ void EnergyScanResults(void) {
uint32_t bars = changeUIntScale(energy_unsigned, bar_min + 0x80, bar_max + 0x80, 0, bar_count);
for (uint32_t j = 0; j < bars; j++) { bar_str[j] = '#'; }
bar_str[bars] = 0;
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Channel %2d: %s"), i + USE_ZIGBEE_CHANNEL_MIN, bar_str);
}
ResponseAppend_P(PSTR("]}"));
@ -667,7 +667,7 @@ const uint8_t Z_bindings[] PROGMEM = {
int32_t Z_ClusterToCxBinding(uint16_t cluster) {
uint8_t cx = ClusterToCx(cluster);
for (uint32_t i=0; i<ARRAY_SIZE(Z_bindings); i++) {
for (uint32_t i=0; i<nitems(Z_bindings); i++) {
if (pgm_read_byte(&Z_bindings[i]) == cx) {
return i;
}
@ -711,7 +711,7 @@ void Z_AutoBindDefer(uint16_t shortaddr, uint8_t endpoint, const SBuffer &buf,
}
// enqueue bind requests
for (uint32_t i=0; i<ARRAY_SIZE(Z_bindings); i++) {
for (uint32_t i=0; i<nitems(Z_bindings); i++) {
if (bitRead(cluster_map, i)) {
uint16_t cluster = CxToCluster(pgm_read_byte(&Z_bindings[i]));
if ((cluster == 0x0001) && (!Z_BatteryReportingDeviceSpecific(shortaddr))) { continue; }
@ -720,7 +720,7 @@ void Z_AutoBindDefer(uint16_t shortaddr, uint8_t endpoint, const SBuffer &buf,
}
// enqueue config attribute requests
for (uint32_t i=0; i<ARRAY_SIZE(Z_bindings); i++) {
for (uint32_t i=0; i<nitems(Z_bindings); i++) {
if (bitRead(cluster_in_map, i)) {
uint16_t cluster = CxToCluster(pgm_read_byte(&Z_bindings[i]));
if ((cluster == 0x0001) && (!Z_BatteryReportingDeviceSpecific(shortaddr))) { continue; }
@ -1534,7 +1534,7 @@ void Z_AutoConfigReportingForCluster(uint16_t shortaddr, uint16_t groupaddr, uin
Response_P(PSTR("ZbSend {\"Device\":\"0x%04X\",\"Config\":{"), shortaddr);
boolean comma = false;
for (uint32_t i=0; i<ARRAY_SIZE(Z_autoAttributeReporting); i++) {
for (uint32_t i=0; i<nitems(Z_autoAttributeReporting); i++) {
uint16_t conv_cluster = pgm_read_word(&(Z_autoAttributeReporting[i].cluster));
uint16_t attr_id = pgm_read_word(&(Z_autoAttributeReporting[i].attr_id));
@ -2000,7 +2000,7 @@ int32_t ZNP_Recv_Default(int32_t res, const SBuffer &buf) {
// if still during initialization phase, ignore any unexpected message
return -1; // ignore message
} else {
for (uint32_t i = 0; i < ARRAY_SIZE(Z_DispatchTable); i++) {
for (uint32_t i = 0; i < nitems(Z_DispatchTable); i++) {
if (Z_ReceiveMatchPrefix(buf, Z_DispatchTable[i].match)) {
(*Z_DispatchTable[i].func)(res, buf);
}
@ -2120,7 +2120,7 @@ void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) {
LightGetHSB(&hue, &sat, nullptr);
LightGetXY(&XY[0], &XY[1]);
uint16_t uxy[2];
for (uint32_t i = 0; i < ARRAY_SIZE(XY); i++) {
for (uint32_t i = 0; i < nitems(XY); i++) {
uxy[i] = XY[i] * 65536.0f;
uxy[i] = (uxy[i] > 0xFEFF) ? uxy[i] : 0xFEFF;
}

View File

@ -622,7 +622,7 @@ void ZbSendRead(JsonParserToken val_attr, ZCLMessage & zcl) {
bool found = false;
// scan attributes to find by name, and retrieve type
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
for (uint32_t i = 0; i < nitems(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
uint16_t local_attr_id = pgm_read_word(&converter->attribute);
uint16_t local_cluster_id = CxToCluster(pgm_read_byte(&converter->cluster_short));
@ -1463,7 +1463,7 @@ void CmndZbPermitJoin(void) {
}
if (0 == zigbee.permit_end_time) { zigbee.permit_end_time = 1; } // avoid very rare case where timer collides with timestamp equals to zero
}
ResponseCmndDone();
}

View File

@ -62,15 +62,15 @@ void TCPLoop(void)
if ((server_tcp) && (server_tcp->hasClient())) {
// find an empty slot
uint32_t i;
for (i=0; i<ARRAY_SIZE(client_tcp); i++) {
for (i=0; i<nitems(client_tcp); i++) {
WiFiClient &client = client_tcp[i];
if (!client) {
client = server_tcp->available();
break;
}
}
if (i >= ARRAY_SIZE(client_tcp)) {
i = client_next++ % ARRAY_SIZE(client_tcp);
if (i >= nitems(client_tcp)) {
i = client_next++ % nitems(client_tcp);
WiFiClient &client = client_tcp[i];
client.stop();
client = server_tcp->available();
@ -92,14 +92,14 @@ void TCPLoop(void)
if (buf_len > 0) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_TCP "from MCU: %*_H"), buf_len, tcp_buf);
for (uint32_t i=0; i<ARRAY_SIZE(client_tcp); i++) {
for (uint32_t i=0; i<nitems(client_tcp); i++) {
WiFiClient &client = client_tcp[i];
if (client) { client.write(tcp_buf, buf_len); }
}
}
// handle data received from TCP
for (uint32_t i=0; i<ARRAY_SIZE(client_tcp); i++) {
for (uint32_t i=0; i<nitems(client_tcp); i++) {
WiFiClient &client = client_tcp[i];
buf_len = 0;
while (client && (buf_len < TCP_BRIDGE_BUF_SIZE) && (client.available())) {
@ -152,7 +152,7 @@ void CmndTCPStart(void) {
delete server_tcp;
server_tcp = nullptr;
for (uint32_t i=0; i<ARRAY_SIZE(client_tcp); i++) {
for (uint32_t i=0; i<nitems(client_tcp); i++) {
WiFiClient &client = client_tcp[i];
client.stop();
}

View File

@ -0,0 +1,323 @@
/*
xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
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/>.
*/
#ifdef USE_BERRY
#include <berry.h>
#include <Wire.h>
/*********************************************************************************************\
* Native functions mapped to Berry functions
*
* log(msg:string [,log_level:int]) ->nil
*
* import tasmota
*
* tasmota.getfreeheap() -> int
* tasmota.publish(topic:string, payload:string[, retain:bool]) -> nil
* tasmota.cmd(command:string) -> string
* tasmota.getoption(index:int) -> int
* tasmota.millis([delay:int]) -> int
* tasmota.timereached(timer:int) -> bool
* tasmota.yield() -> nil
*
\*********************************************************************************************/
extern "C" {
// Berry: `tasmota.publish(topic, payload [,retain]) -> nil``
//
int32_t l_publish(struct bvm *vm);
int32_t l_publish(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { // 2 mandatory string arguments
if (top == 2 || (top == 3 && be_isbool(vm, 3))) { // 3rd optional argument must be bool
const char * topic = be_tostring(vm, 1);
const char * payload = be_tostring(vm, 2);
bool retain = false;
if (top == 3) {
retain = be_tobool(vm, 3);
}
strlcpy(TasmotaGlobal.mqtt_data, payload, sizeof(TasmotaGlobal.mqtt_data));
MqttPublish(topic, retain);
be_return(vm); // Return
}
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `tasmota.cmd(command:string) -> string`
//
int32_t l_cmd(struct bvm *vm);
int32_t l_cmd(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted
const char * command = be_tostring(vm, 1);
ExecuteCommand(command, SRC_BERRY);
be_pushstring(vm, TasmotaGlobal.mqtt_data);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: tasmota.millis([delay:int]) -> int
//
int32_t l_millis(struct bvm *vm);
int32_t l_millis(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 0 || (top == 1 && be_isint(vm, 1))) { // only 1 argument of type string accepted
uint32_t delay = 0;
if (top == 1) {
delay = be_toint(vm, 1);
}
uint32_t ret_millis = millis() + delay;
be_pushint(vm, ret_millis);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: tasmota.getoption(index:int) -> int
//
int32_t l_getoption(struct bvm *vm);
int32_t l_getoption(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1 && be_isint(vm, 1)) {
uint32_t opt = GetOption(be_toint(vm, 1));
be_pushint(vm, opt);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: tasmota.timereached(timer:int) -> bool
//
int32_t l_timereached(struct bvm *vm);
int32_t l_timereached(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted
uint32_t timer = be_toint(vm, 1);
bool reached = TimeReached(timer);
be_pushbool(vm, reached);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `yield() -> nil`
// ESP object
int32_t l_yield(bvm *vm);
int32_t l_yield(bvm *vm) {
optimistic_yield(10);
be_return(vm);
}
// Berry: `save(file:string, f:closure) -> bool`
int32_t l_save(struct bvm *vm);
int32_t l_save(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top ==2 && be_isstring(vm, 1) && be_isclosure(vm, 2)) { // only 1 argument of type string accepted
const char *fname = be_tostring(vm, 1);
int32_t ret = be_savecode(vm, fname);
be_pushint(vm, ret);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
int32_t l_respCmnd(bvm *vm);
int32_t l_respCmnd(bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1) {
const char *msg = be_tostring(vm, 1);
Response_P("%s", msg);
}
be_return_nil(vm); // Return nil when something goes wrong
}
int32_t l_respCmndStr(bvm *vm);
int32_t l_respCmndStr(bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1) {
const char *msg = be_tostring(vm, 1);
ResponseCmndChar(msg);
}
be_return_nil(vm); // Return nil when something goes wrong
}
int32_t l_respCmndDone(bvm *vm);
int32_t l_respCmndDone(bvm *vm) {
ResponseCmndDone();
be_return_nil(vm);
}
int32_t l_respCmndError(bvm *vm);
int32_t l_respCmndError(bvm *vm) {
ResponseCmndError();
be_return_nil(vm);
}
int32_t l_respCmndFailed(bvm *vm);
int32_t l_respCmndFailed(bvm *vm) {
ResponseCmndFailed();
be_return_nil(vm);
}
}
/*********************************************************************************************\
* Native functions mapped to Berry functions
*
* import wire
*
* wire.getfreeheap() -> int
*
\*********************************************************************************************/
extern "C" {
// Berry: `begintransmission(address:int) -> nil`
int32_t b_wire_begintransmission(struct bvm *vm);
int32_t b_wire_begintransmission(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted
int32_t address = be_toint(vm, 1);
Wire.beginTransmission(address);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `endtransmission([stop:bool]) -> nil`
int32_t b_wire_endtransmission(struct bvm *vm);
int32_t b_wire_endtransmission(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 0 || (top == 1 && be_isbool(vm, 1))) { // only 1 argument of type string accepted
bool stop = true;
if (top == 1) {
stop = be_tobool(vm, 1);
}
uint32_t ret = Wire.endTransmission(stop);
be_pushint(vm, ret);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `requestfrom(address:int, quantity:int [stop:bool = true]) -> nil`
int32_t b_wire_requestfrom(struct bvm *vm);
int32_t b_wire_requestfrom(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if ( (top == 2 || (top == 3 && be_isbool(vm, 3)))
&& be_isint(vm, 1) && be_isint(vm, 2) ) {
int32_t address = be_toint(vm, 1);
int32_t quantity = be_toint(vm, 2);
bool stop = true;
if (top == 3) {
stop = be_tobool(vm, 3);
}
Wire.requestFrom((uint16_t)address, (uint8_t)quantity, stop);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `available() -> bool`
int32_t b_wire_available(struct bvm *vm);
int32_t b_wire_available(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 0) {
size_t available = Wire.available();
be_pushint(vm, available);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `write(value:int | s:string) -> nil`
int32_t b_wire_write(struct bvm *vm);
int32_t b_wire_write(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1 && (be_isint(vm, 1) || be_isint(vm, 1))) {
if (be_isint(vm, 1)) {
int32_t value = be_toint(vm, 1);
Wire.write(value);
} else if (be_isstring(vm, 1)) {
const char * s = be_tostring(vm, 1);
Wire.write(s);
} else {
be_return_nil(vm);
}
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `read() -> int`
int32_t b_wire_read(struct bvm *vm);
int32_t b_wire_read(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 0) {
int32_t value = Wire.read();
be_pushint(vm, value);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
}
/*********************************************************************************************\
* Native functions mapped to Berry functions
*
* log(msg:string [,log_level:int]) ->nil
*
\*********************************************************************************************/
extern "C" {
// Berry: `log(msg:string [,log_level:int]) ->nil`
// Logs the string at LOG_LEVEL_INFO (loglevel=2)
int32_t l_logInfo(struct bvm *vm);
int32_t l_logInfo(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top >= 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted
const char * msg = be_tostring(vm, 1);
uint32_t log_level = LOG_LEVEL_INFO;
if (top >= 2 && be_isint(vm, 2)) {
log_level = be_toint(vm, 2);
if (log_level > LOG_LEVEL_DEBUG_MORE) { log_level = LOG_LEVEL_DEBUG_MORE; }
}
AddLog(log_level, PSTR("%s"), msg);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `getFreeHeap() -> int`
// ESP object
int32_t l_getFreeHeap(bvm *vm);
int32_t l_getFreeHeap(bvm *vm) {
be_pushint(vm, ESP.getFreeHeap());
be_return(vm);
}
}
// called as a replacement to Berry `print()`
void berry_log(const char * berry_buf);
void berry_log(const char * berry_buf) {
AddLog(LOG_LEVEL_INFO, PSTR("%s"), berry_buf);
}
#endif // USE_BERRY

View File

@ -0,0 +1,281 @@
/*
xdrv_52_3_berry_embedded.ino - Berry scripting language, embedded code
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
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/>.
*/
#ifdef USE_BERRY
/*********************************************************************************************\
* Handlers for Berry calls and async
*
\*********************************************************************************************/
const char berry_prog[] =
""
//"def func(x) for i:1..x print('a') end end "
//"def testreal() return str(1.2+1) end "
//"def noop() log('noop before'); yield(); log('middle after'); yield(); log('noop after'); end "
//"log(\"foobar\") "
// auto-import modules
// // import alias
"import wire "
// Phase 1
// Prepare the super class that will be eventually in Flash
"class Tasmota_ntv "
"var _op, _operators, _rules, _timers, _cmd "
// Map all native functions to methods
// Again, this will be eventually pre-compiled
"var getfreeheap, publish, cmd, getoption, millis, timereached, yield "
"var respcmnd, respcmndstr, respcmnd_done, respcmnd_error, respcmnd_failed "
"def init_ntv() "
"import tasmota_ntv "
"self.getfreeheap = tasmota_ntv.getfreeheap "
"self.publish = tasmota_ntv.publish "
"self.cmd = tasmota_ntv.cmd "
"self.getoption = tasmota_ntv.getoption "
"self.millis = tasmota_ntv.millis "
"self.timereached = tasmota_ntv.timereached "
"self.yield = tasmota_ntv.yield "
"self._operators = tasmota_ntv._operators "
"self.respcmnd = tasmota_ntv.respcmnd "
"self.respcmndstr = tasmota_ntv.respcmndstr "
"self.respcmnd_done = tasmota_ntv.respcmnd_done "
"self.respcmnd_error = tasmota_ntv.respcmnd_error "
"self.respcmnd_failed = tasmota_ntv.respcmnd_failed "
"end "
"def init() "
"self._op = [ "
"['==', /s1,s2-> str(s1) == str(s2)],"
"['!==',/s1,s2-> str(s1) != str(s2)],"
"['=', /f1,f2-> real(f1) == real(f2)],"
"['!=', /f1,f2-> real(f1) != real(f2)],"
"['>=', /f1,f2-> real(f1) >= real(f2)],"
"['<=', /f1,f2-> real(f1) <= real(f2)],"
"['>', /f1,f2-> real(f1) > real(f2)],"
"['<', /f1,f2-> real(f1) < real(f2)],"
"] "
"self._rules = {} "
"self._timers = [] "
"self._cmd = {} "
"self.init_ntv() "
"end "
"end "
"class Tasmota: Tasmota_ntv "
// add `charsinstring(s:string,c:string) -> int``
// looks for any char in c, and return the position of the first chat
// or -1 if not found
"def charsinstring(s,c) "
"for i:0..size(s)-1 "
"for j:0..size(c)-1 "
"if s[i] == c[j] return i end "
"end "
"end "
"return -1 "
"end "
// find a key in map, case insensitive, return actual key or nil if not found
"def findkeyi(m,keyi) "
"import string "
"var keyu = string.toupper(keyi) "
"if classof(m) == map "
"for k:m.keys() "
"if string.toupper(k)==keyu || keyi=='?' "
"return k "
"end "
"end "
"end "
"end "
// Rules
"def addrule(pat,f) self._rules[pat] = f end "
// # split the item when there is an operator, returns a list of (left,op,right)
// # ex: "Dimmer>50" -> ["Dimmer",tasmota_gt,"50"]
"def find_op(item) "
"import string "
"var pos = self.charsinstring(item, self._operators) "
"if pos>=0 "
"var op_split = string.split(item,pos) "
// #print(op_split)
"var op_left = op_split[0] "
"var op_rest = op_split[1] "
// # iterate through operators
"for op: self._op "
"if string.find(op_rest,op[0]) == 0 "
"var op_func = op[1] "
"var op_right = string.split(op_rest,size(op[0]))[1] "
"return [op_left,op_func,op_right] "
"end "
"end "
"end "
"return [item, nil, nil] "
"end "
// Rules trigger if match. return true if match, false if not
// Note: condition is not yet managed
"def try_rule(ev, rule, f) "
"import string "
"var rl_list = self.find_op(rule) "
"var e=ev "
"var rl=string.split(rl_list[0],'#') "
"for it:rl "
"found=self.findkeyi(e,it) "
"if found == nil "
"return false "
"end "
"e=e[found] "
"end "
// # check if condition is true
"if rl_list[1] "
// # did we find a function
"if !rl_list[1](e,rl_list[2]) "
// # condition is not met
"return false "
"end "
"end "
"f(e,ev) "
"return true "
"end "
// Run rules, i.e. check each individual rule
// Returns true if at least one rule matched, false if none
"def exec_rules(ev_json) "
"import json "
"var ev = json.load(ev_json) "
"var ret = false "
"if ev == nil "
"print('BRY: ERROR, bad json: '+ev_json, 3) "
"else "
"for r: self._rules.keys() "
"ret = self.try_rule(ev,r,self._rules[r]) || ret "
"end "
"end "
"return ret "
"end "
"def settimer(delay,f) self._timers.push([self.millis(delay),f]) end "
"def run_deferred() "
"var i=0 "
"while i<self._timers.size() "
"if self.timereached(self._timers[i][0]) "
"f=self._timers[i][1] "
"self._timers.remove(i) "
"f() "
"else "
"i=i+1 "
"end "
"end "
"end "
// Delay function, internally calls yield() every 10ms to avoid WDT
"def delay(ms) "
"var tend = self.millis(ms) "
"while !self.timereached(tend) "
"self.yield() "
"end "
"end "
// Add command to list
"def addcommand(c,f) "
"self._cmd[c]=f "
"end "
"def exec_cmd(cmd, idx, payload) "
"import json "
"var payload_json = json.load(payload) "
"var cmd_found = self.findkeyi(self._cmd, cmd) "
"if cmd_found != nil "
"return self._cmd[cmd_found](cmd_found, idx, payload, payload_json) "
"end "
"end "
// Force gc and return allocated memory
"def gc() "
"import gc "
"gc.collect() "
"return gc.allocated() "
"end "
"end "
// Instantiate tasmota object
"tasmota = Tasmota() "
// Not sure how to run call methods from C
"def _exec_rules(e) return tasmota.exec_rules(e) end "
"def _run_deferred() return tasmota.run_deferred() end "
"def _exec_cmd(cmd, idx, payload) return tasmota.exec_cmd(cmd, idx, payload) end "
"def _gc() return tasmota.gc() end "
// simple wrapper to load a file
// prefixes '/' if needed, and simpler to use than `compile()`
"def load(f) "
"import string "
"try "
// check that the file ends with '.be' of '.bec'
"var fl = string.split(f,'.') "
"if (size(fl) <= 1 || (fl[-1] != 'be' && fl[-1] != 'bec')) "
"raise \"file extension is not '.be' or '.bec'\" "
"end "
"var native = f[size(f)-1] == 'c' "
// add prefix if needed
"if f[0] != '/' f = '/' + f end "
// load - works the same for .be and .bec
"var c = compile(f,'file') "
// save the compiled bytecode
"if !native "
"save(f+'c', c) "
"end "
// call the compiled code
"c() "
"except .. as e "
"log(string.format(\"BRY: could not load file '%s' - %s\",f,e)) "
"end "
"end "
// try to load "/autoexec.be"
// "try compile('/autoexec.be','file')() except .. log('BRY: no /autoexec.bat file') end "
// Wire
"wire.validread = def(addr, reg, size) "
"var ret = nil "
"for i:0..2 "
"wire.begintransmission(addr) "
"wire.write(reg) "
"if wire.endtransmission(false) == 0 "
"wire.requestfrom(addr, size) "
"if wire.available() == size "
"for j:0..size-1 "
"ret = ((ret != nil ? ret : 0) << 8) + wire.read() "
"end "
"return ret "
"end "
"end "
"end "
"wire.endtransmission() "
"end "
;
#endif // USE_BERRY

354
tasmota/xdrv_52_9_berry.ino Normal file
View File

@ -0,0 +1,354 @@
/*
xdrv_52_9_berry.ino - Berry scripting language
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
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/>.
*/
#ifdef USE_BERRY
#define XDRV_52 52
#include <berry.h>
const char kBrCommands[] PROGMEM = D_PRFX_BR "|" // prefix
D_CMND_BR_RUN "|" D_CMND_BR_RESET
;
void (* const BerryCommand[])(void) PROGMEM = {
CmndBrRun, CmndBrReset,
};
class BerrySupport {
public:
bvm *vm = nullptr; // berry vm
bool rules_busy = false; // are we already processing rules, avoid infinite loop
const char *fname = nullptr; // name of berry function to call
int32_t fret = 0;
};
BerrySupport berry;
//
// Sanity Check for be_top()
//
// Checks that the Berry stack is empty, if not print a Warning and empty it
//
void checkBeTop(void) {
int32_t top = be_top(berry.vm);
if (top != 0) {
be_pop(berry.vm, top); // TODO should not be there
AddLog(LOG_LEVEL_ERROR, D_LOG_BERRY "Error be_top is non zero=%d", top);
}
}
/*********************************************************************************************\
* Handlers for Berry calls and async
*
\*********************************************************************************************/
// // call a function (if exists) of type void -> void
// void callBerryFunctionVoid_berry(const char * fname) {
// berry.fret = 0;
// callBerryFunctionVoid(berry.fname);
// }
bool callBerryRule(void) {
if (berry.rules_busy) { return false; }
berry.rules_busy = true;
char * json_event = TasmotaGlobal.mqtt_data;
bool serviced = false;
checkBeTop();
be_getglobal(berry.vm, "_exec_rules");
if (!be_isnil(berry.vm, -1)) {
// {
// String event_saved = TasmotaGlobal.mqtt_data;
// // json_event = {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}}
// // json_event = {"System":{"Boot":1}}
// // json_event = {"SerialReceived":"on"} - invalid but will be expanded to {"SerialReceived":{"Data":"on"}}
// char *p = strchr(json_event, ':');
// if ((p != NULL) && !(strchr(++p, ':'))) { // Find second colon
// event_saved.replace(F(":"), F(":{\"Data\":"));
// event_saved += F("}");
// // event_saved = {"SerialReceived":{"Data":"on"}}
// }
// be_pushstring(berry.vm, event_saved.c_str());
// }
be_pushstring(berry.vm, TasmotaGlobal.mqtt_data);
int ret = be_pcall(berry.vm, 1);
serviced = be_tobool(berry.vm, 1);
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Event (%s) serviced=%d"), TasmotaGlobal.mqtt_data, serviced);
be_pop(berry.vm, 2); // remove function object
} else {
be_pop(berry.vm, 1); // remove nil object
}
checkBeTop();
berry.rules_busy = false;
return serviced; // TODO event not handled
}
bool callBerryCommand(void) {
const char * command = nullptr;
checkBeTop();
be_getglobal(berry.vm, "_exec_cmd");
if (!be_isnil(berry.vm, -1)) {
be_pushstring(berry.vm, XdrvMailbox.topic);
be_pushint(berry.vm, XdrvMailbox.index);
be_pushstring(berry.vm, XdrvMailbox.data);
int ret = be_pcall(berry.vm, 3);
command = be_tostring(berry.vm, 3);
strlcpy(XdrvMailbox.topic, command, CMDSZ);
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Command (%s) serviced=%d"), XdrvMailbox.command, serviced);
be_pop(berry.vm, 4); // remove function object
} else {
be_pop(berry.vm, 1); // remove nil object
}
checkBeTop();
return command != nullptr; // TODO event not handled
}
size_t callBerryGC(void) {
size_t ram_used = 0;
checkBeTop();
be_getglobal(berry.vm, "_gc");
if (!be_isnil(berry.vm, -1)) {
int ret = be_pcall(berry.vm, 0);
ram_used = be_toint(berry.vm, 1);
be_pop(berry.vm, 1); // remove function object
} else {
be_pop(berry.vm, 1); // remove nil object
}
checkBeTop();
return ram_used;
}
// void callBerryMqttData(void) {
// AddLog(LOG_LEVEL_INFO, D_LOG_BERRY "callBerryMqttData");
// if (nullptr == berry.vm) { return; }
// if (XdrvMailbox.data_len < 1) {
// return;
// }
// const char * topic = XdrvMailbox.topic;
// const char * payload = XdrvMailbox.data;
// checkBeTop();
// be_getglobal(berry.vm, "mqtt_data_dispatch");
// if (!be_isnil(berry.vm, -1)) {
// be_pushstring(berry.vm, topic);
// be_pushstring(berry.vm, payload);
// be_pcall(berry.vm, 0);
// be_pop(berry.vm, 3); // remove function object
// } else {
// be_pop(berry.vm, 1); // remove nil object
// }
// checkBeTop();
// }
// call a function (if exists) of type void -> void
void callBerryFunctionVoid(const char * fname) {
if (nullptr == berry.vm) { return; }
checkBeTop();
be_getglobal(berry.vm, fname);
if (!be_isnil(berry.vm, -1)) {
be_pcall(berry.vm, 0);
}
be_pop(berry.vm, 1); // remove function or nil object
checkBeTop();
}
/*********************************************************************************************\
* VM Init
\*********************************************************************************************/
extern "C" {
extern size_t be_gc_memcount(bvm *vm);
extern void be_gc_collect(bvm *vm);
}
void BrReset(void) {
// clean previous VM if any
if (berry.vm != nullptr) {
be_vm_delete(berry.vm);
berry.vm = nullptr;
}
int32_t ret_code1, ret_code2;
bool berry_init_ok = false;
do {
berry.vm = be_vm_new(); /* create a virtual machine instance */
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry VM created, RAM used=%u"), be_gc_memcount(berry.vm));
// Register functions
be_regfunc(berry.vm, PSTR("log"), l_logInfo);
be_regfunc(berry.vm, PSTR("save"), l_save);
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry function registered, RAM used=%u"), be_gc_memcount(berry.vm));
ret_code1 = be_loadstring(berry.vm, berry_prog);
if (ret_code1 != 0) {
AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_loadstring [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
be_pop(berry.vm, 2);
break;
}
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code loaded, RAM used=%u"), be_gc_memcount(berry.vm));
ret_code2 = be_pcall(berry.vm, 0);
if (ret_code1 != 0) {
AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_pcall [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
be_pop(berry.vm, 2);
break;
}
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code ran, RAM used=%u"), be_gc_memcount(berry.vm));
be_pop(berry.vm, 1);
be_gc_collect(berry.vm);
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_BERRY "Berry initialized, RAM used=%u"), callBerryGC());
// AddLog(LOG_LEVEL_INFO, PSTR("Delete Berry VM"));
// be_vm_delete(vm);
// AddLog(LOG_LEVEL_INFO, PSTR("After Berry"));
berry_init_ok = true;
} while (0);
if (!berry_init_ok) {
// free resources
if (berry.vm != nullptr) {
be_vm_delete(berry.vm);
berry.vm = nullptr;
}
}
}
/*********************************************************************************************\
* Tasmota Commands
\*********************************************************************************************/
//
// Command `BrRun`
//
void CmndBrRun(void) {
int32_t ret_code;
const char * ret_type, * ret_val;
if (berry.vm == nullptr) { ResponseCmndChar_P(PSTR(D_BR_NOT_STARTED)); return; }
char br_cmd[XdrvMailbox.data_len+12];
// encapsulate into a function, copied from `be_repl.c` / `try_return()`
snprintf_P(br_cmd, sizeof(br_cmd), PSTR("return (%s)"), XdrvMailbox.data);
checkBeTop();
do {
// First try with the `return ()` wrapper
ret_code = be_loadbuffer(berry.vm, PSTR("input"), br_cmd, strlen(br_cmd));
if (be_getexcept(berry.vm, ret_code) == BE_SYNTAX_ERROR) {
be_pop(berry.vm, 2); // remove exception values
// if fails, try the direct command
ret_code = be_loadbuffer(berry.vm, PSTR("input"), XdrvMailbox.data, strlen(XdrvMailbox.data));
}
if (0 != ret_code) break;
ret_code = be_pcall(berry.vm, 0); // execute code
} while (0);
if (0 == ret_code) {
// code taken from REPL, look first at top, and if nil, look at return value
if (be_isnil(berry.vm, 0)) {
ret_val = be_tostring(berry.vm, -1);
} else {
ret_val = be_tostring(berry.vm, 0);
}
Response_P("{\"" D_PRFX_BR "\":\"%s\"}", ret_val); // can't use XdrvMailbox.command as it may have been overwritten by subcommand
be_pop(berry.vm, 1);
} else {
Response_P(PSTR("{\"" D_PRFX_BR "\":\"[%s] %s\"}"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
be_pop(berry.vm, 2);
}
checkBeTop();
}
//
// Command `BrReset`
//
void CmndBrReset(void) {
if (berry.vm == nullptr) { ResponseCmndChar_P(PSTR(D_BR_NOT_STARTED)); return; }
BrReset();
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv52(uint8_t function)
{
bool result = false;
switch (function) {
//case FUNC_PRE_INIT:
case FUNC_INIT:
BrReset();
break;
case FUNC_EVERY_50_MSECOND:
callBerryFunctionVoid(PSTR("_run_deferred"));
break;
case FUNC_EVERY_100_MSECOND:
callBerryFunctionVoid(PSTR("every_100ms"));
break;
case FUNC_EVERY_SECOND:
callBerryFunctionVoid(PSTR("every_second"));
break;
case FUNC_COMMAND:
result = DecodeCommand(kBrCommands, BerryCommand);
if (!result) {
result = callBerryCommand();
}
break;
// case FUNC_SET_POWER:
// break;
case FUNC_RULES_PROCESS:
result = callBerryRule();
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_ADD_BUTTON:
break;
case FUNC_WEB_ADD_MAIN_BUTTON:
break;
case FUNC_WEB_ADD_HANDLER:
break;
#endif // USE_WEBSERVER
case FUNC_SAVE_BEFORE_RESTART:
break;
case FUNC_MQTT_DATA:
// callBerryMqttData();
break;
case FUNC_WEB_SENSOR:
break;
case FUNC_JSON_APPEND:
break;
case FUNC_BUTTON_PRESSED:
break;
case FUNC_LOOP:
break;
}
return result;
}
#endif // USE_BERRY

View File

@ -1,650 +0,0 @@
/*
xdrv_52_berry.ino - Berry scripting language
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
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/>.
*/
#ifdef USE_BERRY
#define XDRV_52 52
#include <berry.h>
#include <csetjmp>
const char kBrCommands[] PROGMEM = D_PRFX_BR "|" // prefix
D_CMND_BR_RUN "|" D_CMND_BR_RESET
;
void (* const BerryCommand[])(void) PROGMEM = {
CmndBrRun, CmndBrReset,
};
class BerrySupport {
public:
bvm *vm = nullptr; // berry vm
bool rules_busy = false; // are we already processing rules, avoid infinite loop
const char *fname = nullptr; // name of berry function to call
int32_t fret = 0;
};
BerrySupport berry;
//
// Sanity Check for be_top()
//
// Checks that the Berry stack is empty, if not print a Warning and empty it
//
void checkBeTop(void) {
int32_t top = be_top(berry.vm);
if (top != 0) {
be_pop(berry.vm, top); // TODO should not be there
AddLog(LOG_LEVEL_ERROR, D_LOG_BERRY "Error be_top is non zero=%d", top);
}
}
/*********************************************************************************************\
* Native functions mapped to Berry functions
*
* log(msg:string [,log_level:int]) ->nil
*
* import tasmota
*
* tasmota.getfreeheap() -> int
* tasmota.publish(topic:string, payload:string[, retain:bool]) -> nil
* tasmota.cmd(command:string) -> string
* tasmota.getoption(index:int) -> int
* tasmota.millis([delay:int]) -> int
* tasmota.timereached(timer:int) -> bool
* tasmota.yield() -> nil
*
\*********************************************************************************************/
extern "C" {
// Berry: `log(msg:string [,log_level:int]) ->nil`
// Logs the string at LOG_LEVEL_INFO (loglevel=2)
int32_t l_logInfo(struct bvm *vm);
int32_t l_logInfo(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top >= 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted
const char * msg = be_tostring(vm, 1);
uint32_t log_level = LOG_LEVEL_INFO;
if (top >= 2 && be_isint(vm, 2)) {
log_level = be_toint(vm, 2);
if (log_level > LOG_LEVEL_DEBUG_MORE) { log_level = LOG_LEVEL_DEBUG_MORE; }
}
AddLog(log_level, PSTR("%s"), msg);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `getFreeHeap() -> int`
// ESP object
int32_t l_getFreeHeap(bvm *vm);
int32_t l_getFreeHeap(bvm *vm) {
be_pushint(vm, ESP.getFreeHeap());
be_return(vm);
}
// Berry: `tasmota.publish(topic, payload [,retain]) -> nil``
//
int32_t l_publish(struct bvm *vm);
int32_t l_publish(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { // 2 mandatory string arguments
if (top == 2 || (top == 3 && be_isbool(vm, 3))) { // 3rd optional argument must be bool
const char * topic = be_tostring(vm, 1);
const char * payload = be_tostring(vm, 2);
bool retain = false;
if (top == 3) {
retain = be_tobool(vm, 3);
}
strlcpy(TasmotaGlobal.mqtt_data, payload, sizeof(TasmotaGlobal.mqtt_data));
MqttPublish(topic, retain);
be_return(vm); // Return
}
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `tasmota.cmd(command:string) -> string`
//
int32_t l_cmd(struct bvm *vm);
int32_t l_cmd(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted
const char * command = be_tostring(vm, 1);
ExecuteCommand(command, SRC_BERRY);
be_pushstring(vm, TasmotaGlobal.mqtt_data);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: tasmota.millis([delay:int]) -> int
//
int32_t l_millis(struct bvm *vm);
int32_t l_millis(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 0 || (top == 1 && be_isint(vm, 1))) { // only 1 argument of type string accepted
uint32_t delay = 0;
if (top == 1) {
delay = be_toint(vm, 1);
}
uint32_t ret_millis = millis() + delay;
be_pushint(vm, ret_millis);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: tasmota.getoption(index:int) -> int
//
int32_t l_getoption(struct bvm *vm);
int32_t l_getoption(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1 && be_isint(vm, 1)) {
uint32_t opt = GetOption(be_toint(vm, 1));
be_pushint(vm, opt);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: tasmota.timereached(timer:int) -> bool
//
int32_t l_timereached(struct bvm *vm);
int32_t l_timereached(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted
uint32_t timer = be_toint(vm, 1);
bool reached = TimeReached(timer);
be_pushbool(vm, reached);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
// Berry: `yield() -> nil`
// ESP object
int32_t l_yield(bvm *vm);
int32_t l_yield(bvm *vm) {
optimistic_yield(10);
be_return(vm);
}
// Berry: `save(file:string, f:closure) -> bool`
int32_t l_save(struct bvm *vm);
int32_t l_save(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top ==2 && be_isstring(vm, 1) && be_isclosure(vm, 2)) { // only 1 argument of type string accepted
const char *fname = be_tostring(vm, 1);
int32_t ret = be_savecode(vm, fname);
be_pushint(vm, ret);
be_return(vm); // Return
}
be_return_nil(vm); // Return nil when something goes wrong
}
}
// called as a replacement to Berry `print()`
void berry_log(const char * berry_buf);
void berry_log(const char * berry_buf) {
AddLog(LOG_LEVEL_INFO, PSTR("%s"), berry_buf);
}
/*********************************************************************************************\
* Handlers for Berry calls and async
*
\*********************************************************************************************/
// // call a function (if exists) of type void -> void
// void callBerryFunctionVoid_berry(const char * fname) {
// berry.fret = 0;
// callBerryFunctionVoid(berry.fname);
// }
bool callBerryRule(void) {
if (berry.rules_busy) { return false; }
berry.rules_busy = true;
char * json_event = TasmotaGlobal.mqtt_data;
bool serviced = false;
checkBeTop();
be_getglobal(berry.vm, "_exec_rules");
if (!be_isnil(berry.vm, -1)) {
// {
// String event_saved = TasmotaGlobal.mqtt_data;
// // json_event = {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}}
// // json_event = {"System":{"Boot":1}}
// // json_event = {"SerialReceived":"on"} - invalid but will be expanded to {"SerialReceived":{"Data":"on"}}
// char *p = strchr(json_event, ':');
// if ((p != NULL) && !(strchr(++p, ':'))) { // Find second colon
// event_saved.replace(F(":"), F(":{\"Data\":"));
// event_saved += F("}");
// // event_saved = {"SerialReceived":{"Data":"on"}}
// }
// be_pushstring(berry.vm, event_saved.c_str());
// }
be_pushstring(berry.vm, TasmotaGlobal.mqtt_data);
int ret = be_pcall(berry.vm, 1);
serviced = be_tobool(berry.vm, 1);
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Event (%s) serviced=%d"), TasmotaGlobal.mqtt_data, serviced);
be_pop(berry.vm, 2); // remove function object
} else {
be_pop(berry.vm, 1); // remove nil object
}
checkBeTop();
berry.rules_busy = false;
return serviced; // TODO event not handled
}
// void callBerryMqttData(void) {
// AddLog(LOG_LEVEL_INFO, D_LOG_BERRY "callBerryMqttData");
// if (nullptr == berry.vm) { return; }
// if (XdrvMailbox.data_len < 1) {
// return;
// }
// const char * topic = XdrvMailbox.topic;
// const char * payload = XdrvMailbox.data;
// checkBeTop();
// be_getglobal(berry.vm, "mqtt_data_dispatch");
// if (!be_isnil(berry.vm, -1)) {
// be_pushstring(berry.vm, topic);
// be_pushstring(berry.vm, payload);
// be_pcall(berry.vm, 0);
// be_pop(berry.vm, 3); // remove function object
// } else {
// be_pop(berry.vm, 1); // remove nil object
// }
// checkBeTop();
// }
// call a function (if exists) of type void -> void
void callBerryFunctionVoid(const char * fname) {
if (nullptr == berry.vm) { return; }
checkBeTop();
be_getglobal(berry.vm, fname);
if (!be_isnil(berry.vm, -1)) {
be_pcall(berry.vm, 0);
}
be_pop(berry.vm, 1); // remove function or nil object
checkBeTop();
}
/*********************************************************************************************\
* Handlers for Berry calls and async
*
\*********************************************************************************************/
const char berry_prog[] PROGMEM =
""
//"def func(x) for i:1..x print('a') end end "
//"def testreal() return str(1.2+1) end "
//"def noop() log('noop before'); yield(); log('middle after'); yield(); log('noop after'); end "
//"log(\"foobar\") "
// auto-import modules
"import string "
"import json "
"import gc "
"import tasmota "
// import alias
"import tasmota as t "
// add `charsinstring(s:string,c:string) -> int``
// looks for any char in c, and return the position of the first chat
// or -1 if not found
"def charsinstring(s,c) "
"for i:0..size(s)-1 "
"for j:0..size(c)-1 "
"if s[i] == c[j] return i end "
"end "
"end "
"return -1 "
"end "
// find a key in map, case insensitive, return actual key or nil if not found
"def findkeyi(m,keyi) "
"var keyu = string.toupper(keyi) "
"if classof(m) == map "
"for k:m.keys() "
"if string.toupper(k)==keyu || keyi=='?' "
"return k "
"end "
"end "
"end "
"end "
// Rules
"tasmota._operators='=<>!' " // operators used in rules
// Rules comparisong functions
"tasmota._eqstr=/s1,s2-> str(s1) == str(s2) "
"tasmota._neqstr=/s1,s2-> str(s1) != str(s2) "
"tasmota._eq=/f1,f2-> real(f1) == real(f2) "
"tasmota._neq=/f1,f2-> real(f1) != real(f2) "
"tasmota._gt=/f1,f2-> real(f1) > real(f2) "
"tasmota._lt=/f1,f2-> real(f1) < real(f2) "
"tasmota._ge=/f1,f2-> real(f1) >= real(f2) "
"tasmota._le=/f1,f2-> real(f1) <= real(f2) "
"tasmota._op=["
"['==',tasmota._eqstr],"
"['!==',tasmota._neqstr],"
"['=',tasmota._eq],"
"['!=',tasmota._neq],"
"['>=',tasmota._ge],"
"['<=',tasmota._le],"
"['>',tasmota._gt],"
"['<',tasmota._lt],"
"] "
"tasmota_rules={} "
"tasmota.rule = def(pat,f) tasmota_rules[pat] = f end "
// # split the item when there is an operator, returns a list of (left,op,right)
// # ex: "Dimmer>50" -> ["Dimmer",tasmota_gt,"50"]
"tasmota.find_op = def (item) "
"var pos = charsinstring(item, tasmota._operators) "
"if pos>=0 "
"var op_split = string.split(item,pos) "
// #print(op_split)
"var op_left = op_split[0] "
"var op_rest = op_split[1] "
// # iterate through operators
"for op:tasmota._op "
"if string.find(op_rest,op[0]) == 0 "
"var op_func = op[1] "
"var op_right = string.split(op_rest,size(op[0]))[1] "
"return [op_left,op_func,op_right] "
"end "
"end "
"end "
"return [item, nil, nil] "
"end "
// Rules trigger if match. return true if match, false if not
// Note: condition is not yet managed
"tasmota.try_rule = def (ev, rule, f) "
"var rl_list = tasmota.find_op(rule) "
"var e=ev "
"var rl=string.split(rl_list[0],'#') "
"for it:rl "
"found=findkeyi(e,it) "
"if found == nil "
"return false "
"end "
"e=e[found] "
"end "
// # check if condition is true
"if rl_list[1] "
// # did we find a function
"if !rl_list[1](e,rl_list[2]) "
// # condition is not met
"return false "
"end "
"end "
"f(e,ev) "
"return true "
"end "
// Run rules, i.e. check each individual rule
// Returns true if at least one rule matched, false if none
"tasmota.exec_rules = def (ev_json) "
"var ev = json.load(ev_json) "
"var ret = false "
"if ev == nil "
"log('BRY: ERROR, bad json: '+ev_json, 3) "
"end "
"for r:tasmota_rules.keys() "
"ret = tasmota.try_rule(ev,r,tasmota_rules[r]) || ret "
"end "
"return ret "
"end "
// Not sure how to run `tasmota.exec_rules` from C code, so alias with `_exec_rules()``
"def _exec_rules(e) return tasmota.exec_rules(e) end "
// Timers
"tasmota_timers=[] "
"tasmota.timer = def (delay,f) tasmota_timers.push([tasmota.millis(delay),f]) end "
"def _run_deferred() "
"var i=0 "
"while i<tasmota_timers.size() "
"if tasmota.timereached(tasmota_timers[i][0]) "
"f=tasmota_timers[i][1] "
"tasmota_timers.remove(i) "
"f() "
"else "
"i=i+1 "
"end "
"end "
"end "
// Delay function, internally calls yield() every 10ms to avoid WDT
"tasmota.delay = def(ms) "
"var tend = tasmota.millis(ms) "
"while !tasmota.timereached(tend) "
"tasmota.yield() "
"end "
"end "
// simple wrapper to load a file
// prefixes '/' if needed, and simpler to use than `compile()`
"def load(f) "
"try "
// check that the file ends with '.be' of '.bec'
"var fl = string.split(f,'.') "
"if (size(fl) <= 1 || (fl[-1] != 'be' && fl[-1] != 'bec')) "
"raise \"file extension is not '.be' or '.bec'\" "
"end "
"var native = f[size(f)-1] == 'c' "
// add prefix if needed
"if f[0] != '/' f = '/' + f end "
// load - works the same for .be and .bec
"var c = compile(f,'file') "
// save the compiled bytecode
"if !native "
"save(f+'c', c) "
"end "
// call the compiled code
"c() "
"except .. as e "
"log(string.format(\"BRY: could not load file '%s' - %s\",f,e)) "
"end "
"end "
// try to load "/autoexec.be"
// "try compile('/autoexec.be','file')() except .. log('BRY: no /autoexec.bat file') end "
// trigger Garbage Collector
"gc.collect() "
;
/*********************************************************************************************\
* VM Init
\*********************************************************************************************/
void BrReset(void) {
// clean previous VM if any
if (berry.vm != nullptr) {
be_vm_delete(berry.vm);
berry.vm = nullptr;
}
int32_t ret_code1, ret_code2;
bool berry_init_ok = false;
do {
uint32_t heap_before = ESP.getFreeHeap();
berry.vm = be_vm_new(); /* create a virtual machine instance */
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry VM created, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
// Register functions
be_regfunc(berry.vm, PSTR("log"), l_logInfo);
be_regfunc(berry.vm, PSTR("save"), l_save);
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry function registered, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
ret_code1 = be_loadstring(berry.vm, berry_prog);
if (ret_code1 != 0) {
AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_loadstring [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
be_pop(berry.vm, 2);
break;
}
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code loaded, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
ret_code2 = be_pcall(berry.vm, 0);
if (ret_code1 != 0) {
AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_pcall [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
be_pop(berry.vm, 2);
break;
}
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code ran, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
be_pop(berry.vm, 1);
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_BERRY "Berry initialized, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
// AddLog(LOG_LEVEL_INFO, PSTR("Delete Berry VM"));
// be_vm_delete(vm);
// AddLog(LOG_LEVEL_INFO, PSTR("After Berry"));
berry_init_ok = true;
} while (0);
if (!berry_init_ok) {
// free resources
if (berry.vm != nullptr) {
be_vm_delete(berry.vm);
berry.vm = nullptr;
}
}
}
/*********************************************************************************************\
* Tasmota Commands
\*********************************************************************************************/
//
// Command `BrRun`
//
void CmndBrRun(void) {
int32_t ret_code;
const char * ret_type, * ret_val;
if (berry.vm == nullptr) { ResponseCmndChar_P(PSTR(D_BR_NOT_STARTED)); return; }
char br_cmd[XdrvMailbox.data_len+12];
// encapsulate into a function, copied from `be_repl.c` / `try_return()`
snprintf_P(br_cmd, sizeof(br_cmd), PSTR("return (%s)"), XdrvMailbox.data);
checkBeTop();
do {
// First try with the `return ()` wrapper
ret_code = be_loadbuffer(berry.vm, PSTR("input"), br_cmd, strlen(br_cmd));
if (be_getexcept(berry.vm, ret_code) == BE_SYNTAX_ERROR) {
be_pop(berry.vm, 2); // remove exception values
// if fails, try the direct command
ret_code = be_loadbuffer(berry.vm, PSTR("input"), XdrvMailbox.data, strlen(XdrvMailbox.data));
}
if (0 != ret_code) break;
ret_code = be_pcall(berry.vm, 0); // execute code
} while (0);
if (0 == ret_code) {
// code taken from REPL, look first at top, and if nil, look at return value
if (be_isnil(berry.vm, 0)) {
ret_val = be_tostring(berry.vm, -1);
} else {
ret_val = be_tostring(berry.vm, 0);
}
Response_P("{\"" D_PRFX_BR "\":\"%s\"}", ret_val); // can't use XdrvMailbox.command as it may have been overwritten by subcommand
be_pop(berry.vm, 1);
} else {
Response_P(PSTR("{\"" D_PRFX_BR "\":\"[%s] %s\"}"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
be_pop(berry.vm, 2);
}
checkBeTop();
}
//
// Command `BrReset`
//
void CmndBrReset(void) {
if (berry.vm == nullptr) { ResponseCmndChar_P(PSTR(D_BR_NOT_STARTED)); return; }
BrReset();
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv52(uint8_t function)
{
bool result = false;
switch (function) {
//case FUNC_PRE_INIT:
case FUNC_INIT:
BrReset();
break;
case FUNC_EVERY_50_MSECOND:
callBerryFunctionVoid(PSTR("_run_deferred"));
break;
case FUNC_EVERY_100_MSECOND:
callBerryFunctionVoid(PSTR("every_100ms"));
break;
case FUNC_EVERY_SECOND:
callBerryFunctionVoid(PSTR("every_second"));
break;
case FUNC_COMMAND:
result = DecodeCommand(kBrCommands, BerryCommand);
break;
// case FUNC_SET_POWER:
// break;
case FUNC_RULES_PROCESS:
result = callBerryRule();
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_ADD_BUTTON:
break;
case FUNC_WEB_ADD_MAIN_BUTTON:
break;
case FUNC_WEB_ADD_HANDLER:
break;
#endif // USE_WEBSERVER
case FUNC_SAVE_BEFORE_RESTART:
break;
case FUNC_MQTT_DATA:
// callBerryMqttData();
break;
case FUNC_WEB_SENSOR:
break;
case FUNC_JSON_APPEND:
break;
case FUNC_BUTTON_PRESSED:
break;
case FUNC_LOOP:
break;
}
return result;
}
#endif // USE_BERRY

View File

@ -0,0 +1,66 @@
#ifndef _XDRV53_PROJECTOR_CTRL_H_
#define _XDRV53_PROJECTOR_CTRL_H_
//define RELAY that is forced ON while projector is running
#ifndef PROJECTOR_CTRL_PWR_BY_RELAY
#define PROJECTOR_CTRL_PWR_BY_RELAY 1
#endif //PROJECTOR_CTRL_PWR_BY_RELAY
#define PROJECTOR_CTRL_SERIAL_TIMEOUT 10 //up to 254 seconds
#define PROJECTOR_CTRL_SERIAL_BAUDRATE 9600
#ifdef USE_PROJECTOR_CTRL_NEC
/* see the serial codes in
* https://www.sharpnecdisplays.eu/p/download/v/5e14a015e26cacae3ae64a422f7f8af4/cp/Products/Projectors/Shared/CommandLists/PDF-ExternalControlManual-english.pdf#page=5
* tested with NEC V300W
* final cksum byte is appended automatically
*/
#define PROJECTOR_CTRL_LOGNAME "DLP[NEC]"
static const uint8_t projector_ctrl_msg_qry_typ[] = { 0x00, 0xBF, 0x00, 0x00, 0x01, 0x00 }; //page81
static const uint8_t projector_ctrl_msg_qry_pwr[] = { 0x00, 0xBF, 0x00, 0x00, 0x01, 0x02 }; //page83
static const uint8_t projector_ctrl_msg_pwr_on[] = { 0x02, 0x00, 0x00, 0x00, 0x00 }; //page15
static const uint8_t projector_ctrl_msg_pwr_off[] = { 0x02, 0x01, 0x00, 0x00, 0x00 }; //page16
static const struct projector_ctrl_command_info_s projector_ctrl_commands[] = {
{PROJECTOR_CTRL_S_QRY_TYPE, &projector_ctrl_msg_qry_typ[0], sizeof(projector_ctrl_msg_qry_typ),
PROJECTOR_CTRL_SERIAL_TIMEOUT, 0x20, 22, 8, 4, 0xA0, 8, 5, 2},
{PROJECTOR_CTRL_S_QRY_PWR, &projector_ctrl_msg_qry_pwr[0], sizeof(projector_ctrl_msg_qry_pwr),
PROJECTOR_CTRL_SERIAL_TIMEOUT, 0x20, 22, 6, 1, 0xA0, 8, 5, 2},
{PROJECTOR_CTRL_S_PWR_ON, &projector_ctrl_msg_pwr_on[0], sizeof(projector_ctrl_msg_pwr_on),
PROJECTOR_CTRL_SERIAL_TIMEOUT, 0x22, 6, 0, 1, 0xA2, 8, 5, 2},
{PROJECTOR_CTRL_S_PWR_OFF, &projector_ctrl_msg_pwr_off[0], sizeof(projector_ctrl_msg_pwr_off),
PROJECTOR_CTRL_SERIAL_TIMEOUT, 0x22, 6, 0, 1, 0xA2, 8, 5, 2}
};
#define PROJECTOR_CTRL_QRYPWR_ON 0x04
#define PROJECTOR_CTRL_QRYPWR_COOLING 0x05
#elif defined(USE_PROJECTOR_CTRL_OPTOMA)
/* see the serial codes in
* https://www.optoma.co.uk/uploads/manuals/hd36-m-en-gb.pdf#page=56
* not really tested with OPTOMA devices
*/
#define PROJECTOR_CTRL_LOGNAME "DLP[OPTOMA]"
static const uint8_t projector_ctrl_msg_qry_typ[] = { 0x7e, 0x30, 0x30, 0x31, 0x32, 0x32, 0x20, 0x31, 0x0d }; //page59
static const uint8_t projector_ctrl_msg_qry_pwr[] = { 0x7e, 0x30, 0x30, 0x31, 0x32, 0x34, 0x20, 0x31, 0x0d }; //page59
static const uint8_t projector_ctrl_msg_pwr_on[] = { 0x7e, 0x30, 0x30, 0x30, 0x30, 0x20, 0x31, 0x0d }; //page56
static const uint8_t projector_ctrl_msg_pwr_off[] = { 0x7e, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x0d }; //page56
static const struct projector_ctrl_command_info_s projector_ctrl_commands[] = {
{PROJECTOR_CTRL_S_QRY_TYPE, &projector_ctrl_msg_qry_typ[0], sizeof(projector_ctrl_msg_qry_typ),
PROJECTOR_CTRL_SERIAL_TIMEOUT, 'O', 6, 2, 4, 'I', 5, 4, 1},
{PROJECTOR_CTRL_S_QRY_PWR, &projector_ctrl_msg_qry_pwr[0], sizeof(projector_ctrl_msg_qry_pwr),
PROJECTOR_CTRL_SERIAL_TIMEOUT, 'O', 3, 2, 1, 'I', 5, 4, 1},
{PROJECTOR_CTRL_S_PWR_ON, &projector_ctrl_msg_pwr_on[0], sizeof(projector_ctrl_msg_pwr_on),
PROJECTOR_CTRL_SERIAL_TIMEOUT, 'P', 1, 0, 1, 'F', 1, 0, 1},
{PROJECTOR_CTRL_S_PWR_OFF, &projector_ctrl_msg_pwr_off[0], sizeof(projector_ctrl_msg_pwr_off),
PROJECTOR_CTRL_SERIAL_TIMEOUT, 'P', 1, 0, 1, 'F', 1, 0, 1}
};
#define PROJECTOR_CTRL_QRYPWR_ON 0x31
#define PROJECTOR_CTRL_QRYPWR_COOLING 0x31 //placebo
#else
#error USE_PROJECTOR_CTRL: No projector type defined
#endif
#endif //_XDRV53_PROJECTOR_CTRL_H_

View File

@ -0,0 +1,459 @@
/*
xdrv_53_projector_ctrl.ino - LCD/DLP Projector Serial Control support for Tasmota
Copyright (C) 2021 Jan Bubík <jbubik@centrum.cz>
Written with the gifts I got from Jesus.
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/>.
*/
#ifdef USE_PROJECTOR_CTRL
/*********************************************************************************************\
* LCD/DLP Projector Control via serial interface
* https://www.sharpnecdisplays.eu/p/download/v/5e14a015e26cacae3ae64a422f7f8af4/cp/Products/Projectors/Shared/CommandLists/PDF-ExternalControlManual-english.pdf#page=5
* https://www.optoma.co.uk/uploads/manuals/hd36-m-en-gb.pdf#page=56
\*********************************************************************************************/
#define XDRV_53 53
#ifndef USE_PROJECTOR_CTRL_NEC
#define USE_PROJECTOR_CTRL_NEC // Use at least one projector
#endif
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#define xxstr(s) xstr(s)
#define xstr(s) #s
enum projector_ctrl_dev_state_e : uint8_t {
PROJECTOR_CTRL_DEV_UNKNOWN=0,
PROJECTOR_CTRL_DEV_PWR_OFF,
PROJECTOR_CTRL_DEV_PWR_ON
};
enum projector_ctrl_serial_state_e : uint8_t {
PROJECTOR_CTRL_S_UNCONNECTED=0,
PROJECTOR_CTRL_S_QRY_PWR,
PROJECTOR_CTRL_S_QRY_TYPE,
PROJECTOR_CTRL_S_IDLE,
PROJECTOR_CTRL_S_PWR_ON,
PROJECTOR_CTRL_S_PWR_OFF
};
enum projector_ctrl_serial_result_e : uint8_t {
PROJECTOR_CTRL_R_UNKNOWN=0,
PROJECTOR_CTRL_R_PASS,
PROJECTOR_CTRL_R_FAIL
};
struct projector_ctrl_command_info_s {
const enum projector_ctrl_serial_state_e command;
const uint8_t *send_codes;
const uint8_t send_len;
const uint8_t timeout_ticks;
const uint8_t pass_first_byte;
const uint8_t pass_len;
const uint8_t pass_value_offset;
const uint8_t pass_value_bytes;
const uint8_t fail_first_byte;
const uint8_t fail_len;
const uint8_t fail_value_offset;
const uint8_t fail_value_bytes;
} __packed;
#include "xdrv_53_projector_ctrl.h"
struct projector_ctrl_softc_s {
TasmotaSerial *sc_serial;
uint8_t sc_device;
uint8_t sc_ticks;
enum projector_ctrl_dev_state_e sc_dev_state;
enum projector_ctrl_serial_state_e sc_ser_state;
enum projector_ctrl_serial_result_e sc_ser_result;
enum projector_ctrl_serial_state_e sc_ser_next_cmd;
const struct projector_ctrl_command_info_s *sc_cmd_info;
uint8_t sc_ser_sum;
uint8_t sc_ser_len;
uint32_t sc_ser_value;
} __packed;
static struct projector_ctrl_softc_s *projector_ctrl_sc = nullptr;
static void
projector_ctrl_pre_init(void)
{
struct projector_ctrl_softc_s *sc;
int baudrate = PROJECTOR_CTRL_SERIAL_BAUDRATE;
if (!PinUsed(GPIO_PROJECTOR_CTRL_TX) || !PinUsed(GPIO_PROJECTOR_CTRL_RX))
return;
sc = (struct projector_ctrl_softc_s *)malloc(sizeof(*sc));
if (sc == NULL) {
AddLog_P(LOG_LEVEL_ERROR, PSTR(PROJECTOR_CTRL_LOGNAME ": unable to allocate state"));
return;
}
memset(sc, 0, sizeof(*sc));
sc->sc_serial = new TasmotaSerial(Pin(GPIO_PROJECTOR_CTRL_RX),
Pin(GPIO_PROJECTOR_CTRL_TX), 2);
if (!sc->sc_serial->begin(baudrate, 2)) {
AddLog_P(LOG_LEVEL_ERROR, PSTR(PROJECTOR_CTRL_LOGNAME ": unable to begin serial "
"(baudrate %d)"), baudrate);
goto del;
}
if (sc->sc_serial->hardwareSerial()) {
ClaimSerial();
SetSerial(baudrate, TS_SERIAL_8N1);
}
sc->sc_device = ++(TasmotaGlobal.devices_present); /* claim a POWER device slot */
AddLog_P(LOG_LEVEL_INFO, PSTR(PROJECTOR_CTRL_LOGNAME ": new RELAY%d, polling serial for Projector status"), sc->sc_device);
projector_ctrl_sc = sc;
return;
del:
delete sc->sc_serial;
free:
free(sc);
}
static void
projector_ctrl_write(struct projector_ctrl_softc_s *sc, const uint8_t *bytes, const size_t len)
{
TasmotaSerial *serial;
uint8_t cksum;
size_t i;
cksum = 0;
serial = sc->sc_serial;
for (i = 0; i < len; i++) {
uint8_t b = bytes[i];
serial->write(b);
cksum += b;
}
#ifdef USE_PROJECTOR_CTRL_NEC
serial->write(cksum);
#endif
#ifdef DEBUG_PROJECTOR_CTRL
char hex_b[(len + 1) * 2];
AddLog_P(LOG_LEVEL_DEBUG,PSTR(PROJECTOR_CTRL_LOGNAME ": RAW bytes %s %02x"),
ToHex_P((uint8_t *)bytes, len, hex_b, sizeof(hex_b)), cksum);
#endif //DEBUG_PROJECTOR_CTRL
serial->flush();
return;
}
static void
projector_ctrl_request(struct projector_ctrl_softc_s *sc, const uint8_t command)
{
const struct projector_ctrl_command_info_s *e;
size_t i;
if ((sc->sc_dev_state!=PROJECTOR_CTRL_DEV_UNKNOWN)&&(sc->sc_ser_state!=PROJECTOR_CTRL_S_IDLE)) {
if ((command!=PROJECTOR_CTRL_S_QRY_PWR)&&(command!=PROJECTOR_CTRL_S_QRY_TYPE)) {
sc->sc_ser_next_cmd=(projector_ctrl_serial_state_e)command;
AddLog_P(LOG_LEVEL_INFO, PSTR(PROJECTOR_CTRL_LOGNAME
": Serial CMD %02x already running, enqueueing next (%02x)"), sc->sc_ser_state, command);
};
return;
};
for (i = 0; i < nitems(projector_ctrl_commands); i++) {
e = &projector_ctrl_commands[i];
if (command == e->command){
sc->sc_cmd_info=e;
sc->sc_ser_len=0;
sc->sc_ser_result=PROJECTOR_CTRL_R_UNKNOWN;
sc->sc_ser_state=(projector_ctrl_serial_state_e)command;
sc->sc_ser_sum=0;
sc->sc_ser_next_cmd=PROJECTOR_CTRL_S_UNCONNECTED;
sc->sc_ticks=0;
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": Sending CMD %02x"), command);
#endif //DEBUG_PROJECTOR_CTRL
projector_ctrl_write(sc,e->send_codes,e->send_len);
return;
}
};
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": Undefined serial command %02x"), command);
#endif //DEBUG_PROJECTOR_CTRL
return;
}
static uint8_t
projector_ctrl_parse(struct projector_ctrl_softc_s *sc, const uint8_t byte)
{
enum projector_ctrl_serial_state_e nstate;
const struct projector_ctrl_command_info_s *cmd;
nstate = sc->sc_ser_state;
switch (nstate) {
case PROJECTOR_CTRL_S_IDLE:
case PROJECTOR_CTRL_S_UNCONNECTED:
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": Spurious input in state %02x, got %02x, going UNCONNECTED"), nstate, byte);
#endif //DEBUG_PROJECTOR_CTRL
return(PROJECTOR_CTRL_S_UNCONNECTED);
default:
cmd=sc->sc_cmd_info;
sc->sc_ser_len++;
if (sc->sc_ser_len==1) {
if (byte==cmd->pass_first_byte){
sc->sc_ser_result=PROJECTOR_CTRL_R_PASS;
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": CMD %02x PASS, 1st byte %02x"), nstate, byte);
#endif //DEBUG_PROJECTOR_CTRL
}else if (byte==cmd->fail_first_byte){
sc->sc_ser_result=PROJECTOR_CTRL_R_FAIL;
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": CMD %02x FAIL, 1st byte %02x"), nstate, byte);
#endif //DEBUG_PROJECTOR_CTRL
}else{
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": CMD %02x UNKNOWN, 1st byte %02x, going UNCONNECTED"), nstate, byte);
#endif //DEBUG_PROJECTOR_CTRL
return(PROJECTOR_CTRL_S_UNCONNECTED);
};
};
if (sc->sc_ser_result==PROJECTOR_CTRL_R_PASS){
if (sc->sc_ser_len==(cmd->pass_value_offset+1))
sc->sc_ser_value=byte;
if ((sc->sc_ser_len>(cmd->pass_value_offset+1))&&(sc->sc_ser_len<=(cmd->pass_value_offset+cmd->pass_value_bytes)))
sc->sc_ser_value=(sc->sc_ser_value<<8)|byte;
if (sc->sc_ser_len==cmd->pass_len){
#ifdef USE_PROJECTOR_CTRL_NEC
if(sc->sc_ser_sum!=byte){
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": Failed cksum for CMD %02x. Got %02x bytes, computed cksum: %02x, recevied cksum: %02x, going UNCONNECTED"),
nstate, sc->sc_ser_len, sc->sc_ser_sum, byte);
#endif //DEBUG_PROJECTOR_CTRL
nstate=PROJECTOR_CTRL_S_UNCONNECTED;
} else
#endif //USE_PROJECTOR_CTRL_NEC
{
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": CMD %02x PASS, got %02x bytes, retval %02x, going IDLE"), nstate, sc->sc_ser_len, sc->sc_ser_value);
#endif //DEBUG_PROJECTOR_CTRL
nstate=PROJECTOR_CTRL_S_IDLE;
};
};
};
if (sc->sc_ser_result==PROJECTOR_CTRL_R_FAIL) {
if (sc->sc_ser_len==(cmd->fail_value_offset+1))
sc->sc_ser_value=byte;
if ((sc->sc_ser_len>(cmd->fail_value_offset+1))&&(sc->sc_ser_len<=(cmd->fail_value_offset+cmd->fail_value_bytes)))
sc->sc_ser_value=(sc->sc_ser_value<<8)|byte;
if(sc->sc_ser_len==cmd->fail_len){
#ifdef USE_PROJECTOR_CTRL_NEC
if(sc->sc_ser_sum!=byte){
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": Failed cksum for CMD %02x. Got %02x bytes, computed cksum: %02x, receied cksum: %02x, going UNCONNECTED"),
nstate, sc->sc_ser_len, sc->sc_ser_sum, byte);
#endif //DEBUG_PROJECTOR_CTRL
nstate=PROJECTOR_CTRL_S_UNCONNECTED;
} else
#endif //USE_PROJECTOR_CTRL_NEC
{
#ifdef DEBUG_PROJECTOR_CTRL
AddLog_P(LOG_LEVEL_DEBUG, PSTR(PROJECTOR_CTRL_LOGNAME
": CMD %02x FAIL, got %02x bytes, retval %02x, going idle"), nstate, sc->sc_ser_len, sc->sc_ser_value);
#endif //DEBUG_PROJECTOR_CTRL
nstate=PROJECTOR_CTRL_S_IDLE;
};
};
};
#ifdef USE_PROJECTOR_CTRL_NEC
sc->sc_ser_sum += byte;
#endif //USE_PROJECTOR_CTRL_NEC
break;
}
return (nstate);
}
static void
projector_ctrl_loop(struct projector_ctrl_softc_s *sc)
{
TasmotaSerial *serial;
uint8_t oldstate;
serial = sc->sc_serial;
while (serial->available()) {
yield();
oldstate = sc->sc_ser_state;
switch (sc->sc_ser_state = (projector_ctrl_serial_state_e)projector_ctrl_parse(sc, serial->read())) {
case PROJECTOR_CTRL_S_UNCONNECTED:
sc->sc_dev_state=PROJECTOR_CTRL_DEV_UNKNOWN;
break;
case PROJECTOR_CTRL_S_IDLE:
if ((oldstate==PROJECTOR_CTRL_S_QRY_PWR)&&(sc->sc_ser_result==PROJECTOR_CTRL_R_PASS)){
if(((sc->sc_ser_value==PROJECTOR_CTRL_QRYPWR_ON)||(sc->sc_ser_value==PROJECTOR_CTRL_QRYPWR_COOLING))&&(sc->sc_dev_state!=PROJECTOR_CTRL_DEV_PWR_ON)){
sc->sc_dev_state=PROJECTOR_CTRL_DEV_PWR_ON;
ExecuteCommandPower(sc->sc_device, POWER_ON, SRC_IGNORE);
};
if(((sc->sc_ser_value!=PROJECTOR_CTRL_QRYPWR_ON)&&(sc->sc_ser_value!=PROJECTOR_CTRL_QRYPWR_COOLING))&&(sc->sc_dev_state!=PROJECTOR_CTRL_DEV_PWR_OFF)){
sc->sc_dev_state=PROJECTOR_CTRL_DEV_PWR_OFF;
ExecuteCommandPower(sc->sc_device, POWER_OFF, SRC_IGNORE);
};
};
if ((oldstate==PROJECTOR_CTRL_S_PWR_ON)&&(sc->sc_ser_result==PROJECTOR_CTRL_R_PASS))
sc->sc_dev_state=PROJECTOR_CTRL_DEV_PWR_ON;
if ((oldstate==PROJECTOR_CTRL_S_PWR_OFF)&&(sc->sc_ser_result==PROJECTOR_CTRL_R_PASS))
sc->sc_dev_state=PROJECTOR_CTRL_DEV_PWR_OFF;
if(sc->sc_ser_next_cmd!=PROJECTOR_CTRL_S_UNCONNECTED){
oldstate=sc->sc_ser_next_cmd;
sc->sc_ser_next_cmd=PROJECTOR_CTRL_S_UNCONNECTED;
projector_ctrl_request(sc,oldstate);
};
break;
};
}
}
static void
projector_ctrl_connect(struct projector_ctrl_softc_s *sc)
{
projector_ctrl_request(sc,PROJECTOR_CTRL_S_QRY_PWR);
}
static void
projector_ctrl_tick(struct projector_ctrl_softc_s *sc)
{
if(sc->sc_ser_state==PROJECTOR_CTRL_S_IDLE){
switch (TasmotaGlobal.uptime&0xf) {
case 0:
projector_ctrl_request(sc,PROJECTOR_CTRL_S_QRY_PWR);
break;
case 8:
projector_ctrl_request(sc,PROJECTOR_CTRL_S_QRY_TYPE);
break;
};
}else if(sc->sc_ticks > sc->sc_cmd_info->timeout_ticks){
//current CMD has ran out of time, drop connection
AddLog_P(LOG_LEVEL_INFO,PSTR(PROJECTOR_CTRL_LOGNAME ": DISCONNECTED"));
sc->sc_dev_state=PROJECTOR_CTRL_DEV_UNKNOWN;
sc->sc_ser_state=PROJECTOR_CTRL_S_UNCONNECTED;
};
}
static bool
projector_ctrl_set_power(struct projector_ctrl_softc_s *sc)
{
if (TasmotaGlobal.active_device==PROJECTOR_CTRL_PWR_BY_RELAY){
if ((sc->sc_dev_state == PROJECTOR_CTRL_DEV_PWR_ON) && (0==bitRead(XdrvMailbox.index, PROJECTOR_CTRL_PWR_BY_RELAY -1))) {
TasmotaGlobal.power = bitSet(TasmotaGlobal.power,PROJECTOR_CTRL_PWR_BY_RELAY -1);
AddLog_P(LOG_LEVEL_INFO,PSTR(PROJECTOR_CTRL_LOGNAME ": Keep RELAY" xxstr(PROJECTOR_CTRL_PWR_BY_RELAY) " ON"));
} else {
return(false);
};
} else if (TasmotaGlobal.active_device==sc->sc_device){
if (bitRead(XdrvMailbox.index, sc->sc_device -1)) {
switch (sc->sc_dev_state) {
case PROJECTOR_CTRL_DEV_UNKNOWN:
TasmotaGlobal.power = bitClear(TasmotaGlobal.power,sc->sc_device -1);
break;
case PROJECTOR_CTRL_DEV_PWR_OFF:
projector_ctrl_request(sc,PROJECTOR_CTRL_S_PWR_ON);
break;
};
}else{
if (sc->sc_dev_state == PROJECTOR_CTRL_DEV_PWR_ON)
projector_ctrl_request(sc,PROJECTOR_CTRL_S_PWR_OFF);
};
} else {
return(false);
};
return (true);
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv53(uint8_t function) {
bool result;
struct projector_ctrl_softc_s *sc;
result = false;
sc = projector_ctrl_sc;
switch (function) {
case FUNC_PRE_INIT:
projector_ctrl_pre_init();
return (false);
}
if (sc == NULL)
return (false);
switch (function) {
case FUNC_LOOP:
projector_ctrl_loop(sc);
break;
case FUNC_EVERY_SECOND:
sc->sc_ticks++;
if (sc->sc_dev_state!=PROJECTOR_CTRL_DEV_UNKNOWN)
projector_ctrl_tick(sc);
else if ((TasmotaGlobal.uptime&0x7)==0) //each 8 seconds
projector_ctrl_connect(sc);
break;
case FUNC_SET_DEVICE_POWER:
result = projector_ctrl_set_power(sc);
break;
}
return (result);
}
#endif // USE_PROJECTOR_CTRL

View File

@ -61,10 +61,10 @@ void SSD1351_InitDriver() {
// init renderer
if (TasmotaGlobal.soft_spi_enabled){
ssd1351 = new SSD1351(Pin(GPIO_SSD1351_CS), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_SCLK));
ssd1351 = new SSD1351(Pin(GPIO_SSD1351_CS), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_SCLK), Pin(GPIO_SSD1351_DC));
}
else if (TasmotaGlobal.spi_enabled) {
ssd1351 = new SSD1351(Pin(GPIO_SSD1351_CS), Pin(GPIO_SPI_MOSI), Pin(GPIO_SPI_CLK));
ssd1351 = new SSD1351(Pin(GPIO_SSD1351_CS), Pin(GPIO_SPI_MOSI), Pin(GPIO_SPI_CLK), Pin(GPIO_SSD1351_DC));
}
delay(100);

View File

@ -110,7 +110,7 @@ void Sdm72Every250ms(void)
#endif // SDM72_IMPEXP
}
++Sdm72.read_state %= ARRAY_SIZE(sdm72_register);
++Sdm72.read_state %= nitems(sdm72_register);
if (0 == Sdm72.read_state && !isnan(Sdm72.total_active)) {
EnergyUpdateTotal(Sdm72.total_active, true);
}

View File

@ -2170,7 +2170,7 @@ uint32_t SML_getscriptsize(char *lp) {
#endif
bool Gpio_used(uint8_t gpiopin) {
if ((gpiopin < ARRAY_SIZE(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) {
if ((gpiopin < nitems(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) {
return true;
}
return false;

View File

@ -182,8 +182,7 @@ struct mi_beacon_mac_data_t{ // e.g. 28/08
uint8_t mac[6];
};
struct mi_beacon_payload_data_t{ //
uint8_t type;
uint8_t ten;
uint16_t type;
uint8_t size;
uint8_t data[16];
};
@ -286,6 +285,7 @@ struct mi_sensor_t{
uint32_t Btn:1;
uint32_t events:1;
uint32_t pairing:1;
uint32_t light:1; // binary light sensor
};
uint32_t raw;
} feature;
@ -303,12 +303,16 @@ struct mi_sensor_t{
uint32_t noMotion:1;
uint32_t Btn:1;
uint32_t PairBtn:1;
uint32_t light:1; // binary light sensor
};
uint32_t raw;
} eventType;
int RSSI;
uint8_t pairing;
int8_t light; // binary light sensor - initialise to -1
int16_t Btn; // moved so we can initialise to -1
uint32_t lastTime;
uint32_t lux;
float temp; //Flora, MJ_HT_V1, LYWSD0x, CGx
@ -325,7 +329,6 @@ struct mi_sensor_t{
uint16_t events; //"alarms" since boot
uint32_t NMT; // no motion time in seconds for the MJYD2S
};
uint16_t Btn;
};
union {
uint8_t bat; // many values seem to be hard-coded garbage (LYWSD0x, GCD1)
@ -1152,6 +1155,21 @@ int MIDecryptPayload(const uint8_t *macin, const uint8_t *nonce, uint32_t tag, u
// xxyy FFEEDDCCBBAA 0104 TTTTHHHH
// xxyy FFEEDDCCBBAA 0201 BB
const char *MIaddrStr(const uint8_t *addr, int useAlias = 0){
static char addrstr[32];
const char *id = nullptr;
if (useAlias){
id = BLE_ESP32::getAlias(addr);
}
if (!id || !(*id)){
id = addrstr;
BLE_ESP32::dump(addrstr, 13, addr, 6);
} else {
}
return id;
}
int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const uint8_t *datain, int len){
uint8_t data[32];
@ -1189,6 +1207,10 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const
parsed->framedata.bindingvalidreq = (data[byteindex] & 0x02)>>1; //Byte 0: ......x.
parsed->framedata.registeredflag = (data[byteindex] & 0x01); //Byte 0: .......x
// note:
// if bindingvalidreq, we should connect and establish a key.
// However, how do we determine WHICH TAS should do this?
byteindex++;
parsed->devicetype = *((uint16_t *)(data + byteindex));
@ -1243,17 +1265,17 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const
break;
case 0: // suceeded
parsed->needkey = KEY_REQUIRED_AND_FOUND;
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Payload decrypted"));
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32 %s: Payload decrypted"), MIaddrStr(slotmac));
break;
case -1: // key failed to work
parsed->needkey = KEY_REQUIRED_AND_INVALID;
AddLog(LOG_LEVEL_ERROR,PSTR("M32: Payload decrypt failed"));
AddLog(LOG_LEVEL_ERROR,PSTR("M32 %s: Payload decrypt failed"), MIaddrStr(slotmac));
parsed->payloadpresent = 0;
return 0;
break;
case -2: // key not present
parsed->needkey = KEY_REQUIRED_BUT_NOT_FOUND;
AddLog(LOG_LEVEL_ERROR,PSTR("M32: Payload encrypted but no key"));
AddLog(LOG_LEVEL_ERROR,PSTR("M32 %s: Payload encrypted but no key"), MIaddrStr(slotmac));
parsed->payloadpresent = 0;
return 0;
break;
@ -1288,7 +1310,7 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const
}
if ((len - byteindex) == 0){
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32: No payload"));
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32 %s: No payload"), MIaddrStr(slotmac));
parsed->payload.size = 0;
parsed->payloadpresent = 0;
return 0;
@ -1297,14 +1319,14 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const
// we have payload which did not need decrypt.
if (decres == 1){
parsed->needkey = KEY_NOT_REQUIRED;
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Payload unencrypted"));
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32 %s: Payload unencrypted"), MIaddrStr(slotmac));
}
// already decrypted if required
parsed->payloadpresent = 1;
memcpy(&parsed->payload, (data + byteindex), (len - byteindex));
if (parsed->payload.size != (len - byteindex) - 3){
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Payload length mismatch"));
AddLog(LOG_LEVEL_DEBUG,PSTR("M32 %s: Payload length mismatch"), MIaddrStr(slotmac));
}
return 1;
@ -1399,6 +1421,8 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
_newSensor.bat = 0x00;
_newSensor.RSSI = 0xffff;
_newSensor.lux = 0x00ffffff;
_newSensor.light = -1;
_newSensor.Btn = -1;
switch (_type)
{
@ -1428,9 +1452,13 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
_newSensor.feature.events=1;
break;
case MI_YEERC:
case MI_DOOR:
_newSensor.feature.Btn=1;
break;
case MI_DOOR: // MCCGQ02HL
_newSensor.feature.Btn=1;
_newSensor.feature.light=1;
_newSensor.feature.bat=1;
break;
default:
_newSensor.hum=NAN;
_newSensor.feature.temp=1;
@ -1651,26 +1679,49 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
MIBLEsensors[_slot].pairing = 0;
MIBLEsensors[_slot].eventType.PairBtn = 0;
//https://iot.mi.com/new/doc/embedded-development/ble/object-definition
switch(parsed->payload.type){
case 0x01: // button press
MIBLEsensors[_slot].Btn = pld->Btn.num + (pld->Btn.longPress/2)*6;
MIBLEsensors[_slot].feature.Btn = 1;
MIBLEsensors[_slot].eventType.Btn = 1;
MI32.mode.shallTriggerTele = 1;
MIBLEsensors[_slot].shallSendMQTT = 1;
break;
case 0x02: // related to pair button?
case 0x0002: // related to pair button? 'easypairing'
MIBLEsensors[_slot].pairing = 1;
MIBLEsensors[_slot].eventType.PairBtn = 1;
MIBLEsensors[_slot].feature.pairing = 1;
MI32.mode.shallTriggerTele = 1;
MIBLEsensors[_slot].shallSendMQTT = 1;
break;
case 0x03: {// motion? 1 byte
case 0x0003: {// motion? 1 byte 'near'
uint8_t motion = parsed->payload.data[0];
res = 0;
}break;
case 0x04:{
case 0x000f: // 'Someone is moving (with light)'
MIBLEsensors[_slot].eventType.motion = 1;
MIBLEsensors[_slot].lastTime = millis();
MIBLEsensors[_slot].events++;
MIBLEsensors[_slot].lux = pld->lux;
MIBLEsensors[_slot].eventType.lux = 1;
MIBLEsensors[_slot].NMT = 0;
MI32.mode.shallTriggerTele = 1;
MIBLEsensors[_slot].shallSendMQTT = 1;
MIBLEsensors[_slot].feature.lux = 1;
MIBLEsensors[_slot].feature.NMT = 1;
MIBLEsensors[_slot].feature.events=1;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: PIR: primary"),MIBLEsensors[_slot].lux );
break;
case 0x1001: // button press
MIBLEsensors[_slot].Btn = pld->Btn.num + (pld->Btn.longPress/2)*6;
MIBLEsensors[_slot].feature.Btn = 1;
MIBLEsensors[_slot].eventType.Btn = 1;
MI32.mode.shallTriggerTele = 1;
MIBLEsensors[_slot].shallSendMQTT = 1;
break;
//case 0x1002: // 'sleep'
//case 0x1003: // 'RSSI'
case 0x1004:{ // 'temperature'
float _tempFloat=(float)(pld->temp)/10.0f;
if(_tempFloat<60){
MIBLEsensors[_slot].temp=_tempFloat;
@ -1682,7 +1733,8 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
}
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 4: U16: %u Temp"), _beacon.temp );
} break;
case 0x06: {
// 0x1005 - not documented
case 0x1006: { // 'humidity'
float _tempFloat=(float)(pld->hum)/10.0f;
if(_tempFloat<101){
MIBLEsensors[_slot].hum=_tempFloat;
@ -1694,7 +1746,7 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
}
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 6: U16: %u Hum"), _beacon.hum);
} break;
case 0x07:
case 0x1007: // 'Light illuminance'
MIBLEsensors[_slot].lux=pld->lux & 0x00ffffff;
if(MIBLEsensors[_slot].type==MI_MJYD2S){
MIBLEsensors[_slot].eventType.noMotion = 1;
@ -1703,21 +1755,21 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
MIBLEsensors[_slot].feature.lux = 1;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 7: U24: %u Lux"), _beacon.lux & 0x00ffffff);
break;
case 0x08:
case 0x1008: //'Soil moisture'
MIBLEsensors[_slot].moisture=pld->moist;
MIBLEsensors[_slot].eventType.moist = 1;
MIBLEsensors[_slot].feature.moist = 1;
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: Mode 8: moisture updated"));
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 8: U8: %u Moisture"), _beacon.moist);
break;
case 0x09: // 'conductivity'
case 0x1009: // 'conductivity' / 'Soil EC value'
MIBLEsensors[_slot].fertility=pld->fert;
MIBLEsensors[_slot].eventType.fert = 1;
MIBLEsensors[_slot].feature.fert = 1;
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: Mode 9: fertility updated"));
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 9: U16: %u Fertility"), _beacon.fert);
break;
case 0x0a:
case 0x100a:// 'Electricity'
if(MI32.option.ignoreBogusBattery){
if(MIBLEsensors[_slot].type==MI_LYWSD03MMC || MIBLEsensors[_slot].type==MI_MHOC401){
res = 0;
@ -1736,7 +1788,8 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
}
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode a: U8: %u %%"), _beacon.bat);
break;
case 0x0d:{
// 100b-100d -> undefioend in docs.
case 0x100d:{ // is this right????
MIBLEsensors[_slot].feature.tempHum = 1;
float _tempFloat=(float)(pld->HT.temp)/10.0f;
if(_tempFloat < 60){
@ -1755,36 +1808,26 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
MIBLEsensors[_slot].eventType.tempHum = 1;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode d: U16: %x Temp U16: %x Hum"), _beacon.HT.temp, _beacon.HT.hum);
} break;
case 0x0f:
if (parsed->payload.ten != 0) break;
MIBLEsensors[_slot].eventType.motion = 1;
MIBLEsensors[_slot].lastTime = millis();
MIBLEsensors[_slot].events++;
MIBLEsensors[_slot].lux = pld->lux;
MIBLEsensors[_slot].eventType.lux = 1;
MIBLEsensors[_slot].NMT = 0;
MI32.mode.shallTriggerTele = 1;
MIBLEsensors[_slot].shallSendMQTT = 1;
MIBLEsensors[_slot].feature.lux = 1;
MIBLEsensors[_slot].feature.NMT = 1;
MIBLEsensors[_slot].feature.events=1;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: PIR: primary"),MIBLEsensors[_slot].lux );
break;
case 0x10:{ // 'formaldehide'
// 100e = 'lock'
// 100f = 'door'
case 0x1010:{ // 'formaldehide'
const uint16_t f = uint16_t(parsed->payload.data[0]) | (uint16_t(parsed->payload.data[1]) << 8);
float formaldehyde = (float)f / 100.0f;
res = 0;
} break;
case 0x12:{ // 'active'
// 1011 = 'bind'
case 0x1012:{ // 'switch'
int active = parsed->payload.data[0];
res = 0;
} break;
case 0x13:{ //mosquito tablet
case 0x1013:{ // 'Remaining amount of consumables' - mosquito tablet
int tablet = parsed->payload.data[0];
res = 0;
} break;
case 0x17:{
//Flooding 0x1014 1 1
//smoke 0x1015 1 1
//Gas 0x1016
case 0x1017:{ // 'No one moves'
const uint32_t idle_time =
uint32_t(parsed->payload.data[0]) | (uint32_t(parsed->payload.data[1]) << 8) | (uint32_t(parsed->payload.data[2]) << 16) | (uint32_t(parsed->payload.data[2]) << 24);
float idlemins = (float)idle_time / 60.0f;
@ -1798,17 +1841,29 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 17: NMT: %u seconds"), _beacon.NMT);
} break;
case 0x19:{
MIBLEsensors[_slot].Btn = uint8_t(parsed->payload.data[0]); // just an 8 bit value in a union.
//Light intensity 0x1018
case 0x1018:{ //'Light intensity' - 0=dark, 1=light? - MCCGQ02HL
MIBLEsensors[_slot].light = parsed->payload.data[0];
MIBLEsensors[_slot].eventType.light = 1;
MI32.mode.shallTriggerTele = 1;
MIBLEsensors[_slot].shallSendMQTT = 1;
MIBLEsensors[_slot].feature.light = 1;
} break;
case 0x1019:{ //'Door sensor' - 0=open, 1=closed, 2=timeout? - MCCGQ02HL
MIBLEsensors[_slot].Btn = (uint8_t) parsed->payload.data[0]; // just an 8 bit value in a union.
MIBLEsensors[_slot].eventType.Btn = 1;
MI32.mode.shallTriggerTele = 1;
MIBLEsensors[_slot].shallSendMQTT = 1;
MIBLEsensors[_slot].feature.Btn = 1;
} break;
//Weight attributes 0x101A 600 0
//No one moves over time 0x101B 1 1
//Smart pillow 0x101C 60 1
//Formaldehyde (new) 0x101D
default: {
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Unknown MI pld"));
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Unknown MI pld type %x %s"), parsed->payload.type, tmp);
res = 0;
} break;
}
@ -2179,45 +2234,65 @@ void CmndMi32Block(void){
}
void CmndMi32Option(void){
bool onOff = atoi(XdrvMailbox.data);
bool set = false;
if (strlen(XdrvMailbox.data)){
set = true;
}
int onOff = atoi(XdrvMailbox.data);
switch(XdrvMailbox.index) {
case 0:
MI32.option.allwaysAggregate = onOff;
ResponseCmndIdxNumber(onOff);
return;
if (set){
MI32.option.allwaysAggregate = onOff;
} else {
onOff = MI32.option.allwaysAggregate;
}
break;
case 1:
MI32.option.noSummary = onOff;
ResponseCmndIdxNumber(onOff);
return;
if (set){
MI32.option.noSummary = onOff;
} else {
onOff = MI32.option.noSummary;
}
break;
case 2:
MI32.option.directBridgeMode = onOff;
ResponseCmndIdxNumber(onOff);
return;
if (set){
MI32.option.directBridgeMode = onOff;
} else {
onOff = MI32.option.directBridgeMode;
}
break;
case 4:{
MI32.option.ignoreBogusBattery = onOff;
ResponseCmndIdxNumber(onOff);
return;
if (set){
MI32.option.ignoreBogusBattery = onOff;
} else {
onOff = MI32.option.ignoreBogusBattery;
}
} break;
case 5:{
MI32.option.onlyAliased = onOff;
if (MI32.option.onlyAliased){
// discard all sensors for a restart
MIBLEsensors.clear();
if (set){
MI32.option.onlyAliased = onOff;
if (MI32.option.onlyAliased){
// discard all sensors for a restart
MIBLEsensors.clear();
}
} else {
onOff = MI32.option.onlyAliased;
}
ResponseCmndIdxNumber(onOff);
return;
} break;
case 6:{
MI32.option.MQTTType = onOff;
ResponseCmndIdxNumber(onOff);
if (set){
MI32.option.MQTTType = onOff;
} else {
onOff = MI32.option.MQTTType;
}
} break;
default:{
ResponseCmndIdxError();
return;
} break;
}
ResponseCmndIdxError();
ResponseCmndIdxNumber(onOff);
return;
}
void MI32KeyListResp(){
@ -2325,6 +2400,7 @@ const char HTTP_EVENTS[] PROGMEM = "{s}%s Events{m}%u {e}";
const char HTTP_NMT[] PROGMEM = "{s}%s No motion{m}> %u seconds{e}";
const char HTTP_MI32_FLORA_DATA[] PROGMEM = "{s}%s" " Fertility" "{m}%u us/cm{e}";
const char HTTP_MI32_HL[] PROGMEM = "{s}<hr>{m}<hr>{e}";
const char HTTP_MI32_LIGHT[] PROGMEM = "{s}%s" " Light" "{m}%d{e}";
//const char HTTP_NEEDKEY[] PROGMEM = "{s}%s <a target=\"_blank\" href=\""
// "https://atc1441.github.io/TelinkFlasher.html?mac=%s&cb=http%%3A%%2F%%2F%s%%2Fmikey"
@ -2417,6 +2493,12 @@ void MI32GetOneSensorJson(int slot, int hidename){
p->MAC[3], p->MAC[4], p->MAC[5]);
}
const char *alias = BLE_ESP32::getAlias(p->MAC);
if (alias && alias[0]){
ResponseAppend_P(PSTR("\"alias\":\"%s\","),
alias);
}
ResponseAppend_P(PSTR("\"mac\":\"%02x%02x%02x%02x%02x%02x\""),
p->MAC[0], p->MAC[1], p->MAC[2],
p->MAC[3], p->MAC[4], p->MAC[5]);
@ -2475,6 +2557,15 @@ void MI32GetOneSensorJson(int slot, int hidename){
}
}
}
if (p->feature.light){
if(p->eventType.light || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate
#ifdef USE_HOME_ASSISTANT
||(hass_mode==2)
#endif //USE_HOME_ASSISTANT
){
ResponseAppend_P(PSTR(",\"Light\":%d"), p->light);
}
}
if (p->feature.moist){
if(p->eventType.moist || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){
if (p->moisture!=0xff
@ -2504,12 +2595,12 @@ void MI32GetOneSensorJson(int slot, int hidename){
}
}
if (p->feature.Btn){
if(p->eventType.Btn
if(p->eventType.Btn || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate
#ifdef USE_HOME_ASSISTANT
||(hass_mode==2)
#endif //USE_HOME_ASSISTANT
){
ResponseAppend_P(PSTR(",\"Btn\":%u"),p->Btn);
ResponseAppend_P(PSTR(",\"Btn\":%d"),p->Btn);
}
}
if(p->eventType.PairBtn && p->pairing){
@ -2685,14 +2776,74 @@ const char MI_HA_DISCOVERY_TEMPLATE[] PROGMEM =
"\"model\":\"%s\","
"\"via_device\":\"%s\""
"},"
"\"dev_cla\":\"%s\","
"%s%s%s"
"\"expire_after\":600,"
"\"json_attr_t\":\"%s\","
"\"name\":\"%s_%s\","
"\"state_topic\":\"%s\","
"\"uniq_id\":\"%s_%s\","
"\"unit_of_meas\":\"%s\","
"\"val_tpl\":\"{{ value_json.%s }}\"}";
"%s%s%s"
"\"val_tpl\":\"{{ %s%s%s }}\"}";
// careful - a missing comma causes a crash!!!!
// because of the way we loop?
const char *classes[] = {
// 0
"temperature",
"Temperature",
"°C",
// 1
"humidity",
"Humidity",
"%",
// 2
"temperature",
"DewPoint",
"°C",
// 3
"battery",
"Battery",
"%",
// 4
"signal_strength",
"RSSI",
"dB",
// 5
"",//- empty device class
"Btn",
"",
// 6
"", //- empty device class
"Light",
"",
// 7
"", //- empty device class
"Moisture",
"",
// 8
"", //- empty device class
"Illuminance",
"",
// 9
"", //- empty device class
"Fertility",
"",
// 10
"", //- empty device class
"Firmware",
"",
};
void MI32DiscoveryOneMISensor(){
// don't detect half-added ones here
@ -2708,25 +2859,7 @@ void MI32DiscoveryOneMISensor(){
p = &MIBLEsensors[MI32.mqttCurrentSingleSlot];
// careful - a missing comma causes a crash!!!!
// because of the way we loop?
const char *classes[] = {
"temperature",
"Temperature",
"°C",
"humidity",
"Humidity",
"%",
"temperature",
"DewPoint",
"°C",
"battery",
"Battery",
"%",
"signal_strength",
"RSSI",
"dB"
};
int datacount = (sizeof(classes)/sizeof(*classes))/3;
@ -2758,9 +2891,72 @@ void MI32DiscoveryOneMISensor(){
if (!classes[i] || !classes[i+1] || !classes[i+2]){
return;
}
uint8_t isBinary = 0;
ResponseClear();
switch(i/3){
case 0: // temp
if (!p->feature.temp && !p->feature.tempHum){
continue;
}
break;
case 1:// hum
if (!p->feature.hum && !p->feature.tempHum){
continue;
}
break;
case 2: //dew
if (!p->feature.tempHum && !(p->feature.temp && p->feature.hum)){
continue;
}
break;
case 3: //bat
if (!p->feature.bat){
continue;
}
break;
case 4: //rssi - all
break;
case 5: // button
if (!p->feature.Btn){
continue;
}
//isBinary = 2; // invert payload
break;
case 6: // binary light sense
if (!p->feature.light){
continue;
}
//isBinary = 1;
break;
case 7: // moisture
if (!p->feature.moist){
continue;
}
//isBinary = 1;
break;
case 8: // lux
if (!p->feature.lux){
continue;
}
break;
case 9: // fertility
if (!p->feature.fert){
continue;
}
break;
case 10: // firmware
if (!p->feature.fert){ // Flora only
continue;
}
break;
}
/*
{"availability":[],"device":{"identifiers":["TasmotaBLEa4c1387fc1e1"],"manufacturer":"simon","model":"someBLEsensor","name":"TASBLEa4c1387fc1e1","sw_version":"0.0.0"},"dev_cla":"temperature","json_attr_t":"tele/tasmota_esp32/SENSOR","name":"TASLYWSD037fc1e1Temp","state_topic":"tele/tasmota_esp32/SENSOR","uniq_id":"Tasmotaa4c1387fc1e1temp","unit_of_meas":"°C","val_tpl":"{{ value_json.LYWSD037fc1e1.Temperature }}"}
{"availability":[],"device":{"identifiers":["TasmotaBLEa4c1387fc1e1"],
@ -2781,7 +2977,9 @@ void MI32DiscoveryOneMISensor(){
//\"via_device\":\"%s\"
host,
//"\"dev_cla\":\"%s\","
(classes[i][0]?"\"dev_cla\":\"":""),
classes[i],
(classes[i][0]?"\",":""),
//"\"json_attr_t\":\"%s\"," - the topic the sensor publishes on
SensorTopic,
//"\"name\":\"%s_%s\"," - the name of this DATA
@ -2791,14 +2989,26 @@ void MI32DiscoveryOneMISensor(){
//"\"uniq_id\":\"%s_%s\"," - unique for this data,
id, classes[i+1],
//"\"unit_of_meas\":\"%s\"," - the measure of this type of data
(classes[i+2][0]?"\"unit_of_meas\":\"":""),
classes[i+2],
//"\"val_tpl\":\"{{ value_json.%s }}") // e.g. Temperature
classes[i+1]
(classes[i+2][0]?"\",":""),
//"\"val_tpl\":\"{{ %s%s }}") // e.g. Temperature
// inverted binary - {{ 'off' if value_json.posn else 'on' }}
// binary - {{ 'on' if value_json.posn else 'off' }}
((isBinary < 1)?"value_json.":
((isBinary < 2)?"value_json.":"'off' if value_json.")
),
classes[i+1],
((isBinary < 1)?"":
((isBinary < 2)?"":" else 'on'")
)
//
);
sprintf(DiscoveryTopic, "homeassistant/sensor/%s/%s/config",
id, classes[i+1]);
sprintf(DiscoveryTopic, "homeassistant/%ssensor/%s/%s/config",
(isBinary? "binary_":""), id, classes[i+1]);
MqttPublish(DiscoveryTopic);
p->nextDiscoveryData++;
@ -3013,6 +3223,10 @@ void MI32Show(bool json)
WSContentSend_PD(HTTP_SNS_ILLUMINANCE, typeName, p->lux);
}
}
if (p->feature.light){
WSContentSend_PD(HTTP_MI32_LIGHT, typeName, p->light);
}
if(p->bat!=0x00){
WSContentSend_PD(HTTP_BATTERY, typeName, p->bat);
}

View File

@ -767,7 +767,7 @@ void NeoPool250ms(void) // Every 250 mSec
}
#endif // DEBUG_TASMOTA_SENSOR
++neopool_read_state %= ARRAY_SIZE(NeoPoolReg);
++neopool_read_state %= nitems(NeoPoolReg);
#ifdef NEOPOOL_OPTIMIZE_READINGS
if (0 == neopool_read_state) {
neopool_first_read = false;
@ -795,7 +795,7 @@ void NeoPool250ms(void) // Every 250 mSec
#ifdef DEBUG_TASMOTA_SENSOR
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NEO: notify 0x%04X - addr block 0x%04X ignored"), NeoPoolGetData(MBF_NOTIFICATION), NeoPoolReg[neopool_read_state].addr);
#endif // DEBUG_TASMOTA_SENSOR
++neopool_read_state %= ARRAY_SIZE(NeoPoolReg);
++neopool_read_state %= nitems(NeoPoolReg);
}
}
#endif // NEOPOOL_OPTIMIZE_READINGS
@ -840,7 +840,7 @@ bool NeoPoolInitData(void)
bool res = false;
neopool_error = true;
for(uint32_t i=0; i<ARRAY_SIZE(NeoPoolReg); i++) {
for(uint32_t i=0; i<nitems(NeoPoolReg); i++) {
if (nullptr == NeoPoolReg[i].data) {
NeoPoolReg[i].data = (uint16_t *)malloc(sizeof(uint16_t)*NeoPoolReg[i].cnt);
if (nullptr != NeoPoolReg[i].data) {
@ -1001,7 +1001,7 @@ uint8_t NeoPoolWriteRegister(uint16_t addr, uint16_t *data, uint16_t cnt)
uint16_t NeoPoolGetData(uint16_t addr)
{
for(uint32_t i=0; i<ARRAY_SIZE(NeoPoolReg); i++) {
for(uint32_t i=0; i<nitems(NeoPoolReg); i++) {
if (nullptr != NeoPoolReg[i].data && addr >= NeoPoolReg[i].addr && addr < NeoPoolReg[i].addr+NeoPoolReg[i].cnt) {
return NeoPoolReg[i].data[addr - NeoPoolReg[i].addr];
}
@ -1206,14 +1206,14 @@ void NeoPoolShow(bool json)
}
// Filtration mode
GetTextIndexed(stemp, sizeof(stemp), NeoPoolGetData(MBF_PAR_FILT_MODE) < MBV_PAR_FILT_INTELLIGENT ? NeoPoolGetData(MBF_PAR_FILT_MODE) : ARRAY_SIZE(kNeoPoolFiltrationMode)-1, kNeoPoolFiltrationMode);
GetTextIndexed(stemp, sizeof(stemp), NeoPoolGetData(MBF_PAR_FILT_MODE) < MBV_PAR_FILT_INTELLIGENT ? NeoPoolGetData(MBF_PAR_FILT_MODE) : nitems(kNeoPoolFiltrationMode)-1, kNeoPoolFiltrationMode);
WSContentSend_PD(HTTP_SNS_NEOPOOL_FILT_MODE, neopool_type, stemp);
// Relays
for(uint32_t i=0; i<8; i++) {
char sdesc[24];
memset(sdesc, 0, ARRAY_SIZE(sdesc));
memset(stemp, 0, ARRAY_SIZE(stemp));
memset(sdesc, 0, nitems(sdesc));
memset(stemp, 0, nitems(stemp));
if (0 != NeoPoolGetData(MBF_PAR_PH_ACID_RELAY_GPIO) && i == NeoPoolGetData(MBF_PAR_PH_ACID_RELAY_GPIO)-1) {
strncpy_P(sdesc, PSTR(D_NEOPOOL_RELAY_PH_ACID), sizeof(sdesc));
}
@ -1306,14 +1306,14 @@ void CmndNeopoolReadReg(void)
{
uint16_t addr, data[30] = { 0 }, cnt=1;
uint32_t value[2] = { 0 };
uint32_t params_cnt = ParseParameters(ARRAY_SIZE(value), value);
uint32_t params_cnt = ParseParameters(nitems(value), value);
bool fbits32 = !strcasecmp_P(XdrvMailbox.command, PSTR(D_PRFX_NEOPOOL D_CMND_NP_READL));
cnt = 1;
if (2 == params_cnt) {
cnt = value[1];
}
if (params_cnt && cnt < (fbits32 ? (ARRAY_SIZE(data)/2) : ARRAY_SIZE(data))) {
if (params_cnt && cnt < (fbits32 ? (nitems(data)/2) : nitems(data))) {
addr = value[0];
if (NEOPOOL_OK != NeoPoolReadRegister(addr, data, fbits32 ? (cnt*2) : cnt)) {
NeopoolResponseError();
@ -1326,8 +1326,8 @@ void CmndNeopoolReadReg(void)
void CmndNeopoolWriteReg(void)
{
uint16_t addr, data[20] = { 0 }, cnt;
uint32_t value[(ARRAY_SIZE(data)/2)+1] = { 0 };
uint32_t params_cnt = ParseParameters(ARRAY_SIZE(value), value);
uint32_t value[(nitems(data)/2)+1] = { 0 };
uint32_t params_cnt = ParseParameters(nitems(value), value);
bool fbits32 = !strcasecmp_P(XdrvMailbox.command, PSTR(D_PRFX_NEOPOOL D_CMND_NP_WRITEL));
if (params_cnt > 1) {
@ -1359,7 +1359,7 @@ void CmndNeopoolBit(void)
uint16_t addr, data;
int8_t bit;
uint32_t value[3] = { 0 };
uint32_t params_cnt = ParseParameters(ARRAY_SIZE(value), value);
uint32_t params_cnt = ParseParameters(nitems(value), value);
bool fbits32 = !strcasecmp_P(XdrvMailbox.command, PSTR(D_PRFX_NEOPOOL D_CMND_NP_BITL));
uint16_t tempdata[2];
@ -1457,7 +1457,7 @@ void CmndNeopoolFiltrationMode(void)
NeopoolResponseError();
return;
}
ResponseCmndChar(GetTextIndexed(stemp, sizeof(stemp), data < MBV_PAR_FILT_INTELLIGENT ? data : ARRAY_SIZE(kNeoPoolFiltrationMode)-1, kNeoPoolFiltrationMode));
ResponseCmndChar(GetTextIndexed(stemp, sizeof(stemp), data < MBV_PAR_FILT_INTELLIGENT ? data : nitems(kNeoPoolFiltrationMode)-1, kNeoPoolFiltrationMode));
}
void CmndNeopoolTime(void)
@ -1508,7 +1508,7 @@ void CmndNeopoolLight(void)
return;
}
if (relay >=1 && relay <=8) {
if (XdrvMailbox.data_len && XdrvMailbox.payload >= 0 && XdrvMailbox.payload < ARRAY_SIZE(timer_val)) {
if (XdrvMailbox.data_len && XdrvMailbox.payload >= 0 && XdrvMailbox.payload < nitems(timer_val)) {
addr = MBF_PAR_TIMER_BLOCK_LIGHT_INT + MBV_TIMER_OFFMB_TIMER_ENABLE;
data = timer_val[XdrvMailbox.payload];
NeoPoolWriteRegister(MBF_PAR_TIMER_BLOCK_LIGHT_INT + MBV_TIMER_OFFMB_TIMER_ENABLE, &data, 1);

View File

@ -247,7 +247,7 @@ a_features = [[
"USE_DISPLAY_ILI9488","USE_DISPLAY_SSD1351","USE_DISPLAY_RA8876","USE_DISPLAY_ST7789",
"USE_DISPLAY_SSD1331","USE_UFILESYS","USE_TIMEPROP","USE_PID",
"USE_BS814A2","USE_SEESAW_SOIL","USE_WIEGAND","USE_NEOPOOL",
"USE_TOF10120","USE_SDM72","USE_DISPLAY_TM1637",""
"USE_TOF10120","USE_SDM72","USE_DISPLAY_TM1637","USE_PROJECTOR_CTRL"
],[
"","","","",
"","","","",