Merge branch 'arendst/development' into development

This commit is contained in:
reloxx13 2018-06-26 16:51:01 +02:00
commit 45da326230
61 changed files with 5483 additions and 212 deletions

2
.gitattributes vendored
View File

@ -1,5 +1,5 @@
# Auto detect text files and perform LF normalization
* text=auto
* text=off
# Custom for Visual Studio
*.cs diff=csharp

View File

@ -6,24 +6,27 @@ about: Create a report to help us improve
**Describe the bug**
A clear and concise description of what the bug is.
_A clear and concise description of what the bug is._
Also, make sure these boxes are checked [x] before submitting your issue - Thank you!
- [ ] Searched the problem in issues and in the wiki
- [ ] Hardware used :
- [ ] Provide the output of command ``status 0`` :
```
STATUS 0 OUTPUT HERE
```
**To Reproduce**
Steps to reproduce the behavior:
_Steps to reproduce the behavior:_
**Expected behavior**
A clear and concise description of what you expected to happen.
_A clear and concise description of what you expected to happen._
**Screenshots**
If applicable, add screenshots to help explain your problem.
_If applicable, add screenshots to help explain your problem._
**Additional context**
Add any other context about the problem here.
_Add any other context about the problem here._
**(Please, remember to close the issue when the problem has been addressed)**

View File

@ -12,5 +12,8 @@ Make sure these boxes are checked [x] before submitting your issue - Thank you!
- [ ] Searched the problem in the discussion group (https://groups.google.com/d/forum/sonoffusers)
- [ ] Hardware used :
- [ ] Provide the output of command ``status 0`` :
```
STATUS 0 OUTPUT HERE
```
**(Please, remember to close the issue when the problem has been addressed)**

View File

@ -6,15 +6,15 @@ about: Suggest an idea for this project
**Have you look for this feature in other issues and in the wiki?**
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is.
_A clear and concise description of what the problem is._
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
_A clear and concise description of what you want to happen._
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
_A clear and concise description of any alternative solutions or features you've considered._
**Additional context**
Add any other context or screenshots about the feature request here.
_Add any other context or screenshots about the feature request here._
**(Please, remember to close the issue when the problem has been addressed)**

4
.github/stale.yml vendored
View File

@ -1,9 +1,9 @@
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 120
daysUntilStale: 45
# Number of days of inactivity before a stale Issue or Pull Request is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 14
daysUntilClose: 15
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:

2489
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,13 @@ If you like **Sonoff-Tasmota**, give it a star, or fork it and contribute!
Current version is **6.0.0a** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information.
### Disclaimer
:warning: **DANGER OF ELECTROCUTION** :warning:
A Sonoff device is not a toy. It uses Mains AC so there is a danger of electrocution if not installed properly. If you don't know how to install it, please call an electrician. Remember: _**SAFETY FIRST**_. It is not worth to risk yourself, your family and your home if you don't know exactly what you are doing. Never try to flash a Sonoff device while it is connected to MAINS AC.
We don't take any responsibility nor liability for using this software nor for the installation or any tips, advice, videos, etc. given by any member of this site or any related site.
### Quick Install
Download one of the released binaries from https://github.com/arendst/Sonoff-Tasmota/releases and flash it to your hardware as documented in the wiki.

View File

@ -0,0 +1,10 @@
# c2_prog_wifi
WiFi-enabled programmer for Silicon Labs microcontrollers using the C2 programmer protocol, and to act as a serial-wifi bridge.
Designed to run in the Arduino environment for ESP8266 module: https://github.com/esp8266/Arduino
New programs can be loaded sending .hex files through the web-interface.
Everything is still alpha. Currently tested with EFM8BB10F2G-A-QFN20 and ESP-01 module: http://app.cear.ufpb.br/~lucas.hartmann/tag/efm8bb1/
LICENSE: GPLv3 or newer.

View File

@ -0,0 +1,19 @@
#######################################
# Syntax Coloring Map for C2Programmer
# (esp8266)
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
#######################################
# Methods and Functions (KEYWORD2)
#######################################
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,15 @@
{
"name": "C2Programmer",
"version": "1.0.0",
"keywords": [
"C2", "io", "Programmer"
],
"description": "Implementation of C2 programmer allowing update of Sonoff Bridge RF chip.",
"repository":
{
"type": "git",
"url": "https://github.com/lhartmann/c2_prog_wifi"
},
"frameworks": "arduino",
"platforms": "espressif8266"
}

View File

@ -0,0 +1,9 @@
name=C2Programmer
version=1.0.0
author=Lucas Hartmann
maintainer=Theo Arends <theo@arends.com>
sentence=Implementation of C2 programmer allowing update of Sonoff Bridge RF chip.
paragraph=
category=Signal Input/Output
url=
architectures=esp8266

View File

@ -0,0 +1,649 @@
#include "c2.h"
/////////////////////////////////////////////
// Nothing should need change on this file //
/////////////////////////////////////////////
// Times in microseconds
#define T_RD (20+5)
#define T_SD ( 2+5)
// Layer 0: Bit shifter
static bool c2_bit(bool b) {
C2D(b);
// C2_DELAY_US(1);
C2CK(0);
// C2_DELAY_US(1);
b = C2D();
C2CK(1);
return b;
}
// Layer 1: C2D Register read/write
void c2_address_write(uint8_t address) {
#ifdef C2_DEBUG
Serial.print("AW");
Serial.println(address, HEX);
#endif
// start
c2_bit(true);
C2D_enable(true);
// instruction
c2_bit(1);
c2_bit(1);
// Address
for (int i = 0; i < 8; ++i) {
c2_bit(address & 1);
address >>= 1;
}
// Stop
C2D_enable(false);
c2_bit(1);
}
uint8_t c2_address_read() {
// start
c2_bit(true);
C2D_enable(true);
// instruction
c2_bit(0);
c2_bit(1);
// Change C2D direction
C2D_enable(false);
c2_bit(0);
// Address
uint8_t a = 0, m = 1;
for (int i = 0; i < 8; ++i) {
if (c2_bit(a & 1)) {
a |= m;
}
m <<= 1;
}
// Stop is implied
#ifdef C2_DEBUG
Serial.print("AR");
Serial.println(a, HEX);
#endif
return a;
}
uint8_t c2_data_write(uint32_t d, uint8_t bytes) {
#ifdef C2_DEBUG
Serial.print("DW");
Serial.println(d, HEX);
#endif
// start
c2_bit(true);
C2D_enable(true);
// instruction
c2_bit(1);
c2_bit(0);
// Length
bytes--;
c2_bit(bytes & 1);
c2_bit(bytes & 2);
bytes++;
// Data
for (int i = 0; i < 8 * bytes; ++i) {
c2_bit(d & 1);
d >>= 1;
}
// Reverse C2D direction
C2D_enable(false);
c2_bit(0);
// Wait
uint8_t to = 128;
while (!c2_bit(0)) if (!--to) return C2_SHIFT_TIMEOUT;
// Stop
//c2_bit(0); implied
return C2_SUCCESS;
}
uint8_t c2_data_read(uint32_t &d, uint8_t bytes) {
// start
c2_bit(true);
C2D_enable(true);
// instruction
c2_bit(0);
c2_bit(0);
// Length
bytes--;
c2_bit(bytes & 1);
c2_bit(bytes & 2);
bytes++;
// Reverse C2D direction
C2D_enable(false);
c2_bit(0);
// Wait
uint8_t to = 128;
while (!c2_bit(0)) if (!--to) return C2_SHIFT_TIMEOUT;
// Data
d = 0;
uint32_t m = 1;
for (int i = 0; i < 8 * bytes; ++i) {
if (c2_bit(d & 1)) {
d |= m;
}
m <<= 1;
}
// Stop is implied
#ifdef C2D_DEBUG
Serial.print("DR");
Serial.println(d, HEX);
#endif
return C2_SUCCESS;
}
// Layer 2: Operations
#define C2_POLL_INBUSY() { \
uint16_t to = 1000; \
uint8_t a; \
while (1) { \
a = c2_address_read(); \
if (a == 0xFF) return C2_BROKEN_LINK; \
if (~a & C2_INBUSY) break; \
if (--to == 0) return C2_POLL_TIMEOUT; \
C2_DELAY_MS(1); \
}; \
}
#define C2_POLL_OUTREADY() { \
uint16_t to = 10000; \
uint8_t a; \
while (1) { \
a = c2_address_read(); \
if (a == 0xFF) return C2_BROKEN_LINK; \
if (a & C2_OUTREADY) break; \
if (--to == 0) return C2_POLL_TIMEOUT; \
C2_DELAY_MS(1); \
}; \
}
#define C2_DATA_WRITE_AND_CHECK(v, s) { \
uint8_t r = c2_data_write(v, s); \
if (r != C2_SUCCESS) return r; \
}
#define C2_DATA_READ_AND_CHECK(v, s) { \
uint8_t r = c2_data_read(v, s); \
if (r != C2_SUCCESS) return r; \
}
#define C2_EXPECT_DATA(value) { \
uint8_t d; \
C2_DATA_READ_AND_CHECK(d, 1); \
if (d != (value)) return C2_CMD_ERROR; \
}
uint8_t c2_reset() {
C2CK(false);
C2_DELAY_US(T_RD);
C2CK(true);
C2_DELAY_US(T_SD);
return C2_SUCCESS;
}
uint8_t c2_programming_init() {
c2_reset();
c2_address_write(C2FPCTL);
C2_DATA_WRITE_AND_CHECK(C2FPCTL_ENABLE0, 1);
C2_DATA_WRITE_AND_CHECK(C2FPCTL_CORE_HALT, 1);
C2_DATA_WRITE_AND_CHECK(C2FPCTL_ENABLE1, 1)
C2_DELAY_MS(21);
return C2_SUCCESS;
}
uint8_t c2_block_write(uint32_t address, uint8_t *data, uint8_t len) {
// 1. Perform an Address Write with a value of FPDAT
c2_address_write(C2FPDAT);
// 2. Perform a Data Write with the Block Write command.
C2_DATA_WRITE_AND_CHECK(C2FPDAT_BLOCK_WRITE, 1);
// 3. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 4. Poll on OutReady using Address Read until the bit set.
C2_POLL_OUTREADY();
// 5. Perform a Data Read instruction. A value of 0x0D is okay.
C2_EXPECT_DATA(0x0D);
// 6. Perform a Data Write with the high byte of the address.
C2_DATA_WRITE_AND_CHECK(address >> 8, 1);
// 7. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 8. Perform a Data Write with the low byte of the address.
C2_DATA_WRITE_AND_CHECK(address & 255, 1);
// 9. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 10. Perform a Data Write with the length.
C2_DATA_WRITE_AND_CHECK(len, 1);
// 12a. Repeat steps 11 and 12 for each byte specified by the length field.
uint8_t i = 0;
do {
// 11. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 12. Perform a Data Write with the data. This will write the data to the flash.
C2_DATA_WRITE_AND_CHECK(data[i], 1);
} while (++i != len);
// 13. Poll on OutReady using Address Read until the bit set.
C2_POLL_OUTREADY();
// 14. Perform a Data Read instruction. A value of 0x0D is okay. write to an EPROM block:
C2_EXPECT_DATA(0x0D);
return C2_SUCCESS;
}
uint8_t c2_eeprom_write(uint32_t address, uint8_t *data, uint8_t len) {
// 1. Write 0x04 to the FPCTL register.
c2_address_write(C2FPCTL);
C2_DATA_WRITE_AND_CHECK(0x04, 1);
// 2. Write 0x40 to EPCTL.
c2_address_write(C2EPCTL);
C2_DATA_WRITE_AND_CHECK(0x40, 1);
// 3. Write 0x58 to EPCTL.
C2_DATA_WRITE_AND_CHECK(0x58, 1);
// 4. Write the high byte of the address to EPADDRH.
c2_address_write(C2EPADDRH);
C2_DATA_WRITE_AND_CHECK(address >> 8, 1);
// 5. Write the low byte of the address to address EPADDRL.
c2_address_write(C2EPADDRL);
C2_DATA_WRITE_AND_CHECK(address, 1);
// 6. Perform an Address Write with a value of EPDAT.
c2_address_write(C2EPDAT);
// 7. Turn on VPP.
// 8. Wait for the VPP settling time.
// 10a. Repeat steps 9 and 10 until all bytes are written.
uint8_t i = 0;
do {
// 9. Write the data to the device using a Data Write.
C2_DATA_WRITE_AND_CHECK(data[i], 1);
// 10. Perform Address Read instructions until the value returned is not 0x80 and the EPROM is no longer busy.
C2_POLL_INBUSY();
} while (++i != len);
// 12. Turn off VPP. Note that VPP can only be applied for a maximum lifetime amount, and this value is specified in the device data sheet.
// 13. Write 0x40 to EPCTL.
c2_address_write(C2EPCTL);
C2_DATA_WRITE_AND_CHECK(0x40, 1);
// 14. Write 0x00 to EPCTL.
C2_DATA_WRITE_AND_CHECK(0x00, 1);
// 15. Write 0x02 to FPCTL.
c2_address_write(C2FPCTL);
C2_DATA_WRITE_AND_CHECK(0x02, 1);
// 16. Write 0x04 to FPCTL.
C2_DATA_WRITE_AND_CHECK(0x04, 1);
// 17. Write 0x01 to FPCTL.
C2_DATA_WRITE_AND_CHECK(0x01, 1);
return C2_SUCCESS;
}
uint8_t c2_block_read(uint32_t address, uint8_t *data, uint8_t len) {
// 1. Perform an Address Write with a value of FPDAT.
c2_address_write(C2FPDAT);
// 2. Perform a Data Write with the Block Read command.
C2_DATA_WRITE_AND_CHECK(C2FPDAT_BLOCK_READ, 1);
// 3. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 4. Poll on OutReady using Address Read until the bit set.
C2_POLL_OUTREADY();
// 5. Perform a Data Read instruction. A value of 0x0D is okay.
C2_EXPECT_DATA(0x0D);
// 6. Perform a Data Write with the high byte of the address.
C2_DATA_WRITE_AND_CHECK(address >> 8, 1);
// 7. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 8. Perform a Data Write with the low byte of the address.
C2_DATA_WRITE_AND_CHECK(address, 1);
// 9. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 10. Perform a Data Write with the length.
C2_DATA_WRITE_AND_CHECK(len, 1);
// 11. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 12. Poll on OutReady using Address Read until the bit set.
C2_POLL_OUTREADY();
// 13. Read FPI Command Status. Abort if Status != 0x0D.
C2_EXPECT_DATA(0x0D);
// 15a. Repeat step 14 and 15 for each byte specified by the length field.
uint8_t i = 0;
do {
// 14. Poll on OutReady using Address Read until the bit set.
C2_POLL_OUTREADY();
// 15. Perform a Data Read instruction. This will read the data from the flash.
C2_DATA_READ_AND_CHECK(data[i], 1);
} while (++i != len);
return C2_SUCCESS;
}
uint8_t c2_eeprom_read(uint32_t address, uint8_t *data, uint8_t len) {
// 1. Write 0x04 to the FPCTL register.
c2_address_write(C2FPCTL);
C2_DATA_WRITE_AND_CHECK(0x04, 1);
// 2. Write 0x00 to EPCTL.
c2_address_write(C2EPCTL);
C2_DATA_WRITE_AND_CHECK(0x00, 1);
// 3. Write 0x58 to EPCTL.
C2_DATA_WRITE_AND_CHECK(0x58, 1);
// 4. Write the high byte of the address to EPADDRH.
c2_address_write(C2EPADDRH);
C2_DATA_WRITE_AND_CHECK(address >> 8, 1);
// 5. Write the low byte of the address to address EPADDRL.
c2_address_write(C2EPADDRL);
C2_DATA_WRITE_AND_CHECK(address, 1);
// 6. Perform an Address Write with a value of EPDAT.
c2_address_write(C2EPDAT);
// 9. Repeat steps 7 and 8 until all bytes are read.
uint8_t i = 0;
do {
// 7.1. Perform an Address Write operation with a value of EPSTAT.
c2_address_write(C2EPSTAT);
// 7.2. Perform a Data Read operation and check the bits of the EPSTAT register.
uint8_t err;
C2_DATA_READ_AND_CHECK(err, 1);
if (err & C2EPSTAT_ERROR) return C2_CMD_ERROR;
// 7.3. Perform an Address Write operation with a value of EPDAT.
c2_address_write(C2EPDAT);
// 7. Perform Address Read instructions until the value returned is not 0x80 and the EPROM is no longer busy.
C2_POLL_INBUSY();
// 8.1. Perform an Address Write operation with a value of EPSTAT.
c2_address_write(C2EPSTAT);
// 8.2. Perform a Data Read operation and check the ERROR bit in the EPSTAT register.
C2_DATA_READ_AND_CHECK(err, 1);
if (err & C2EPSTAT_ERROR) return C2_CMD_ERROR;
// 8.3. Perform an Address Write operation with a value of EPDAT.
C2_DATA_WRITE_AND_CHECK(C2EPDAT, 1);
// 8. Read the byte using the Data Read instruction.
C2_DATA_READ_AND_CHECK(data[i], 1);
} while (++i != len);
// 10. Write 0x40 to EPCTL.
c2_address_write(C2EPCTL);
C2_DATA_WRITE_AND_CHECK(0x40, 1);
// 11. Write 0x00 to EPCTL.
C2_DATA_WRITE_AND_CHECK(0x00, 1);
// 12. Write 0x02 to FPCTL.
c2_address_write(C2FPCTL);
C2_DATA_WRITE_AND_CHECK(0x02, 1);
// 13. Write 0x04 to FPCTL.
C2_DATA_WRITE_AND_CHECK(0x04, 1);
// 14. Write 0x01 to FPCTL.
C2_DATA_WRITE_AND_CHECK(0x01, 1);
return C2_SUCCESS;
}
uint8_t c2_page_erase(uint8_t page) {
// 1. Perform an Address Write with a value of FPDAT.
c2_address_write(C2FPDAT);
// 2. Perform a Data Write with the Page Erase command.
c2_data_write(C2FPDAT_FLASH_PAGE_ERASE, 1);
// 3. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 4. Poll on OutReady using Address Read until the bit set.
C2_POLL_OUTREADY();
// 5. Perform a Data Read instruction. A value of 0x0D is okay.
C2_EXPECT_DATA(0x0D);
// 6. Perform a Data Write with the page number.
c2_data_write(page, 1);
// 7. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 8. Poll on OutReady using Address Read until the bit clears.
C2_POLL_OUTREADY();
// 9. Perform a Data Read instruction. A value of 0x0D is okay.
C2_EXPECT_DATA(0x0D);
// 10. Perform a Data Write with the a value of 0x00.
c2_data_write(0x00, 1);
// 11. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 12. Poll on OutReady using Address Read until the bit set.
C2_POLL_OUTREADY();
// 13. Perform a Data Read instruction. A value of 0x0D is okay.
C2_EXPECT_DATA(0x0D);
return C2_SUCCESS;
}
uint8_t c2_device_erase() {
// 1. Perform an Address Write with a value of FPDAT.
c2_address_write(C2FPDAT);
// 2. Perform a Data Write with the Device Erase command.
C2_DATA_WRITE_AND_CHECK(C2FPDAT_DEVICE_ERASE, 1);
// 3. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 4. Poll on OutReady using Address Read until the bit set.
C2_POLL_OUTREADY();
// 5. Perform a Data Read instruction. A value of 0x0D is okay.
C2_EXPECT_DATA(0x0D);
// 6. Perform a Data Write with a value of 0xDE.
C2_DATA_WRITE_AND_CHECK(0xDE, 1);
// 7. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 8. Perform a Data Write with a value of 0xAD.
C2_DATA_WRITE_AND_CHECK(0xAD, 1);
// 9. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 10. Perform a Data Write with a value of 0xA5.
C2_DATA_WRITE_AND_CHECK(0xA5, 1);
// 11. Poll on InBusy using Address Read until the bit clears.
C2_POLL_INBUSY();
// 12. Poll on OutReady using Address Read until the bit set.
C2_POLL_OUTREADY();
// 13. Perform a Data Read instruction. A value of 0x0D is okay.
C2_EXPECT_DATA(0x0D);
return C2_SUCCESS;
}
uint8_t c2_sfr_write_non_paged(uint8_t address, uint8_t data) {
// 1. Write the SFR address to the device using the Address Write instruction.
c2_address_write(address);
// 2. Write the SFR value to the device using the Data Write instruction.
C2_DATA_WRITE_AND_CHECK(data, 1);
return C2_SUCCESS;
}
uint8_t c2_sfr_write_paged(uint8_t address, uint8_t data) {
// 1. Perform an Address Write with a value of FPDAT.
c2_address_write(C2FPDAT);
// 2. Write the Direct Write command (0x0A) using a Data Write
C2_DATA_WRITE_AND_CHECK(C2FPDAT_DIRECT_WRITE, 1);
// 3. Poll InBusy until the data is processed by the PI.
C2_POLL_INBUSY();
// 4. Poll OutReady it sets to 1.
C2_POLL_OUTREADY();
// 5. Perform a Data Read to ensure a return value of 0x0D (no errors).
C2_EXPECT_DATA(0x0D);
// 6. Perform a Data Write with a value of the SFR address.
C2_DATA_WRITE_AND_CHECK(address, 1);
// 7. Poll InBusy until the data is processed by the PI.
C2_POLL_INBUSY();
// 8. Perform a Data Write with a value of 0x01.
C2_DATA_WRITE_AND_CHECK(0x01, 1);
// 9. Poll InBusy until the data is processed by the PI.
C2_POLL_INBUSY();
// 10. Perform a Data Write with the new SFR value.
C2_DATA_WRITE_AND_CHECK(data, 1);
// 11. Poll InBusy until the data is processed by the PI.
C2_POLL_INBUSY();
return C2_SUCCESS;
}
// 4.6. Reading from an SFR
// To read from an SFR on a device that does not have SFR paging:
uint8_t c2_sfr_read_non_paged(uint8_t address, uint8_t &v) {
// 1. Write the SFR address to the device using the Address Write instruction.
c2_address_write(address);
// 2. Read the SFR value from the device using the Data Read instruction.
C2_DATA_READ_AND_CHECK(v, 1);
return C2_SUCCESS;
}
// For devices with SFR paging, direct reads through the PI using the Direct Read command are recommended to ensure the SFR Page is managed properly.
// To read an SFR from a device with SFR paging:
uint8_t c2_sfr_read_paged(uint8_t address, uint8_t &v) {
// 1. Perform an Address Write with a value of FPDAT.
c2_address_write(C2FPDAT);
// 2. Write the Direct Read command (0x09) using a Data Write.
C2_DATA_WRITE_AND_CHECK(C2FPDAT_DIRECT_READ, 1);
// 3. Poll InBusy until the data is processed by the PI.
C2_POLL_INBUSY();
// 4. Poll OutReady until it sets to 1.
C2_POLL_OUTREADY();
// 5. Perform a Data Read to ensure a return value of 0x0D (no errors).
C2_EXPECT_DATA(0x0D);
// 6. Perform a Data Write with a value of the SFR address.
C2_DATA_WRITE_AND_CHECK(address, 1);
// 7. Poll InBusy until the data is processed by the PI.
C2_POLL_INBUSY();
// 8. Perform a Data Write with a value of 0x01.
C2_DATA_WRITE_AND_CHECK(0x01, 1);
// 9. Poll InBusy until the data is processed by the PI.
C2_POLL_INBUSY();
// 10. Poll OutReady until it sets to 0.
C2_POLL_OUTREADY();
// 11. Read the SFR value from the device using the Data Read instruction.
C2_DATA_READ_AND_CHECK(v, 1);
return C2_SUCCESS;
}
const char *c2_print_status_by_name(uint8_t ch) {
switch (ch) {
case C2_SUCCESS: return "Success";
case C2_SHIFT_TIMEOUT: return "Shift wait timeout error";
case C2_POLL_TIMEOUT: return "Register poll timeout error";
case C2_CMD_ERROR: return "In-command error";
case C2_BROKEN_LINK: return "Broken link, address read failed";
default: return "unknownl error";
}
}
// This is to enforce arduino-like formatting in kate
// kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;

View File

@ -0,0 +1,141 @@
#ifndef C2_H
#define C2_H
#include <stdint.h>
#include <Arduino.h>
////////////////////////////////
// Hardware Abstraction Layer //
////////////////////////////////
// Rewrite these for your hardware
#define PIN_C2CK 4
#define PIN_C2D 5
// Set C2CK state
inline void C2CK(bool ck) {
digitalWrite(PIN_C2CK, ck);
}
// get C2CK state
inline bool C2CK() {
return digitalRead(PIN_C2CK);
}
// Set C2D state
inline void C2D(bool d) {
digitalWrite(PIN_C2D, d);
}
// Get C2D state
inline bool C2D() {
return digitalRead(PIN_C2D);
}
// Enable/disable C2D output butter
inline void C2D_enable(bool oe) {
if (oe) pinMode(PIN_C2D, OUTPUT);
else pinMode(PIN_C2D, INPUT);
}
// Delay functions
#define C2_DELAY_US(n) delayMicroseconds(n)
#define C2_DELAY_MS(n) delay(n)
////////////////////////////////////////////
// Nothing should need change from now on //
////////////////////////////////////////////
// Exceptions:
#define C2_SUCCESS 0x00 // Compare for success
#define C2_ERROR 0xFF // Mask for all errors
#define C2_TIMEOUT 0x03 // Mask for timeouts
#define C2_SHIFT_TIMEOUT 0x01 // Shift wait
#define C2_POLL_TIMEOUT 0x02 // Register poll
#define C2_CMD_ERROR 0x04 // In-command Error
#define C2_BROKEN_LINK 0x08 // Address read returned 0xFF, comms disabled
// Register Addresses
#define C2DEVID 0x00
#define C2REVID 0x01
#define C2FPCTL 0x02
#define C2FPDAT 0xB4
#define C2EPCTL 0x00
#define C2EPDAT 0x00
#define C2EPDAT 0x00
#define C2EPADDRH 0x00
#define C2EPADDRL 0x00
#define C2EPSTAT 0x00
// Commands for FPCTL register
#define C2FPCTL_ENABLE0 0x02
#define C2FPCTL_CORE_HALT 0x04
#define C2FPCTL_ENABLE1 0x01
// Commands for FPDAT register
#define C2FPDAT_DEVICE_ERASE 0x03
#define C2FPDAT_FLASH_BLOCK_READ 0x06
#define C2FPDAT_BLOCK_WRITE 0x07
#define C2FPDAT_FLASH_PAGE_ERASE 0x08
#define C2FPDAT_BLOCK_READ 0x06
#define C2FPDAT_GET_VERSION 0x01
#define C2FPDAT_GET_DERIVATIVE 0x02
#define C2FPDAT_DIRECT_READ 0x09
#define C2FPDAT_DIRECT_WRITE 0x0A
#define C2FPDAT_INDIRECT_READ 0x0B
#define C2FPDAT_INDIRECT_WRITE 0x0C
// Commands for EPCTL register
#define C2EPCTL_ENABLE0 0x40
#define C2EPCTL_ENABLE1 0x58
// EPSTAT status bits
#define C2EPSTAT_WLOCK 0x80
#define C2EPSTAT_RLOCK 0x40
#define C2EPSTAT_ERROR 0x01
// 'Address read' status bits
#define C2_FLBUSY 0x08
#define C2_EEBUSY C2_FLBUSY
#define C2_EEERROR 0x04
#define C2_INBUSY 0x02
#define C2_OUTREADY 0x01
// Layer 1: C2 Programmig Interface (PI) Register access
void c2_address_write(uint8_t address);
uint8_t c2_address_read();
uint8_t c2_data_write(uint32_t d, uint8_t bytes);
uint8_t c2_data_read(uint32_t &d, uint8_t bytes=4);
// Shorcuts for smaller words
inline uint8_t c2_data_read(uint16_t &d, uint8_t bytes=2) {
uint32_t dd;
uint8_t r = c2_data_read(dd, 2);
d = dd;
return r;
}
inline uint8_t c2_data_read(uint8_t &d, uint8_t bytes=1) {
uint32_t dd;
uint8_t r = c2_data_read(dd, 1);
d = dd;
return r;
}
// Layer 2: Operations
uint8_t c2_reset();
uint8_t c2_programming_init();
uint8_t c2_block_write(uint32_t address, uint8_t *data, uint8_t len);
uint8_t c2_block_read(uint32_t address, uint8_t *data, uint8_t len);
uint8_t c2_eeprom_read(uint32_t address, uint8_t *data, uint8_t len);
uint8_t c2_page_erase(uint8_t page);
uint8_t c2_device_erase();
uint8_t c2_sfr_write_non_paged(uint8_t address, uint8_t data);
uint8_t c2_sfr_write_paged(uint8_t address, uint8_t data);
uint8_t c2_sfr_read_non_paged(uint8_t address, uint8_t &data);
uint8_t c2_sfr_read_paged(uint8_t address, uint8_t &data);
const char *c2_print_status_by_name(uint8_t ch);
#endif // C2_H

View File

@ -0,0 +1,71 @@
#include "ihx.h"
#include <Arduino.h>
static const char *conv = "0123456789ABCDEFabcdef";
static uint8_t value_of_hex(uint8_t ch) {
uint8_t i = 0;
//Loop through list
while (conv[i] && ch != conv[i]) i++;
if (!conv[i]) return 0;
//Convert to upper case
if (i >= 16) return i - 6; // lowercase
return i;
}
uint8_t ihx_decode(uint8_t *buff, uint16_t slen) {
// Make sure the line looks like intel
if (buff[0] != ':') {
#ifdef IHX_DEBUG
Serial.println("IHX: Bad start:" + buff[0]);
#endif
return IHX_ERROR;
}
// Remove strayline terminators at the end of the file
while (buff[slen - 1] == '\n' || buff[slen - 1] == '\r') slen--;
// Length must be odd: start followed by hex pairs
if (slen < 11) {
#ifdef IHX_DEBUG
Serial.printf("IHX: Short read: %u\n", slen);
#endif
return IHX_ERROR;
}
if (slen % 2 != 1) {
#ifdef IHX_DEBUG
Serial.printf("IHX: Length not odd (%u)\n", slen);
#endif
return IHX_ERROR;
}
// Decode
uint8_t cs = 0;
for (int i = 0; i < (slen - 1) / 2; ++i) {
buff[i] = (value_of_hex(buff[2 * i + 1]) << 4) | value_of_hex(buff[2 * i + 2]);
cs += buff[i];
}
// Validate checksum
if (cs) {
#ifdef IHX_DEBUG
Serial.print("IHX: Bad checksum: ");
Serial.println(cs, HEX);
#endif
return IHX_ERROR;
}
// Check if lengths match
if (buff[0] * 2 + 11 != slen) {
#ifdef IHX_DEBUG
Serial.println("IHX: Length mismatch");
#endif
return IHX_ERROR;
}
return IHX_SUCCESS;
}

View File

@ -0,0 +1,39 @@
#ifndef IHX_H
#define IHX_H
#include <stdint.h>
// Decoded
// Intel HEX file format:
// 1B - Start ':'
// 2B - data bytes
// 4B - address
// 2B - record type
// ?B - data
// 2B - checksum
// 01234567890123
// :NNAAAATTDDSS
struct ihx_t {
uint8_t len;
uint8_t address_high;
uint8_t address_low;
uint8_t record_type; // See IHX_RT_* below
uint8_t data[];
};
#define IHX_RT_DATA 0x00
#define IHX_RT_END_OF_FILE 0x01
#define IHX_RT_EXTENDED_SEGMENT_ADDRESS 0x02
#define IHX_RT_START_SEGMENT_ADDRESS 0x03
#define IHX_RT_EXTENDED_LINEAR_ADDRESS 0x04
#define IHX_RT_START_LINEAR_ADDRESS 0x05
#define IHX_SUCCESS 0x00
#define IHX_ERROR 0xFF
extern uint8_t ihx_decode(uint8_t *buff, uint16_t slen);
#endif // IHX_H
// This is to enforce arduino-like formatting in kate
// kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;

View File

@ -1,7 +1,22 @@
/* 6.0.0a
* Add option 0 to command Timers disarming all timers (#2962)
* Add time in minutes to rule Time#Initialized, Time#set and Time#Minute (#2669)
* Add rule variables %time% for minutes since midnight, %uptime%, %sunrise% and %sunset% giving time in minutes (#2669)
* Add heap and stack debug information
* Add command SetOption28 to switch between hex or decimal Sonoff Bridge RF received data format (#3008)
* Add command SetOption29 to switch between hex or decimal IR received data format
* Add performance improvement when updating multiple individual WS2812 pixels (#3007)
* Add debug facilities using optional xdrv_99_debug.ino to enable in user_config.h
* Add KNX support for DS18S20 Temperature sensor
* Add CRC to Settings making future upgrades more fail-safe
* Add support for uploading Sonoff Bridge firmware found in tools/fw_efm8bb1 folder build by Portisch using Web Gui File Upload (#2886)
* Add support for I2C temperature sensor LM75AD (#2909)
* Add command RfRaw to control Portisch firmware features
* Remove version 3, 4 and pre 5.2 settings auto-upgrade. See https://github.com/arendst/Sonoff-Tasmota/wiki/Upgrade#migration-path
* Change default CFG_HOLDER from 0x20161209 to 4617 (=0x1209) - no impact on default upgrades
* Fix Pzem004T checksum error
* Fix KNX bug when doing reply of sensors values
* Fix rules induced LWT message
*
* 5.14.0b
* Add Console Commands to send KNX Commands
@ -13,10 +28,11 @@
where [slot] is any of the 5 slots on the KNX Menu and value is a number
example: KnxTx_Val1 35
* Add Slots on the KNX Web Menu to select Group Addess to send data from console commands
* Add Events to trigger rules when received data from KNX
usage on rules as: event#KnxRx_Val[slot]
* Add Events to trigger rules when a command is received from KNX
usage on rules as: event#KnxRx_Cmnd[slot]
where [slot] is any of the 5 slots on the KNX Menu
example: rule on event#KnxRx_Val1 do VAR1 %value% endon
example: rule on event#KnxRx_Cmnd1 do VAR1 %value% endon
(where %value% can be 0 or 1)
* Add Events to trigger rules when received read requests from KNX
usage on rules as: event#KnxRx_Req[slot]
where [slot] is any of the 5 slots on the KNX Menu

View File

@ -345,6 +345,7 @@
#define D_CMND_RFLOW "RfLow"
#define D_CMND_RFSYNC "RfSync"
#define D_JSON_RFRECEIVED "RfReceived"
#define D_CMND_RFRAW "RfRaw"
// Commands xdrv_07_domoticz.ino
#define D_CMND_DOMOTICZ "Domoticz"
@ -511,7 +512,7 @@ const char kOptionToggle[] PROGMEM = "TOGGLE|" D_TOGGLE "|" D_ADMIN ;
const char kOptionBlink[] PROGMEM = "BLINK|" D_BLINK ;
const char kOptionBlinkOff[] PROGMEM = "BLINKOFF|" D_BLINKOFF ;
// webserver.ino
// xdrv_02_webserver.ino
#ifdef USE_WEBSERVER
const char HTTP_SNS_TEMP[] PROGMEM = "%s{s}%s " D_TEMPERATURE "{m}%s&deg;%c{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_HUM[] PROGMEM = "%s{s}%s " D_HUMIDITY "{m}%s%%{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
* Updated until v5.14.0a
* Updated until v6.0.0a
\*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -206,7 +206,7 @@
#define D_ERASED_SECTOR "Изтрит сектор"
// xdrv_02_webserver.ino
#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "Минимаен фърмуеър - моля надградете го"
#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "Минимален фърмуеър - моля надградете го"
#define D_WEBSERVER_ACTIVE_ON "Уеб сървърът е активен на"
#define D_WITH_IP_ADDRESS "с IP адрес"
#define D_WEBSERVER_STOPPED "Уеб сървърът е спрян"
@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Зареждането е прекъснато"
#define D_UPLOAD_ERR_8 "Файлът е невалиден"
#define D_UPLOAD_ERR_9 "Файлът е прекалено голям"
#define D_UPLOAD_ERR_10 "Грешка при инициализация на RF чипа"
#define D_UPLOAD_ERR_11 "Грешка при изтриване на RF чипа"
#define D_UPLOAD_ERR_12 "Грешка при записване в RF чипа"
#define D_UPLOAD_ERR_13 "Грешка при декодиране на RF фирмуера"
#define D_UPLOAD_ERROR_CODE "Код на грешка при зареждането"
#define D_ENTER_COMMAND "Въвеждане на команда"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Nahrávání přerušeno"
#define D_UPLOAD_ERR_8 "Špatný soubor"
#define D_UPLOAD_ERR_9 "Soubor je příliš velký"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Chyba nahrávání"
#define D_ENTER_COMMAND "Vlož příkaz"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Upload abgebrochen"
#define D_UPLOAD_ERR_8 "Datei ungültig"
#define D_UPLOAD_ERR_9 "Datei zu groß"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Upload Fehler Nummer"
#define D_ENTER_COMMAND "Befehl eingeben"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Το ανεβάσμα διακόπηκε"
#define D_UPLOAD_ERR_8 "Μη έγκυρο αρχείο"
#define D_UPLOAD_ERR_9 "Το αρχείο είναι πολύ μεγάλο"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Κωδικός λάθους ανεβάσματος"
#define D_ENTER_COMMAND "Εισαγωγή εντολής"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Upload aborted"
#define D_UPLOAD_ERR_8 "File invalid"
#define D_UPLOAD_ERR_9 "File too large"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Upload error code"
#define D_ENTER_COMMAND "Enter command"

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
* Updated until v5.14.0b
* Updated until v6.0.0a
\*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Carga cancelada"
#define D_UPLOAD_ERR_8 "Archivo no válido"
#define D_UPLOAD_ERR_9 "Archivo muy grande"
#define D_UPLOAD_ERR_10 "No inició chip RF"
#define D_UPLOAD_ERR_11 "No se pudo borrar en el chip RF"
#define D_UPLOAD_ERR_12 "No se puedo escribir en el chip RF"
#define D_UPLOAD_ERR_13 "No se pudo decodificar firmware RF"
#define D_UPLOAD_ERROR_CODE "Código de error de carga"
#define D_ENTER_COMMAND "Ingresar comando"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Téléchargement annulé"
#define D_UPLOAD_ERR_8 "Fichier invalide"
#define D_UPLOAD_ERR_9 "Fichier trop grand"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Code d'erreur téléchargement"
#define D_ENTER_COMMAND "Saisir une commande"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Feltöltés megszakítva"
#define D_UPLOAD_ERR_8 "Érvénytelen file"
#define D_UPLOAD_ERR_9 "File túl nagy"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Feltöltés hiba kód"
#define D_ENTER_COMMAND "Parancsolj"

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
* Updated until v5.14.0
* Updated until v6.0.0a
\*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Invio annullato"
#define D_UPLOAD_ERR_8 "File non valido"
#define D_UPLOAD_ERR_9 "File troppo grande"
#define D_UPLOAD_ERR_10 "Inizializzazione fallita del chip RF"
#define D_UPLOAD_ERR_11 "Cancellazione fallita del chip RF"
#define D_UPLOAD_ERR_12 "Scrittura fallita del chip RF"
#define D_UPLOAD_ERR_13 "Decodifica fallita del firmware RF"
#define D_UPLOAD_ERROR_CODE "Codice errore invio"
#define D_ENTER_COMMAND "Inserire comando"

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
* Updated until v5.14.0a
* Updated until v6.0.0a
\*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Opwaarderen afgebroken"
#define D_UPLOAD_ERR_8 "Ongeldig bestand"
#define D_UPLOAD_ERR_9 "Bestand is te groot"
#define D_UPLOAD_ERR_10 "Init RF chip mislukt"
#define D_UPLOAD_ERR_11 "Wissen RF chip mislukt"
#define D_UPLOAD_ERR_12 "Opwaarderen RF chip mislukt"
#define D_UPLOAD_ERR_13 "Decoderen RF bestand mislukt"
#define D_UPLOAD_ERROR_CODE "Opwaardeer foutcode"
#define D_ENTER_COMMAND "Geef opdracht"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Wgrywanie przerwane"
#define D_UPLOAD_ERR_8 "Błędny plik"
#define D_UPLOAD_ERR_9 "Plik jest za duży"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Błąd wgrywania"
#define D_ENTER_COMMAND "Wprowadź polecenie"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Envio cancelado"
#define D_UPLOAD_ERR_8 "Arquivo inválido"
#define D_UPLOAD_ERR_9 "Arquivo muito grande"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Código de erro do envio"
#define D_ENTER_COMMAND "Inserir comando"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Envio cancelado"
#define D_UPLOAD_ERR_8 "Ficheiro inválido"
#define D_UPLOAD_ERR_9 "Ficheiro demasiado grande"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Código de erro do envio"
#define D_ENTER_COMMAND "Inserir comando"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Загрузка прервана"
#define D_UPLOAD_ERR_8 "Файл неверный"
#define D_UPLOAD_ERR_9 "Слишком большой файл"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Код ошибки загрузки"
#define D_ENTER_COMMAND "Введите команду"

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "Завантаження перервано"
#define D_UPLOAD_ERR_8 "Файл невірний"
#define D_UPLOAD_ERR_9 "Занадто великий файл"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "Код помилки завантаження"
#define D_ENTER_COMMAND "Уведіть команду"

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
* Updated until v5.12.0d
* Updated until v5.14.0b
\*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -44,8 +44,8 @@
#define D_HOUR_MINUTE_SEPARATOR ":"
#define D_MINUTE_SECOND_SEPARATOR ":"
#define D_DAY3LIST "SunMonTueWedThuFriSat"
#define D_MONTH3LIST "JanFebMarAprMayJunJulAugSepOctNovDec"
#define D_DAY3LIST "日 一 二 三 四 五 六 "
#define D_MONTH3LIST "1月 2月 3月 4月 5月 6月 7月 8月 9月 10月11月12月"
// Non JSON decimal separator
#define D_DECIMAL_SEPARATOR "."
@ -59,9 +59,9 @@
#define D_BLINK "闪烁"
#define D_BLINKOFF "闪烁关"
#define D_BOOT_COUNT "启动次数"
#define D_BRIGHTLIGHT "亮"
#define D_BRIGHTLIGHT "亮"
#define D_BUTTON "按钮"
#define D_BY "by" // Written by me
#define D_BY "汉化: killadm 作者:" // Written by me
#define D_BYTES "大小:"
#define D_CELSIUS "摄氏"
#define D_CO2 "二氧化碳"
@ -70,13 +70,13 @@
#define D_COMMAND "命令:"
#define D_CONNECTED "已连接"
#define D_COUNT "数量:"
#define D_COUNTER "Counter"
#define D_COUNTER "计数器"
#define D_CURRENT "电流" // As in Voltage and Current
#define D_DATA "数据:"
#define D_DARKLIGHT "Dark"
#define D_DARKLIGHT ""
#define D_DEBUG "调试"
#define D_DISABLED "禁用"
#define D_DISTANCE "Distance"
#define D_DISTANCE "距离"
#define D_DNS_SERVER "DNS服务器"
#define D_DONE "完成"
#define D_DST_TIME "DST"
@ -87,12 +87,12 @@
#define D_ERROR "错误"
#define D_FAHRENHEIT "华氏"
#define D_FAILED "失败"
#define D_FALLBACK "Fallback"
#define D_FALLBACK_TOPIC "Fallback Topic"
#define D_FALLBACK "回退"
#define D_FALLBACK_TOPIC "回退主题"
#define D_FALSE "False"
#define D_FILE "文件:"
#define D_FREE_MEMORY "空闲内存"
#define D_FREQUENCY "Frequency"
#define D_FREQUENCY "频率"
#define D_GAS "气体"
#define D_GATEWAY "网关"
#define D_GROUP "组:"
@ -100,10 +100,10 @@
#define D_HOSTNAME "主机名"
#define D_HUMIDITY "湿度"
#define D_ILLUMINANCE "照度"
#define D_IMMEDIATE "immediate" // Button immediate
#define D_IMMEDIATE "单次按键" // Button immediate
#define D_INDEX "索引:"
#define D_INFO "信息"
#define D_INFRARED "Infrared"
#define D_INFRARED "红外线"
#define D_INITIALIZED "初始化完成"
#define D_IP_ADDRESS "IP地址"
#define D_LIGHT "灯"
@ -122,9 +122,9 @@
#define D_PORT "端口"
#define D_POWER_FACTOR "功率因数"
#define D_POWERUSAGE "功率"
#define D_POWERUSAGE_ACTIVE "Active Power"
#define D_POWERUSAGE_APPARENT "Apparent Power"
#define D_POWERUSAGE_REACTIVE "Reactive Power"
#define D_POWERUSAGE_ACTIVE "有功功率"
#define D_POWERUSAGE_APPARENT "视在功率"
#define D_POWERUSAGE_REACTIVE "无功功率"
#define D_PRESSURE "气压"
#define D_PRESSUREATSEALEVEL "海平面气压"
#define D_PROGRAM_FLASH_SIZE "固件 Flash 大小"
@ -136,7 +136,7 @@
#define D_RESTART_REASON "重启原因"
#define D_RESTORE "恢复"
#define D_RETAINED "已保留"
#define D_RULE "Rule"
#define D_RULE "规则"
#define D_SAVE "保存"
#define D_SENSOR "传感器"
#define D_SSID "名称"
@ -146,8 +146,8 @@
#define D_SUBNET_MASK "子网掩码"
#define D_SUBSCRIBE_TO "订阅"
#define D_SUCCESSFUL "成功"
#define D_SUNRISE "Sunrise"
#define D_SUNSET "Sunset"
#define D_SUNRISE "日出"
#define D_SUNSET "日落"
#define D_TEMPERATURE "温度"
#define D_TO "to"
#define D_TOGGLE "切换"
@ -160,7 +160,7 @@
#define D_UPTIME "运行时间"
#define D_USER "用户名"
#define D_UTC_TIME "UTC"
#define D_UV_INDEX "UV Index"
#define D_UV_INDEX "紫外线指数"
#define D_UV_LEVEL "紫外线水平"
#define D_VERSION "版本"
#define D_VOLTAGE "电压"
@ -182,43 +182,43 @@
// support.ino
#define D_OSWATCH "osWatch"
#define D_BLOCKED_LOOP "Blocked Loop"
#define D_WPS_FAILED_WITH_STATUS "WPSconfig FAILED with status"
#define D_ACTIVE_FOR_3_MINUTES "active for 3 minutes"
#define D_WPS_FAILED_WITH_STATUS "WPS 配置失败,状态:"
#define D_ACTIVE_FOR_3_MINUTES "激活 3 分钟"
#define D_FAILED_TO_START "未能启动"
#define D_PATCH_ISSUE_2186 "Patch issue 2186"
#define D_CONNECTING_TO_AP "连接到 AP"
#define D_IN_MODE "模式:"
#define D_CONNECT_FAILED_NO_IP_ADDRESS "连接失败,因为没有获取到IP地址"
#define D_CONNECT_FAILED_AP_NOT_REACHED "连接失败,无法连接AP"
#define D_CONNECT_FAILED_WRONG_PASSWORD "连接失败AP密码不正确"
#define D_CONNECT_FAILED_AP_TIMEOUT "连接失败AP超时"
#define D_CONNECT_FAILED_NO_IP_ADDRESS "连接失败,因为没有获取到 IP 地址"
#define D_CONNECT_FAILED_AP_NOT_REACHED "连接失败,无法连接 AP"
#define D_CONNECT_FAILED_WRONG_PASSWORD "连接失败AP 密码不正确"
#define D_CONNECT_FAILED_AP_TIMEOUT "连接失败AP 超时"
#define D_ATTEMPTING_CONNECTION "尝试连接..."
#define D_CHECKING_CONNECTION "检查连接..."
#define D_QUERY_DONE "查询完成。 发现MQTT服务"
#define D_MQTT_SERVICE_FOUND "发现MQTT服务:"
#define D_FOUND_AT "found at"
#define D_SYSLOG_HOST_NOT_FOUND "Syslog主机未找到"
#define D_QUERY_DONE "查询完成。 发现 MQTT 服务"
#define D_MQTT_SERVICE_FOUND "发现 MQTT 服务:"
#define D_FOUND_AT "发现:"
#define D_SYSLOG_HOST_NOT_FOUND "Syslog 主机未找到"
// settings.ino
#define D_SAVED_TO_FLASH_AT "保存到 flash:"
#define D_LOADED_FROM_FLASH_AT "从 flash 载入"
#define D_LOADED_FROM_FLASH_AT "从 flash 载入:"
#define D_USE_DEFAULTS "使用默认设置"
#define D_ERASED_SECTOR "擦除删除"
#define D_ERASED_SECTOR "擦除扇区"
// xdrv_02_webserver.ino
#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "固件版本过低 - 请升级"
#define D_WEBSERVER_ACTIVE_ON "Web服务器:"
#define D_WITH_IP_ADDRESS "IP地址:"
#define D_WEBSERVER_STOPPED "Web 服务已停止"
// webserver.ino
#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "当前是精简版固件 - 请升级"
#define D_WEBSERVER_ACTIVE_ON "Web 服务器地址:"
#define D_WITH_IP_ADDRESS "IP 地址:"
#define D_WEBSERVER_STOPPED "Web 服务已停止"
#define D_FILE_NOT_FOUND "文件未找到"
#define D_REDIRECTED "重定向到认证页面"
#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager set AccessPoint and keep Station"
#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager 设置无线操作模式"
#define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager 设置接入点"
#define D_TRYING_TO_CONNECT "尝试将设备连接到网络"
#define D_RESTART_IN "重启需要"
#define D_SECONDS "秒"
#define D_DEVICE_WILL_RESTART "设备将在几钟内重启"
#define D_DEVICE_WILL_RESTART "设备将在几钟内重启"
#define D_BUTTON_TOGGLE "状态切换"
#define D_CONFIGURATION "设置"
#define D_INFORMATION "信息"
@ -260,7 +260,7 @@
#define D_AP2_SSID "AP2 名称"
#define D_AP2_PASSWORD "AP2 密码"
#define D_MQTT_PARAMETERS "MQTT设置"
#define D_MQTT_PARAMETERS "MQTT 设置"
#define D_CLIENT "客户端"
#define D_FULL_TOPIC "完整主题"
@ -274,7 +274,7 @@
#define D_TELEMETRY_PERIOD "上报周期"
#define D_OTHER_PARAMETERS "其他设置"
#define D_WEB_ADMIN_PASSWORD "WEB管理密码"
#define D_WEB_ADMIN_PASSWORD "WEB 管理密码"
#define D_MQTT_ENABLE "启用MQTT"
#define D_FRIENDLY_NAME "昵称"
#define D_BELKIN_WEMO "贝尔金 WeMo"
@ -288,46 +288,50 @@
#define D_PROGRAM_VERSION "固件版本"
#define D_BUILD_DATE_AND_TIME "编译时间"
#define D_CORE_AND_SDK_VERSION "内核版本"
#define D_FLASH_WRITE_COUNT "刷机次数"
#define D_MAC_ADDRESS "MAC地址"
#define D_MQTT_HOST "MQTT主机"
#define D_MQTT_PORT "MQTT端口"
#define D_MQTT_CLIENT "MQTT客户端"
#define D_MQTT_USER "MQTT用户名"
#define D_MQTT_TOPIC "MQTT 主题(Topic)"
#define D_MQTT_GROUP_TOPIC "MQTT 主题组(Group Topic)"
#define D_MQTT_FULL_TOPIC "MQTT 完整主题(Full Topic)"
#define D_CORE_AND_SDK_VERSION "内核和 SDK 版本"
#define D_FLASH_WRITE_COUNT "Flash 写入次数"
#define D_MAC_ADDRESS "MAC 地址"
#define D_MQTT_HOST "MQTT 主机"
#define D_MQTT_PORT "MQTT 端口"
#define D_MQTT_CLIENT "MQTT 客户端"
#define D_MQTT_USER "MQTT 用户名"
#define D_MQTT_TOPIC "MQTT 主题"
#define D_MQTT_GROUP_TOPIC "MQTT 主题组"
#define D_MQTT_FULL_TOPIC "MQTT 完整主题"
#define D_MDNS_DISCOVERY "mDNS 发现"
#define D_MDNS_ADVERTISE "mDNS 广播"
#define D_ESP_CHIP_ID "ESP芯片ID"
#define D_FLASH_CHIP_ID "Flash芯片ID"
#define D_FLASH_CHIP_SIZE "Flash大小"
#define D_ESP_CHIP_ID "ESP 芯片 ID"
#define D_FLASH_CHIP_ID "Flash 芯片 ID"
#define D_FLASH_CHIP_SIZE "Flash 大小"
#define D_FREE_PROGRAM_SPACE "空闲程序空间"
#define D_UPGRADE_BY_WEBSERVER "通过Web升级"
#define D_OTA_URL "OTA地址"
#define D_UPGRADE_BY_WEBSERVER "通过 Web 升级"
#define D_OTA_URL "OTA 地址"
#define D_START_UPGRADE "开始升级"
#define D_UPGRADE_BY_FILE_UPLOAD "通过文件升级"
#define D_UPLOAD_STARTED "开始上传"
#define D_UPGRADE_STARTED "开始升级"
#define D_UPLOAD_DONE "上传完成"
#define D_UPLOAD_ERR_1 "没有选择文件"
#define D_UPLOAD_ERR_1 "没有选择任何文件"
#define D_UPLOAD_ERR_2 "没有足够空间"
#define D_UPLOAD_ERR_3 "固件头不是 0xE9"
#define D_UPLOAD_ERR_4 "固件大"
#define D_UPLOAD_ERR_5 "上传缓冲区不匹配"
#define D_UPLOAD_ERR_6 "上传失败。 启用日志记录 3"
#define D_UPLOAD_ERR_4 "固件小超过 flash 容量"
#define D_UPLOAD_ERR_5 "上传缓冲区不足,请先刷入精简固件再升级"
#define D_UPLOAD_ERR_6 "上传失败。 启用日志级别 3 调试"
#define D_UPLOAD_ERR_7 "上传取消"
#define D_UPLOAD_ERR_8 "错误的固件"
#define D_UPLOAD_ERR_9 "固件太大"
#define D_UPLOAD_ERR_10 "初始化 RF 芯片失败"
#define D_UPLOAD_ERR_11 "擦除 RF 芯片失败"
#define D_UPLOAD_ERR_12 "写入 RF 芯片失败"
#define D_UPLOAD_ERR_13 "解码 RF 固件失败"
#define D_UPLOAD_ERROR_CODE "上传错误代码"
#define D_ENTER_COMMAND "输入命令"
#define D_ENABLE_WEBLOG_FOR_RESPONSE "如果预期响应则启用Weblog 2"
#define D_ENABLE_WEBLOG_FOR_RESPONSE "如果想得到预期响应,请调整日志级别至: 2 信息"
#define D_NEED_USER_AND_PASSWORD "需要 user=<用户名>&password=<密码>"
// xdrv_01_mqtt.ino
// xdrv_00_mqtt.ino
#define D_FINGERPRINT "验证 TLS 指纹..."
#define D_TLS_CONNECT_FAILED_TO "TLS 连接失败"
#define D_RETRY_IN "重试倒计时:"
@ -335,7 +339,7 @@
#define D_INSECURE "指纹无效导致连接不安全"
#define D_CONNECT_FAILED_TO "连接失败:"
// xplg_wemohue.ino
// xdrv_wemohue.ino
#define D_MULTICAST_DISABLED "组播已禁用"
#define D_MULTICAST_REJOINED "组播已(重新)加入"
#define D_MULTICAST_JOIN_FAILED "组播加入失败"
@ -355,7 +359,7 @@
#define D_HUE_POST_ARGS "Hue POST 参数"
#define D_3_RESPONSE_PACKETS_SENT "3 请求包发送"
// xdrv_07_domoticz.ino
// xdrv_05_domoticz.ino
#define D_DOMOTICZ_PARAMETERS "Domoticz 设置"
#define D_DOMOTICZ_IDX "Idx"
#define D_DOMOTICZ_KEY_IDX "Key idx"
@ -373,35 +377,35 @@
#define D_DOMOTICZ_UPDATE_TIMER "更新计时器"
// xdrv_09_timers.ino
#define D_CONFIGURE_TIMER "Configure Timer"
#define D_TIMER_PARAMETERS "Timer parameters"
#define D_TIMER_ARM "Arm"
#define D_TIMER_TIME "Time"
#define D_TIMER_DAYS "Days"
#define D_TIMER_REPEAT "Repeat"
#define D_TIMER_OUTPUT "Output"
#define D_TIMER_ACTION "Action"
#define D_CONFIGURE_TIMER "定时器设置"
#define D_TIMER_PARAMETERS "定时器参数"
#define D_TIMER_ARM "启用"
#define D_TIMER_TIME "时间"
#define D_TIMER_DAYS ""
#define D_TIMER_REPEAT "重复"
#define D_TIMER_OUTPUT "输出"
#define D_TIMER_ACTION "动作"
// xdrv_10_knx.ino
#define D_CONFIGURE_KNX "Configure KNX"
#define D_KNX_PARAMETERS "KNX Parameters"
#define D_KNX_GENERAL_CONFIG "General"
#define D_KNX_PHYSICAL_ADDRESS "Physical Address"
#define D_KNX_PHYSICAL_ADDRESS_NOTE "( Must be unique on the KNX network )"
#define D_KNX_ENABLE "Enable KNX"
#define D_KNX_GROUP_ADDRESS_TO_WRITE "Data to Send to Group Addresses"
#define D_ADD "Add"
#define D_DELETE "Delete"
#define D_REPLY "Reply"
#define D_KNX_GROUP_ADDRESS_TO_READ "Group Addresses to Receive Data from"
#define D_CONFIGURE_KNX "KNX 配置"
#define D_KNX_PARAMETERS "KNX 参数"
#define D_KNX_GENERAL_CONFIG "同用"
#define D_KNX_PHYSICAL_ADDRESS "物理地址"
#define D_KNX_PHYSICAL_ADDRESS_NOTE "( 在 KNX 网络上必须是唯一的 )"
#define D_KNX_ENABLE "启用 KNX"
#define D_KNX_GROUP_ADDRESS_TO_WRITE "要发送到组地址的数据"
#define D_ADD "添加"
#define D_DELETE "删除"
#define D_REPLY "回复"
#define D_KNX_GROUP_ADDRESS_TO_READ "用来接收数据的组地址"
#define D_LOG_KNX "KNX: "
#define D_RECEIVED_FROM "Received from"
#define D_KNX_COMMAND_WRITE "Write"
#define D_KNX_COMMAND_READ "Read"
#define D_KNX_COMMAND_OTHER "Other"
#define D_SENT_TO "sent to"
#define D_KNX_WARNING "The group address ( 0 / 0 / 0 ) is reserved and can not be used."
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_RECEIVED_FROM "接收自"
#define D_KNX_COMMAND_WRITE ""
#define D_KNX_COMMAND_READ ""
#define D_KNX_COMMAND_OTHER "其他"
#define D_SENT_TO "发送到"
#define D_KNX_WARNING "组地址0/0/0被保留不能使用。"
#define D_KNX_ENHANCEMENT "通讯增强"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
@ -432,7 +436,7 @@
#define D_PARTICALS_BEYOND "颗粒物直径大于"
// sonoff_template.h
#define D_SENSOR_NONE "None"
#define D_SENSOR_NONE ""
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
@ -470,8 +474,7 @@
// Units
#define D_UNIT_AMPERE "安"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_CENTIMETER "厘米"
#define D_UNIT_HOUR "时"
#define D_UNIT_KILOOHM "千欧"
#define D_UNIT_KILOWATTHOUR "千瓦时"
@ -493,6 +496,7 @@
#define D_UNIT_VOLT "伏"
#define D_UNIT_WATT "瓦"
#define D_UNIT_WATTHOUR "瓦时"
#define D_UNIT_HERTZ "赫兹"
// Log message prefix
#define D_LOG_APPLICATION "APP: " // Application

View File

@ -321,6 +321,10 @@
#define D_UPLOAD_ERR_7 "上傳取消"
#define D_UPLOAD_ERR_8 "錯誤的固件"
#define D_UPLOAD_ERR_9 "固件太大"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERROR_CODE "上傳錯誤代碼"
#define D_ENTER_COMMAND "輸入命令"

View File

@ -53,8 +53,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t knx_enabled : 1; // bit 25 (v5.12.0l) KNX
uint32_t device_index_enable : 1; // bit 26 (v5.13.1a)
uint32_t knx_enable_enhancement : 1; // bit 27 (v5.14.0a) KNX
uint32_t spare28 : 1;
uint32_t spare29 : 1;
uint32_t rf_receive_decimal : 1; // bit 28 (v6.0.0a)
uint32_t ir_receive_decimal : 1; // bit 29 (v6.0.0a)
uint32_t spare30 : 1;
uint32_t spare31 : 1;
};
@ -318,6 +318,29 @@ struct XDRVMAILBOX {
char *data;
} XdrvMailbox;
#define MAX_RULES_FLAG 5 // Number of bits used in RulesBitfield (tricky I know...)
typedef union { // Restricted by MISRA-C Rule 18.4 but so usefull...
uint16_t data; // Allow bit manipulation
struct {
uint16_t system_boot : 1;
uint16_t time_init : 1;
uint16_t time_set : 1;
uint16_t mqtt_connected : 1;
uint16_t mqtt_disconnected : 1;
uint16_t spare05 : 1;
uint16_t spare06 : 1;
uint16_t spare07 : 1;
uint16_t spare08 : 1;
uint16_t spare09 : 1;
uint16_t spare10 : 1;
uint16_t spare11 : 1;
uint16_t spare12 : 1;
uint16_t spare13 : 1;
uint16_t spare14 : 1;
uint16_t spare15 : 1;
};
} RulesBitfield;
// See issue https://github.com/esp8266/Arduino/issues/2913
#ifdef USE_ADC_VCC
ADC_MODE(ADC_VCC); // Set ADC input for Power Supply Voltage usage

View File

@ -193,8 +193,8 @@ enum LightTypes {LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT_PWM5, LT_PWM6,
enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_RGBWC};
enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX};
enum XsnsFunctions {FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART,
FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR, FUNC_RULES_PROCESS};
enum XsnsFunctions {FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART,
FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR, FUNC_RULES_PROCESS, FUNC_FREE_MEM};
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };

View File

@ -181,6 +181,7 @@ uint8_t light_type = 0; // Light types
bool pwm_present = false; // Any PWM channel configured with SetOption15 0
boolean mdns_begun = false;
uint8_t ntp_force_sync = 0; // Force NTP sync
RulesBitfield rules_flag;
char my_version[33]; // Composed version string
char my_hostname[33]; // Composed Wifi hostname
@ -390,6 +391,8 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
uint16_t index;
uint32_t address;
ShowFreeMem(PSTR("MqttDataHandler"));
strncpy(topicBuf, topic, sizeof(topicBuf));
for (i = 0; i < data_len; i++) {
if (!isspace(data[i])) break;
@ -569,7 +572,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
XsnsCall(FUNC_COMMAND);
// if (!XsnsCall(FUNC_COMMAND)) type = NULL;
}
else if ((CMND_SETOPTION == command_code) && ((index <= 26) || ((index > 31) && (index <= P_MAX_PARAM8 + 31)))) {
else if ((CMND_SETOPTION == command_code) && ((index <= 29) || ((index > 31) && (index <= P_MAX_PARAM8 + 31)))) {
if (index <= 31) {
ptype = 0; // SetOption0 .. 31
} else {
@ -604,6 +607,9 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
// case 24: // rules_once
// case 25: // knx_enabled
case 26: // device_index_enable
// case 27: // knx_enable_enhancement
case 28: // rf_receive_decimal
case 29: // ir_receive_decimal
bitWrite(Settings.flag.data, index, payload);
}
if (12 == index) { // stop_flash_rotate
@ -740,6 +746,8 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
}
else if (CMND_GPIOS == command_code) {
mytmplt cmodule;
memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule));
for (byte i = 0; i < GPIO_SENSOR_END; i++) {
if (!jsflg) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_GPIOS "%d\":["), lines);
@ -747,12 +755,14 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
}
jsflg = 1;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i, GetTextIndexed(stemp1, sizeof(stemp1), i, kSensorNames));
if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == GPIO_SENSOR_END -1)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]}"), mqtt_data);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
jsflg = 0;
lines++;
if (!GetUsedInModule(i, cmodule.gp.io)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i, GetTextIndexed(stemp1, sizeof(stemp1), i, kSensorNames));
if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == GPIO_SENSOR_END -1)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]}"), mqtt_data);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
jsflg = 0;
lines++;
}
}
}
mqtt_data[0] = '\0';
@ -1000,7 +1010,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
break;
case 99:
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING));
ESP.restart();
EspRestart();
break;
default:
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_ONE_TO_RESTART);
@ -1258,6 +1268,7 @@ void ExecuteCommand(char *cmnd, int source)
char *start;
char *token;
ShowFreeMem(PSTR("ExecuteCommand"));
ShowSource(source);
token = strtok(cmnd, " ");
@ -1937,7 +1948,7 @@ void StateLoop()
restart_flag--;
if (restart_flag <= 0) {
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING));
ESP.restart();
EspRestart();
}
}
break;
@ -2012,8 +2023,7 @@ void ArduinoOTAInit()
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA %s. " D_RESTARTING), error_str);
AddLog(LOG_LEVEL_INFO);
delay(100); // Allow time for message xfer
ESP.restart();
EspRestart();
});
ArduinoOTA.onEnd([]()
@ -2021,8 +2031,7 @@ void ArduinoOTAInit()
if ((LOG_LEVEL_DEBUG <= seriallog_level)) Serial.println();
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_SUCCESSFUL ". " D_RESTARTING));
AddLog(LOG_LEVEL_INFO);
delay(100); // Allow time for message xfer
ESP.restart();
EspRestart();
});
ArduinoOTA.begin();
@ -2322,7 +2331,7 @@ void GpioInit()
}
SetLedPower(Settings.ledstate &8);
XdrvCall(FUNC_INIT);
XdrvCall(FUNC_PRE_INIT);
}
extern "C" {
@ -2447,6 +2456,7 @@ void setup()
ArduinoOTAInit();
#endif // USE_ARDUINO_OTA
XdrvCall(FUNC_INIT);
XsnsCall(FUNC_INIT);
}

View File

@ -247,6 +247,9 @@ void KNX_CB_Action(message_t const &msg, void *arg);
#ifdef DEBUG_THEO
#undef DEBUG_THEO // Disable debug code
#endif
#ifdef USE_DEBUG_DRIVER
#undef USE_DEBUG_DRIVER // Disable debug code
#endif
#endif // BE_MINIMAL
/*********************************************************************************************\

View File

@ -644,7 +644,7 @@ void ShowSource(int source)
void GetFeatures()
{
feature_drv1 = 0x00000000; // xdrv_00_mqtt.ino, xdrv_01_light.ino, xdrv_04_snfbridge.ino
feature_drv1 = 0x00000000; // xdrv_01_mqtt.ino, xdrv_01_light.ino, xdrv_04_snfbridge.ino
// feature_drv1 |= 0x00000001;
// feature_drv1 |= 0x00000002;
@ -861,6 +861,9 @@ void GetFeatures()
#ifdef USE_SDM630
feature_sns1 |= 0x10000000; // xsns_25_sdm630.ino
#endif
#ifdef USE_LM75AD
feature_sns1 |= 0x20000000; // xsns_26_lm75ad.ino
#endif
/*********************************************************************************************/
@ -1006,6 +1009,7 @@ void WifiBegin(uint8_t flag)
WiFi.mode(WIFI_OFF); // See https://github.com/esp8266/Arduino/issues/2186
#endif
WiFi.persistent(false); // Solve possible wifi init errors
WiFi.disconnect(true); // Delete SDK wifi config
delay(200);
WiFi.mode(WIFI_STA); // Disable AP mode
@ -1219,13 +1223,30 @@ int WifiState()
void WifiConnect()
{
WiFi.persistent(false); // Solve possible wifi init errors
WiFi.persistent(false); // Solve possible wifi init errors
wifi_status = 0;
wifi_retry_init = WIFI_RETRY_OFFSET_SEC + ((ESP.getChipId() & 0xF) * 2);
wifi_retry = wifi_retry_init;
wifi_counter = 1;
}
void WifiDisconnect()
{
// Courtesy of EspEasy
WiFi.persistent(true); // use SDK storage of SSID/WPA parameters
ETS_UART_INTR_DISABLE();
wifi_station_disconnect(); // this will store empty ssid/wpa into sdk storage
ETS_UART_INTR_ENABLE();
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
}
void EspRestart()
{
delay(100); // Allow time for message xfer
WifiDisconnect();
ESP.restart();
}
#ifdef USE_DISCOVERY
/*********************************************************************************************\
* mDNS
@ -1557,6 +1578,29 @@ String GetUptime()
return String(dt);
}
uint32_t GetMinutesUptime()
{
TIME_T ut;
if (restart_time) {
BreakTime(utc_time - restart_time, ut);
} else {
BreakTime(uptime, ut);
}
return (ut.days *1440) + (ut.hour *60) + ut.minute;
}
uint32_t GetMinutesPastMidnight()
{
uint32_t minutes = 0;
if (RtcTime.valid) {
minutes = (RtcTime.hour *60) + RtcTime.minute;
}
return minutes;
}
void BreakTime(uint32_t time_input, TIME_T &tm)
{
// break the given time_input into time components
@ -1733,11 +1777,10 @@ void RtcSecond()
GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str());
AddLog(LOG_LEVEL_DEBUG);
if (local_time < 1451602800) { // 2016-01-01
strncpy_P(mqtt_data, PSTR("{\"Time\":{\"Initialized\":1}}"), sizeof(mqtt_data));
rules_flag.time_init = 1;
} else {
strncpy_P(mqtt_data, PSTR("{\"Time\":{\"Set\":1}}"), sizeof(mqtt_data));
rules_flag.time_set = 1;
}
XdrvRulesProcess();
} else {
ntp_sync_minute++; // Try again in next minute
}

View File

@ -178,7 +178,7 @@
* - Disable a feature by preceding it with //
\*********************************************************************************************/
//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+4k5 code)
//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+13k code)
// -- Localization --------------------------------
// If non selected the default en-GB will be used
@ -263,6 +263,7 @@
#define USE_SHT // Add I2C emulating code for SHT1X sensor (+1k4 code)
#define USE_SHT3X // Add I2C code for SHT3x or SHTC3 sensor (+0k7 code)
#define USE_HTU // Add I2C code for HTU21/SI7013/SI7020/SI7021 sensor (+1k5 code)
#define USE_LM75AD // Add I2C code for LM75AD sensor (+0k5 code)
#define USE_BMP // Add I2C code for BMP085/BMP180/BMP280/BME280 sensor (+4k code)
// #define USE_BME680 // Add additional support for BME680 sensor using Adafruit Sensor and BME680 libraries (+6k code)
#define USE_SGP30 // Add I2C code for SGP30 sensor (+1k1 code)
@ -310,11 +311,19 @@
#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code)
#define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB
/*********************************************************************************************\
* Debug features are only supported in development branch
\*********************************************************************************************/
//#define USE_DEBUG_DRIVER // Use xdrv_99_debug.ino providing commands CpuChk, CfgXor, CfgDump, CfgPeek and CfgPoke
/*********************************************************************************************\
* Select features and sensors enabled in previous version saving space
\*********************************************************************************************/
//#define USE_CLASSIC // Create sonoff-classic (See sonoff_post.h for selected features)
//#define USE_CLASSIC // Create sonoff-classic (See sonoff_post.h for selected features)
/*********************************************************************************************\
* Select all sensors - overrides above undefines!!

View File

@ -204,6 +204,8 @@ void MqttPublishDirect(const char* topic, boolean retained)
char sretained[CMDSZ];
char slog_type[10];
ShowFreeMem(PSTR("MqttPublishDirect"));
sretained[0] = '\0';
snprintf_P(slog_type, sizeof(slog_type), PSTR(D_LOG_RESULT));
@ -315,8 +317,7 @@ void MqttDisconnected(int state)
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d, rc %d. " D_RETRY_IN " %d " D_UNIT_SECOND),
Settings.mqtt_host, Settings.mqtt_port, state, mqtt_retry_counter);
AddLog(LOG_LEVEL_INFO);
strncpy_P(mqtt_data, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(mqtt_data));
XdrvRulesProcess();
rules_flag.mqtt_disconnected = 1;
}
void MqttConnected()
@ -368,13 +369,11 @@ void MqttConnected()
tele_period = Settings.tele_period -9;
}
status_update_timer = 2;
strncpy_P(mqtt_data, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(mqtt_data));
XdrvRulesProcess();
rules_flag.system_boot = 1;
XdrvCall(FUNC_MQTT_INIT);
}
mqtt_initial_connection_state = 0;
strncpy_P(mqtt_data, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(mqtt_data));
XdrvRulesProcess();
rules_flag.mqtt_connected = 1;
}
#ifdef USE_MQTT_TLS

View File

@ -25,6 +25,12 @@
* Based on source by AlexT (https://github.com/tzapu)
\*********************************************************************************************/
#ifdef USE_RF_FLASH
uint8_t *efm8bb1_update = NULL;
#endif // USE_RF_FLASH
enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1 };
const char HTTP_HEAD[] PROGMEM =
"<!DOCTYPE html><html lang=\"" D_HTML_LANGUAGE "\" class=\"\">"
"<head>"
@ -942,15 +948,6 @@ void HandleBackupConfiguration()
WebServer->send(200, FPSTR(HDR_CTYPE_STREAM), "");
memcpy(settings_buffer, &Settings, sizeof(Settings));
/*
settings_buffer[0] = CONFIG_FILE_SIGN;
settings_buffer[1] = (!config_xor_on_set) ? 0 : 1;
if (settings_buffer[1]) {
for (uint16_t i = 2; i < sizeof(Settings); i++) {
settings_buffer[i] ^= (config_xor_on_set +i);
}
}
*/
if (config_xor_on_set) {
for (uint16_t i = 2; i < sizeof(Settings); i++) {
settings_buffer[i] ^= (config_xor_on_set +i);
@ -1171,7 +1168,7 @@ void HandleRestoreConfiguration()
ShowPage(page);
upload_error = 0;
upload_file_type = 1;
upload_file_type = UPL_SETTINGS;
}
void HandleUpgradeFirmware()
@ -1190,7 +1187,7 @@ void HandleUpgradeFirmware()
ShowPage(page);
upload_error = 0;
upload_file_type = 0;
upload_file_type = UPL_TASMOTA;
}
void HandleUpgradeFirmwareStart()
@ -1247,6 +1244,12 @@ void HandleUploadDone()
case 7: strncpy_P(error, PSTR(D_UPLOAD_ERR_7), sizeof(error)); break;
case 8: strncpy_P(error, PSTR(D_UPLOAD_ERR_8), sizeof(error)); break;
case 9: strncpy_P(error, PSTR(D_UPLOAD_ERR_9), sizeof(error)); break;
#ifdef USE_RF_FLASH
case 10: strncpy_P(error, PSTR(D_UPLOAD_ERR_10), sizeof(error)); break;
case 11: strncpy_P(error, PSTR(D_UPLOAD_ERR_11), sizeof(error)); break;
case 12: strncpy_P(error, PSTR(D_UPLOAD_ERR_12), sizeof(error)); break;
case 13: strncpy_P(error, PSTR(D_UPLOAD_ERR_13), sizeof(error)); break;
#endif
default:
snprintf_P(error, sizeof(error), PSTR(D_UPLOAD_ERROR_CODE " %d"), upload_error);
}
@ -1257,9 +1260,8 @@ void HandleUploadDone()
} else {
page += F("green'>" D_SUCCESSFUL "</font></b><br/>");
page += FPSTR(HTTP_MSG_RSTRT);
ShowWebSource(SRC_WEBGUI);
restart_flag = 2;
restart_flag = 2; // Always restart to re-enable disabled features during update
}
SettingsBufferFree();
page += F("</div><br/>");
@ -1274,7 +1276,7 @@ void HandleUploadLoop()
if (HTTP_USER == webserver_state) { return; }
if (upload_error) {
if (!upload_file_type) { Update.end(); }
if (UPL_TASMOTA == upload_file_type) { Update.end(); }
return;
}
@ -1289,7 +1291,7 @@ void HandleUploadLoop()
SettingsSave(1); // Free flash for upload
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD D_FILE " %s ..."), upload.filename.c_str());
AddLog(LOG_LEVEL_INFO);
if (upload_file_type) {
if (UPL_SETTINGS == upload_file_type) {
if (!SettingsBufferAlloc()) {
upload_error = 2; // Not enough space
return;
@ -1305,6 +1307,12 @@ void HandleUploadLoop()
if (Settings.flag.mqtt_enabled) MqttDisconnect();
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if (!Update.begin(maxSketchSpace)) { //start with max available size
// if (_serialoutput) Update.printError(Serial);
// if (Update.getError() == UPDATE_ERROR_BOOTSTRAP) {
// if (_serialoutput) Serial.println("Device still in UART update mode, perform powercycle");
// }
upload_error = 2; // Not enough space
return;
}
@ -1312,22 +1320,34 @@ void HandleUploadLoop()
upload_progress_dot_count = 0;
} else if (!upload_error && (UPLOAD_FILE_WRITE == upload.status)) {
if (0 == upload.totalSize) {
if (upload_file_type) {
if (UPL_SETTINGS == upload_file_type) {
config_block_count = 0;
} else {
if (upload.buf[0] != 0xE9) {
upload_error = 3; // Magic byte is not 0xE9
return;
}
else {
#ifdef USE_RF_FLASH
if ((SONOFF_BRIDGE == Settings.module) && (upload.buf[0] == ':')) { // Check if this is a RF bridge FW file
Update.end(); // End esp8266 update session
upload_file_type = UPL_EFM8BB1;
upload_error = SnfBrUpdateInit();
if (upload_error != 0) { return; }
} else
#endif // USE_RF_FLASH
{
if (upload.buf[0] != 0xE9) {
upload_error = 3; // Magic byte is not 0xE9
return;
}
uint32_t bin_flash_size = ESP.magicFlashChipSize((upload.buf[3] & 0xf0) >> 4);
if(bin_flash_size > ESP.getFlashChipRealSize()) {
upload_error = 4; // Program flash size is larger than real flash size
return;
}
upload.buf[2] = 3; // Force DOUT - ESP8285
}
uint32_t bin_flash_size = ESP.magicFlashChipSize((upload.buf[3] & 0xf0) >> 4);
if(bin_flash_size > ESP.getFlashChipRealSize()) {
upload_error = 4; // Program flash size is larger than real flash size
return;
}
upload.buf[2] = 3; // Force DOUT - ESP8285
}
}
if (upload_file_type) { // config
if (UPL_SETTINGS == upload_file_type) {
if (!upload_error) {
if (upload.currentSize > (sizeof(Settings) - (config_block_count * HTTP_UPLOAD_BUFLEN))) {
upload_error = 9; // File too large
@ -1336,7 +1356,42 @@ void HandleUploadLoop()
memcpy(settings_buffer + (config_block_count * HTTP_UPLOAD_BUFLEN), upload.buf, upload.currentSize);
config_block_count++;
}
} else { // firmware
}
#ifdef USE_RF_FLASH
else if (UPL_EFM8BB1 == upload_file_type) {
if (efm8bb1_update != NULL) { // We have carry over data since last write, i. e. a start but not an end
ssize_t result = rf_glue_remnant_with_new_data_and_write(efm8bb1_update, upload.buf, upload.currentSize);
free(efm8bb1_update);
efm8bb1_update = NULL;
if (result != 0) {
upload_error = abs(result); // 2 = Not enough space, 8 = File invalid
return;
}
}
ssize_t result = rf_search_and_write(upload.buf, upload.currentSize);
if (result < 0) {
upload_error = abs(result);
return;
} else if (result > 0) {
if (result > upload.currentSize) {
// Offset is larger than the buffer supplied, this should not happen
upload_error = 9; // File too large - Failed to decode RF firmware
return;
}
// A remnant has been detected, allocate data for it plus a null termination byte
size_t remnant_sz = upload.currentSize - result;
efm8bb1_update = (uint8_t *) malloc(remnant_sz + 1);
if (efm8bb1_update == NULL) {
upload_error = 2; // Not enough space - Unable to allocate memory to store new RF firmware
return;
}
memcpy(efm8bb1_update, upload.buf + result, remnant_sz);
// Add null termination at the end of of remnant buffer
efm8bb1_update[remnant_sz] = '\0';
}
}
#endif // USE_RF_FLASH
else { // firmware
if (!upload_error && (Update.write(upload.buf, upload.currentSize) != upload.currentSize)) {
upload_error = 5; // Upload buffer miscompare
return;
@ -1351,7 +1406,7 @@ void HandleUploadLoop()
if (_serialoutput && (upload_progress_dot_count % 80)) {
Serial.println();
}
if (upload_file_type) {
if (UPL_SETTINGS == upload_file_type) {
if (config_xor_on_set) {
for (uint16_t i = 2; i < sizeof(Settings); i++) {
settings_buffer[i] ^= (config_xor_on_set +i);
@ -1379,7 +1434,14 @@ void HandleUploadLoop()
upload_error = 8; // File invalid
return;
}
} else {
}
#ifdef USE_RF_FLASH
else if (UPL_EFM8BB1 == upload_file_type) {
// RF FW flash done
upload_file_type = UPL_TASMOTA;
}
#endif // USE_RF_FLASH
else {
if (!Update.end(true)) { // true to set the size to the current progress
if (_serialoutput) { Update.printError(Serial); }
upload_error = 6; // Upload failed. Enable logging 3
@ -1394,7 +1456,7 @@ void HandleUploadLoop()
restart_flag = 0;
MqttRetryCounter(0);
upload_error = 7; // Upload aborted
if (!upload_file_type) { Update.end(); }
if (UPL_TASMOTA == upload_file_type) { Update.end(); }
}
delay(0);
}

View File

@ -281,6 +281,9 @@ long cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED;
void CseReceived()
{
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// 55 5A 02 F7 60 00 03 AB 00 40 10 02 60 5D 51 A6 58 03 E9 EF 71 0B 7A 36
// Hd Id VCal---- Voltage- ICal---- Current- PCal---- Power--- Ad CF--- Ck
AddLogSerial(LOG_LEVEL_DEBUG_MORE);
uint8_t header = serial_in_buffer[0];
@ -481,7 +484,17 @@ bool PzemReceiveReady()
bool PzemRecieve(uint8_t resp, float *data)
{
uint8_t buffer[sizeof(PZEMCommand)];
// 0 1 2 3 4 5 6
// A4 00 00 00 00 00 A4 - Set address
// A0 00 D4 07 00 00 7B - Voltage (212.7V)
// A1 00 00 0A 00 00 AB - Current (0.1A)
// A1 00 00 00 00 00 A1 - No current
// A2 00 16 00 00 00 B8 - Power (22W)
// A2 00 00 00 00 00 A2 - No power
// A3 00 08 A4 00 00 4F - Energy (2.212kWh)
// A3 01 86 9F 00 00 C9 - Energy (99.999kWh)
uint8_t buffer[sizeof(PZEMCommand)] = { 0 };
unsigned long start = millis();
uint8_t len = 0;
@ -491,6 +504,10 @@ bool PzemRecieve(uint8_t resp, float *data)
if (!c && !len) {
continue; // skip 0 at startup
}
if ((1 == len) && (buffer[0] == c)) {
len--;
continue; // fix skewed data
}
buffer[len++] = c;
}
}
@ -1148,7 +1165,7 @@ boolean Xdrv03(byte function)
if (energy_flg) {
switch (function) {
case FUNC_INIT:
case FUNC_PRE_INIT:
EnergyDrvInit();
break;
case FUNC_COMMAND:

View File

@ -1118,6 +1118,7 @@ boolean LightCommand()
if (XdrvMailbox.data_len > 0) {
char *p;
uint16_t idx = XdrvMailbox.index;
Ws2812ForceSuspend();
for (char *color = strtok_r(XdrvMailbox.data, " ", &p); color; color = strtok_r(NULL, " ", &p)) {
if (LightColorEntry(color, strlen(color))) {
Ws2812SetColor(idx, light_entry_color[0], light_entry_color[1], light_entry_color[2], light_entry_color[3]);
@ -1127,6 +1128,8 @@ boolean LightCommand()
break;
}
}
Ws2812ForceUpdate();
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, Ws2812GetColor(XdrvMailbox.index, scolor));
}
@ -1295,7 +1298,7 @@ boolean Xdrv04(byte function)
if (light_type) {
switch (function) {
case FUNC_INIT:
case FUNC_PRE_INIT:
LightInit();
break;
case FUNC_EVERY_50_MSECOND:

View File

@ -89,6 +89,7 @@ void IrReceiveInit(void)
void IrReceiveCheck()
{
char sirtype[14]; // Max is AIWA_RC_T501
char stemp[16];
int8_t iridx = 0;
decode_results results;
@ -107,8 +108,15 @@ void IrReceiveCheck()
if ((iridx < 0) || (iridx > 14)) {
iridx = 0;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":\"%lX\"}}"),
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, (uint32_t)results.value);
if (Settings.flag.ir_receive_decimal) {
snprintf_P(stemp, sizeof(stemp), PSTR("%u"), (uint32_t)results.value);
} else {
snprintf_P(stemp, sizeof(stemp), PSTR("\"%lX\""), (uint32_t)results.value);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":%s}}"),
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, stemp);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED));
XdrvRulesProcess();
#ifdef USE_DOMOTICZ
@ -401,7 +409,7 @@ boolean Xdrv05(byte function)
if ((pin[GPIO_IRSEND] < 99) || (pin[GPIO_IRRECV] < 99)) {
switch (function) {
case FUNC_INIT:
case FUNC_PRE_INIT:
if (pin[GPIO_IRSEND] < 99) {
IrSendInit();
}

View File

@ -1,7 +1,7 @@
/*
xdrv_06_snfbridge.ino - sonoff RF bridge 433 support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
Copyright (C) 2018 Theo Arends and Erik Andrén Zachrisson (fw update)
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
@ -24,11 +24,12 @@
#define SFB_TIME_AVOID_DUPLICATE 2000 // Milliseconds
enum SonoffBridgeCommands {
CMND_RFSYNC, CMND_RFLOW, CMND_RFHIGH, CMND_RFHOST, CMND_RFCODE, CMND_RFKEY };
CMND_RFSYNC, CMND_RFLOW, CMND_RFHIGH, CMND_RFHOST, CMND_RFCODE, CMND_RFKEY, CMND_RFRAW };
const char kSonoffBridgeCommands[] PROGMEM =
D_CMND_RFSYNC "|" D_CMND_RFLOW "|" D_CMND_RFHIGH "|" D_CMND_RFHOST "|" D_CMND_RFCODE "|" D_CMND_RFKEY ;
D_CMND_RFSYNC "|" D_CMND_RFLOW "|" D_CMND_RFHIGH "|" D_CMND_RFHOST "|" D_CMND_RFCODE "|" D_CMND_RFKEY "|" D_CMND_RFRAW;
uint8_t sonoff_bridge_receive_flag = 0;
uint8_t sonoff_bridge_receive_raw_flag = 0;
uint8_t sonoff_bridge_learn_key = 1;
uint8_t sonoff_bridge_learn_active = 0;
uint8_t sonoff_bridge_expected_bytes = 0;
@ -37,6 +38,206 @@ uint32_t sonoff_bridge_last_send_code = 0;
unsigned long sonoff_bridge_last_time = 0;
unsigned long sonoff_bridge_last_learn_time = 0;
#ifdef USE_RF_FLASH
/*********************************************************************************************\
* EFM8BB1 RF microcontroller in-situ firmware update
*
* Enables upload of EFM8BB1 firmware provided by https://github.com/Portisch/RF-Bridge-EFM8BB1 using the web gui.
* Based on source by Erik Andrén Zachrisson (https://github.com/arendst/Sonoff-Tasmota/pull/2886)
\*********************************************************************************************/
#include "ihx.h"
#include "c2.h"
#define RF_RECORD_NO_START_FOUND -1
#define RF_RECORD_NO_END_FOUND -2
ssize_t rf_find_hex_record_start(uint8_t *buf, size_t size)
{
for (int i = 0; i < size; i++) {
if (buf[i] == ':') {
return i;
}
}
return RF_RECORD_NO_START_FOUND;
}
ssize_t rf_find_hex_record_end(uint8_t *buf, size_t size)
{
for (ssize_t i = 0; i < size; i++) {
if (buf[i] == '\n') {
return i;
}
}
return RF_RECORD_NO_END_FOUND;
}
ssize_t rf_glue_remnant_with_new_data_and_write(const uint8_t *remnant_data, uint8_t *new_data, size_t new_data_len)
{
ssize_t record_start;
ssize_t record_end;
ssize_t glue_record_sz;
uint8_t *glue_buf;
ssize_t result;
if (remnant_data[0] != ':') { return -8; } // File invalid - RF Remnant data did not start with a start token
// Find end token in new data
record_end = rf_find_hex_record_end(new_data, new_data_len);
record_start = rf_find_hex_record_start(new_data, new_data_len);
// Be paranoid and check that there is no start marker before the end record
// If so this implies that there was something wrong with the last start marker saved
// in the last upload part
if ((record_start != RF_RECORD_NO_START_FOUND) && (record_start < record_end)) {
return -8; // File invalid - Unexpected RF start marker found before RF end marker
}
glue_record_sz = strlen((const char *) remnant_data) + record_end;
glue_buf = (uint8_t *) malloc(glue_record_sz);
if (glue_buf == NULL) { return -2; } // Not enough space
// Assemble new glue buffer
memcpy(glue_buf, remnant_data, strlen((const char *) remnant_data));
memcpy(glue_buf + strlen((const char *) remnant_data), new_data, record_end);
result = rf_decode_and_write(glue_buf, glue_record_sz);
free(glue_buf);
return result;
}
ssize_t rf_decode_and_write(uint8_t *record, size_t size)
{
uint8_t err = ihx_decode(record, size);
if (err != IHX_SUCCESS) { return -13; } // Failed to decode RF firmware
ihx_t *h = (ihx_t *) record;
if (h->record_type == IHX_RT_DATA) {
int retries = 5;
uint16_t address = h->address_high * 0x100 + h->address_low;
do {
err = c2_programming_init();
err = c2_block_write(address, h->data, h->len);
} while (err != C2_SUCCESS && retries--);
} else if (h->record_type == IHX_RT_END_OF_FILE) {
// RF firmware upgrade done, restarting RF chip
err = c2_reset();
}
if (err != C2_SUCCESS) { return -12; } // Failed to write to RF chip
return 0;
}
ssize_t rf_search_and_write(uint8_t *buf, size_t size)
{
// Binary contains a set of commands, decode and program each one
ssize_t rec_end;
ssize_t rec_start;
ssize_t err;
for (size_t i = 0; i < size; i++) {
// Find starts and ends of commands
rec_start = rf_find_hex_record_start(buf + i, size - i);
if (rec_start == RF_RECORD_NO_START_FOUND) {
// There is nothing left to save in this buffer
return -8; // File invalid
}
// Translate rec_start from local buffer position to chunk position
rec_start += i;
rec_end = rf_find_hex_record_end(buf + rec_start, size - rec_start);
if (rec_end == RF_RECORD_NO_END_FOUND) {
// We have found a start but not an end, save remnant
return rec_start;
}
// Translate rec_end from local buffer position to chunk position
rec_end += rec_start;
err = rf_decode_and_write(buf + rec_start, rec_end - rec_start);
if (err < 0) { return err; }
i = rec_end;
}
// Buffer was perfectly aligned, start and end found without any remaining trailing characters
return 0;
}
uint8_t rf_erase_flash()
{
uint8_t err;
for (int i = 0; i < 4; i++) { // HACK: Try multiple times as the command sometimes fails (unclear why)
err = c2_programming_init();
if (err != C2_SUCCESS) {
return 10; // Failed to init RF chip
}
err = c2_device_erase();
if (err != C2_SUCCESS) {
if (i < 3) {
c2_reset(); // Reset RF chip and try again
} else {
return 11; // Failed to erase RF chip
}
} else {
break;
}
}
return 0;
}
uint8_t SnfBrUpdateInit()
{
pinMode(PIN_C2CK, OUTPUT);
pinMode(PIN_C2D, INPUT);
return rf_erase_flash(); // 10, 11
}
#endif // USE_RF_FLASH
/********************************************************************************************/
void SonoffBridgeSendRaw(char *codes, int size)
{
char *p;
char stemp[3];
uint8_t code;
while (size > 0) {
snprintf(stemp, sizeof(stemp), codes);
code = strtol(stemp, &p, 16);
Serial.write(code);
size -= 2;
codes += 2;
}
}
void SonoffBridgeReceivedRaw()
{
// Decoding according to https://github.com/Portisch/RF-Bridge-EFM8BB1
uint8_t buckets = 0;
if (0xB1 == serial_in_buffer[1]) { buckets = serial_in_buffer[2] << 1; } // Bucket sniffing
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RFRAW "\":{\"" D_JSON_DATA "\":\""));
for (int i = 0; i < serial_in_byte_counter; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%02X"), mqtt_data, serial_in_buffer[i]);
if (0xB1 == serial_in_buffer[1]) {
if ((i > 3) && buckets) { buckets--; }
if ((i < 3) || (buckets % 2) || (i == serial_in_byte_counter -2)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s "), mqtt_data);
}
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"}}"), mqtt_data);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_CMND_RFRAW));
XdrvRulesProcess();
}
/********************************************************************************************/
void SonoffBridgeLearnFailed()
{
sonoff_bridge_learn_active = 0;
@ -51,6 +252,7 @@ void SonoffBridgeReceived()
uint16_t high_time = 0;
uint32_t received_id = 0;
char rfkey[8];
char stemp[16];
AddLogSerial(LOG_LEVEL_DEBUG);
@ -94,8 +296,13 @@ void SonoffBridgeReceived()
}
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":\"%06X\",\"" D_CMND_RFKEY "\":%s}}"),
sync_time, low_time, high_time, received_id, rfkey);
if (Settings.flag.rf_receive_decimal) {
snprintf_P(stemp, sizeof(stemp), PSTR("%u"), received_id);
} else {
snprintf_P(stemp, sizeof(stemp), PSTR("\"%06X\""), received_id);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":%s,\"" D_CMND_RFKEY "\":%s}}"),
sync_time, low_time, high_time, stemp, rfkey);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED));
XdrvRulesProcess();
#ifdef USE_DOMOTICZ
@ -110,12 +317,28 @@ boolean SonoffBridgeSerialInput()
{
// iTead Rf Universal Transceiver Module Serial Protocol Version 1.0 (20170420)
if (sonoff_bridge_receive_flag) {
if (!((0 == serial_in_byte_counter) && (0 == serial_in_byte))) { // Skip leading 0
if (sonoff_bridge_receive_raw_flag) {
if (!serial_in_byte_counter) {
serial_in_buffer[serial_in_byte_counter++] = 0xAA;
}
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
if (0x55 == serial_in_byte) { // 0x55 - End of text
SonoffBridgeReceivedRaw();
sonoff_bridge_receive_flag = 0;
return 1;
}
}
else if (!((0 == serial_in_byte_counter) && (0 == serial_in_byte))) { // Skip leading 0
if (0 == serial_in_byte_counter) {
sonoff_bridge_expected_bytes = 2; // 0xA0, 0xA1, 0xA2
if (serial_in_byte >= 0xA3) {
sonoff_bridge_expected_bytes = 11; // 0xA3, 0xA4, 0xA5
}
if (serial_in_byte == 0xA6) {
sonoff_bridge_expected_bytes = 0; // 0xA6 and up supported by Portisch firmware only
serial_in_buffer[serial_in_byte_counter++] = 0xAA;
sonoff_bridge_receive_raw_flag = 1;
}
}
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
if ((sonoff_bridge_expected_bytes == serial_in_byte_counter) && (0x55 == serial_in_byte)) { // 0x55 - End of text
@ -134,6 +357,13 @@ boolean SonoffBridgeSerialInput()
return 0;
}
void SonoffBridgeSendCommand(byte code)
{
Serial.write(0xAA); // Start of Text
Serial.write(code); // Command or Acknowledge
Serial.write(0x55); // End of Text
}
void SonoffBridgeSendAck()
{
Serial.write(0xAA); // Start of Text
@ -294,11 +524,49 @@ boolean SonoffBridgeCommand()
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, sonoff_bridge_learn_key, D_JSON_LEARNING_ACTIVE);
}
}
else if (CMND_RFRAW == command_code) {
if (XdrvMailbox.data_len) {
if (XdrvMailbox.data_len < 6) { // On, Off
switch (XdrvMailbox.payload) {
case 0: // Receive Raw Off
SonoffBridgeSendCommand(0xA7); // Stop reading RF signals enabling iTead default RF handling
case 1: // Receive Raw On
sonoff_bridge_receive_raw_flag = XdrvMailbox.payload;
break;
case 166: // 0xA6 - Start reading RF signals disabling iTead default RF handling
case 167: // 0xA7 - Stop reading RF signals enabling iTead default RF handling
case 169: // 0xA9 - Start learning predefined protocols
case 176: // 0xB0 - Stop sniffing
case 177: // 0xB1 - Start sniffing
case 255: // 0xFF - Show firmware version
SonoffBridgeSendCommand(XdrvMailbox.payload);
sonoff_bridge_receive_raw_flag = 1;
break;
case 192: // 0xC0 - Beep
char beep[] = "AAC000C055";
SonoffBridgeSendRaw(beep, sizeof(beep));
break;
}
} else {
SonoffBridgeSendRaw(XdrvMailbox.data, XdrvMailbox.data_len);
sonoff_bridge_receive_raw_flag = 1;
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(sonoff_bridge_receive_raw_flag));
} else serviced = false; // Unknown command
return serviced;
}
/*********************************************************************************************/
void SonoffBridgeInit()
{
sonoff_bridge_receive_raw_flag = 0;
SonoffBridgeSendCommand(0xA7); // Stop reading RF signals enabling iTead default RF handling
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
@ -311,6 +579,9 @@ boolean Xdrv06(byte function)
if (SONOFF_BRIDGE == Settings.module) {
switch (function) {
case FUNC_INIT:
SonoffBridgeInit();
break;
case FUNC_COMMAND:
result = SonoffBridgeCommand();
break;

View File

@ -135,7 +135,7 @@ boolean Xdrv08(byte function)
if (serial_bridge_active) {
switch (function) {
case FUNC_INIT:
case FUNC_PRE_INIT:
SerialBridgeInit();
break;
case FUNC_LOOP:

View File

@ -451,6 +451,11 @@ boolean TimerCommand()
}
}
else if (CMND_TIMERS == command_code) {
if (XdrvMailbox.data_len && (XdrvMailbox.payload == 0)) {
for (byte i = 0; i < MAX_TIMERS; i++) {
Settings.timer[i].arm = 0; // Disable all timers
}
}
byte jsflg = 0;
byte lines = 1;
for (byte i = 0; i < MAX_TIMERS; i++) {
@ -726,7 +731,7 @@ boolean Xdrv09(byte function)
boolean result = false;
switch (function) {
case FUNC_INIT:
case FUNC_PRE_INIT:
TimerSetRandomWindows();
break;
case FUNC_EVERY_SECOND:

View File

@ -35,6 +35,7 @@
* on mqtt#connected do color 000010 endon
* on mqtt#disconnected do color 00100C endon
* on time#initialized do color 001000 endon
* on time#initialized>120 do color 001000 endon
* on time#set do color 001008 endon
* on clock#timer=3 do color 080800 endon
* on rules#timer=1 do color 080800 endon
@ -74,11 +75,15 @@
#define D_CMND_EVENT "Event"
#define D_CMND_VAR "Var"
#define D_CMND_MEM "Mem"
#define D_CMND_ADD "Add"
#define D_CMND_SUB "Sub"
#define D_CMND_MULT "Mult"
#define D_CMND_SCALE "Scale"
#define D_JSON_INITIATED "Initiated"
enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM };
const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM ;
enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM, CMND_ADD, CMND_SUB, CMND_MULT, CMND_SCALE };
const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE ;
String rules_event_value;
unsigned long rules_timer[MAX_RULE_TIMERS] = { 0 };
@ -87,6 +92,7 @@ long rules_new_power = -1;
long rules_old_power = -1;
uint32_t rules_triggers[MAX_RULE_SETS] = { 0 };
uint16_t rules_last_minute = 60;
uint8_t rules_trigger_count[MAX_RULE_SETS] = { 0 };
uint8_t rules_teleperiod = 0;
@ -162,7 +168,7 @@ bool RulesRuleMatch(byte rule_set, String &event, String &rule)
rule_task = rule.substring(5, pos); // "INA219" or "SYSTEM"
}
String rule_name = rule.substring(pos +1); // "CURRENT>0.100" or "BOOT"
String rule_name = rule.substring(pos +1); // "CURRENT>0.100" or "BOOT" or "%var1%"
char compare = ' ';
pos = rule_name.indexOf(">");
@ -316,6 +322,13 @@ bool RuleSetProcess(byte rule_set, String &event_saved)
snprintf_P(stemp, sizeof(stemp), PSTR("%%mem%d%%"), i +1);
commands.replace(stemp, Settings.mems[i]);
}
commands.replace(F("%time%"), String(GetMinutesPastMidnight()));
commands.replace(F("%uptime%"), String(GetMinutesUptime()));
#if defined(USE_TIMERS) && defined(USE_SUNRISE)
commands.replace(F("%sunrise%"), String(GetSunMinutes(0)));
commands.replace(F("%sunset%"), String(GetSunMinutes(1)));
#endif // USE_TIMERS and USE_SUNRISE
char command[commands.length() +1];
snprintf(command, sizeof(command), commands.c_str());
@ -335,11 +348,13 @@ bool RuleSetProcess(byte rule_set, String &event_saved)
/*******************************************************************************************/
bool RulesProcess()
bool RulesProcessEvent(char *json_event)
{
bool serviced = false;
String event_saved = mqtt_data;
ShowFreeMem(PSTR("RulesProcessEvent"));
String event_saved = json_event;
event_saved.toUpperCase();
for (byte i = 0; i < MAX_RULE_SETS; i++) {
@ -350,8 +365,14 @@ bool RulesProcess()
return serviced;
}
bool RulesProcess()
{
return RulesProcessEvent(mqtt_data);
}
void RulesInit()
{
rules_flag.data = 0;
for (byte i = 0; i < MAX_RULE_SETS; i++) {
if (Settings.rules[i][0] == '\0') {
bitWrite(Settings.rule_enabled, i, 0);
@ -364,19 +385,21 @@ void RulesInit()
void RulesEvery50ms()
{
if (Settings.rule_enabled) { // Any rule enabled
char json_event[120];
if (rules_new_power != rules_old_power) {
if (rules_old_power != -1) {
for (byte i = 0; i < devices_present; i++) {
uint8_t new_state = (rules_new_power >> i) &1;
if (new_state != ((rules_old_power >> i) &1)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Power%d\":{\"State\":%d}}"), i +1, new_state);
RulesProcess();
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Power%d\":{\"State\":%d}}"), i +1, new_state);
RulesProcessEvent(json_event);
}
}
}
rules_old_power = rules_new_power;
}
else if(event_data[0]) {
else if (event_data[0]) {
char *event;
char *parameter;
event = strtok_r(event_data, "=", &parameter); // event_data = fanspeed=10
@ -387,13 +410,34 @@ void RulesEvery50ms()
} else {
parameter = event + strlen(event); // '\0'
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Event\":{\"%s\":\"%s\"}}"), event, parameter);
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Event\":{\"%s\":\"%s\"}}"), event, parameter);
event_data[0] ='\0';
RulesProcess();
RulesProcessEvent(json_event);
} else {
event_data[0] ='\0';
}
}
else if (rules_flag.data) {
uint16_t mask = 1;
for (byte i = 0; i < MAX_RULES_FLAG; i++) {
if (rules_flag.data & mask) {
rules_flag.data ^= mask;
json_event[0] = '\0';
switch (i) {
case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break;
case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), GetMinutesPastMidnight()); break;
case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), GetMinutesPastMidnight()); break;
case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break;
case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
}
if (json_event[0]) {
RulesProcessEvent(json_event);
break; // Only service one event within 50mS
}
}
mask <<= 1;
}
}
else {
rules_quota++;
if (rules_quota &1) { // Every 100 ms
@ -415,12 +459,21 @@ void RulesEvery50ms()
void RulesEverySecond()
{
if (Settings.rule_enabled) { // Any rule enabled
char json_event[120];
if (RtcTime.valid) {
if ((uptime > 60) && (RtcTime.minute != rules_last_minute)) { // Execute from one minute after restart every minute only once
rules_last_minute = RtcTime.minute;
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Minute\":%d}}"), GetMinutesPastMidnight());
RulesProcessEvent(json_event);
}
}
for (byte i = 0; i < MAX_RULE_TIMERS; i++) {
if (rules_timer[i] != 0L) { // Timer active?
if (TimeReached(rules_timer[i])) { // Timer finished?
rules_timer[i] = 0L; // Turn off this timer
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Rules\":{\"Timer\":%d}}"), i +1);
RulesProcess();
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Rules\":{\"Timer\":%d}}"), i +1);
RulesProcessEvent(json_event);
}
}
}
@ -500,6 +553,60 @@ boolean RulesCommand()
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]);
}
else if ((CMND_ADD == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) {
if ( (XdrvMailbox.data_len > 0) && (XdrvMailbox.payload >= 0) ){
int16_t tempvar = atol(vars[index -1]) + XdrvMailbox.payload;
snprintf_P(vars[index -1], sizeof(vars[index -1]), PSTR("%d"), tempvar );
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_SUB == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) {
if ( (XdrvMailbox.data_len > 0) && (XdrvMailbox.payload >= 0) ){
int16_t tempvar = atol(vars[index -1]) - XdrvMailbox.payload;
snprintf_P(vars[index -1], sizeof(vars[index -1]), PSTR("%d"), tempvar );
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_MULT == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) {
if ( (XdrvMailbox.data_len > 0) && (XdrvMailbox.payload >= 0) ){
int16_t tempvar = atol(vars[index -1]) * XdrvMailbox.payload;
snprintf_P(vars[index -1], sizeof(vars[index -1]), PSTR("%d"), tempvar );
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_SCALE == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) {
if ( XdrvMailbox.data_len > 0 ) {
if (strstr(XdrvMailbox.data, ",")) { // Process parameter entry
uint8_t tpos = 0; // Parameter index
int16_t value = 0;
int16_t valueIN = 0;
int16_t fromLow = 0;
int16_t fromHigh = 0;
int16_t toLow = 0;
int16_t toHigh = 0;
char *p = XdrvMailbox.data; // Parameters like "1, 2, 3, 4"
char *q = p; // Value entered flag
while (p && (tpos < 6)) {
if (p > q) { // Any value entered
if (1 == tpos) { valueIN = value; }
if (2 == tpos) { fromLow = value; }
if (3 == tpos) { fromHigh = value; }
if (4 == tpos) { toLow = value; }
if (5 == tpos) { toHigh = value; }
}
p = LTrim(p); // Skip spaces
if (tpos && (*p == ',')) { p++; } // Skip separator
p = LTrim(p); // Skip spaces
q = p; // Reset any value entered flag
value = strtol(p, &p, 10);
tpos++; // Next parameter
}
value = map(valueIN, fromLow, fromHigh, toLow, toHigh);
snprintf_P(vars[index -1], sizeof(vars[index -1]), PSTR("%d"), value );
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else serviced = false; // Unknown command
return serviced;
@ -516,7 +623,7 @@ boolean Xdrv10(byte function)
boolean result = false;
switch (function) {
case FUNC_INIT:
case FUNC_PRE_INIT:
RulesInit();
break;
case FUNC_EVERY_50_MSECOND:

View File

@ -462,6 +462,7 @@ void KNX_INIT()
if (GetUsedInModule(GPIO_DHT11, my_module.gp.io)) { device_param[KNX_TEMPERATURE-1].show = true; }
if (GetUsedInModule(GPIO_DHT22, my_module.gp.io)) { device_param[KNX_TEMPERATURE-1].show = true; }
if (GetUsedInModule(GPIO_SI7021, my_module.gp.io)) { device_param[KNX_TEMPERATURE-1].show = true; }
if (GetUsedInModule(GPIO_DSB, my_module.gp.io)) { device_param[KNX_TEMPERATURE-1].show = true; }
if (GetUsedInModule(GPIO_DHT11, my_module.gp.io)) { device_param[KNX_HUMIDITY-1].show = true; }
if (GetUsedInModule(GPIO_DHT22, my_module.gp.io)) { device_param[KNX_HUMIDITY-1].show = true; }
if (GetUsedInModule(GPIO_SI7021, my_module.gp.io)) { device_param[KNX_HUMIDITY-1].show = true; }
@ -547,7 +548,7 @@ void KNX_CB_Action(message_t const &msg, void *arg)
{
if (!toggle_inhibit) {
char command[25];
snprintf_P(command, sizeof(command), PSTR("event KNXRX_VAL%d=%d"), ((chan->type) - KNX_SLOT1 + 1 ), msg.data[0]);
snprintf_P(command, sizeof(command), PSTR("event KNXRX_CMND%d=%d"), ((chan->type) - KNX_SLOT1 + 1 ), msg.data[0]);
ExecuteCommand(command, SRC_KNX);
if (Settings.flag.knx_enable_enhancement) {
toggle_inhibit = TOGGLE_INHIBIT_TIME;
@ -566,7 +567,7 @@ void KNX_CB_Action(message_t const &msg, void *arg)
knx.answer_1bit(msg.received_on, chan->last_state);
}
}
else if (chan->type = KNX_TEMPERATURE) // Reply Temperature
else if (chan->type == KNX_TEMPERATURE) // Reply Temperature
{
knx.answer_2byte_float(msg.received_on, last_temp);
if (Settings.flag.knx_enable_enhancement) {
@ -574,7 +575,7 @@ void KNX_CB_Action(message_t const &msg, void *arg)
knx.answer_2byte_float(msg.received_on, last_temp);
}
}
else if (chan->type = KNX_HUMIDITY) // Reply Humidity
else if (chan->type == KNX_HUMIDITY) // Reply Humidity
{
knx.answer_2byte_float(msg.received_on, last_hum);
if (Settings.flag.knx_enable_enhancement) {
@ -1078,7 +1079,7 @@ boolean Xdrv11(byte function)
{
boolean result = false;
switch (function) {
case FUNC_INIT:
case FUNC_PRE_INIT:
KNX_INIT();
break;
case FUNC_LOOP:

377
sonoff/xdrv_99_debug.ino Normal file
View File

@ -0,0 +1,377 @@
/*
xdrv_99_debug.ino - debug support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//#define USE_DEBUG_DRIVER
#ifdef DEBUG_THEO
#ifndef USE_DEBUG_DRIVER
#define USE_DEBUG_DRIVER
#endif // USE_DEBUG_DRIVER
#endif // DEBUG_THEO
#ifdef USE_DEBUG_DRIVER
#ifndef CPU_LOAD_CHECK
#define CPU_LOAD_CHECK 1 // Seconds between each CPU_LOAD log
#endif
/*********************************************************************************************\
* Debug commands
\*********************************************************************************************/
#define D_CMND_CFGDUMP "CfgDump"
#define D_CMND_CFGPOKE "CfgPoke"
#define D_CMND_CFGPEEK "CfgPeek"
#define D_CMND_CFGXOR "CfgXor"
#define D_CMND_EXCEPTION "Exception"
#define D_CMND_CPUCHECK "CpuChk"
enum DebugCommands { CMND_CFGDUMP, CMND_CFGPEEK, CMND_CFGPOKE, CMND_CFGXOR, CMND_EXCEPTION, CMND_CPUCHECK };
const char kDebugCommands[] PROGMEM = D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" D_CMND_CFGXOR "|" D_CMND_EXCEPTION "|" D_CMND_CPUCHECK;
uint32_t CPU_loops = 0;
uint32_t CPU_last_millis = 0;
uint32_t CPU_last_loop_time = 0;
uint8_t CPU_load_check = CPU_LOAD_CHECK;
/*******************************************************************************************/
#ifdef DEBUG_THEO
void ExceptionTest(byte type)
{
/*
Exception (28):
epc1=0x4000bf64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000007 depc=0x00000000
ctx: cont
sp: 3fff1f30 end: 3fff2840 offset: 01a0
>>>stack>>>
3fff20d0: 202c3573 756f7247 2c302070 646e4920
3fff20e0: 40236a6e 7954202c 45206570 00454358
3fff20f0: 00000010 00000007 00000000 3fff2180
3fff2100: 3fff2190 40107bfc 3fff3e4c 3fff22c0
3fff2110: 40261934 000000f0 3fff22c0 401004d8
3fff2120: 40238fcf 00000050 3fff2100 4021fc10
3fff2130: 3fff32bc 4021680c 3ffeade1 4021ff7d
3fff2140: 3fff2190 3fff2180 0000000c 7fffffff
3fff2150: 00000019 00000000 00000000 3fff21c0
3fff2160: 3fff23f3 3ffe8e08 00000000 4021ffb4
3fff2170: 3fff2190 3fff2180 0000000c 40201118
3fff2180: 3fff21c0 0000003c 3ffef840 00000007
3fff2190: 00000000 00000000 00000000 40201128
3fff21a0: 3fff23f3 000000f1 3fff23ec 4020fafb
3fff21b0: 3fff23f3 3fff21c0 3fff21d0 3fff23f6
3fff21c0: 00000000 3fff23fb 4022321b 00000000
Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
Decoding 14 results
0x40236a6e: ets_vsnprintf at ?? line ?
0x40107bfc: vsnprintf at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/libc_replacements.c line 387
0x40261934: bignum_exptmod at ?? line ?
0x401004d8: malloc at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1664
0x40238fcf: wifi_station_get_connect_status at ?? line ?
0x4021fc10: operator new[](unsigned int) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/abi.cpp line 57
0x4021680c: ESP8266WiFiSTAClass::status() at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WiFi\src/ESP8266WiFiSTA.cpp line 569
0x4021ff7d: vsnprintf_P(char*, unsigned int, char const*, __va_list_tag) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146
0x4021ffb4: snprintf_P(char*, unsigned int, char const*, ...) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146
0x40201118: atol at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45
0x40201128: atoi at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45
0x4020fafb: MqttDataHandler(char*, unsigned char*, unsigned int) at R:\Arduino\Work-ESP8266\Theo\sonoff\sonoff-4\sonoff/sonoff.ino line 679 (discriminator 1)
0x4022321b: pp_attach at ?? line ?
00:00:08 MQTT: tele/sonoff/INFO3 = {"Started":"Fatal exception:28 flag:2 (EXCEPTION) epc1:0x4000bf64 epc2:0x00000000 epc3:0x00000000 excvaddr:0x00000007 depc:0x00000000"}
*/
if (1 == type) {
char svalue[10];
snprintf_P(svalue, sizeof(svalue), PSTR("%s"), 7); // Exception 28 as number in string (7 in excvaddr)
}
/*
14:50:52 osWatch: FreeRam 25896, rssi 68, last_run 0
14:51:02 osWatch: FreeRam 25896, rssi 58, last_run 0
14:51:03 CMND: exception 2
14:51:12 osWatch: FreeRam 25360, rssi 60, last_run 8771
14:51:22 osWatch: FreeRam 25360, rssi 62, last_run 18771
14:51:32 osWatch: FreeRam 25360, rssi 62, last_run 28771
14:51:42 osWatch: FreeRam 25360, rssi 62, last_run 38771
14:51:42 osWatch: Warning, loop blocked. Restart now
*/
if (2 == type) {
while(1) delay(1000); // this will trigger the os watch
}
}
/*******************************************************************************************/
void RtcSettingsDump()
{
#define CFG_COLS 16
uint16_t idx;
uint16_t maxrow;
uint16_t row;
uint16_t col;
uint8_t *buffer = (uint8_t *) &RtcSettings;
maxrow = ((sizeof(RTCMEM)+CFG_COLS)/CFG_COLS);
for (row = 0; row < maxrow; row++) {
idx = row * CFG_COLS;
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx);
for (col = 0; col < CFG_COLS; col++) {
if (!(col%4)) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data);
for (col = 0; col < CFG_COLS; col++) {
// if (!(col%4)) {
// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
// }
snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' ');
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data);
AddLog(LOG_LEVEL_INFO);
}
}
#endif // DEBUG_THEO
/*******************************************************************************************/
void CpuLoadLoop()
{
CPU_last_loop_time = millis();
if (CPU_load_check && CPU_last_millis) {
CPU_loops ++;
if ((CPU_last_millis + (CPU_load_check *1000)) <= CPU_last_loop_time) {
#if defined(F_CPU) && (F_CPU == 160000000L)
int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *800) );
CPU_loops = CPU_loops / CPU_load_check;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(160MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops);
#else
int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *400) );
CPU_loops = CPU_loops / CPU_load_check;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(80MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops);
#endif
AddLog(LOG_LEVEL_DEBUG);
CPU_last_millis = CPU_last_loop_time;
CPU_loops = 0;
}
}
}
/*******************************************************************************************/
extern "C" {
#include <cont.h>
extern cont_t g_cont;
}
void DebugFreeMem()
{
// https://github.com/esp8266/Arduino/issues/2557
register uint32_t *sp asm("a1");
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d, UnmodifiedStack %d (%s)"),
// ESP.getFreeHeap(), 4 * (sp - g_cont.stack), cont_get_free_stack(&g_cont), XdrvMailbox.data);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"),
ESP.getFreeHeap(), 4 * (sp - g_cont.stack), XdrvMailbox.data);
AddLog(LOG_LEVEL_DEBUG);
}
/*******************************************************************************************/
void DebugCfgDump(char* parms)
{
#define CFG_COLS 16
uint16_t idx;
uint16_t maxrow;
uint16_t row;
uint16_t col;
char *p;
uint8_t *buffer = (uint8_t *) &Settings;
maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS);
uint16_t srow = strtol(parms, &p, 16) / CFG_COLS;
uint16_t mrow = strtol(p, &p, 10);
// snprintf_P(log_data, sizeof(log_data), PSTR("Cnfg: Parms %s, Start row %d, rows %d"), parms, srow, mrow);
// AddLog(LOG_LEVEL_DEBUG);
if (0 == mrow) { // Default only 8 lines
mrow = 8;
}
if (srow > maxrow) {
srow = maxrow - mrow;
}
if (mrow < (maxrow - srow)) {
maxrow = srow + mrow;
}
for (row = srow; row < maxrow; row++) {
idx = row * CFG_COLS;
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx);
for (col = 0; col < CFG_COLS; col++) {
if (!(col%4)) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data);
for (col = 0; col < CFG_COLS; col++) {
// if (!(col%4)) {
// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
// }
snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' ');
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data);
AddLog(LOG_LEVEL_INFO);
delay(1);
}
}
void DebugCfgPeek(char* parms)
{
char *p;
uint16_t address = strtol(parms, &p, 16);
if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4;
address = (address >> 2) << 2;
uint8_t *buffer = (uint8_t *) &Settings;
uint8_t data8 = buffer[address];
uint16_t data16 = (buffer[address +1] << 8) + buffer[address];
uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + data16;
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), address);
for (byte i = 0; i < 4; i++) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[address +i]);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data);
for (byte i = 0; i < 4; i++) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[address +i] > 0x20) && (buffer[address +i] < 0x7F)) ? (char)buffer[address +i] : ' ');
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s| 0x%02X (%d), 0x%04X (%d), 0x%0LX (%lu)"), log_data, data8, data8, data16, data16, data32, data32);
AddLog(LOG_LEVEL_INFO);
}
void DebugCfgPoke(char* parms)
{
char *p;
uint16_t address = strtol(parms, &p, 16);
if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4;
address = (address >> 2) << 2;
uint32_t data = strtol(p, &p, 16);
uint8_t *buffer = (uint8_t *) &Settings;
uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address];
uint8_t *nbuffer = (uint8_t *) &data;
for (byte i = 0; i < 4; i++) { buffer[address +i] = nbuffer[+i]; }
uint32_t ndata32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address];
snprintf_P(log_data, sizeof(log_data), PSTR("%03X: 0x%0LX (%lu) poked to 0x%0LX (%lu)"), address, data32, data32, ndata32, ndata32);
AddLog(LOG_LEVEL_INFO);
}
/*******************************************************************************************/
boolean DebugCommand()
{
char command[CMDSZ];
boolean serviced = true;
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kDebugCommands);
if (-1 == command_code) {
serviced = false; // Unknown command
}
else if (CMND_CFGDUMP == command_code) {
DebugCfgDump(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
else if (CMND_CFGPEEK == command_code) {
DebugCfgPeek(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
else if (CMND_CFGPOKE == command_code) {
DebugCfgPoke(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
#ifdef USE_WEBSERVER
else if (CMND_CFGXOR == command_code) {
if (XdrvMailbox.data_len > 0) {
config_xor_on_set = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, config_xor_on_set);
}
#endif // USE_WEBSERVER
#ifdef DEBUG_THEO
else if (CMND_EXCEPTION == command_code) {
if (XdrvMailbox.data_len > 0) ExceptionTest(XdrvMailbox.payload);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
#endif // DEBUG_THEO
else if (CMND_CPUCHECK == command_code) {
if (XdrvMailbox.data_len > 0) {
CPU_load_check = XdrvMailbox.payload;
CPU_last_millis = CPU_last_loop_time;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, CPU_load_check);
}
else serviced = false; // Unknown command
return serviced;
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
#define XDRV_99
boolean Xdrv99(byte function)
{
boolean result = false;
switch (function) {
case FUNC_PRE_INIT:
CPU_last_millis = millis();
break;
case FUNC_LOOP:
CpuLoadLoop();
break;
case FUNC_COMMAND:
result = DebugCommand();
break;
case FUNC_FREE_MEM:
DebugFreeMem();
break;
}
return result;
}
#endif // USE_DEBUG_DRIVER

View File

@ -176,9 +176,18 @@ boolean XdrvRulesProcess()
return XdrvCall(FUNC_RULES_PROCESS);
}
void ShowFreeMem(const char *where)
{
char stemp[20];
snprintf_P(stemp, sizeof(stemp), where);
XdrvMailbox.data = stemp;
XdrvCall(FUNC_FREE_MEM);
}
/*********************************************************************************************\
* Function call to all xdrv
*
* FUNC_PRE_INIT
* FUNC_INIT
* FUNC_LOOP
* FUNC_MQTT_SUBSCRIBE
@ -190,6 +199,7 @@ boolean XdrvRulesProcess()
* FUNC_EVERY_SECOND
* FUNC_EVERY_50_MSECOND
* FUNC_RULES_PROCESS
* FUNC_FREE_MEM
\*********************************************************************************************/
boolean XdrvCall(byte Function)

View File

@ -93,7 +93,7 @@ uint8_t kRepeat[5] = {
1 }; // All
uint8_t ws_show_next = 1;
bool ws_suspend_update = false;
/********************************************************************************************/
void Ws2812StripShow()
@ -365,6 +365,19 @@ void Ws2812SetColor(uint16_t led, uint8_t red, uint8_t green, uint8_t blue, uint
strip->SetPixelColor(i, lcolor);
}
}
if (!ws_suspend_update) {
strip->Show();
ws_show_next = 1;
}
}
void Ws2812ForceSuspend () {
ws_suspend_update = true;
}
void Ws2812ForceUpdate () {
ws_suspend_update = false;
strip->Show();
ws_show_next = 1;
}

View File

@ -199,6 +199,11 @@ void Ds18b20Show(boolean json)
#ifdef USE_DOMOTICZ
if (0 == tele_period) DomoticzSensor(DZ_TEMP, temperature);
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, t);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, "DS18B20", temperature, TempUnit());

View File

@ -385,6 +385,11 @@ void Ds18x20Show(boolean json)
domoticz_flag = false;
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if ((0 == tele_period) && (0 == i)) {
KnxSensor(KNX_TEMPERATURE, t);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, (1 == ds18x20_sensors) ? ds18x20_types : stemp, temperature, TempUnit());

View File

@ -192,6 +192,11 @@ void Ds18x20Show(boolean json)
DomoticzSensor(DZ_TEMP, temperature);
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if ((0 == tele_period) && (1 == dsxflg)) {
KnxSensor(KNX_TEMPERATURE, t);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(stemp, sizeof(stemp), PSTR("%s-%d"), ds18x20_types, i +1);

128
sonoff/xsns_26_lm75ad.ino Normal file
View File

@ -0,0 +1,128 @@
/*
xsns_26_lm75ad.ino - Support for I2C LM75AD Temperature Sensor
Copyright (C) 2018 Andre Thomas and Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_I2C
#ifdef USE_LM75AD
/*********************************************************************************************\
* LM75AD - Temperature
*
* Docs at https://www.nxp.com/docs/en/data-sheet/LM75A.pdf
*
* I2C Address: 0x48 - 0x4F
\*********************************************************************************************/
#define LM75AD_ADDRESS1 0x48
#define LM75AD_ADDRESS2 0x49
#define LM75AD_ADDRESS3 0x4A
#define LM75AD_ADDRESS4 0x4B
#define LM75AD_ADDRESS5 0x4C
#define LM75AD_ADDRESS6 0x4D
#define LM75AD_ADDRESS7 0x4E
#define LM75AD_ADDRESS8 0x4F
#define LM75_TEMP_REGISTER 0x00
#define LM75_CONF_REGISTER 0x01
#define LM75_THYST_REGISTER 0x02
#define LM75_TOS_REGISTER 0x03
uint8_t lm75ad_type = 0;
uint8_t lm75ad_address;
uint8_t lm75ad_addresses[] = { LM75AD_ADDRESS1, LM75AD_ADDRESS2, LM75AD_ADDRESS3, LM75AD_ADDRESS4, LM75AD_ADDRESS5, LM75AD_ADDRESS6, LM75AD_ADDRESS7, LM75AD_ADDRESS8 };
void LM75ADDetect()
{
uint8_t buffer;
if (lm75ad_type) { return; }
for (byte i = 0; i < sizeof(lm75ad_addresses); i++) {
lm75ad_address = lm75ad_addresses[i];
if (I2cValidRead8(&buffer, lm75ad_address, LM75_CONF_REGISTER)) {
lm75ad_type = 1;
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "LM75AD", lm75ad_address);
AddLog(LOG_LEVEL_DEBUG);
break;
}
}
}
float LM75ADGetTemp() {
int16_t sign = 1;
uint16_t t = I2cRead16(lm75ad_address, LM75_TEMP_REGISTER);
if (t & 0x8000) { // we are getting a negative temperature value
t = (~t) +0x20;
sign = -1;
}
t = t >> 5; // shift value into place (5 LSB not used)
return ConvertTemp(sign * t * 0.125);
}
void LM75ADShow(boolean json)
{
if (lm75ad_type) {
char temperature[10];
float t = LM75ADGetTemp();
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"LM75AD\":{\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, temperature);
#ifdef USE_DOMOTICZ
if (0 == tele_period) DomoticzSensor(DZ_TEMP, temperature);
#endif // USE_DOMOTICZ
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, "LM75AD", temperature, TempUnit());
#endif // USE_WEBSERVER
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
#define XSNS_26
boolean Xsns26(byte function)
{
boolean result = false;
if (i2c_flg) {
switch (function) {
case FUNC_PREP_BEFORE_TELEPERIOD:
LM75ADDetect();
break;
case FUNC_JSON_APPEND:
LM75ADShow(1);
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_APPEND:
LM75ADShow(0);
break;
#endif // USE_WEBSERVER
}
}
return result;
}
#endif // USE_LM75AD
#endif // USE_I2C

View File

@ -77,7 +77,9 @@ a_setoption = [
"KNX",
"Use Power device index on single relay devices",
"KNX enhancement",
"","","",""]
"RF receive decimal",
"IR receive decimal",
"",""]
a_features = [[
"","","USE_I2C","USE_SPI",
@ -87,7 +89,8 @@ a_features = [[
"USE_WS2812_DMA","USE_IR_REMOTE","USE_IR_HVAC","USE_IR_RECEIVE",
"USE_DOMOTICZ","USE_DISPLAY","USE_HOME_ASSISTANT","USE_SERIAL_BRIDGE",
"USE_TIMERS","USE_SUNRISE","USE_TIMERS_WEB","USE_RULES",
"USE_KNX","","",""],[
"USE_KNX","","",""
],[
"USE_CONFIG_OVERRIDE","BE_MINIMAL","USE_ALL_SENSORS","USE_CLASSIC",
"USE_KNX_NO_EMULATION","","","",
"","","","",
@ -95,7 +98,8 @@ a_features = [[
"","","","",
"","","","",
"","","VTABLES_IN_FLASH","PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH",
"PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY","PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH","DEBUG_THEO","USE_DEBUG_DRIVER"],[
"PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY","PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH","DEBUG_THEO","USE_DEBUG_DRIVER"
],[
"","USE_ADC_VCC","USE_ENERGY_SENSOR","USE_PZEM004T",
"USE_DS18B20","USE_DS18x20_LEGACY","USE_DS18x20","USE_DHT",
"USE_SHT","USE_HTU","USE_BMP","USE_BME680",
@ -103,7 +107,8 @@ a_features = [[
"USE_INA219","USE_SHT3X","USE_MHZ19","USE_TSL2561",
"USE_SENSEAIR","USE_PMS5003","USE_MGS","USE_NOVA_SDS",
"USE_SGP30","USE_SR04","USE_SDM120","USE_SI1145",
"USE_SDM630","","",""],[
"USE_SDM630","USE_LM75AD","",""
],[
"","","","",
"","","","",
"","","","",

View File

@ -0,0 +1,406 @@
:020000040000FA
:10000000020FEFED24F8FEEFD39E4015ED2408FD1E
:10001000E433FCC3EF9DEC6480F874809850028058
:1000200001C322020ED0E4F5A922220213637EFF4F
:10003000EFD394004022EF9480501DE4FDED75F065
:100040000EA424A5F582E43418F583E493B50704DF
:10005000AE0580040DBD05E5AF062202110612189B
:100060004E53D87853DBFE12180FE4900085F0222F
:10007000D2DE220213B6D2011215F6C290C296D277
:1000800080E4FBFD7F101217F612064374A4F0D231
:10009000AFE4F52FF530D2960530E5307002052F2C
:1000A000B410F3E52FB427EEC29630010912150DF6
:1000B0008E328F338006753201753300E53370045C
:1000C000E532640170409000CCE07007F52FF53008
:1000D0000202870530E5307002052FD39410E52F1A
:1000E00094274002D296D3E5309430E52F94755092
:1000F00003020287E4F52FF5309000CCF09000CB9E
:10010000F0C296020287E4F52FF5309000CCE0149F
:10011000602A14700302025914700302021E147044
:100120000302023424046003020287E53364AA60F8
:10013000030202879000CC04F0020287E5339000AE
:10014000CBF0A37402F0E5331208B30206A00170ED
:10015000A10182A501A6A601BAA701C3A801DFA932
:1001600001C6B001CFB10197C00287FF00000215A0
:100170001205E69000A87401F0E4900075F07FA1EC
:10018000806E12005E9000CC7404F0753108E4F5C6
:10019000357534090202879000CC7404F0E4F5351B
:1001A000753402020287E49000A8F0900075F07F99
:1001B000A612067474A6F002028712064374A4F015
:1001C0000202877531089000CC7403F00202879018
:1001D00000757401F07FB1120674EFF0020287120D
:1001E00005E69000A8E0F52EE4F0900075F07FA9F8
:1001F0001214D090007CEFF07D307C757F017E0082
:1002000012164902028712065790007CEFF0E49024
:1002100000CCF08072E49000CBF0A3F08069E4F5AC
:1002200035E533F534E534D394009000CC402574A3
:1002300004F0805374042535F582E43400F583E539
:1002400033F00535E53565346007E535C394704016
:10025000369000CC7402F0802EE5336455702890FF
:1002600000CCF0C2019000CBE02460601824FC6058
:100270000F24FE600B14600824F66004241070073D
:100280007FA01217C3D2019000CBE01208B302B0D6
:10029000A102DAA402ECA503C5A603E1A8051FA9E3
:1002A000055CB005CFB1038DC003B3FF000000AA09
:1002B000900084E030E70F7DC87C001206167FA313
:1002C00012140902053912180740030200AA7DE83A
:1002D0007C031206167FA2020554900084E020E7FA
:1002E000030200AA7FA41214090203D99000CCE0F3
:1002F00060030200AA900085E024FC606D24046085
:10030000030200AA1531900008E0FEA3E0FF7C0084
:100310007D641208D9C006C0071215A0D007D00608
:100320001208218F3E900006E0FEA3E0FF8E3FF50D
:10033000407C007D641208D9C006C0071215A0D009
:1003400007D0061208218F41754218900008E0FA84
:10035000A3E0FB900004E0FCA3E0FDA3E0FEA3E02B
:10036000FF12067B7406F00204EBE53160171206FB
:100370002DD39400500302051012062D12066012B0
:1003800018400205101206577FA00205549000CCB9
:10039000E060030200AA900004E0FCA3E0FD7F01FE
:1003A0007E00121649D296121840C2967FA01217EC
:1003B000C3800AE4FF1217C3E49000CCF0D201120C
:1003C000066B0200AA900084E020E7030200AA5412
:1003D0007FF537FD7FA612130CE4900084F0020035
:1003E000AA9000CCE060030200AA900085E024FC03
:1003F00070030204F1240460030200AA1531120004
:100400005E900004E0647F702FA3E0FEA3E0FFA3F2
:10041000E0FCA3E0FDA3E0FAA3E0FBA3E0F53EA32C
:10042000E0F53FA3E0F540A3E0F541A3E0F542127B
:10043000067B740CF00204E2900004E0FF12002E30
:100440008F36E536F470030204DDEF75F00EA42458
:1004500060F582E43418F583E493FE740193FFC0E1
:1004600006C0071215BA2462F582E434181215C1C9
:10047000C004C0051215BA2465F582E43418F5836A
:10048000E493FA740193FB1215BA2469F582E434FB
:1004900018F583E493FF1215BA2467F582E4341843
:1004A0001215C11215BA246AF582E43418F583E4F2
:1004B00093FE1215BA246BF582E43418F583E493A5
:1004C000F5428E418C3F8D408F3ED005D004D00741
:1004D000D0061212929000747401F08005E490002E
:1004E000CBF09000CBE070030200AA121749020083
:1004F000AAE53160231215BA246CF582E43418F5AC
:1005000083E493FFD394004007EF12066012184073
:10051000E4900085F00200AA12066B7FA08035905F
:100520000084E0FF30E71C547FF5377DC87C001263
:1005300005F9AD377FAB12130CE4900084F0D201C3
:100540000200AA12180740030200AA7DE87C0312E9
:1005500005F97FAA1217C3D2010200AA900004E095
:1005600025E0F5379000CCE060030200AA900085FA
:10057000E0700512005E800B900085E0640460036B
:100580000200AAE5376007E534C394045008E490FC
:1005900000CBF00200AA74062537F9E43400753B5D
:1005A00001F53C893DC3E534953724FEF53E9000C6
:1005B00005E0F53F7B017A00790612118B7FA012CE
:1005C00017C390007CE0FF1214D0D2010200AA9061
:1005D0000084E020E7030200AA7FB1121210E49029
:1005E0000084F00200AA7D327C007F017E0012169A
:1005F00049D296121840C296227F017E00121649F7
:10060000D296121840C2969000A8E52EF090007C79
:10061000E0FF1214D0227F017E00121649D29612FA
:100620001840C29690007CE0FF1214D0227F011285
:10063000002EEF75F00EA4246CF582E43418F583D7
:10064000E493229000A87401F0E4900075F07FA478
:100650001214D090007C2290007CE0FF1214D02273
:10066000FD7C007F017E001216492290007CE0FF95
:100670001214D0221214D090007C221212929000F8
:100680007422BB010CE58229F582E5833AF583E00B
:10069000225006E92582F8E622BBFE06E92582F80B
:1006A000E222E58229F582E5833AF583E49322BBD1
:1006B000010689828A83F0225002F722BBFE01F3F1
:1006C00022EF8DF0A4A8F0CF8CF0A428CE8DF0A45A
:1006D0002EFE22BC000BBE0029EF8DF084FFADF092
:1006E00022E4CCF875F008EF2FFFEE33FEEC33FC7C
:1006F000EE9DEC984005FCEE9DFE0FD5F0E9E4CEB2
:10070000FD22EDF8F5F0EE8420D21CFEADF075F080
:1007100008EF2FFFED33FD4007985006D5F0F22289
:10072000C398FD0FD5F0EA22C2D5EC30E709B2D567
:10073000E4C39DFDE49CFCEE30E715B2D5E4C39F15
:10074000FFE49EFE1206D3C3E49DFDE49CFC8003FF
:100750001206D330D507C3E49FFFE49EFE22BB01FF
:1007600010E58229F582E5833AF583E0F5F0A3E010
:10077000225009E92582F886F008E622BBFE0AE944
:100780002582F8E2F5F008E222E5832AF583E99371
:10079000F5F0A3E99322E88FF0A4CC8BF0A42CFC15
:1007A000E98EF0A42CFC8AF0EDA42CFCEA8EF0A4D7
:1007B000CDA8F08BF0A42DCC3825F0FDE98FF0A466
:1007C0002CCD35F0FCEB8EF0A4FEA9F0EB8FF0A45D
:1007D000CFC5F02ECD39FEE43CFCEAA42DCE35F099
:1007E000FDE43CFC2275F008758200EF2FFFEE332C
:1007F000FECD33CDCC33CCC58233C5829BED9AEC94
:1008000099E58298400CF582EE9BFEED9AFDEC99FD
:10081000FC0FD5F0D6E4CEFBE4CDFAE4CCF9A88207
:1008200022B800C1B90059BA002DEC8BF084CFCEAC
:10083000CDFCE5F0CBF97818EF2FFFEE33FEED336A
:10084000FDEC33FCEB33FB10D703994004EB99FB31
:100850000FD8E5E4F9FA227818EF2FFFEE33FEED1A
:1008600033FDEC33FCC933C910D7059BE99A400727
:10087000EC9BFCE99AF90FD8E0E4C9FAE4CCFB223E
:1008800075F010EF2FFFEE33FEED33FDCC33CCC807
:1008900033C810D7079BEC9AE899400AED9BFDEC12
:1008A0009AFCE899F80FD5F0DAE4CDFBE4CCFAE451
:1008B000C8F922D083D082F8E49370127401937047
:1008C0000DA3A393F8740193F5828883E4737402F3
:1008D000936860EFA3A3A380DFEC8EF0A4CCC5F0F7
:1008E000CCCDF8EFA4CEC5F02DFDE43CFCE8A42E61
:1008F000C8C5F03DFDE43CFCEFA4FFE5F028FEE4B4
:100900003DFDE43CFC22EF4E6012EF60010EEDBBBA
:10091000010B89828A83F0A3DFFCDEFA2289F05082
:1009200007F709DFFCA9F022BBFEFCF309DFFCA9F5
:10093000F022AFE9AEEA7C007D0A1206C18E088F74
:1009400009209303020B2185080A85090BC3E509D9
:10095000950DF511E508950CF510900075E01470F3
:1009600003020B1B046003020B42900085E014603D
:1009700065046003020B42900084E06003020B42B6
:100980009000A8E0FFAB11AA10AD0FAC0E120E1331
:100990008F12E51264807003020B4290007F120CEC
:1009A000A3900002E510F0A3E511120C5FE49000A3
:1009B00074F0900077F090007EF0F513F514FE7F50
:1009C00070FD7B017A007904120906E490007DF045
:1009D00090008504F022E51275F00EA424AAF58299
:1009E000E43418F583E493FFD39400400B90007E29
:1009F000E09F5004E004F022900088E014F09000A2
:100A000077E004F0AE10AF11AB07AA06E50F2BFF9D
:100A1000E50E3AFEE433FDE433FCC004A905AA0662
:100A2000AB07AE0EAF0F120CABD0001208218F2215
:100A3000120C231200034029E51275F00EA424B015
:100A4000F582E43418F583E493FDAF2212000340ED
:100A500010120B436F600AE4900084F0C290A3F080
:100A600022120C23AF221200035007120B43C39F24
:100A70004011D3E50F9514E50E9513402B120B434F
:100A80006F7025900086120CA3D290120BF6C083D3
:100A9000C082120C9B7401A806088002C333D8FCE4
:100AA0004FD082D083F0801790007A120CA3C290AE
:100AB000D39514E50E95134006850E13850F1490FB
:100AC0000088E07015120BF6E0FF90007DE06FFFEC
:100AD00012176490007DEF120C5F120B436F70626F
:100AE0001217FF5005E4900083F0900083E0FF9020
:100AF000007DE06F601D12180F7DF47C017F017E88
:100B00000012162090007DE0900083F0A3E512F023
:100B10004480F0C290E4900085F022AF11AE1080C6
:100B20001E85080C85090DC3E509950BF50FE50831
:100B3000950AF50E900075E0147007AF0FAE0E1217
:100B40000CC822E51275F00EA424B1F582E4341825
:100B5000F583E493FF900077E022120821AB07AA07
:100B600006E4F9F87F407E427D0FFC120821E47B09
:100B7000FFFAF9F8120796A804A905AA06AB077FA1
:100B8000207ED77D757C01120821EFF40422AE2669
:100B9000AF277C007D1F1206D38E2A8F2B7C007D11
:100BA000051206D3C3E52B9FFDE52A9EFCD3E52560
:100BB0009DE5249C22E52975F00EA424A8F582E485
:100BC0003418F583E493FE740193FF2438FDEE346A
:100BD000FFFCD3E5279DE5269C22900074E02404C9
:100BE000F582E43400F58322E52525E0248AF582A8
:100BF000E43400F58322900077E024FFFFE434FF23
:100C0000FE7C007D0812072874042FF58274003ED4
:100C1000F58322E52B2FFFE52A3EC3FEE5259FE560
:100C2000249E22E51275F00EA424AFF582E4341858
:100C3000F583E493FD22E52975F00EA424A6F58240
:100C4000E43418F5832253DAFE53F7DF53F7BF225B
:100C5000AB3BAA3CA93D854082758300020682F029
:100C60009000887408F022EF24C8FFE43EFEC3E53C
:100C7000279FE5269E2275F0FFA4FFAEF07C007D45
:100C8000640206D3900078E523F0A3E524F02290D7
:100C90000081E0FF900077E0D39F22E0FF90008882
:100CA000E0FE22E50EF0A3E50FF0227C007D640259
:100CB00008D9540F75F002A4F58285F08322D3E59C
:100CC000279470E5269417228E238F24900085E0C8
:100CD000146035147003020D9D24026003020E049B
:100CE000C290900084E06003020E04AF24AE231291
:100CF00017914003020E04E4900001F0120C84905E
:100D000000857401F0D29022900078E0FCA3E0FD11
:100D1000AE047802CEC313CE13D8F92DFFEC3EFEFD
:100D2000D3E5249FE5239E4009120C84E490000142
:100D3000F022AF24AE23121492501A900001E094D6
:100D4000004012E4900074F09000887404F0900069
:100D5000857402F022C3E5249464E5239400403AAC
:100D6000120E05501C120BE8E0FEA3E02524FFE55F
:100D7000233EC313FEEF13FF120BE8EEF0A3EFF0D8
:100D800022900001E0120BEA120C87900001E004AF
:100D9000F0E0D3941E406DE4805EE48063B290AFD7
:100DA00024AE23121492500D900084E04480F0C2CF
:100DB00090E4A3F022120E055041900088E0B404A4
:100DC00011E525C454F0FF120BDAEFF0E49000882F
:100DD000F022120BDAE0FFE525540FFEEF4EF09003
:100DE0000074E004F09000887404F0900074E0D384
:100DF00094704010E4900001F08005E4900001F050
:100E0000900085F0227B007A007925AF24AE231272
:100E1000107E228F238C248D258A268B277528808F
:100E2000E523707CE4F5297F0112002EEF6529701F
:100E30001B120CBE405FE5279450E52694465055A2
:100E4000120B8E4050120C13504B807E120C36E465
:100E500093FE740193FFD39400EE9400402BEF2493
:100E600038FFEE34FFD3120C1B402A120C367401EB
:100E70009324C8FFE4933400120C1A5018120BB5D7
:100E80004013120C67500E8041120BB54007120C34
:100E900067500280350529E529C394054089802DD6
:100EA000AF2312002E8F297F0112002EEF652970CB
:100EB0001C120CBE4017E5279450E5269446500DB1
:100EC000120B8E4008120C135003852928AF2822DC
:100ED000C0E0C0F0C083C082C0D075D000C000C0E8
:100EE00001C002C003C004C005C006C007E5985495
:100EF00003F547F45298E54730E017121857900071
:100F0000C0121690EFF09000C0E004F0E0B41402BC
:100F1000E4F0E54730E12E9000C2E0D39400401A9F
:100F20009000BFE02448F8E6FF1218549000BFE09C
:100F300004F09000C2E014F08002D2029000BFE002
:100F4000B42002E4F0D007D006D005D004D003D0FE
:100F500002D001D000D0D0D082D083D0F0D0E03207
:100F60004200C700004200C300004200C900004226
:100F700000C500004100CC004100CB0041008400CE
:100F8000410085004100A8004100750041007C003F
:100F900041007656410089AB4100000041008200CB
:100FA00042007F0000420002000042008600004232
:100FB000007A000041008100410088004100770074
:100FC00041007E00410074004100830041007D002B
:100FD000410001004100C0004100C1004100BE00CD
:100FE0004100BF004100C2004100BD00C10200122B
:100FF000002A787FE4F6D8FD758167021039020077
:1010000076E493A3F8E493A34003F68001F208DFAB
:10101000F48029E493A3F85407240CC8C333C454C0
:101020000F4420C8834004F456800146F6DFE48074
:101030000B0102040810204080900F60E47E0193B1
:1010400060BCA3FF543F30E509541FFEE493A36046
:10105000010ECF54C025E060A840B8E493A3FAE4A1
:1010600093A3F8E493A3C8C582C8CAC583CAF0A3F2
:10107000C8C582C8CAC583CADFE9DEE780BE8E263E
:101080008F278B288A29892AC200E4F52B9000013A
:10109000E0FFE52BC39F506BE527AE267803CEC358
:1010A00013CE13D8F9FDAC06E527AE267802CEC3E1
:1010B00013CE13D8F92DF52DEE3CF52CE52B120BA4
:1010C000EAE0FEA3E0FFC3952DFDEE952CFCC3EDF9
:1010D0009527EC95265028E52D2FFFE52C3EFEC3E5
:1010E000E5279FE5269E5017E52A45294528600BF0
:1010F000AB28AA29A92AE52B1206AFD20080040545
:101100002B808AA20022C0E0C0F0C083C082C0D081
:1011100075D000C000C001C002C003C004C005C03B
:1011200006C007E5D85487F521F452D8E5F730E535
:1011300008E5F730E60312154353F7DFE52130E702
:1011400008E5D930E00312185DE52130E008E5DA62
:1011500030E00312169BE52130E108E5DB30E003C7
:10116000120932E52130E208E5DC30E00312185EB6
:10117000D007D006D005D004D003D002D001D000D3
:10118000D0D0D082D083D0F0D0E0328B388A398969
:101190003A53DBFE120C4653E2FDE4F540E540C352
:1011A000953E504FAB38AA39A93AC003C002C001DE
:1011B000120C50C4120CB2D001D002D00312075E40
:1011C000F54285F041D280121202AB38AA39A93A11
:1011D000C003C002C001120C50120CB2D001D002E8
:1011E000D00312075EF54285F041C280121202055B
:1011F0004080AAB290AF3F153FEF709E43E202C21B
:101200009022FDAC417F0A7E001215741218402214
:10121000AE07E4F5381216EA900001E004FF12165A
:10122000F112128B900001E0FFE538C39F501212BB
:101230001684121677121684F58312167E053880EE
:10124000E3900078E0FF1216F190007812167E12FB
:10125000128B900088E07006900074E004F0E4F5D2
:1012600038900074E0FFE538C39F501774042538A8
:101270001216720538E538541F70E612185112180C
:101280004A80DE7F551216F10218511218511218B9
:101290004A228E388F398C3A8D3BAE02AF03120C46
:1012A000ABC007AF3EAB07E4FAF9F8D007120B5A10
:1012B000900000F0AE3FAF40120CABC007AF41ABA7
:1012C00007E4FAF9F8D007120B5A900082F0E53ED5
:1012D000120C76900076EFF0E541120C76900089C2
:1012E000EFF090007FE538F0A3E539F0900002E5DB
:1012F0003AF0A3E53BF0900081E542F043DA015378
:10130000F7DF43F74053DBFE75F9FF22AE07E4FC3D
:10131000FB1216EAED75F00EA424F7F582E43418FA
:10132000F583E493FFECC39F500774082CFC0B80FB
:10133000E3EB04FF1216F1ED75F00EA424EBF58239
:10134000E43418F583E493FF1216F1E4FCECC39B3C
:10135000500974042C1216720C80F27F551216F18B
:10136000021851C0E0C083C082C0D075D000C00454
:10137000C005C006C00753C87F9000C7E0FEA3E0C9
:10138000FF4E700353C8FB9000C31214875009909E
:1013900000C7E4F0A3F0800DC39000C8E09DF0907A
:1013A00000C7E09CF0D007D006D005D004D0D0D044
:1013B00082D083D0E032C0E0C083C082C0D075D07C
:1013C00000C004C005C006C00753917F9000C9E06B
:1013D000FEA3E0FF4E70035391FB9000C5121487EB
:1013E00050099000C9E4F0A3F0800DC39000CAE05A
:1013F0009DF09000C9E09CF0D007D006D005D00445
:10140000D0D0D082D083D0E032AE07E4FDF53812E0
:1014100016EA900002E0FF1216F190000212167E0A
:1014200090007AE0FF1216F190007A12167E90007A
:1014300086E0FF1216F190008612167E74042D12BB
:1014400016720DBD03F67F551216F1021851AB0747
:10145000AA06E4F9F87F407E427D0FFC120821A81D
:1014600004A905AA06AB077F207ED77D757C0112F3
:101470000821C3E49FFFE49EFE22AB07AA06E4F91D
:10148000F87FE87E03FD22E0FCA3E0FDC3EF9DEEC4
:101490009C22AD07AC06900078E0FEA3E07802CE77
:1014A000C313CE13D8F9FFC3900079E09FFB9000DF
:1014B00078E09EFAC3EB9DEA9C5013A3E02FFF90C7
:1014C0000078E03EFEC3ED9FEC9E50028001C322F7
:1014D0008F3890007CE0F5397F0B12185A43DB01FE
:1014E000120C461200707D0A7C007F017E001216ED
:1014F0004912184043E202E4900085F0900084F025
:101500009000CBE538F090007CF0AF39229000C01D
:10151000E0FF9000BEE0B507057E017F002290004D
:10152000BE121690E0FD7C009000BEE004F0E0B436
:101530001402E4F09000BDE0FEEE4204E4F0AE04DC
:10154000AF0522120C8F400302172B120BDA120C7C
:101550009BEFA806088002C313D8FC30E00B900074
:1015600000E0FF12185AD29022900082E0FF121879
:101570005AC290228E438F448C458D4612144E12CF
:1015800017ABE54624BF9000CAF0E54534FF900054
:10159000C9F09000C5E543F0A3E544F0439104226F
:1015A000900006E0FEA3E0FF900009E02FFF90000E
:1015B00008E03EAB07FAE4F9F822E53675F00EA430
:1015C00022F583E493FC740193FD22D29053E2FD53
:1015D000D28090007F1215E6C290C2809000021265
:1015E00015E643E20222E0FCA3E0FD7F0A7E001242
:1015F00015741218402212181612181D12182412EF
:1016000017CE12002612177B1217EC1217D81217DA
:10161000E21217B712182B12183212184602183994
:101620008E238F248C258D2612147A12145B1217A8
:101630009F9000C7E525F0A3E526F09000C3E523C1
:10164000F0A3E524F043C804228E3A8F3B8C3C8DF6
:101650003D12147A12145B1217AB9000C9E53CF0EE
:10166000A3E53DF09000C5E53AF0A3E53BF04391DA
:101670000422F582E43400F583E0FF0216F1A3E0D2
:10168000FF0216F1E53825E0248AF582E4340022D1
:10169000E024A9F582E43400F58322900088E0700C
:1016A00008900074E004120C5F900077E004F09062
:1016B0000088E014F0120C8F50030216C353E2FDB1
:1016C000C28022120BDA120C9BEFA806088002C31C
:1016D00013D8FC30E0059000768003900089E07D0F
:1016E00000FCE4FF12170D22AE077FAA1216F1AF1D
:1016F00006C2029000C1E0B42002E4F09000C1E014
:101700002448F8A607E004F0A3E004F022AB07AFFA
:1017100004EB14600C14600E2402700E8DFB8FFC21
:10172000228DE98FEA228DEB8FEC22E4FDFCFF1283
:10173000170D120C4612184E53D87853E2FDC28092
:10174000C2909000857404F022120C60E014F090B6
:1017500000777401F09000857403F01216C312151F
:10176000CB0200707E1DE4FDEF30E70625E06EFF42
:101770008004EF25E0FF0DBD08EE22AF885388AF4F
:10178000758CA0758DCBEF5440FEEF54104E4288FF
:1017900022C3EF94ACEE940D4003D38001C322AD7D
:1017A00007AC06ECF5CBAF058FCA22AD07AC06EC53
:1017B000F593AF058F9222C2DE75D90575F9FF75D5
:1017C0009601221216E87F551216F102185175E3A0
:1017D0004075E10175E20222E59154045391FB4208
:1017E0009122758E5475892243885022E5C854048D
:1017F00053C8FB42C82253984FEB4F4DF59822E552
:10180000C8C320E201D322E591C320E201D32253D1
:10181000C8FB53C87F227597DE7597AD2275A4115A
:1018200075D4CE2275A54175D5772253F77F75DA29
:101830004A2253F77F75DB302275E69075A8B022F7
:10184000E59120E2FB22439810223002FD22C2DE05
:1018500022D299228F9922AF99228F8C22222201A3
:101860000190307000064001904B1918000212C020
:1018700005DC0002BC012C461E2808030BB82328F7
:1018800000044C01904B19180004251C0BB80003F0
:10189000840140461E180005000072D80702BC01F2
:1018A0002C26404000010190307000064001904B12
:1018B0001918000212C005DC0002BC012C461E28CB
:1018C00008030BB8232800044C01904B191800049E
:1018D000251C0BB80003840140461E1800050000BB
:1018E00072D80702BC012C264040000101903070E4
:1018F00000064001904B1918000212C005DC0002DE
:10190000BC012C461E2808030BB8232800044C01F8
:10191000904B19180004251C0BB8000384014046A5
:101920001E180005000072D80702BC012C2640409A
:0119300000B6
:00000001FF

View File

@ -0,0 +1,207 @@
:020000040000FA
:10000000020779AB07AA06EB2401FEE43A900080D0
:10001000F0A3CEF0ED1490007DF08B828A83E0F5A2
:100020009922220204D0C204C29022020B03120CB5
:100030009C120CA3120CAA120C8012006E120B91CF
:10004000120BAA120BC3120C8A120C75120B5D0252
:100050000C5C53984FEB4F4DF598220208CC1200E0
:100060002E120C30D2AF120B77120C0A80F8E4F586
:10007000A922FF020A37020218E86480F8E933E88F
:100080003360110460F0ED33EC337009E8FCE9FDF6
:10009000EAFEEBFF220460DED3EB9FEA9EE99DE8D7
:1000A000C2E78CF0C2F795F0400CE8CCF8E9CDF946
:1000B000EACEFAEBCFFB1201E385D0F058047003CF
:1000C00020D5B3E80470075002B2D502022292D5BF
:1000D000EC0460F7E4CCC0E0C398F8603B9418608F
:1000E00008400DD0E0FB0201FAE4FBFAC9FC8028CD
:1000F000E830E406E4C9FBE4CAFCE830E305E4C9FF
:10010000CACBFCE854076010F8C3E913F9EA13FA04
:10011000EB13FBEC13FCD8F130F52FC3E49CFCEFA0
:100120009BFFEE9AFEED99FDD0E0FBEF4E4D4C703B
:100130001222DB0302021FEC2CFCEF33FFEE33FE36
:10014000ED33FDED30E7EB0201FAEF2BFFEE3AFE67
:10015000ED39FDD0E0FB50130BBB0003020222ED92
:1001600013FDEE13FEEF13FFEC13FC0201FA75F022
:1001700020800E75F010800575F0087D007E007FF0
:10018000003392D530D5031202E3EC334010EF3345
:10019000FFEE33FEED33FDEC33FCD5F0ED22E5F060
:1001A000247EA2D513CC92E7CDCEFF22EDD2E7CDAF
:1001B00033EC3392D524814006E4FFFEFDFC22FCA3
:1001C000E4CFCECDCC24E0501174FF80EDC3CC132E
:1001D000CCCD13CDCE13CECF13CF0470F030D5DEFF
:1001E0000202E3E9D2E7C933E833F892D5EDD2E76A
:1001F000CD33EC33FC5002B2D522EC30E7100FBF08
:10020000000C0EBE00080DBD00040BEB6014A2D55F
:10021000EB13FCED92E7FD2274FFFCFDFEFF22E4F0
:1002200080F8A2D574FF13FC7D80E480EFEF8DF0A1
:10023000A4A8F0CF8CF0A428CE8DF0A42EFE22BC72
:10024000000BBE0029EF8DF084FFADF022E4CCF866
:1002500075F008EF2FFFEE33FEEC33FCEE9DEC98CB
:100260004005FCEE9DFE0FD5F0E9E4CEFD22EDF851
:10027000F5F0EE8420D21CFEADF075F008EF2FFFF4
:10028000ED33FD4007985006D5F0F222C398FD0FDC
:10029000D5F0EA22E88FF0A4CC8BF0A42CFCE98EF8
:1002A000F0A42CFC8AF0EDA42CFCEA8EF0A4CDA8DE
:1002B000F08BF0A42DCC3825F0FDE98FF0A42CCDE7
:1002C00035F0FCEB8EF0A4FEA9F0EB8FF0A4CFC5C7
:1002D000F02ECD39FEE43CFCEAA42DCE35F0FDE451
:1002E0003CFC22C3E49FFFE49EFEE49DFDE49CFCF5
:1002F00022EB9FF5F0EA9E42F0E99D42F0E89C4532
:10030000F022E8600FECC313FCED13FDEE13FEEFDB
:1003100013FFD8F122E8600FEFC333FFEE33FEED99
:1003200033FDEC33FCD8F122E4F50BF50AF509F5C1
:1003300008F50CF50DF50EF50FF510F511F512F5A4
:1003400013F514F515F516F517900000E06401603B
:10035000030204C7F0E52C7015900004E0F524A317
:10036000E0F525A3E0F526A3E0F5271208ADE52585
:100370002527F50DE5243526F50CFEAF0D7C007D17
:100380000512023F8E108F11AE22AF237C007D0537
:1003900012023F8E128F13E4FBEBC3943040030232
:1003A000044F12086A12087BF583E0FCA3E0FD2FDE
:1003B000F50FEC3EF50EE50D2511FFE50C3510FEB1
:1003C000D3E50F9FE50E9E5014C3E50D9511FFE593
:1003D0000C9510FEC3E50F9FE50E9E5009052EE516
:1003E0002E7002052D2212086AFFD3ED9FEC9E406D
:1003F000221208A0EF4401F50BEEF50AEDF509EC29
:10040000F50812086A1208B812087C12087412085B
:10041000C2803712086A12087BF583E0FCA3E0C3B0
:100420009FEC9E501C1208A08F0B8E0A8D098C0821
:1004300012086A1208C212087C1208741208B880E6
:1004400009052EE52E7002052D220B0B0203999053
:100450000002E0FEA3E0FF2511FDE5103EFCC3E530
:10046000239DE5229C5027C3EF9511FFEE9510FECA
:10047000D3E5239FE5229E4015AF2BAE2AAD29ACD4
:1004800028AB0BAA0AA909A8081202F160311208C8
:10049000AD850B2B850A2A850929850828752C012D
:1004A000E4F52DF52EAE14AF15FC1208878E268FBD
:1004B00027AE16AF177C001208878E248F252205E1
:1004C0002CE4F52DF52E22052EE52E7002052D22A9
:1004D000C0E0C0F0C083C082C0D075D000C000C0F2
:1004E00001C002C003C004C005C006C007E598549F
:1004F00003F51EF4529890007CE0700302058AE533
:100500001E20E00302058A90007EE0FEA3E0FFF5D6
:10051000828E83E599F08F828E83E0FF20000B644A
:10052000AA60030205BCD200803A200137300034B3
:10053000EF64A0601EEF64A16019EF64A26014EF85
:1005400064A3600FEF64A4600AEF64A56005120C59
:10055000698069D201EF64A06008EF64A16003BF05
:10056000A202D20290007FE004F0700690007EE0CC
:1005700004F090007CE014F0E0FE6008BF550B3002
:1005800002086006120C691209E3E51E30E12D90A5
:10059000007DE06024900080E0FEA3E0F5828E8381
:1005A000E0F599900081E004F07006900080E0048E
:1005B000F090007DE014F08003120022D007D006F6
:1005C000D005D004D003D002D001D000D0D0D0824A
:1005D000D083D0F0D0E032E4F518F519F51DF51C04
:1005E000F51BF51A30AF6890006612096BF522ED25
:1005F000F52312096AF526EDF52712096AF524EDAF
:10060000F525A3E0FFE4FCFDFEFBFA7901F81202F8
:1006100094A804A905AA06AB0790006DE0FEE4FCCF
:10062000FD2BFBEA3EFAED39F9EC38F8A3E0FFE4E4
:10063000FEEB2FFFEE3AFEED39FDEC388F2B8E2AC4
:100640008D29F5287F0A7E00120BDCC291C2AFE42F
:10065000F51812095EAF23AE22120BF4852B1D850F
:100660002A1C85291B85281AE4F519E4FFFEE51BE1
:100670005480FDE4FCFBFAF9F8C31202F16011D2D8
:1006800080AF25AE24120BF4C280AF27AE268007C0
:1006900012095EAF25AE24120BF4AF1DAE1CAD1BCC
:1006A000AC1A78011203158F1D8E1C8D1B8C1A0538
:1006B00019E519C3941840B30518E518C394084008
:1006C00091D291D2AF7F0A7E00120BDC12092D125B
:1006D0000003120CC3E4F537220233000001370097
:1006E0000235000041007D0041007C00C100C101D5
:1006F000C102C105C104C1030139000138006064B1
:1007000000000000000000000000000000000000E9
:1007100000000000000000000000000000000000D9
:1007200000000000000000000000000000000000C9
:1007300000000000000000000000000000000000B9
:1007400000000000000000000000000000000000A9
:100750000000000000000000000000000000000099
:100760000000000000000D2200000000000000005A
:10077000000000000001210000787FE4F6D8FD753C
:1007800081390207C002005EE493A3F8E493A3401A
:1007900003F68001F208DFF48029E493A3F85407FC
:1007A000240CC8C333C4540F4420C8834004F456F7
:1007B000800146F6DFE4800B01020408102040802F
:1007C0009006D9E47E019360BCA3FF543F30E50955
:1007D000541FFEE493A360010ECF54C025E060A82F
:1007E00040B8E493A3FAE493A3F8E493A3C8C582C2
:1007F000C8CAC583CAF0A3C8C582C8CAC583CADF30
:10080000E9DEE780BEAB07AA06900001E07019C3DD
:10081000EB94C8EA9400405130934EA3EAF0A3EB66
:10082000F09000017401F0227C007D05AF03AE0260
:1008300012022DD3900003E09F900002E09E401032
:10084000E52112087DF583EAF0A3EBF0052180078E
:10085000E4900001F0F521E521C39430400BE4F56C
:100860002190000004F0E4A3F022EB25E02406F53B
:1008700082E43400F583E0FEA3E022FFEB25E024D0
:1008800004F582E43400227D1812023FAC06AD0765
:10089000E4120173E4FBFAF9783F12007D0201AC27
:1008A000AF0BAE0AAD09AC08780102031590000247
:1008B000E0F522A3E0F523222515F515EE3514F514
:1008C00014222517F517EE3516F51622C0E0C0F0F4
:1008D000C083C082C0D075D000C000C001C002C0BB
:1008E00003C004C005C006C00730D823C2D885FCA9
:1008F0002F85FB30C3E5309532F534E52F9531F582
:1009000033852F31853032AF34FE12080580035312
:10091000D879D007D006D005D004D003D002D001BA
:10092000D000D0D0D082D083D0F0D0E03290007010
:1009300074AAF074A0A3F0A37455F07E007F707DBC
:100940000322AF2BAE2AAD29AC28120302A3EFF08D
:1009500022120A7D120C207E007F707D0C22D28034
:10096000AF27AE26120BF4C28022A3E0FEA3E0FD67
:10097000EE2212022DEEA3F02275F00AA4A3F022BB
:10098000C3E52E9496E52D940022053930052AE51D
:1009900039C39414404C0538E538D394045002B25E
:1009A00096E4F539B290E538C394084035E4F5385B
:1009B000C296C290C205C20422300412E539C39423
:1009C0000A401F309602C296E4F539B290223003F5
:1009D00011E539D3940A400AE4F539B29020900227
:1009E000C20322900064E0FFB4AA0BA3E0B4A00607
:1009F000A3E064556040EF64AA7022900065E06453
:100A0000A1701AA3E0B45515120C2012092D120082
:100A100003E4F535F536120C947537012290006425
:100A2000E0B4AA12A3E0B4A50D90006FE0B455069F
:100A3000753702120C2022C0E0C0F0C083C082C013
:100A4000D075D000C000C001C002C003C004C00502
:100A5000C006C00712098A0536E53670020535530F
:100A6000917FD007D006D005D004D003D002D001AA
:100A7000D000D0D0D082D083D0F0D0E032900070BF
:100A800074AAF0A3EFF0AE22AF237C007D0A120916
:100A900072E523120979AE26AF27120972E52712F3
:100AA0000979AE24AF25120972E52512097978106B
:100AB0001209427808120942A3E52BF0A37455F0FD
:100AC00022E52CB40A03120CBD1209804015E52C56
:100AD000940A400FE4F52DF52E7FA3120951120060
:100AE00003801CC3E5369470E535941740149000DC
:100AF0007074AAF074A2120935120003120026E4E1
:100B0000F53722C0E0C0F0C083C082C0D075D000ED
:100B1000C000C001C002C003C004C005C006C007B9
:100B2000120328C2CFD007D006D005D004D003D0FE
:100B300002D001D000D0D0D082D083D0F0D0E0322B
:100B40001209804017E52CD394004010E4F52DF5F0
:100B50002E7FA4120951120003120CC322E5D854AF
:100B600040FFE5F75480FE53D8BF53F77F75DA3165
:100B7000EF42D8EE42F722E5377015120CB7EF704E
:100B80000F120CB1EF70097E007F647D0C120C4EC9
:100B900022AF885388AF758C0B758AD7758DCBEFD4
:100BA0005440FEEF54104E428822E5C8540453C806
:100BB000FB75CD4075CC9875CB4075CA9843C80479
:100BC00042C822E59154045391FB7595FF75940B2F
:100BD0007593B075923F439104429122AD07AC06E4
:100BE000D3ED9400EC9400400A120C40ED1D70F01F
:100BF0001C80ED22EF1FAC0670011E4C600B000044
:100C00000000000000000080EB22E53714600A14A9
:100C1000600A24027009020B40020AC11205D722A1
:100C2000E4F52CF52BF52AF529F528F522F52322F4
:100C3000C280D291C290C296E4FBFD7F10020052A6
:100C40007F927E09EF1F70011EEF4E70F722900019
:100C50007EEEF0A3EFF090007CEDF02275E690754B
:100C6000F31075A8B075B8102290007CE4F0C200B3
:100C7000C201C20222C2DE75D904759E01D2DE22F3
:100C800075E34075E10175E20122758E14758922C4
:100C900043885022D204E4F539D296227597DE7546
:100CA00097AD2275A41375D4CF2275A54375D507CA
:100CB0002290007DE0FF2290007CE0FF22D205E43C
:090CC000F53922D203E4F53922D2
:00000001FF

9
updateDocs.sh Normal file
View File

@ -0,0 +1,9 @@
#!/bin/sh
SCRIPTPATH="$(readlink -f "$0")"
SCRIPTPATH="${SCRIPTPATH%/*}"
rm -rf "$SCRIPTPATH/html"
echo -e "\n\n\n\n"
#cd "$SCRIPTPATH/" && doxygen && git add $DOCDIR && git commit -a -m "Documentation update."
cd "$SCRIPTPATH/" && doxygen