mirror of https://github.com/arendst/Tasmota.git
Merge branch 'development' into prerelease-12.4
This commit is contained in:
commit
dafa28f8ba
|
@ -7,7 +7,7 @@
|
|||
- [ ] Only relevant files were touched
|
||||
- [ ] Only one feature/fix was added per PR and the code change compiles without warnings
|
||||
- [ ] The code change is tested and works with Tasmota core ESP8266 V.2.7.4.9
|
||||
- [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.5
|
||||
- [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.6
|
||||
- [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla).
|
||||
|
||||
_NOTE: The code change must pass CI tests. **Your PR cannot be merged unless tests pass**_
|
||||
|
|
|
@ -58,7 +58,7 @@ jobs:
|
|||
matrix:
|
||||
variant:
|
||||
- tasmota
|
||||
- tasmota4M
|
||||
- tasmota-4M
|
||||
- tasmota-minimal
|
||||
- tasmota-display
|
||||
- tasmota-ir
|
||||
|
@ -200,7 +200,7 @@ jobs:
|
|||
mkdir -p ./firmware/map
|
||||
[ ! -f ./mv_firmware/map/* ] || mv ./mv_firmware/map/* ./firmware/map/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota.* ] || mv ./mv_firmware/firmware/tasmota.* ./firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota4M.* ] || mv ./mv_firmware/firmware/tasmota4M.* ./firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota-4M.* ] || mv ./mv_firmware/firmware/tasmota-4M.* ./firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota-sensors.* ] || mv ./mv_firmware/firmware/tasmota-sensors.* ./firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota-minimal.bin.gz ] || mv ./mv_firmware/firmware/tasmota-minimal.bin.gz ./firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota-lite.* ] || mv ./mv_firmware/firmware/tasmota-lite.* ./firmware/tasmota/
|
||||
|
|
|
@ -57,7 +57,7 @@ jobs:
|
|||
matrix:
|
||||
variant:
|
||||
- tasmota
|
||||
- tasmota4M
|
||||
- tasmota-4M
|
||||
- tasmota-minimal
|
||||
- tasmota-display
|
||||
- tasmota-ir
|
||||
|
@ -208,7 +208,7 @@ jobs:
|
|||
mkdir -p ./release-firmware/map
|
||||
[ ! -f ./mv_firmware/map/* ] || mv ./mv_firmware/map/* ./release-firmware/map/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota.* ] || mv ./mv_firmware/firmware/tasmota.* ./release-firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota4M.* ] || mv ./mv_firmware/firmware/tasmota4M.* ./release-firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota-4M.* ] || mv ./mv_firmware/firmware/tasmota-4M.* ./release-firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota-sensors.* ] || mv ./mv_firmware/firmware/tasmota-sensors.* ./release-firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota-minimal.bin.gz ] || mv ./mv_firmware/firmware/tasmota-minimal.bin.gz ./release-firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/firmware/tasmota-lite.* ] || mv ./mv_firmware/firmware/tasmota-lite.* ./release-firmware/tasmota/
|
||||
|
|
|
@ -81,7 +81,7 @@ jobs:
|
|||
matrix:
|
||||
variant:
|
||||
- tasmota
|
||||
- tasmota4M
|
||||
- tasmota-4M
|
||||
- tasmota-display
|
||||
- tasmota-ir
|
||||
- tasmota-knx
|
||||
|
@ -113,10 +113,6 @@ jobs:
|
|||
- tasmota32s3-safeboot
|
||||
- tasmota32s3cdc-safeboot
|
||||
steps:
|
||||
- name: Sleep a while, try to start MacOS / Windows CI env first
|
||||
uses: jakejarvis/wait-action@master
|
||||
with:
|
||||
time: '1m'
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
|
|
|
@ -34,5 +34,6 @@ lib/libesp32/berry/berry
|
|||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/settings.json
|
||||
*.bak
|
||||
*.code-workspace
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"platformio-ide.toolbar": [
|
||||
{
|
||||
"text": "$(home)",
|
||||
"tooltip": "PlatformIO: Home",
|
||||
"commands": [
|
||||
{
|
||||
"id": "platformio-ide.runPIOCoreCommand",
|
||||
"args": "pio home"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "$(trash)",
|
||||
"tooltip": "PlatformIO: Clean All",
|
||||
"commands": [
|
||||
{
|
||||
"id": "workbench.action.tasks.runTask",
|
||||
"args": "PlatformIO: Clean All"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "$(check)",
|
||||
"tooltip": "PlatformIO: Build",
|
||||
"commands": [
|
||||
{
|
||||
"id": "workbench.action.tasks.runTask",
|
||||
"args": "PlatformIO: Build"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "$(zap)",
|
||||
"tooltip": "PlatformIO: Build and Upload",
|
||||
"commands": [
|
||||
{
|
||||
"id": "workbench.action.tasks.runTask",
|
||||
"args": "PlatformIO: Upload"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "$(flame)",
|
||||
"tooltip": "PlatformIO: Build, Erase and Upload",
|
||||
"commands": [
|
||||
{
|
||||
"id": "platformio-ide.runPIOCoreCommand",
|
||||
"args": "pio run -t erase_upload"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "$(device-desktop)",
|
||||
"tooltip": "PlatformIO: Serial Monitor",
|
||||
"commands": [
|
||||
{
|
||||
"id": "workbench.action.tasks.runTask",
|
||||
"args": "PlatformIO: Monitor"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "$(refresh)",
|
||||
"tooltip": "PlatformIO: Rebuild IntelliSense Index",
|
||||
"commands": [
|
||||
{
|
||||
"id": "workbench.action.tasks.runTask",
|
||||
"args": "PlatformIO: Rebuild IntelliSense Index"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
5
API.md
5
API.md
|
@ -1,4 +1,7 @@
|
|||
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./tools/logo/TASMOTA_FullLogo_Vector_White.svg">
|
||||
<img alt="Logo" src="./tools/logo/TASMOTA_FullLogo_Vector.svg" align="right" height="76">
|
||||
</picture>
|
||||
|
||||
# Basic API information
|
||||
|
||||
|
|
|
@ -89,7 +89,8 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
|
|||
| USE_BL09XX | - | x / x | x | x | - | - |
|
||||
| USE_TELEINFO | - | - / - | - | - | - | - |
|
||||
| USE_IEM3000 | - | - / - | - | - | - | - |
|
||||
| USE_WE517 | - | - / - | - | - | - | - |
|
||||
| USE_WE517 | - | - / x | - | - | - | - |
|
||||
| USE_MODBUS_ENERGY | - | - / x | - | - | - | - |
|
||||
| | | | | | | |
|
||||
| USE_ADC_VCC | x | - / - | - | - | x | - |
|
||||
| USE_COUNTER | - | x / x | x | x | - | x |
|
||||
|
@ -117,10 +118,12 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
|
|||
| USE_MGS | - | - / x | - | x | - | - |
|
||||
| USE_SGP30 | - | - / x | - | x | - | - |
|
||||
| USE_SGP40 | - | - / x | - | x | - | - |
|
||||
| USE_SEN5X | - | - / x | - | x | - | - |
|
||||
| USE_SI1145 | - | - / - | - | - | - | - |
|
||||
| USE_LM75AD | - | - / x | - | x | - | - |
|
||||
| USE_APDS9960 | - | - / - | - | - | - | - |
|
||||
| USE_MCP230xx | - | - / - | - | - | - | - |
|
||||
| USE_PCA9632 | - | - / - | - | - | - | - |
|
||||
| USE_PCA9685 | - | - / - | - | - | - | - |
|
||||
| USE_MPR121 | - | - / - | - | - | - | - |
|
||||
| USE_CCS811 | - | - / - | - | x | - | - |
|
||||
|
@ -246,6 +249,7 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
|
|||
| USE_DISPLAY_ST7789 | - | - / - | - | - | - | x |
|
||||
| USE_DISPLAY_TM1637 | - | - / - | - | - | - | x |
|
||||
| USE_DISPLAY_TM1621_SONOFF | - | - / x | - | - | - | - |
|
||||
| USE_DISPLAY_TM1650 | - | - / - | - | - | - | - |
|
||||
| | | | | | | |
|
||||
| USE_FT5206 | - | - / - | - | - | - | - |
|
||||
| USE_FTC532 | - | - / - | - | - | - | - |
|
||||
|
|
96
CHANGELOG.md
96
CHANGELOG.md
|
@ -3,6 +3,102 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
## [Released]
|
||||
|
||||
## [12.4.0] 20230215
|
||||
- Release Peter
|
||||
|
||||
## [12.3.1.6] 20230215
|
||||
### Added
|
||||
- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger
|
||||
- Basic support for Shelly Pro 4PM
|
||||
|
||||
### Breaking Changed
|
||||
- TM1638 button and led support are handled as virtual switches and relays (#11031)
|
||||
|
||||
### Fixed
|
||||
- ESP8266 Fix TLS SNI which would prevent AWS IoT connection (#17936)
|
||||
|
||||
## [12.3.1.5] 20230208
|
||||
### Added
|
||||
- ESP32 support for eigth energy phases/channels
|
||||
- ESP32 command ``EnergyCols 1..8`` to change number of GUI columns
|
||||
- ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation
|
||||
- Support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736)
|
||||
- Berry add ``mdns`` advanced features and query
|
||||
- ESP32 support for Biomine BioPDU 625x12 (#17857)
|
||||
|
||||
### Breaking Changed
|
||||
- Berry energy_ctypes changed with new energy driver
|
||||
- Berry energy_ctypes fixed accordingly
|
||||
|
||||
### Changed
|
||||
- Energy refactoring preparing for ESP32 phase/channel extension
|
||||
|
||||
### Fixed
|
||||
- ADE7953 when calibration data for second channel is used regression from v12.2.0.2
|
||||
- Shelly Pro 1/2 relay click at restart regression from v12.3.1.4
|
||||
- Zigbee extend plug-in modifiers to 16 bits
|
||||
- Broken I2C priority regression from v12.3.1.3 (#17810)
|
||||
- Energy usage and return migrated too small (/10000) regression from v12.3.1.3
|
||||
|
||||
## [12.3.1.4] 20230127
|
||||
### Added
|
||||
- Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol)
|
||||
- Berry add up flag to ``tasmota.wifi()`` and ``tasmota.eth()``, always return MAC
|
||||
|
||||
## [12.3.1.3] 20230115
|
||||
### Added
|
||||
- Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich (#17557)
|
||||
- Berry `bytes()` now evaluates to `false` if empty
|
||||
- Berry ``crypto.AES_CCM`` (required by Matter protocol)
|
||||
- ESP32 support for BMPxxx sensors on two I2C busses (#17643)
|
||||
- Berry add implicit ``_class`` parameter to static methods
|
||||
|
||||
### Changed
|
||||
- Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh
|
||||
- Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching
|
||||
- Increase rule event buffer from 100 to 256 characters (#16943)
|
||||
- All calls to atof() into CharToFloat() reducing code size by 8k
|
||||
- Keep webserver enabled on command ``upload``
|
||||
|
||||
### Fixed
|
||||
- Energy dummy switched voltage and power regression from v12.2.0.2
|
||||
- Orno WE517 modbus serial config 8E1 setting (#17545)
|
||||
- No IP address shown when in AP mode regression from v12.3.1.1 (#17599)
|
||||
- Rename ``tasmota4M.bin`` to ``tasmota-4M.bin`` to solve use of ``tasmota-minimal.bin`` (#17674)
|
||||
- DNS lookup for ``upload`` from ota server using http regression from v12.3.1.1
|
||||
|
||||
## [12.3.1.2] 20221231
|
||||
### Added
|
||||
- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol
|
||||
- Berry crypto add ``random`` to generate series of random bytes
|
||||
- Berry crypto add ``HKDF_HMAC_SHA256``
|
||||
- Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver
|
||||
- Berry crypto add ``SPAKE2P_Matter`` for Matter support
|
||||
- Support for IPv6 only networks on Ethernet (not yet Wifi)
|
||||
- Support for TM1650 display as used in some clocks by Stefan Oskamp (#17594)
|
||||
|
||||
### Changed
|
||||
- ESP32 Framework (Core) from v2.0.5.4 to v2.0.6 (IPv6 support)
|
||||
- Tasmota OTA scripts now support both unzipped and gzipped file uploads (#17378)
|
||||
- NTP default servers to dual-stack (IPv4/IPv6)
|
||||
- Revert TuyaMcu rewrite by btsimonh as lack of support
|
||||
|
||||
### Fixed
|
||||
- Shutter default motorstop set to 0 (#17403)
|
||||
- Shutter default tilt configuration (#17484)
|
||||
- Modbus transmit enable GPIO enabled once during write buffer
|
||||
- ESP8266 set GPIO's to input on power on fixing relay spikes (#17531)
|
||||
|
||||
## [12.3.1.1] 20221221
|
||||
### Added
|
||||
- Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 (#17417)
|
||||
- Berry support for ``crypto.SHA256`` (#17430)
|
||||
- Support for RGB displays (#17414)
|
||||
- Berry add crypto AES_CTR, HDMAC_SHA256, MD5
|
||||
|
||||
### Changed
|
||||
- ESP32 Framework (Core) from v2.0.5.3 to v2.0.5.4 (IPv6 support)
|
||||
|
||||
## [12.3.1] 20221216
|
||||
- Release Percy
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./tools/logo/TASMOTA_FullLogo_Vector_White.svg">
|
||||
<img alt="Logo" src="./tools/logo/TASMOTA_FullLogo_Vector.svg" align="right" height="76">
|
||||
</picture>
|
||||
|
||||
# Code Owners
|
||||
|
||||
|
@ -72,6 +75,7 @@ In addition to @arendst the following code is mainly owned by:
|
|||
| xdrv_61_ds3502 | f-reiling
|
||||
| xdrv_62_improv | @arendst
|
||||
| xdrv_63_modbus_bridge | @jeroenst
|
||||
| xdrv_64_pca9632 | Pascal Heinrich
|
||||
| |
|
||||
| xdrv_79_esp32_ble | @staars, @btsimonh
|
||||
| xdrv_81_esp32_webcam | @gemu, @philrich
|
||||
|
@ -194,6 +198,7 @@ In addition to @arendst the following code is mainly owned by:
|
|||
| xsns_100_ina3221 | @barbudor
|
||||
| xsns_101_hmc5883l | Andreas Achtzehn
|
||||
| xsns_102_ld2410 | @arendst
|
||||
| xsns_103_sen5x | @tyeth
|
||||
| |
|
||||
| Libraries |
|
||||
| |
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./tools/logo/TASMOTA_FullLogo_Vector_White.svg">
|
||||
<img alt="Logo" src="./tools/logo/TASMOTA_FullLogo_Vector.svg" align="right" height="76">
|
||||
</picture>
|
||||
|
||||
# Contributing
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
![Tasmota logo](https://github.com/arendst/Tasmota/blob/development/tools/logo/TASMOTA_FullLogo_Vector.svg)
|
||||
![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector.svg#gh-light-mode-only)![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector_White.svg#gh-dark-mode-only)
|
||||
|
||||
Alternative firmware for [ESP8266](https://en.wikipedia.org/wiki/ESP8266) based devices with **easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX**.
|
||||
_Written for PlatformIO with limited support for Arduino IDE._
|
||||
|
@ -13,6 +13,7 @@ If you like **Tasmota**, give it a star, or fork it and contribute!
|
|||
[![GitHub stars](https://img.shields.io/github/stars/arendst/Tasmota.svg?style=social&label=Star)](https://github.com/arendst/Tasmota/stargazers)
|
||||
[![GitHub forks](https://img.shields.io/github/forks/arendst/Tasmota.svg?style=social&label=Fork)](https://github.com/arendst/Tasmota/network)
|
||||
[![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/tasmota)
|
||||
[![donate](https://img.shields.io/badge/donate-buy%20me%20a%20coffee-yellow.svg)](https://www.buymeacoffee.com/tasmota)
|
||||
|
||||
See [CHANGELOG.md](https://github.com/arendst/Tasmota/blob/development/tasmota/CHANGELOG.md) for changes since last release.
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ The following table lists the supported I2C devices
|
|||
Index | Define | Driver | Device | Address(es) | Description
|
||||
------|---------------------|----------|----------|-------------|-----------------------------------------------
|
||||
1 | USE_PCA9685 | xdrv_15 | PCA9685 | 0x40 - 0x47 | 16-channel 12-bit pwm driver
|
||||
2 | USE_PCF8574 | xdrv_28 | PCF8574 | 0x20 - 0x26 | 8-bit I/O expander
|
||||
2 | USE_PCF8574 | xdrv_28 | PCF8574A | 0x39 - 0x3F | 8-bit I/O expander
|
||||
2 | USE_PCF8574 | xdrv_28 | PCF8574 | 0x20 - 0x26 | 8-bit I/O expander (address range overridable)
|
||||
2 | USE_PCF8574 | xdrv_28 | PCF8574A | 0x39 - 0x3F | 8-bit I/O expander (address range overridable)
|
||||
3 | USE_DISPLAY_LCD | xdsp_01 | | 0x27, 0x3F | LCD display
|
||||
4 | USE_DISPLAY_SSD1306 | xdsp_02 | SSD1306 | 0x3C - 0x3D | Oled display
|
||||
5 | USE_DISPLAY_MATRIX | xdsp_03 | HT16K33 | 0x70 - 0x77 | 8x8 led matrix
|
||||
|
@ -45,6 +45,7 @@ Index | Define | Driver | Device | Address(es) | Description
|
|||
22 | USE_MCP230xx | xsns_29 | MCP23017 | 0x20 - 0x26 | 16-bit I/O expander
|
||||
23 | USE_MPR121 | xsns_30 | MPR121 | 0x5A - 0x5D | Proximity capacitive touch sensor
|
||||
24 | USE_CCS811 | xsns_31 | CCS811 | 0x5A | Gas (TVOC) and air quality sensor
|
||||
24' | USE_CCS811_V2 | xsns_31 | CCS811 | 0x5A - 0x5B | Gas (TVOC) and air quality sensor
|
||||
25 | USE_MPU6050 | xsns_32 | MPU6050 | 0x68 - 0x69 | 3-axis gyroscope and temperature sensor
|
||||
26 | USE_DS3231 | xsns_33 | DS3231 | 0x68 | Real time clock
|
||||
27 | USE_MGC3130 | xsns_36 | MGC3130 | 0x42 | Electric field sensor
|
||||
|
@ -60,7 +61,7 @@ Index | Define | Driver | Device | Address(es) | Description
|
|||
37 | USE_24C256 | xdrv_10 | 24C256 | 0x50 | Scripter EEPROM storage
|
||||
38 | USE_DISPLAY_ILI9488 | xdsp_08 | FT6236 | 0x38 | Touch panel controller
|
||||
39 | USE_DISPLAY_RA8876 | xdsp_10 | FT5316 | 0x38 | Touch panel controller
|
||||
40 | USE_TSL2591 | xsns_57 | TLS2591 | 0x29 | Light intensity sensor
|
||||
40 | USE_TSL2591 | xsns_57 | TSL2591 | 0x29 | Light intensity sensor
|
||||
41 | USE_DHT12 | xsns_58 | DHT12 | 0x5C | Temperature and humidity sensor
|
||||
42 | USE_DS1624 | xsns_59 | DS1621 | 0x48 - 0x4F | Temperature sensor
|
||||
42 | USE_DS1624 | xsns_59 | DS1624 | 0x48 - 0x4F | Temperature sensor
|
||||
|
@ -108,3 +109,6 @@ Index | Define | Driver | Device | Address(es) | Description
|
|||
71 | USE_QMC5883L | xsns_33 | QMC5883L | 0x0D | Magnetic Field Sensor
|
||||
72 | USE_INA3221 | xsns_100 | INA3221 | 0x40-0x43 | 3-channels Voltage and Current sensor
|
||||
73 | USE_HMC5883L | xsns_101 | HMC5883L | 0x1E | 3-channels Magnetic Field Sensor
|
||||
74 | USE_DISPLAY_TM1650 | xdsp_20 | TM1650 | 0x24 - 0x27, 0x34 - 0x37 | Four-digit seven-segment LED controller
|
||||
75 | USE_PCA9632 | xdrv_64 | PCA9632 | 0x60 | 4-channel 4-bit pwm driver
|
||||
76 | USE_SEN5X | xsns_103 | SEN5X | 0x69 | Gas (VOC/NOx index) and air quality (PPM <1,<2.5,<4,<10)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector.svg)
|
||||
![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector.svg#gh-light-mode-only)![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector_White.svg#gh-dark-mode-only)
|
||||
|
||||
Alternative firmware for [ESP8266](https://en.wikipedia.org/wiki/ESP8266) and [ESP32](https://en.wikipedia.org/wiki/ESP32) based devices with **easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX**.
|
||||
_Written for PlatformIO._
|
||||
|
@ -24,6 +24,7 @@ If you like **Tasmota**, give it a star, or fork it and contribute!
|
|||
[![GitHub stars](https://img.shields.io/github/stars/arendst/Tasmota.svg?style=social&label=Star)](https://github.com/arendst/Tasmota/stargazers)
|
||||
[![GitHub forks](https://img.shields.io/github/forks/arendst/Tasmota.svg?style=social&label=Fork)](https://github.com/arendst/Tasmota/network)
|
||||
[![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/tasmota)
|
||||
[![donate](https://img.shields.io/badge/donate-buy%20me%20a%20coffee-yellow.svg)](https://www.buymeacoffee.com/tasmota)
|
||||
|
||||
See [RELEASENOTES.md](https://github.com/arendst/Tasmota/blob/master/RELEASENOTES.md) for release information.
|
||||
|
||||
|
@ -46,7 +47,7 @@ Note that there is a chance, as with any upgrade, that the device may not functi
|
|||
|
||||
## Disclaimer
|
||||
|
||||
st:warning: **DANGER OF ELECTROCUTION** :warning:
|
||||
:warning: **DANGER OF ELECTROCUTION** :warning:
|
||||
|
||||
If your device connects to mains electricity (AC power) there is danger of electrocution if not installed properly. If you don't know how to install it, please call an electrician (***Beware:*** certain countries prohibit installation without a licensed electrician present). Remember: _**SAFETY FIRST**_. It is not worth the risk to yourself, your family and your home if you don't know exactly what you are doing. Never tinker or try to flash a device using the serial programming interface while it is connected to MAINS ELECTRICITY (AC power).
|
||||
|
||||
|
@ -125,6 +126,7 @@ You can contribute to Tasmota by
|
|||
- Contributing missing [documentation](https://tasmota.github.io/docs) for features and devices
|
||||
|
||||
[![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/tasmota)
|
||||
[![donate](https://img.shields.io/badge/donate-buy%20me%20a%20coffee-yellow.svg)](https://www.buymeacoffee.com/tasmota)
|
||||
|
||||
## Credits
|
||||
|
||||
|
@ -170,4 +172,4 @@ People helping to keep the show on the road:
|
|||
|
||||
## License
|
||||
|
||||
This program is licensed under GPL-3.0
|
||||
This program is licensed under GPL-3.0
|
||||
|
|
115
RELEASENOTES.md
115
RELEASENOTES.md
|
@ -1,4 +1,7 @@
|
|||
<img src="https://github.com/arendst/Tasmota/blob/master/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./tools/logo/TASMOTA_FullLogo_Vector_White.svg">
|
||||
<img alt="Logo" src="./tools/logo/TASMOTA_FullLogo_Vector.svg" align="right" height="76">
|
||||
</picture>
|
||||
|
||||
# RELEASE NOTES
|
||||
|
||||
|
@ -33,9 +36,9 @@ While fallback or downgrading is common practice it was never supported due to S
|
|||
|
||||
This release will be supported from ESP8266/Arduino library Core version **2.7.4.9** due to reported security and stability issues on previous Core version. This will also support gzipped binaries.
|
||||
|
||||
This release will be supported from ESP32/Arduino library Core version **2.0.5.3**.
|
||||
This release will be supported from ESP32/Arduino library Core version **2.0.6**.
|
||||
|
||||
Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.5.3 have been removed.
|
||||
Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.6 have been removed.
|
||||
|
||||
## Support of TLS
|
||||
|
||||
|
@ -55,7 +58,7 @@ Easy initial installation of Tasmota can be performed using the [Tasmota WebInst
|
|||
The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.4.9**.
|
||||
|
||||
- **tasmota.bin** = The Tasmota version with most drivers for 1M+ flash. **RECOMMENDED RELEASE BINARY**
|
||||
- **tasmota4M.bin** = The Tasmota version with most drivers and filesystem for 4M+ flash.
|
||||
- **tasmota-4M.bin** = The Tasmota version with most drivers and filesystem for 4M+ flash.
|
||||
- **tasmota-AD.bin** to **tasmota-VN.bin** = The Tasmota version in different languages for 1M+ flash.
|
||||
- **tasmota-lite.bin** = The Lite version without most drivers and sensors for 1M+ flash.
|
||||
- **tasmota-knx.bin** = The Knx version without some features but adds KNX support for 1M+ flash.
|
||||
|
@ -72,12 +75,12 @@ Latest released binaries can be downloaded from
|
|||
- http://ota.tasmota.com/tasmota/release
|
||||
|
||||
Historical binaries can be downloaded from
|
||||
- http://ota.tasmota.com/tasmota/release-12.3.1
|
||||
- http://ota.tasmota.com/tasmota/release-12.4.0
|
||||
|
||||
The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz``
|
||||
|
||||
### ESP32, ESP32-C3, ESP32-S2 and ESP32-S3 based
|
||||
The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.5.3**.
|
||||
The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.6**.
|
||||
|
||||
- **tasmota32.bin** = The Tasmota version with most drivers including additional sensors and KNX for 4M+ flash. **RECOMMENDED RELEASE BINARY**
|
||||
- **tasmota32xy.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C3/S2/S3 and 4M+ flash.
|
||||
|
@ -97,7 +100,7 @@ Latest released binaries can be downloaded from
|
|||
- https://ota.tasmota.com/tasmota32/release
|
||||
|
||||
Historical binaries can be downloaded from
|
||||
- https://ota.tasmota.com/tasmota32/release-12.3.1
|
||||
- https://ota.tasmota.com/tasmota32/release-12.4.0
|
||||
|
||||
The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasmota.com/tasmota32/release/tasmota32.bin``
|
||||
|
||||
|
@ -107,71 +110,47 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
|
|||
|
||||
[Complete list](BUILDS.md) of available feature and sensors.
|
||||
|
||||
## Changelog v12.3.1 Percy
|
||||
|
||||
## Changelog v12.4.0 Peter
|
||||
### Added
|
||||
- Command ``SetOption35 0..255`` to skip number of received messages in Serial Bridge (default 0) [#17140](https://github.com/arendst/Tasmota/issues/17140)
|
||||
- Command ``SetOption47 1..255`` to delay power on relay state in seconds reducing power surge. ``SO47 1`` delays until network connected. ``SO47 2`` delays until mqtt connected
|
||||
- Command ``RgxClients`` for range extender clients list [#17048](https://github.com/arendst/Tasmota/issues/17048)
|
||||
- Command ``RgxPort [tcp|udp], gateway_port, client_mac, client_port`` for range extender port forwardings [#17092](https://github.com/arendst/Tasmota/issues/17092)
|
||||
- Command ``SSerialBuffer 256..SERIAL_BRIDGE_BUFFER_SIZE`` to change serial bridge rx buffer size [#17120](https://github.com/arendst/Tasmota/issues/17120)
|
||||
- Command ``SwitchMode 16`` sending only MQTT message on inverted switch change [#17028](https://github.com/arendst/Tasmota/issues/17028)
|
||||
- Command NeoPool ``NPFiltration 2`` toggle [#16859](https://github.com/arendst/Tasmota/issues/16859)
|
||||
- Optional define ``SERIAL_BRIDGE_BUFFER_SIZE`` to set Serial Bridge internal buffer size (Default ESP8266 = 256, ESP32 = 800)
|
||||
- Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2``
|
||||
- Support for HLK-LD2410 24GHz smart wave motion sensor
|
||||
- Support for Shelly Pro 1/1PM and 2/2PM [#16773](https://github.com/arendst/Tasmota/issues/16773)
|
||||
- Support for up to four DS18x20 GPIOs by md5sum-as [#16833](https://github.com/arendst/Tasmota/issues/16833)
|
||||
- Support for Digital Addressable Lighting Interface (DALI) by Andrei Kazmirtsuk [#16938](https://github.com/arendst/Tasmota/issues/16938)
|
||||
- Support for NTAG2xx tags read and write on PN532 NFC reader [#16939](https://github.com/arendst/Tasmota/issues/16939)
|
||||
- Support for Plantower PMSx003T AQI models with temperature and humidity [#16971](https://github.com/arendst/Tasmota/issues/16971)
|
||||
- Support for BP1658CJ RGBCW led bulbs like Orein OS0100411267 by Cossid [#17011](https://github.com/arendst/Tasmota/issues/17011)
|
||||
- Support for Dingtian x595 shift register based relay boards by Barbudor [#17032](https://github.com/arendst/Tasmota/issues/17032)
|
||||
- Support for HMC5883L 3-Axis Digital Compass sensor by Andreas Achtzehn [#17069](https://github.com/arendst/Tasmota/issues/17069)
|
||||
- Support for ME007-ULS narrow FoV ultrasonic distance sensor by Mathias Buder [#17376](https://github.com/arendst/Tasmota/issues/17376)
|
||||
- WS2812 and Light ArtNet DMX control over UDP port 6454 [#17059](https://github.com/arendst/Tasmota/issues/17059)
|
||||
- Teleinfo TEMPO (BBR) contract [#17160](https://github.com/arendst/Tasmota/issues/17160)
|
||||
- Serial Modbus transmit enable GPIOs to all modbus energy drivers and modbus bridge [#17247](https://github.com/arendst/Tasmota/issues/17247)
|
||||
- Berry ``bytes().setbytes()`` method [#16892](https://github.com/arendst/Tasmota/issues/16892)
|
||||
- Berry ``bytes().reverse()`` method [#16977](https://github.com/arendst/Tasmota/issues/16977)
|
||||
- Berry ``mdns`` module [#17202](https://github.com/arendst/Tasmota/issues/17202)
|
||||
- Zigbee router firmware for Sonoff ZBBridgePro [#16900](https://github.com/arendst/Tasmota/issues/16900)
|
||||
- ESP32 Support for DMX ArtNet Led matrix animations [#16984](https://github.com/arendst/Tasmota/issues/16984)
|
||||
- ESP32 DS18x20 parasitic power usage when defining W1_PARASITE_POWER [#17112](https://github.com/arendst/Tasmota/issues/17112)
|
||||
- Support for up to 3 (ESP8266) or 8 (ESP32) phase modbus energy monitoring device using generic Energy Modbus driver
|
||||
- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414)
|
||||
- Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417)
|
||||
- Support for IPv6 only networks on Ethernet (not yet Wifi)
|
||||
- Support for TM1650 display as used in some clocks by Stefan Oskamp [#17594](https://github.com/arendst/Tasmota/issues/17594)
|
||||
- Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich [#17557](https://github.com/arendst/Tasmota/issues/17557)
|
||||
- support for SEN5X gas and air quality sensor by Tyeth Gundry [#17736](https://github.com/arendst/Tasmota/issues/17736)
|
||||
- Basic support for Shelly Pro 4PM
|
||||
- Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430)
|
||||
- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473)
|
||||
- Berry crypto add ``random`` to generate series of random bytes
|
||||
- Berry crypto add ``HKDF_HMAC_SHA256``
|
||||
- Berry crypto add ``SPAKE2P_Matter`` for Matter support
|
||||
- Berry add ``mdns`` advanced features and query
|
||||
- ESP32 command ``EnergyCols 1..8`` to change number of GUI columns
|
||||
- ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation
|
||||
- ESP32 support for eigth energy phases/channels
|
||||
- ESP32 support for BMPxxx sensors on two I2C busses [#17643](https://github.com/arendst/Tasmota/issues/17643)
|
||||
- ESP32 support for Biomine BioPDU 625x12 [#17857](https://github.com/arendst/Tasmota/issues/17857)
|
||||
- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger
|
||||
|
||||
### Breaking Changed
|
||||
- Redesign distance sensors VL53LXX, TOF10120, HRXL and DYP to use cm instead of mm [#17021](https://github.com/arendst/Tasmota/issues/17021)
|
||||
- TM1638 button and led support are handled as virtual switches and relays [#11031](https://github.com/arendst/Tasmota/issues/11031)
|
||||
|
||||
### Changed
|
||||
- TasmotaSerial library from v3.5.0 to v3.6.0
|
||||
- ESP32 Framework (Core) from v2.0.5 to v2.0.5.3
|
||||
- ESP32 LVGL library from v8.3.2 to v8.3.3 (no functional change)
|
||||
- ESP32 NimBLE library from v1.4.0 to v1.4.1 [#16775](https://github.com/arendst/Tasmota/issues/16775)
|
||||
- Serial Bridge default internal serial rx buffer size from 64 to 256 [#17120](https://github.com/arendst/Tasmota/issues/17120)
|
||||
- DS18x20 ``DS18Alias`` to ``DS18Sens`` [#16833](https://github.com/arendst/Tasmota/issues/16833)
|
||||
- Compiling with reduced boards manifests in favour of Autoconfig [#16848](https://github.com/arendst/Tasmota/issues/16848)
|
||||
- ADE7953 monitoring from instant power to accumulated energy [#16941](https://github.com/arendst/Tasmota/issues/16941)
|
||||
- WS2812 sends signal to only ``Pixels`` leds instead of sending to 512 leds [#17055](https://github.com/arendst/Tasmota/issues/17055)
|
||||
- AC PWM dimmer lineair power distribution [#17177](https://github.com/arendst/Tasmota/issues/17177)
|
||||
- Zigbee improved Aqara plug support and completed cluster 0x0702 [#17073](https://github.com/arendst/Tasmota/issues/17073)
|
||||
- Removed leading spaces on commands ``(S)SerialSend1 to 6`` but keep on duplicate commands ``(S)SerialSend11 to 16`` [#16723](https://github.com/arendst/Tasmota/issues/16723
|
||||
- Shutter bug fixes and functionality upgrade [#17380](https://github.com/arendst/Tasmota/issues/17380
|
||||
- MQTT now uses Tasmota's DNS resolver instead of LWIP [#17387](https://github.com/arendst/Tasmota/issues/17387
|
||||
- ESP32 initial otaurl from http to https
|
||||
- ESP32 Framework (Core) from v2.0.5.3 to v2.0.6 (IPv6 support)
|
||||
- Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh
|
||||
- Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching
|
||||
- Keep webserver enabled on command ``upload``
|
||||
- Better support for virtual buttons and switches up to a total of 28
|
||||
- Increase rule event buffer from 100 to 256 characters [#16943](https://github.com/arendst/Tasmota/issues/16943)
|
||||
- Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378)
|
||||
|
||||
### Fixed
|
||||
- TasmotaSerial ``read(buffer, size)`` regression from v9.3.0
|
||||
- Serial bridge default serial configuration from 5N1 to 8N1 regression from v10.1.0.3
|
||||
- BP5758D red channel corruption regression from v12.1.1.6 [#16850](https://github.com/arendst/Tasmota/issues/16850)
|
||||
- Deduplicate code and fix %timer n% rule regression from v12.2.0 [#16914](https://github.com/arendst/Tasmota/issues/16914)
|
||||
- Serial initialization for baudrate and config [#16970](https://github.com/arendst/Tasmota/issues/16970)
|
||||
- ModbusBridge buffer overflow [#16979](https://github.com/arendst/Tasmota/issues/16979)
|
||||
- ModbusBridge baudrates over 76500 baud [#17106](https://github.com/arendst/Tasmota/issues/17106)
|
||||
- SenseAir S8 module detection [#17033](https://github.com/arendst/Tasmota/issues/17033)
|
||||
- Analog MQ exception 28 on restart [#17271](https://github.com/arendst/Tasmota/issues/17271)
|
||||
- RCSwitch exception 0/6 on some protocols [#17285](https://github.com/arendst/Tasmota/issues/17285)
|
||||
- ESP32 exception 28 when RtcNtpServer is enabled on restart [#17338](https://github.com/arendst/Tasmota/issues/17338)
|
||||
- ESP8266 zigbee exception 3 regression from v12.3.0 [#17397](https://github.com/arendst/Tasmota/issues/17397)
|
||||
|
||||
### Removed
|
||||
- Define ``USE_PN532_DATA_RAW`` from NFC reader [#16939](https://github.com/arendst/Tasmota/issues/16939)
|
||||
- Modbus transmit enable GPIO enabled once during write buffer
|
||||
- Energy dummy switched voltage and power regression from v12.2.0.2
|
||||
- Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403)
|
||||
- Shutter default tilt configuration [#17484](https://github.com/arendst/Tasmota/issues/17484)
|
||||
- Orno WE517 modbus serial config 8E1 setting [#17545](https://github.com/arendst/Tasmota/issues/17545)
|
||||
- Rename ``tasmota4M.bin`` to ``tasmota-4M.bin`` to solve use of ``tasmota-minimal.bin`` [#17674](https://github.com/arendst/Tasmota/issues/17674)
|
||||
- ESP8266 set GPIO's to input on power on fixing relay spikes [#17531](https://github.com/arendst/Tasmota/issues/17531)
|
||||
- ESP8266 TLS SNI which would prevent AWS IoT connection [#17936](https://github.com/arendst/Tasmota/issues/17936)
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./tools/logo/TASMOTA_FullLogo_Vector_White.svg">
|
||||
<img alt="Logo" src="./tools/logo/TASMOTA_FullLogo_Vector.svg" align="right" height="76">
|
||||
</picture>
|
||||
|
||||
# Templates
|
||||
|
||||
|
|
89
TEMPLATES.md
89
TEMPLATES.md
|
@ -1,8 +1,11 @@
|
|||
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./tools/logo/TASMOTA_FullLogo_Vector_White.svg">
|
||||
<img alt="Logo" src="./tools/logo/TASMOTA_FullLogo_Vector.svg" align="right" height="76">
|
||||
</picture>
|
||||
|
||||
# Templates
|
||||
|
||||
Find below the available templates as of December 2022. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates)
|
||||
Find below the available templates as of February 2023. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates)
|
||||
|
||||
## Adapter Board
|
||||
```
|
||||
|
@ -21,6 +24,7 @@ Kogan 5-Stage 3S {"NAME":"Kogan Air Purifier 3S","GPIO":[0,2272,0,23
|
|||
## Air Quality Sensor
|
||||
```
|
||||
AirGradient Pro Version DIY {"NAME":"AirGradient Pro","GPIO":[1600,1,1632,0,640,608,1,1,1664,1,1696,1,1,1],"FLAG":0,"BASE":18}
|
||||
Tuya PM Box {"NAME":"PM Box","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 99,91 | TuyaMCU 71,2 | TuyaMCU 73,3 | HumRes 1 | TempRes 1 "}
|
||||
```
|
||||
|
||||
## Aroma Diffuser
|
||||
|
@ -46,6 +50,7 @@ GL.iNet POE Ethernet {"NAME":"GL-S10 v1.0","GPIO":[32,0,0,0,0,0,0,0,321,
|
|||
|
||||
## CCT
|
||||
```
|
||||
3W KLG 320lm {"NAME":"3W_KLG","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
AICase 800lm {"NAME":"AICase Smart L","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
AiYaTo 12W {"NAME":"AiYaTo-CW","GPIO":[0,0,0,0,416,0,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Ajax Online 380lm {"NAME":"AjaxOnline","GPIO":[32,0,0,0,0,416,0,0,417,0,0,0,0,0],"FLAG":0,"BASE":38}
|
||||
|
@ -297,7 +302,7 @@ Silicognition wESP32 {"NAME":"wESP32","GPIO":[0,0,1,0,1,1,0,0,1,1,1,1,55
|
|||
TZT ESP8266 Weather Station Kit {"NAME":"TZT Weather Station","GPIO":[32,0,640,0,1,1184,0,0,1,1,608,1,1,1],"FLAG":0,"BASE":18}
|
||||
Wemos D1 Mini ESP32 {"NAME":"Wemos D1 Mini ESP32","GPIO":[0,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Wemos LOLIN32 Lite V1.0.0 (ESP32) {"NAME":"Wemos LOLIN32 Lite V1.0.0","GPIO":[1,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Wireless Tag ESP32 Ethernet {"NAME":"WT32-ETH01","GPIO":[1,1,1,1,1,1,0,0,1,0,1,1,3840,576,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1],"FLAG":0,"BASE":1}
|
||||
Wireless Tag ESP32 Ethernet {"NAME":"WT32_ETH01","GPIO":[1,1,1,1,1,1,0,0,1,0,1,1,3840,576,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1],"FLAG":0,"BASE":1}
|
||||
Witty Cloud {"NAME":"Witty Cloud","GPIO":[1,1,320,1,32,1,0,0,417,418,1,416,1,4704],"FLAG":0,"BASE":32}
|
||||
Yison ESP-01/ESP-202 {"NAME":"Yison Dev Board","GPIO":[259,544,258,1,260,261,1,1,416,418,257,417,256,1],"FLAG":0,"BASE":18}
|
||||
```
|
||||
|
@ -395,9 +400,9 @@ CE Smart Home CFW500D-3W 3 Way {"NAME":"CE-WF500D-3W","GPIO":[0,0,0,0,0,0,0,0,0
|
|||
CNSKOU Touch {"NAME":"CNSKOU Dimmer Switch","GPIO":[0,0,0,0,0,0,0,0,0,0,290,0,0,0],"FLAG":0,"BASE":54}
|
||||
Eva Logik {"NAME":"WF31 Dimmer","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
|
||||
Eva Logik 3 Way {"NAME":"EL WF31T","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
|
||||
Feit Electric Smart {"NAME":"Feit DIM/WIFI","GPIO":[1,2272,1,2304,1,1,0,0,1,0,1,0,1,0],"FLAG":0,"BASE":54}
|
||||
Feit Electric Smart {"NAME":"Feit DIM/WIFI","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
|
||||
Globe 3 Way {"NAME":"Globe Dimmer","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
|
||||
Gosund SW2 {"NAME":"Gosund Dimmer","GPIO":[1,3200,1,3232,32,0,1,1,320,576,416,1,1,0],"FLAG":0,"BASE":18}
|
||||
Gosund {"NAME":"Gosund Dimmer","GPIO":[1,3200,1,3232,32,0,1,1,320,576,416,1,1,0],"FLAG":0,"BASE":18}
|
||||
iLintek / Lumary {"NAME":"L-DS100","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
|
||||
iSwitch Touch Switch {"NAME":"iSwitchOZ Dimmer","GPIO":[0,0,0,0,0,0,0,0,0,0,290,0,0,0],"FLAG":0,"BASE":54}
|
||||
Martin Jerry SD01 {"NAME":"MJ-SD01 Dimmer","GPIO":[34,33,0,323,576,322,0,0,321,416,320,96,256,0],"FLAG":0,"BASE":73}
|
||||
|
@ -683,7 +688,7 @@ RGB 12-24V {"NAME":"WS03","GPIO":[0,0,0,0,0,0,0,0,418,417,416,
|
|||
RGB+CCT 12-24V {"NAME":"WS05","GPIO":[0,0,0,0,0,420,0,0,418,417,416,419,0,0],"FLAG":0,"BASE":18}
|
||||
RGBW 12-24V {"NAME":"*WS04","GPIO":[0,0,0,0,0,0,0,0,417,418,416,419,0,0],"FLAG":0,"BASE":18}
|
||||
Shelly RGBW2 {"NAME":"Shelly RGBW2","GPIO":[0,0,288,0,419,1,0,0,416,32,418,417,0,0],"FLAG":0,"BASE":18}
|
||||
Spectrum Smart RGBCCT {"NAME":"Spectrum Smart WOJ+05641","GPIO":[32,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Spectrum Smart RGBCCT {"NAME":"Spectrum Smart RGB CCT Controller","GPIO":[32,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
Xunata Led Controller High Voltage 110/220V {"NAME":"KL-LED-WIFI-AC","GPIO":[0,0,0,0,0,0,0,0,0,416,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
ZJ-WF-ESP-A v1.1 {"NAME":"RGB2","GPIO":[0,0,0,0,0,0,0,0,417,416,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
```
|
||||
|
@ -691,7 +696,9 @@ ZJ-WF-ESP-A v1.1 {"NAME":"RGB2","GPIO":[0,0,0,0,0,0,0,0,417,416,418,
|
|||
## LED Strip
|
||||
```
|
||||
Aldi Casalux RGB {"NAME":"DW-RGB-WI01","GPIO":[1088,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
Arlec Smart 1m CCT LED Strip Light {"NAME":"ALD155HA","GPIO":[0,0,1088,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Arlec Smart 2m LED Colour Changing Strip Light {"NAME":"Arlec_Light_Strip","GPIO":[1,1,1088,1,416,419,1,1,417,420,418,0,1,1],"FLAG":0,"BASE":18}
|
||||
Arlec Smart 5m White & Colour Changing {"NAME":"ALD556HA","GPIO":[0,0,1088,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
B.K. Licht 2m RGB {"NAME":"RGBW-Strip","GPIO":[0,0,0,0,416,32,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
BAZZ 10 ft RGBW {"NAME":"BAZZ U183MRGBWWF RGBW LED Strip","GPIO":[32,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
BlitzWolf BW-LT11 {"NAME":"BW-LT11 Strip","GPIO":[32,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -771,7 +778,7 @@ BrilliantSmart RGB Garden Kit {"NAME":"Brilliant Gard","GPIO":[0,0,0,0,416,0,0,
|
|||
Connect SmartHome CSH-FSTN12 {"NAME":"CSH-FSTN12","GPIO":[0,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
Deta 18W 1900lm T8 Tube {"NAME":"DETA Smart LED","GPIO":[0,0,0,0,0,0,0,0,0,0,416,0,0,0],"FLAG":0,"BASE":18}
|
||||
electriQ MOODL Ambiance Lamp {"NAME":"ElectriQ MOODL","GPIO":[0,4640,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Gosund Table Lamp {"NAME":"Gosund LED Light","GPIO":[0,0,0,0,0,418,0,0,417,419,0,416,0,0],"FLAG":0,"BASE":18}
|
||||
Gosund Table Lamp {"NAME":"Gosund LB3","GPIO":[0,0,0,0,0,418,0,0,417,419,0,416,0,0],"FLAG":0,"BASE":18}
|
||||
Hama Wall Light Square, 10 cm, IP 44 {"NAME":"Hama Wifi Wall Light","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,1],"FLAG":0,"BASE":18}
|
||||
Hugoai Table Lamp {"NAME":"HG02","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,20 | TuyaMCU 26,21 | TuyaMCU 21,22 | TuyaMCU 23,23 | TuyaMCU 24,24 | DimmerRange 34,1000"}
|
||||
Iwoole Table Lamp {"NAME":"GLOBELAMP","GPIO":[0,0,0,0,419,0,0,0,417,418,416,0,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -824,7 +831,7 @@ Kogan Pet Fountain {"NAME":"Pet Fountain","GPIO":[0,2272,0,2304,0,0,0,
|
|||
LED Starry Sky Projector Light {"NAME":"STAR PROJECTOR","GPIO":[0,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
Liectroux C30B Robot Vacuum {"NAME":"Liectroux C30B","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
|
||||
Mosquito Killer Lamp {"NAME":"MosquitoKiller","GPIO":[32,0,0,0,0,0,0,0,416,320,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
NEO Coolcam Mouse Trap {"NAME":"Neo Mouse Trap","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
|
||||
NEO Coolcam Mouse Trap {"NAME":"NAS-MA01W","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 51,51 | TuyaMCU 99,11"}
|
||||
PCI-e Desktop PC Remote Control {"NAME":"PC-Switch-01","GPIO":[32,0,0,0,0,0,0,0,224,544,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Petoneer Smart Dot Cat Toy {"NAME":"Petoneer Smart Dot","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
|
||||
Proscenic T21 Air Fryer {"NAME":"Proscenic T21","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
|
||||
|
@ -853,11 +860,6 @@ Sinilink MODBUS Interface {"NAME":"XY-WFPOW","GPIO":[0,8768,544,8800,32,0,0,0
|
|||
TYWE2S Replacement {"NAME":"ESP-02S","GPIO":[1,1,1,1,1,1,0,0,1,1,1,0,0,1],"FLAG":0,"BASE":18}
|
||||
```
|
||||
|
||||
## Module Switch
|
||||
```
|
||||
Moes Mini 3 Gang 1/2 Way {"NAME":"Moes MS-104C","GPIO":[0,0,0,34,32,33,0,0,224,225,226,0,0,0],"FLAG":0,"BASE":18}
|
||||
```
|
||||
|
||||
## Motion Sensor
|
||||
```
|
||||
DP-WP001 PIR {"NAME":"TUYA PIR","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
|
||||
|
@ -899,7 +901,7 @@ Dewenwils Heavy Duty 40A {"NAME":"Dewenwils HOWT01A","GPIO":[0,0,544,0,0,0,0
|
|||
ECF-SOP03 {"NAME":"Outdoor3Outlet","GPIO":[0,0,0,226,320,0,0,0,224,32,225,0,0,0],"FLAG":0,"BASE":18}
|
||||
Ecoolbuy 4 Socket IP44 {"NAME":"ECCOLBUY 4","GPIO":[0,0,0,0,225,226,0,0,224,321,32,0,227,0],"FLAG":0,"BASE":18}
|
||||
Edimax 2AC {"NAME":"EDI SP-1122WTO","GPIO":[0,0,0,0,225,576,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18}
|
||||
Emax IP44 {"NAME":"Emax Smart Socket","GPIO":[0,0,0,0,320,0,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18}
|
||||
Emax IP44 {"NAME":"Emax Smart Socket","GPIO":[0,0,0,0,320,0,0,0,224,321,32,0,0,0],"FLAG":0,"BASE":18}
|
||||
Energizer 2AC Weather Resistant {"NAME":"Energizer EOX3-1001-BLK","GPIO":[0,0,0,0,320,576,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18}
|
||||
Etekcity {"NAME":"ES015-TB","GPIO":[0,0,0,0,224,225,288,0,2656,2688,32,2592,289,0],"FLAG":0,"BASE":18}
|
||||
Feit Electric PLUG/WIFI/WP {"NAME":"Prime Smart ou","GPIO":[0,1,0,1,544,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -1053,6 +1055,7 @@ BAW {"NAME":"BAW TPSWIFI-10","GPIO":[0,0,0,0,320,0,0,0,
|
|||
Bawoo {"NAME":"Bawoo S120","GPIO":[0,0,0,0,288,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Be HiTech 16A {"NAME":"Be HiTech","GPIO":[0,0,0,288,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18}
|
||||
Bearware 303492 3AC+2USB {"NAME":"Bearware 30349","GPIO":[0,320,0,32,225,226,0,0,227,224,544,0,0,0],"FLAG":0,"BASE":18}
|
||||
Beghelli Dom-e Presa Smart IT {"NAME":"Beghelli DOM-E Smart Plug","GPIO":[32,0,0,0,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Bestek MRJ1011 {"NAME":"BestekMRJ1011","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
BlitzWolf 1200W Dual {"NAME":"BlitzWolf SHP3","GPIO":[320,0,321,0,225,2720,0,0,2624,33,2656,224,32,0],"FLAG":0,"BASE":45}
|
||||
BlitzWolf 16A Dual {"NAME":"SHP7 v2","GPIO":[33,576,320,2624,2720,2656,0,0,32,321,224,0,225,0],"FLAG":0,"BASE":45}
|
||||
|
@ -1106,6 +1109,8 @@ Coosa SP1 {"NAME":"COOSA SP1","GPIO":[321,1,320,1,0,2720,0,0,
|
|||
CooWoo {"NAME":"CooWoo AW01","GPIO":[0,0,0,0,288,160,0,0,256,0,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
CozyLife HomeKit 16A {"NAME":"CozyLife 16A","GPIO":[0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,2720,0,0,2656,576,0,224,2624,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
CrazyLynX WiFi {"NAME":"CrazyLynX","GPIO":[0,0,0,0,321,320,0,0,224,32,0,0,0,4704],"FLAG":0,"BASE":18}
|
||||
CurrySmarter 16A {"NAME":"CurrySmarter 16A","GPIO":[0,0,0,32,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
CurrySmarter 16A Power Monitoring {"NAME":"Currysmarter XH-TW2P","GPIO":[0,0,0,2624,32,320,0,0,224,2720,2656,0,0,0],"FLAG":0,"BASE":18}
|
||||
CYYLTF BIFANS J23 {"NAME":"CYYLTD BIFANS J23","GPIO":[0,0,0,0,288,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
CZ100 10A {"NAME":"ASZKJ","GPIO":[320,0,321,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
|
||||
D3D Smart Plug with USB & Power Monitor {"NAME":"D3D FLHS-ZN04","GPIO":[321,1,320,2624,1,2688,1,1,1,32,2656,224,1,1],"FLAG":0,"BASE":18}
|
||||
|
@ -1187,13 +1192,13 @@ Globe Smart {"NAME":"GlobeSmartPlug","GPIO":[0,0,0,0,320,0,0,0,
|
|||
GoldenDot Mini {"NAME":"GoldenDot Mini","GPIO":[0,32,0,0,0,0,0,0,0,321,224,0,0,0],"FLAG":0,"BASE":52}
|
||||
GoldenDot with ADC {"NAME":"W-US003-Power","GPIO":[320,0,0,0,0,0,0,0,0,32,0,224,0,4896],"FLAG":0,"BASE":18}
|
||||
Goliath 16A {"NAME":"GOLIATH AV-SSTE01","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
|
||||
Gosund {"NAME":"Gosund EP2","GPIO":[320,1,576,1,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45}
|
||||
Gosund {"NAME":"Gosund EP2","GPIO":[576,1,320,1,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45}
|
||||
Gosund {"NAME":"Gosund SP111","GPIO":[320,0,321,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18}
|
||||
Gosund {"NAME":"SHP5","GPIO":[321,3072,320,3104,1,225,0,0,1,1,224,1,32,0],"FLAG":0,"BASE":18}
|
||||
Gosund 13A {"NAME":"Gosund UP111","GPIO":[0,320,0,32,2720,2656,0,0,2624,576,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Gosund 2 in 1 {"NAME":"Gosund WP212","GPIO":[321,288,544,0,224,2720,0,0,2624,32,2656,225,33,0],"FLAG":0,"BASE":18}
|
||||
Gosund Dual {"NAME":"Gosund SP211","GPIO":[33,576,320,2624,2720,2656,0,0,32,321,224,0,225,0],"FLAG":0,"BASE":18}
|
||||
Gosund SP1 {"NAME":"Gosund SP1 v23","GPIO":[0,321,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":55}
|
||||
Gosund SP111 {"NAME":"Gosund SP111","GPIO":[320,0,321,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18}
|
||||
Gosund SP111 v1.1 {"NAME":"Gosund SP111 v1.1","GPIO":[320,0,576,0,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45}
|
||||
Gosund SP111 v1.4 {"NAME":"Gosund SP111 v1.4","GPIO":[321,1,320,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45}
|
||||
Gosund SP112 {"NAME":"Gosund 112v3.4","GPIO":[320,0,321,0,2656,2720,0,0,2624,257,224,0,0,4800],"FLAG":0,"BASE":18}
|
||||
|
@ -1224,10 +1229,12 @@ HiHome {"NAME":"HiHome WPP-10S","GPIO":[32,0,0,0,2720,2656
|
|||
HiHome {"NAME":"HIhome WPP-10S","GPIO":[320,0,576,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":49}
|
||||
HiHome {"NAME":"HiHome WPP-16T","GPIO":[32,320,1,1,2720,2656,0,0,33,1,225,2592,224,4704],"FLAG":0,"BASE":18}
|
||||
HIPER IoT P01 {"NAME":"HIPER IoT P01","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
HIPER IoT P05 {"NAME":"HIPER IoT P05","GPIO":[0,320,0,32,0,0,0,0,0,224,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
hiwild W-US002 {"NAME":"W-US002","GPIO":[0,32,0,0,0,0,0,0,0,288,224,0,576,0],"FLAG":0,"BASE":18}
|
||||
HLT-309 {"NAME":"HLT-309","GPIO":[0,0,0,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
|
||||
Hoin 10A {"NAME":"NIOH XS-SSC01","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Hombli Socket Duo {"NAME":"HombliSocketDuo","GPIO":[33,0,0,0,0,0,0,0,0,544,224,225,32,0],"FLAG":0,"BASE":18}
|
||||
Homecube {"NAME":"Homecube SP1","GPIO":[0,321,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":55}
|
||||
HomeMate 16A Heavy Duty {"NAME":"HMLPG16","GPIO":[0,288,0,32,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Houzetek {"NAME":"AWP07L","GPIO":[320,0,0,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18}
|
||||
HS108 {"NAME":"HS108","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,4704],"FLAG":0,"BASE":18}
|
||||
|
@ -1318,11 +1325,12 @@ Luminea ZX-2820 {"NAME":"ZX2820-675","GPIO":[0,0,0,32,2688,2656,0,0
|
|||
Luminea ZX-2858 {"NAME":"ZX2858-675","GPIO":[32,0,0,0,2688,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":65}
|
||||
Lunvon 2000W {"NAME":"Lunvon Smart Plug","GPIO":[32,0,0,0,0,0,288,224,0,0,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Lunvon 3000W {"NAME":"Lunvon Smart Plug","GPIO":[32,0,0,0,0,0,288,224,0,0,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Marmitek Power SI {"NAME":"Marmitek PowerSi","GPIO":[0,0,0,32,2720,0,0,0,0,288,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Martin Jerry V01 {"NAME":"MJ V01","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Martin Jerry XS-SSA01 {"NAME":"MJ_XS-SSA01","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Maxcio 16A Mini {"NAME":"MAXCIO RMC021","GPIO":[0,0,0,32,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":1}
|
||||
Maxcio W-UK007S {"NAME":"Maxcio","GPIO":[320,0,1,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45}
|
||||
Maxcio W-US002S {"NAME":"W-US002S","GPIO":[321,0,320,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45}
|
||||
Maxcio W-US002S {"NAME":"W-US002S","GPIO":[0,32,0,544,2688,2656,0,0,2592,288,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Maxcio W-US003 {"NAME":"W-US003","GPIO":[1,32,1,1,1,1,0,0,1,225,224,1,1,0],"FLAG":0,"BASE":18}
|
||||
Maxcio YX-DE02 {"NAME":"Maxcio DE02","GPIO":[0,32,0,224,320,225,0,0,416,417,418,0,0,0],"FLAG":0,"BASE":18}
|
||||
Maxcio YX-DE04 {"NAME":"Maxcio YX-DE04","GPIO":[1,32,1,224,320,419,0,0,416,417,418,1,1,4704],"FLAG":0,"BASE":18}
|
||||
|
@ -1408,6 +1416,7 @@ PrimeCables {"NAME":"CAB-LA-WF4","GPIO":[0,0,0,320,321,0,0,0,0,
|
|||
PrimeCables 2 USB Mini {"NAME":"CAB-LA-WF4-G2","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Prokord {"NAME":"PSH-WS007-EU","GPIO":[0,0,320,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45}
|
||||
Prokord 16A {"NAME":"PROKORD PSH-WS021-EU","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
|
||||
QNCX {"NAME":"QNCX","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Qnect 16A {"NAME":"Qnect QN-WP01","GPIO":[0,0,0,0,0,224,0,0,288,0,32,0,0,0],"FLAG":0,"BASE":18}
|
||||
qnect 16A {"NAME":"QNECT QN-WP01E","GPIO":[0,0,0,32,2688,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Qualitel Mini {"NAME":"Qualitel HG01WT","GPIO":[320,0,321,0,0,2688,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -1523,6 +1532,7 @@ Vettora Smart Plug {"NAME":"Vettora","GPIO":[0,0,0,32,0,0,0,0,0,320,22
|
|||
Vingo {"NAME":"Karpal-01","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Vivanco 39625 Smart Home Power Adapter {"NAME":"Vivianco","GPIO":[0,0,0,32,2688,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Vivitar {"NAME":"Vivitar HA1003","GPIO":[576,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
|
||||
Vivitar {"NAME":"Vivitar HA1004","GPIO":[576,0,0,0,0,320,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Vivitar HA-1006 {"NAME":"HA-1006","GPIO":[0,0,0,0,320,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Vivitar HA-1006-AU {"NAME":"HA-1006-AU","GPIO":[0,0,0,0,320,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Vivitar Plug {"NAME":"HA-1005N-AU","GPIO":[0,0,0,0,544,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -1541,6 +1551,7 @@ Wipro 16A {"NAME":"Wip-DSP1160","GPIO":[0,0,0,32,2720,2656,0,
|
|||
Wisdom Dual {"NAME":"ZY-ACU02","GPIO":[0,0,0,544,225,224,0,0,320,32,321,0,0,0],"FLAG":0,"BASE":18}
|
||||
WiZ 10A {"NAME":"WIZ 9290024276","GPIO":[0,0,0,0,544,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
WL-SC01 {"NAME":"WL-SC01","GPIO":[0,0,0,0,320,0,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":1}
|
||||
Woox EU {"NAME":"WOOX R6113","GPIO":[0,2624,0,320,32,289,0,0,2656,224,2720,0,0,0],"FLAG":0,"BASE":18}
|
||||
WOOX R4026 {"NAME":"WOOX R4026","GPIO":[0,0,0,32,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
WOOX R4785 {"NAME":"WOOXR4785","GPIO":[0,0,0,0,288,224,0,0,0,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
WOOX R5024 {"NAME":"WOOX5024","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -1614,7 +1625,7 @@ Calex 4AC 2USB {"NAME":"Calex Power Strip 429228","GPIO":[0,320,0,
|
|||
Calex 4AC 4USB {"NAME":"Calex Power Strip 429228","GPIO":[0,0,0,288,224,226,0,0,0,228,227,225,32,0],"FLAG":0,"BASE":18}
|
||||
CE Smart Home {"NAME":"CE Power Strip","GPIO":[288,0,0,0,227,228,0,0,225,226,224,0,32,0],"FLAG":0,"BASE":18}
|
||||
CE Smart Home Garden Stake {"NAME":"CE Power Stake","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
CRST LTS-4G-W {"NAME":"CRST LTS-4G-W","GPIO":[0,0,0,0,227,0,0,0,225,226,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
CRST LTS-4G-W {"NAME":"CRST LTS-4G-W","GPIO":[544,0,0,0,227,32,0,0,225,226,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Curv 4 Plug {"NAME":"CURV","GPIO":[0,32,0,228,0,0,1,1,227,225,226,224,0,1],"FLAG":0,"BASE":18}
|
||||
Deltaco SH-P03USB {"NAME":"Deltaco SH-P03","GPIO":[320,0,0,0,0,226,0,0,224,32,225,227,0,0],"FLAG":0,"BASE":18}
|
||||
Digma DiPlug Strip 40 {"NAME":"DiPlug Strip 40","GPIO":[1,320,1,32,225,224,1,1,226,227,260,1,1,1],"FLAG":0,"BASE":18}
|
||||
|
@ -1646,6 +1657,7 @@ Idinio 3AC 4USB {"NAME":"Idinio-140135","GPIO":[0,320,0,32,225,224,
|
|||
Jinvoo 4AC+2USB {"NAME":"JINVOO Model SM-SO306-2A","GPIO":[320,0,0,0,259,32,0,0,257,258,256,0,228,0],"FLAG":0,"BASE":18}
|
||||
KaBuM! Filtro de Linha {"NAME":"Kabum Power Strip","GPIO":[0,544,0,32,227,228,0,0,0,225,226,224,320,0],"FLAG":0,"BASE":18}
|
||||
KMC 5AC 3USB QC {"NAME":"KMC 5-Outlet","GPIO":[320,0,0,0,228,160,0,0,225,224,226,0,227,0],"FLAG":0,"BASE":18}
|
||||
KMC Smart Strip 3 {"NAME":"KMC 3-Outlet (20307)","GPIO":[0,320,0,32,0,226,0,0,224,0,225,0,0,0],"FLAG":0,"BASE":18}
|
||||
Kogan Power Strip USB Ports & Energy Meter {"NAME":"Generic","GPIO":[64,320,0,227,2720,2656,0,0,2624,225,226,224,0,0],"FLAG":0,"BASE":18}
|
||||
Konesky Type 1 {"NAME":"Konesky","GPIO":[0,0,0,0,228,225,0,0,227,32,226,224,0,0],"FLAG":0,"BASE":18}
|
||||
Koogeek KLOE4 {"NAME":"Koogeek KLOE4","GPIO":[0,320,0,32,225,224,0,0,226,227,228,0,0,4704],"FLAG":0,"BASE":18}
|
||||
|
@ -1680,7 +1692,7 @@ Surge Protector 3AC 2USB {"NAME":"C158","GPIO":[260,0,0,0,261,230,0,0,224,0,
|
|||
SWB1 {"NAME":"SWB1","GPIO":[288,0,0,0,0,227,0,0,224,32,225,226,0,0],"FLAG":0,"BASE":18}
|
||||
SWB2 3AC + 2USB {"NAME":"SWB2","GPIO":[576,1,0,1,0,226,0,0,224,32,225,227,0,0],"FLAG":0,"BASE":18}
|
||||
Swisstone 4AC 4USB {"NAME":"Swisstone SH140","GPIO":[0,576,0,32,225,224,0,0,226,227,228,0,0,0],"FLAG":0,"BASE":18}
|
||||
Sygonix 4AC {"NAME":"Sygonix SY-4538254","GPIO":[576,32,0,231,229,230,0,0,225,224,226,228,259,0],"FLAG":0,"BASE":18}
|
||||
Sygonix 4AC {"NAME":"Sygonix SY-4538254","GPIO":[544,32,0,8678,8676,8679,0,0,8672,8673,8675,8677,8706,0],"FLAG":0,"BASE":18}
|
||||
TCP Smart 4AC+USB {"NAME":"TCP WPS4WUK","GPIO":[1,320,0,32,226,227,0,0,225,224,228,0,0,1],"FLAG":0,"BASE":18}
|
||||
Teckin SS30 {"NAME":"Teckin SS30","GPIO":[288,1,1,321,256,32,0,0,258,257,259,1,228,0],"FLAG":0,"BASE":18}
|
||||
Tellur 3AC 4USB {"NAME":"Tellur","GPIO":[0,320,0,32,225,224,0,0,0,226,227,0,0,4704],"FLAG":0,"BASE":18}
|
||||
|
@ -1939,6 +1951,7 @@ cod.m WLAN Pixel Controller v0.8 {"NAME":"cod.m Pixel Controller V0.8","GPIO":[
|
|||
ESP01 NeoPixel Ring {"NAME":"ESP-01S-RGB-LED-v1.0","GPIO":[1,1,1376,1,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
H803WF 2048 Pixel 5V-24V {"NAME":"H803WF","GPIO":[0,0,0,0,3840,3840,0,0,3872,1376,0,3872,0,0],"FLAG":0,"BASE":18}
|
||||
IOTMCU {"NAME":"IOTMCU_ESP-12S-RGB-LED-v1","GPIO":[1,1,1,1,0,1376,0,0,1,1088,32,0,0,0],"FLAG":0,"BASE":18}
|
||||
LifeSmart Cololight PRO Hexagonal {"NAME":"Cololight PRO","GPIO":[0,0,0,0,32,0,0,0,0,33,0,0,1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4704,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
SP501E WS2812B {"NAME":"SP501E","GPIO":[0,32,0,1376,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
```
|
||||
|
||||
|
@ -2122,11 +2135,6 @@ Zemismart A19 10W {"NAME":"Zemism_E27_A19","GPIO":[0,0,0,0,0,0,0,0,0,
|
|||
Zilotek A19 800lm {"NAME":"Zilotek RGBW","GPIO":[0,0,0,0,2912,416,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18}
|
||||
```
|
||||
|
||||
## Relay
|
||||
```
|
||||
LilyGo T-Relay 8 {"NAME":"LilyGo ESP32 Relay 8","GPIO":[1,1,1,1,1,231,1,1,227,226,1,1,1,1,230,229,0,228,1,1,0,544,1,1,0,0,0,0,225,224,1,1,1,0,0,1],"FLAG":0,"BASE":1}
|
||||
```
|
||||
|
||||
## Relay Board
|
||||
```
|
||||
2 Channel Tuya {"NAME":"TY-DIY-S02","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1 | TuyaMCU 12,2 | TuyaMCU 13,13 | TuyaMCU 1,101"}
|
||||
|
@ -2171,8 +2179,10 @@ LC Technology 5V/8-80V 1 Channel {"NAME":"LC-Relay-ESP12-1R-MV","GPIO":[1,1,544
|
|||
LC Technology 5V/8-80V 1 Channel {"NAME":"LC-Relay-ESP12-1R-D8","GPIO":[1,1,544,1,1,224,1,1,1,1,1,1,321,1],"FLAG":0,"BASE":18}
|
||||
LC Technology AC90V-250V 1 Channel {"NAME":"ESP32_Relay_AC_X1","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,224,1,1,1,0,1,1,544,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
|
||||
LC Technology DC5-60V 1 Channel {"NAME":"ESP32_Relay_X1","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,224,1,1,1,0,1,1,544,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
|
||||
LC Technology DC5-60V 4 Channel {"NAME":"ESP32_Relay_X4","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,226,227,1,0,0,0,0,224,225,1,1,1,0,0,1],"FLAG":0,"BASE":1}
|
||||
LC Technology DC5-60V 2 Channel {"NAME":"ESP32_Relay_X2","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,544,0,225,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
LC Technology DC5-60V 4 Channel {"NAME":"ESP32_Relay_X4","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,544,0,226,227,1,0,0,0,0,224,225,1,1,1,0,0,1],"FLAG":0,"BASE":1}
|
||||
LC Technology ESP8266 5V {"NAME":"ESP8266-01S","GPIO":[224,3200,0,3232,0,0,0,0,0,0,0,0,0,4704],"FLAG":0,"BASE":18}
|
||||
LilyGo T-Relay 8 {"NAME":"LilyGo ESP32 Relay 8","GPIO":[1,1,1,1,1,231,1,1,227,226,1,1,1,1,230,229,0,228,1,1,0,544,1,1,0,0,0,0,225,224,1,1,1,0,0,1],"FLAG":0,"BASE":1}
|
||||
LilyGO TTGO 4 Channel ESP32 {"NAME":"T-Relay ESP32","GPIO":[0,0,1,0,1,227,0,0,1,1,1,1,0,0,226,225,0,224,1,1,0,544,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
|
||||
LinkNode R4 {"NAME":"LinkNode R4","GPIO":[0,0,0,0,0,0,0,0,224,225,226,0,227,0],"FLAG":0,"BASE":18}
|
||||
LinkNode R8 {"NAME":"LinkNode R8","GPIO":[0,0,0,0,228,229,0,231,226,227,225,230,224,0],"FLAG":0,"BASE":18}
|
||||
|
@ -2194,11 +2204,6 @@ Yunshan 7-30V 10A {"NAME":"Yunshan 10A","GPIO":[32,1,288,1,224,161,0,
|
|||
|
||||
## Relay Module
|
||||
```
|
||||
2 CH Smart Switch {"NAME":"Generic","GPIO":[32,1,1,1,1,225,33,1,224,288,1,1,1,1],"FLAG":0,"BASE":18}
|
||||
Aubess Power Monitor Switch 16A {"NAME":"Aubess with (BL0942)","GPIO":[0,3200,0,7520,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Mini Smart Switch {"NAME":"SmartSwitch-MK601","GPIO":[0,0,0,160,32,224,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18}
|
||||
Moes 10A {"NAME":"Moes MS-101","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Smarsecur Smart Switch {"NAME":"ESP-02S","GPIO":[0,0,0,32,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
```
|
||||
|
||||
## Sensor
|
||||
|
@ -2242,7 +2247,7 @@ AGL 2 Gang {"NAME":"AGL WiFi 02","GPIO":[0,0,544,0,0,33,0,0,22
|
|||
AGL 3 Gang {"NAME":"AGL WiFi 03","GPIO":[0,0,544,0,34,33,0,0,225,224,226,0,32,0],"FLAG":0,"BASE":18}
|
||||
Aoycocr SW1 {"NAME":"Aoycocr SW1","GPIO":[576,1,321,1,1,1,1,1,320,32,1,224,1,1],"FLAG":0,"BASE":18}
|
||||
APPIO 1 Gang Switch {"NAME":"Appio-9608","GPIO":[0,0,0,0,0,32,0,0,0,0,0,224,288,0],"FLAG":0,"BASE":18}
|
||||
Appio 3 Gang Touch {"NAME":"Appio 9611","GPIO":[0,0,0,0,226,33,0,0,32,224,34,225,288,0],"FLAG":0,"BASE":18}
|
||||
Appio 3 Gang Touch {"NAME":"Appio-9611","GPIO":[0,0,0,0,224,33,0,0,34,226,32,225,288,0],"FLAG":0,"BASE":18}
|
||||
Athom 1 Gang {"NAME":"Athom SW011EU","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1}
|
||||
Athom 1 Gang {"NAME":"Athom SW031US","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1}
|
||||
Athom 1 Gang No Neutral {"NAME":"Athom SW111EU","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1}
|
||||
|
@ -2351,6 +2356,7 @@ Kuled KS602S {"NAME":"KULED","GPIO":[32,1,1,1,1,1,0,0,224,320,1,
|
|||
Kygne CD-301 {"NAME":"KYGNE Touch","GPIO":[0,0,0,0,288,289,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":10}
|
||||
Laghten SS02S {"NAME":"Laghten SS02S","GPIO":[0,0,0,0,288,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
LCARE Modular 2 Gang {"NAME":"2SW1-In","GPIO":[32,1,1,1,0,225,33,0,224,320,0,0,0,0],"FLAG":0,"BASE":29}
|
||||
LerLink 1 Gang {"NAME":"LerLink X801","GPIO":[0,0,0,0,32,0,0,0,224,320,0,0,0,1],"FLAG":0,"BASE":18}
|
||||
LerLink 1 Gang No Neutral {"NAME":"LerLink X801-L","GPIO":[0,0,0,0,32,0,0,0,224,320,0,0,0,1],"FLAG":0,"BASE":18}
|
||||
Lerlink 2 Gang {"NAME":"Lerlink X802A","GPIO":[0,0,0,33,32,0,0,0,224,288,225,0,0,0],"FLAG":0,"BASE":18}
|
||||
LerLink 2 Gang No Neutral {"NAME":"Lonsonho 2gang","GPIO":[0,0,0,33,32,0,0,0,224,288,225,0,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -2422,6 +2428,7 @@ MoKo Scene Life {"NAME":"Moko Smart Swi","GPIO":[576,0,0,0,418,417,
|
|||
MoKo Smart Life {"NAME":"Moko Switch (Single)","GPIO":[544,0,0,32,224,0,0,0,0,0,320,0,0,0],"FLAG":0,"BASE":59}
|
||||
NaamaSmart KS602 {"NAME":"KS-602","GPIO":[32,0,0,0,0,0,0,0,224,576,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Nedis Dual {"NAME":"SM-SW102U-2","GPIO":[576,0,0,33,225,0,0,0,32,224,0,0,0,4704],"FLAG":0,"BASE":18}
|
||||
NEO Coolcam 2Ch Touch Light {"NAME":"Neo NAS-SC01W-2","GPIO":[0,0,0,0,225,0,0,0,32,224,33,0,544,0],"FLAG":0,"BASE":18}
|
||||
Nexete DS-123 {"NAME":"DS-123","GPIO":[544,321,1,32,224,33,0,0,1,225,320,1,1,0],"FLAG":0,"BASE":18}
|
||||
Nexete DS-123 Single {"NAME":"DS-123","GPIO":[544,0,1,33,0,32,0,0,1,224,320,1,1,0],"FLAG":0,"BASE":18}
|
||||
Novadigital Interruptor Touch Led 1 Boto {"NAME":"Nova Digital Switch 1 Gang","GPIO":[544,0,0,32,224,0,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -2555,6 +2562,7 @@ ZUCZUG 3 Gang {"NAME":"2ph105626a x3","GPIO":[0,288,0,32,34,33,0,
|
|||
|
||||
## Switch Module
|
||||
```
|
||||
2 CH Smart Switch {"NAME":"Generic","GPIO":[32,1,1,1,1,225,33,1,224,288,1,1,1,1],"FLAG":0,"BASE":18}
|
||||
AGL Modulo Relay 01 Canal {"NAME":"AGL-Basic","GPIO":[0,1,0,0,224,32,0,0,0,0,320,0,0,0],"FLAG":0,"BASE":18}
|
||||
Albohes 2 Channel {"NAME":"Albohes SH-08","GPIO":[0,3200,33,3232,321,320,0,0,224,544,32,0,225,1],"FLAG":0,"BASE":18}
|
||||
Athom 10A {"NAME":"CB01-TAS-1","GPIO":[0,0,0,32,320,0,0,0,0,224,0,0,0,1],"FLAG":0,"BASE":18}
|
||||
|
@ -2563,6 +2571,7 @@ Athom 3-Way Mini Relay {"NAME":"RS01-TAS-1","GPIO":[0,0,0,32,576,0,0,0,0,2
|
|||
Athom 4Ch Inching/Self-locking 10A {"NAME":"Athom R04","GPIO":[1,1,1,1,32,576,1,1,226,227,225,1,224,0],"FLAG":0,"BASE":18}
|
||||
Athom 4Ch Inching/Self-locking 30A {"NAME":"Athom R04-30A","GPIO":[1,1,1,1,32,576,1,1,226,227,225,1,224,0],"FLAG":0,"BASE":18}
|
||||
ATMS1601 230VAC DIN Timer/Switch {"NAME":"ATMS1601","GPIO":[1,1,1,1,544,320,1,1,224,32,1,1,1,1],"FLAG":0,"BASE":18}
|
||||
Aubess Power Monitor Switch 16A {"NAME":"Aubess with (BL0942)","GPIO":[0,3200,0,7520,0,0,0,0,160,0,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
BH OnOfre Dual Rev5 Silent Edition {"NAME":"bhonofre","GPIO":[0,0,0,0,225,224,0,0,160,161,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
BlitzWolf BW-SS1 {"NAME":"BW-SS1","GPIO":[1,1,1,1,544,224,0,0,1,32,1,1,0,0],"FLAG":0,"BASE":18}
|
||||
BlitzWolf BW-SS5 1 Gang {"NAME":"BlitzWolf SS5 1 Gang","GPIO":[0,0,0,0,288,0,0,0,160,224,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -2589,8 +2598,12 @@ LoraTap 10A {"NAME":"LoraTap RR400W","GPIO":[0,0,0,0,544,0,0,0,
|
|||
LoraTap RR500W {"NAME":"LoraTap RR500W","GPIO":[544,0,0,0,160,0,0,0,32,224,0,0,320,0],"FLAG":0,"BASE":18}
|
||||
LoveAnna AC85-250V 10A {"NAME":"2xSwitch No RF LoveAnna","GPIO":[32,0,0,0,0,225,33,0,224,320,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Luani HVIO {"NAME":"Luani HVIO","GPIO":[0,1,1,1,224,225,0,0,160,161,1,288,0,4704],"FLAG":0,"BASE":35}
|
||||
Luminea {"NAME":"Luminea NX-4651","GPIO":[0,0,0,0,288,0,0,0,160,224,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Milfra Smart {"NAME":"Milfra Smart Module TB41","GPIO":[576,0,0,225,2688,2656,0,0,2592,193,480,224,192,0],"FLAG":0,"BASE":18}
|
||||
Mini Smart Switch {"NAME":"SmartSwitch-MK601","GPIO":[0,0,0,160,32,224,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18}
|
||||
Moes {"NAME":"Moes MS-104B","GPIO":[0,0,32,0,480,0,0,0,161,160,224,225,0,0],"FLAG":0,"BASE":18}
|
||||
Moes 10A {"NAME":"Moes MS-101","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Moes Mini 3 Gang 1/2 Way {"NAME":"Moes MS-104C","GPIO":[0,0,0,34,32,33,0,0,224,225,226,0,0,0],"FLAG":0,"BASE":18}
|
||||
Nedis 10A {"NAME":"Nedis WIFIPS10WT","GPIO":[0,0,0,0,224,0,0,0,32,321,0,288,0,0],"FLAG":0,"BASE":18}
|
||||
Nova Digital Basic 1 MS101 {"NAME":"NovaDigBasic1","GPIO":[0,1,0,1,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
PPA Contatto Wi-Fi {"NAME":"PPA Contatto","GPIO":[0,0,32,0,224,162,0,0,288,225,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -2605,11 +2618,12 @@ Shelly 2 {"NAME":"Shelly 2","GPIO":[0,2752,0,2784,224,225,0,
|
|||
Shelly 2.5 {"NAME":"Shelly 2.5","GPIO":[320,0,0,0,224,193,0,0,640,192,608,225,3456,4736],"FLAG":0,"BASE":18}
|
||||
Shelly EM {"NAME":"Shelly EM","GPIO":[0,0,0,0,0,0,0,0,640,3457,608,224,8832,1],"FLAG":0,"BASE":18}
|
||||
Shelly i3 Action and Scenes Activation Device {"NAME":"Shelly i3","GPIO":[0,0,0,0,0,320,0,0,193,194,192,0,0,4736],"FLAG":0,"BASE":18}
|
||||
Shelly Plus 1 {"NAME":"Shelly Plus 1 ","GPIO":[0,0,0,0,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Shelly Plus 1 {"NAME":"Shelly Plus 1 ","GPIO":[288,0,0,0,192,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,32,224,0,0,0,0,0,4736,4705,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Shelly Plus 1PM {"NAME":"Shelly Plus 1PM","GPIO":[0,0,0,0,192,2720,0,0,0,0,0,0,0,0,2656,0,0,0,0,2624,0,32,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Shelly Plus 2PM {"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,32,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3456,0,0,0,0,0,0,0,4736,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"}
|
||||
Shelly Plus 2PM {"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,34,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3458,0,0,0,0,0,9472,0,4736,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Shelly Plus i4 {"NAME":"Shelly Plus i4","GPIO":[0,0,0,0,0,0,0,0,192,0,193,0,0,0,0,0,0,0,0,0,0,0,195,194,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"SwitchMode1 1 | SwitchMode2 1 | SwitchMode3 1 | SwitchMode4 1 | SwitchTopic 0 | SetOption114 1"}
|
||||
Sinilink USB {"NAME":"XY-WFUSB","GPIO":[1,1,0,1,32,224,0,0,0,0,320,0,544,0],"FLAG":0,"BASE":18}
|
||||
Smarsecur Smart Switch {"NAME":"ESP-02S","GPIO":[0,0,0,32,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18}
|
||||
Smart Home SS-8839-01 {"NAME":"SS-8839-01","GPIO":[0,1,0,1,224,0,0,0,32,321,0,320,0,0],"FLAG":0,"BASE":18}
|
||||
Sonoff 4CH (R2) {"NAME":"Sonoff 4CH","GPIO":[32,1,1,1,226,225,33,34,224,320,35,227,0,0],"FLAG":0,"BASE":7}
|
||||
Sonoff 4CH Pro (R2) {"NAME":"Sonoff 4CH Pro","GPIO":[32,1,1,1,226,225,33,34,224,320,35,227,0,0],"FLAG":0,"BASE":23}
|
||||
|
@ -2624,6 +2638,7 @@ Sonoff Dual R3 {"NAME":"Sonoff Dual R3","GPIO":[32,0,0,0,0,0,0,0,0
|
|||
Sonoff Dual R3 Lite {"NAME":"Sonoff Dual R3 Lite","GPIO":[32,0,0,0,0,0,0,0,0,576,225,0,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,160,161,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Sonoff Dual R3 v2 {"NAME":"Sonoff Dual R3 v2","GPIO":[32,0,0,0,0,0,0,0,0,576,225,0,0,0,0,0,0,0,0,0,0,3200,8128,224,0,0,0,0,160,161,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Sonoff Mini {"NAME":"Sonoff Mini","GPIO":[32,0,0,0,160,0,0,0,224,320,0,0,1,0],"FLAG":0,"BASE":1}
|
||||
Sonoff Mini Extreme {"NAME":"Sonoff MINIR4","GPIO":[32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,576,0,0,0,0,0,0,224,160,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Sonoff Mini R2 {"NAME":"Sonoff MINIR2","GPIO":[32,0,0,0,160,0,0,0,224,544,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Sonoff Pow {"NAME":"Sonoff Pow","GPIO":[32,0,0,0,0,2592,0,0,224,2656,2688,288,0,0],"FLAG":0,"BASE":6}
|
||||
Sonoff POW Elite 16A {"NAME":"Sonoff POWR316D","GPIO":[32,0,0,0,0,576,0,0,0,224,9280,0,3104,0,320,0,0,0,0,0,0,9184,9248,9216,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
|
@ -2644,6 +2659,7 @@ SUPLA inCan by Espablo {"NAME":"Supla Espablo","GPIO":[0,1,1312,1,32,224,0
|
|||
SW-R03 {"NAME":"SW-R03","GPIO":[0,0,0,0,0,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Switch Module 2x5A {"NAME":"QS-WIFI-S04-2C","GPIO":[1,1,32,1,480,0,0,0,161,160,224,225,0,0],"FLAG":0,"BASE":18}
|
||||
Syrotech {"NAME":"Syrotech SY-LS80","GPIO":[0,0,0,0,224,32,0,0,0,320,320,0,0,0],"FLAG":0,"BASE":18}
|
||||
Tinxy 1 Node 16A for AC/Geyser {"NAME":"Tnxy16A","GPIO":[32,0,0,0,160,224,0,0,288,0,416,0,0,0],"FLAG":0,"BASE":18}
|
||||
Tinxy Single Node 7A {"NAME":"Tnxy07A","GPIO":[32,0,0,0,160,224,0,0,288,0,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
WL-SW01_10 {"NAME":"WL-SW01_10","GPIO":[32,3232,0,3200,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
Woox Integrational Switch {"NAME":"WOOXR4967","GPIO":[0,0,0,1,320,224,0,0,0,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
|
@ -2664,7 +2680,7 @@ Shelly Add-on {"NAME":"Shelly 1 Temp ","GPIO":[1344,0,0,1312,224,
|
|||
```
|
||||
Floor Heating or Water/Gas Boiler {"NAME":"ME81H Thermostat","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
|
||||
Lytko 101 {"NAME":"Lytko 101","GPIO":[1,7584,1312,1,1792,1824,0,0,1,1,1,224,1,4736],"FLAG":0,"BASE":18}
|
||||
Moes Floor Heating or Water/Gas Boiler Wall {"NAME":"WHT-HY609-GB-WH-MS","GPIO":[0,2304,0,2272,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
|
||||
Moes Floor Heating or Water/Gas Boiler Wall {"NAME":"WHT-HY609-GB-WH-MS","GPIO":[0,2304,0,2272,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"tuyamcu 11,1 | tuyamcu 71,3 | tuyamcu 72,2 | tuyamcu 12,102"}
|
||||
Mysa V1 Electric Baseboard Heater {"NAME":"Mysa Thermostat","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,640,608,0,0,0,0,0,0],"FLAG":0,"BASE":1}
|
||||
```
|
||||
|
||||
|
@ -2695,15 +2711,16 @@ CE Smart Home LQ-2-W3 {"NAME":"LITESUN","GPIO":[0,0,0,0,544,32,0,0,224,0,
|
|||
DETA Double GPO + USB {"NAME":"DETA 6920HA","GPIO":[0,0,0,3104,32,288,0,0,33,224,225,0,0,0],"FLAG":0,"BASE":18}
|
||||
Deta Double Power Point {"NAME":"DETA 2G GPO","GPIO":[0,0,0,0,544,0,0,0,65,224,225,0,64,0],"FLAG":0,"BASE":18}
|
||||
DETA Outdoor Double Powerpoint {"NAME":"DETA 6294HA","GPIO":[0,0,0,3104,32,288,0,0,33,224,225,0,0,0],"FLAG":0,"BASE":18}
|
||||
Deta Single Power Point {"NAME":"DETA 2G GPO USB","GPIO":[0,0,0,2720,64,576,0,0,65,224,225,0,0,0],"FLAG":0,"BASE":18}
|
||||
Deta Single Power Point {"NAME":"DETA 1G GPO","GPIO":[0,0,0,3104,64,576,0,0,0,224,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Ener-J 13A Twin Wall Sockets with USB {"NAME":"Ener-J 2-Gang ","GPIO":[32,0,0,0,0,224,33,0,225,320,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Gosund {"NAME":"Gosund WO1","GPIO":[320,0,576,0,2656,2720,0,0,2624,321,225,224,0,4704],"FLAG":0,"BASE":18}
|
||||
Gosund USB Charger {"NAME":"Gosund WO2","GPIO":[320,0,576,0,0,257,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
|
||||
Hevolta Glasense {"NAME":"Hevolta Socket","GPIO":[0,0,0,0,288,289,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Kapok T16 {"NAME":"tiltech-t16","GPIO":[0,320,0,32,192,0,0,0,224,225,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Kesen KS-604 {"NAME":"KS-604","GPIO":[1,1,288,1,1,33,0,0,225,224,1,1,32,0],"FLAG":0,"BASE":18}
|
||||
Kesen KS-604S {"NAME":"KS-604S","GPIO":[1,1,258,1,1,33,0,0,225,224,1,1,32,4704],"FLAG":0,"BASE":18}
|
||||
Keygma KS-15TW {"NAME":"Keygma KS-15T","GPIO":[0,0,0,0,0,320,0,0,224,160,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
Knightsbridge Dual Waterproof {"NAME":"Knightsbridge Dual Socket","GPIO":[321,544,320,544,225,0,0,0,0,33,0,224,32,0],"FLAG":0,"BASE":18}
|
||||
Knightsbridge Dual Waterproof {"NAME":"Knightsbridge Dual Socket","GPIO":[321,544,320,544,225,2720,0,0,2624,33,2656,224,32,0],"FLAG":0,"BASE":18}
|
||||
KS-621 {"NAME":"KS-621","GPIO":[32,0,0,0,2688,2656,0,0,2592,288,0,224,65,1],"FLAG":0,"BASE":18}
|
||||
Makegood MG-AUWF01 {"NAME":"MG-AUWF01","GPIO":[320,161,544,323,2720,2656,0,0,2624,225,321,224,160,0],"FLAG":0,"BASE":18}
|
||||
Makegood MG-UKWSG01 {"NAME":"Aseer 2-Gang","GPIO":[321,160,544,323,2720,2656,0,0,2624,224,320,225,161,0],"FLAG":0,"BASE":18}
|
||||
|
|
|
@ -42,7 +42,7 @@ $target_file = "tasmota/".$image;
|
|||
$hostname = $_SERVER['SERVER_NAME'];
|
||||
|
||||
if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
|
||||
if (strpos($target_file, "tasmota32")) {
|
||||
if (strpos($target_file, "tasmota32") | strpos($target_file, ".gz")) {
|
||||
echo "The file $image has been uploaded to OTA server $hostname. \n";
|
||||
} else {
|
||||
gzCompressFile($target_file);
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
name=DnsClient
|
||||
version=1.0
|
||||
author=MCQN Ltd, Theo Arends
|
||||
maintainer=Theo
|
||||
sentence=Dns client allowing timeout selection.
|
||||
paragraph=This class uses WifiUdp.
|
||||
architectures=esp8266,esp32
|
|
@ -1,334 +0,0 @@
|
|||
/*
|
||||
DnsClient.cpp - DNS client for Arduino
|
||||
|
||||
SPDX-FileCopyrightText: 2009-2010 MCQN Ltd. and Theo Arends
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
// Arduino DNS client for WizNet5100-based Ethernet shield
|
||||
// (c) Copyright 2009-2010 MCQN Ltd.
|
||||
// Released under Apache License, version 2.0
|
||||
|
||||
#include "DnsClient.h"
|
||||
|
||||
// Various flags and header field values for a DNS message
|
||||
#define UDP_HEADER_SIZE 8
|
||||
#define DNS_HEADER_SIZE 12
|
||||
#define TTL_SIZE 4
|
||||
#define QUERY_FLAG (0)
|
||||
#define RESPONSE_FLAG (1<<15)
|
||||
#define QUERY_RESPONSE_MASK (1<<15)
|
||||
#define OPCODE_STANDARD_QUERY (0)
|
||||
#define OPCODE_INVERSE_QUERY (1<<11)
|
||||
#define OPCODE_STATUS_REQUEST (2<<11)
|
||||
#define OPCODE_MASK (15<<11)
|
||||
#define AUTHORITATIVE_FLAG (1<<10)
|
||||
#define TRUNCATION_FLAG (1<<9)
|
||||
#define RECURSION_DESIRED_FLAG (1<<8)
|
||||
#define RECURSION_AVAILABLE_FLAG (1<<7)
|
||||
#define RESP_NO_ERROR (0)
|
||||
#define RESP_FORMAT_ERROR (1)
|
||||
#define RESP_SERVER_FAILURE (2)
|
||||
#define RESP_NAME_ERROR (3)
|
||||
#define RESP_NOT_IMPLEMENTED (4)
|
||||
#define RESP_REFUSED (5)
|
||||
#define RESP_MASK (15)
|
||||
#define TYPE_A (0x0001)
|
||||
#define CLASS_IN (0x0001)
|
||||
#define LABEL_COMPRESSION_MASK (0xC0)
|
||||
// Port number that DNS servers listen on
|
||||
#define DNS_PORT 53
|
||||
|
||||
// Possible return codes from ProcessResponse
|
||||
#define SUCCESS 1
|
||||
#define TIMED_OUT -1
|
||||
#define INVALID_SERVER -2
|
||||
#define TRUNCATED -3
|
||||
#define INVALID_RESPONSE -4
|
||||
|
||||
#ifndef htons
|
||||
#define htons(x) ( ((x)<< 8 & 0xFF00) | ((x)>> 8 & 0x00FF) )
|
||||
#endif
|
||||
|
||||
void DNSClient::begin(const IPAddress& aDNSServer) {
|
||||
iDNSServer = aDNSServer;
|
||||
iRequestId = 0;
|
||||
}
|
||||
|
||||
void DNSClient::setTimeout(uint32_t aTimeout) {
|
||||
iTimeout = aTimeout;
|
||||
}
|
||||
|
||||
int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) {
|
||||
// See if it's a numeric IP address
|
||||
if (aResult.fromString(aHostname)) {
|
||||
// It is, our work here is done
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
// Check we've got a valid DNS server to use
|
||||
if ((0xFFFFFFFF == (uint32_t)iDNSServer) || (0 == (uint32_t)iDNSServer)) {
|
||||
return INVALID_SERVER;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
// Find a socket to use
|
||||
if (iUdp.begin(1024+(millis() & 0xF)) == 1) {
|
||||
// Try up to three times
|
||||
int retries = 0;
|
||||
// while ((retries < 3) && (ret <= 0)) {
|
||||
// Send DNS request
|
||||
ret = iUdp.beginPacket(iDNSServer, DNS_PORT);
|
||||
if (ret != 0) {
|
||||
// Now output the request data
|
||||
ret = BuildRequest(aHostname);
|
||||
if (ret != 0) {
|
||||
// And finally send the request
|
||||
ret = iUdp.endPacket();
|
||||
if (ret != 0) {
|
||||
// Now wait for a response
|
||||
int wait_retries = 0;
|
||||
ret = TIMED_OUT;
|
||||
while ((wait_retries < 3) && (ret == TIMED_OUT)) {
|
||||
ret = ProcessResponse(iTimeout, aResult);
|
||||
wait_retries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
retries++;
|
||||
// }
|
||||
// We're done with the socket now
|
||||
iUdp.stop();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DNSClient::BuildRequest(const char* aName) {
|
||||
// Build header
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | ID |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | QDCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | ANCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | NSCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | ARCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// As we only support one request at a time at present, we can simplify
|
||||
// some of this header
|
||||
iRequestId = millis(); // generate a random ID
|
||||
uint16_t twoByteBuffer;
|
||||
|
||||
// FIXME We should also check that there's enough space available to write to, rather
|
||||
// FIXME than assume there's enough space (as the code does at present)
|
||||
iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId));
|
||||
|
||||
twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG);
|
||||
iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
|
||||
|
||||
twoByteBuffer = htons(1); // One question record
|
||||
iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
|
||||
|
||||
twoByteBuffer = 0; // Zero answer records
|
||||
iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
|
||||
|
||||
iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
|
||||
// and zero additional records
|
||||
iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
|
||||
|
||||
// Build question
|
||||
const char* start =aName;
|
||||
const char* end =start;
|
||||
uint8_t len;
|
||||
// Run through the name being requested
|
||||
while (*end) {
|
||||
// Find out how long this section of the name is
|
||||
end = start;
|
||||
while (*end && (*end != '.') ) {
|
||||
end++;
|
||||
}
|
||||
|
||||
if (end-start > 0) {
|
||||
// Write out the size of this section
|
||||
len = end-start;
|
||||
iUdp.write(&len, sizeof(len));
|
||||
// And then write out the section
|
||||
iUdp.write((uint8_t*)start, end-start);
|
||||
}
|
||||
start = end+1;
|
||||
}
|
||||
|
||||
// We've got to the end of the question name, so terminate it with a zero-length section
|
||||
len = 0;
|
||||
iUdp.write(&len, sizeof(len));
|
||||
// Finally the type and class of question
|
||||
twoByteBuffer = htons(TYPE_A);
|
||||
iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
|
||||
|
||||
twoByteBuffer = htons(CLASS_IN); // Internet class of question
|
||||
iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
|
||||
// Success! Everything buffered okay
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int DNSClient::ProcessResponse(uint32_t aTimeout, IPAddress& aAddress) {
|
||||
uint32_t startTime = millis();
|
||||
|
||||
// Wait for a response packet
|
||||
while(iUdp.parsePacket() <= 0) {
|
||||
if ((millis() - startTime) > aTimeout) {
|
||||
return TIMED_OUT;
|
||||
}
|
||||
delay(20);
|
||||
}
|
||||
|
||||
// We've had a reply!
|
||||
// Read the UDP header
|
||||
uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header
|
||||
// Check that it's a response from the right server and the right port
|
||||
if ( (iDNSServer != iUdp.remoteIP()) || (iUdp.remotePort() != DNS_PORT) ) {
|
||||
// It's not from who we expected
|
||||
return INVALID_SERVER;
|
||||
}
|
||||
|
||||
// Read through the rest of the response
|
||||
if (iUdp.available() < DNS_HEADER_SIZE) {
|
||||
return TRUNCATED;
|
||||
}
|
||||
iUdp.read(header, DNS_HEADER_SIZE);
|
||||
|
||||
uint16_t staging; // Staging used to avoid type-punning warnings
|
||||
memcpy(&staging, &header[2], sizeof(uint16_t));
|
||||
uint16_t header_flags = htons(staging);
|
||||
memcpy(&staging, &header[0], sizeof(uint16_t));
|
||||
// Check that it's a response to this request
|
||||
if ( (iRequestId != staging) || ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) ) {
|
||||
// Mark the entire packet as read
|
||||
iUdp.flush();
|
||||
return INVALID_RESPONSE;
|
||||
}
|
||||
// Check for any errors in the response (or in our request)
|
||||
// although we don't do anything to get round these
|
||||
if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) {
|
||||
// Mark the entire packet as read
|
||||
iUdp.flush();
|
||||
return -5; // INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// And make sure we've got (at least) one answer
|
||||
memcpy(&staging, &header[6], sizeof(uint16_t));
|
||||
uint16_t answerCount = htons(staging);
|
||||
if (answerCount == 0 ) {
|
||||
// Mark the entire packet as read
|
||||
iUdp.flush();
|
||||
return -6; // INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// Skip over any questions
|
||||
memcpy(&staging, &header[4], sizeof(uint16_t));
|
||||
for (uint32_t i = 0; i < htons(staging); i++) {
|
||||
// Skip over the name
|
||||
uint8_t len;
|
||||
do {
|
||||
iUdp.read(&len, sizeof(len));
|
||||
if (len > 0) {
|
||||
// Don't need to actually read the data out for the string, just
|
||||
// advance ptr to beyond it
|
||||
while(len--) {
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
}
|
||||
}
|
||||
} while (len != 0);
|
||||
|
||||
// Now jump over the type and class
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
}
|
||||
}
|
||||
|
||||
// Now we're up to the bit we're interested in, the answer
|
||||
// There might be more than one answer (although we'll just use the first
|
||||
// type A answer) and some authority and additional resource records but
|
||||
// we're going to ignore all of them.
|
||||
|
||||
for (uint32_t i = 0; i < answerCount; i++) {
|
||||
// Skip the name
|
||||
uint8_t len;
|
||||
do {
|
||||
iUdp.read(&len, sizeof(len));
|
||||
if ((len & LABEL_COMPRESSION_MASK) == 0) {
|
||||
// It's just a normal label
|
||||
if (len > 0) {
|
||||
// And it's got a length
|
||||
// Don't need to actually read the data out for the string,
|
||||
// just advance ptr to beyond it
|
||||
while(len--) {
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This is a pointer to a somewhere else in the message for the
|
||||
// rest of the name. We don't care about the name, and RFC1035
|
||||
// says that a name is either a sequence of labels ended with a
|
||||
// 0 length octet or a pointer or a sequence of labels ending in
|
||||
// a pointer. Either way, when we get here we're at the end of
|
||||
// the name
|
||||
// Skip over the pointer
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
// And set len so that we drop out of the name loop
|
||||
len = 0;
|
||||
}
|
||||
} while (len != 0);
|
||||
|
||||
// Check the type and class
|
||||
uint16_t answerType;
|
||||
uint16_t answerClass;
|
||||
iUdp.read((uint8_t*)&answerType, sizeof(answerType));
|
||||
iUdp.read((uint8_t*)&answerClass, sizeof(answerClass));
|
||||
|
||||
// Ignore the Time-To-Live as we don't do any caching
|
||||
for (uint32_t i = 0; i < TTL_SIZE; i++) {
|
||||
iUdp.read(); // We don't care about the returned byte
|
||||
}
|
||||
|
||||
// And read out the length of this answer
|
||||
// Don't need header_flags anymore, so we can reuse it here
|
||||
iUdp.read((uint8_t*)&header_flags, sizeof(header_flags));
|
||||
|
||||
if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) {
|
||||
if (htons(header_flags) != 4) {
|
||||
// It's a weird size
|
||||
// Mark the entire packet as read
|
||||
iUdp.flush();
|
||||
return -9; // INVALID_RESPONSE;
|
||||
}
|
||||
iUdp.read(aAddress.raw_address(), 4);
|
||||
// uint32_t address;
|
||||
// iUdp.read((uint8_t*)&address, sizeof(address));
|
||||
// aAddress = (IPAddress)address;
|
||||
|
||||
// Check we've got a valid address
|
||||
if ((0xFFFFFFFF != (uint32_t)aAddress) && (0 != (uint32_t)aAddress)) {
|
||||
return SUCCESS;
|
||||
}
|
||||
} else {
|
||||
// This isn't an answer type we're after, move onto the next one
|
||||
for (uint32_t i = 0; i < htons(header_flags); i++) {
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the entire packet as read
|
||||
iUdp.flush();
|
||||
|
||||
// If we get here then we haven't found an answer
|
||||
return -10; // INVALID_RESPONSE;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
DnsClient.h - DNS client for Arduino
|
||||
|
||||
SPDX-FileCopyrightText: 2009-2010 MCQN Ltd. and Theo Arends
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
// Arduino DNS client for WizNet5100-based Ethernet shield
|
||||
// (c) Copyright 2009-2010 MCQN Ltd.
|
||||
// Released under Apache License, version 2.0
|
||||
|
||||
#ifndef DNSClient_h
|
||||
#define DNSClient_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <IPAddress.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
class DNSClient {
|
||||
public:
|
||||
void begin(const IPAddress& aDNSServer);
|
||||
void setTimeout(uint32_t aTimeout = 1000);
|
||||
|
||||
/* Resolve the given hostname to an IP address.
|
||||
@param aHostname Name to be resolved
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@result 1 if aIPAddrString was successfully converted to an IP address, else error code
|
||||
*/
|
||||
int getHostByName(const char* aHostname, IPAddress& aResult);
|
||||
|
||||
protected:
|
||||
int BuildRequest(const char* aName);
|
||||
int ProcessResponse(uint32_t aTimeout, IPAddress& aAddress);
|
||||
|
||||
IPAddress iDNSServer;
|
||||
uint16_t iRequestId;
|
||||
uint16_t iTimeout = 1000;
|
||||
WiFiUDP iUdp;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -46,7 +46,6 @@ static uint32_t tasmota_serial_uart_bitmap = 0; // Assigned UARTs
|
|||
|
||||
TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback, int nwmode, int buffer_size) {
|
||||
m_valid = false;
|
||||
m_tx_enable_valid = false;
|
||||
m_hardserial = false;
|
||||
m_hardswap = false;
|
||||
m_overflow = false;
|
||||
|
@ -56,6 +55,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
|
|||
serial_buffer_size = buffer_size;
|
||||
m_rx_pin = receive_pin;
|
||||
m_tx_pin = transmit_pin;
|
||||
m_tx_enable_pin = -1;
|
||||
m_in_pos = 0;
|
||||
m_out_pos = 0;
|
||||
#ifdef ESP8266
|
||||
|
@ -134,12 +134,9 @@ bool TasmotaSerial::isValidGPIOpin(int pin) {
|
|||
|
||||
void TasmotaSerial::setTransmitEnablePin(int tx_enable_pin) {
|
||||
if ((tx_enable_pin > -1) && isValidGPIOpin(tx_enable_pin)) {
|
||||
m_tx_enable_valid = true;
|
||||
m_tx_enable_pin = tx_enable_pin;
|
||||
pinMode(m_tx_enable_pin, OUTPUT);
|
||||
digitalWrite(m_tx_enable_pin, LOW);
|
||||
} else {
|
||||
m_tx_enable_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,7 +422,7 @@ void IRAM_ATTR TasmotaSerial::_fast_write(uint8_t b) {
|
|||
size_t TasmotaSerial::write(uint8_t b) {
|
||||
if (!m_hardserial && (-1 == m_tx_pin)) { return 0; }
|
||||
|
||||
if (m_tx_enable_valid) {
|
||||
if (m_tx_enable_pin > -1) {
|
||||
digitalWrite(m_tx_enable_pin, HIGH);
|
||||
}
|
||||
size_t size = 0;
|
||||
|
@ -462,8 +459,7 @@ size_t TasmotaSerial::write(uint8_t b) {
|
|||
}
|
||||
size = 1;
|
||||
}
|
||||
if (m_tx_enable_valid) {
|
||||
delay(1);
|
||||
if (m_tx_enable_pin > -1) {
|
||||
digitalWrite(m_tx_enable_pin, LOW);
|
||||
}
|
||||
return size;
|
||||
|
|
|
@ -95,7 +95,6 @@ class TasmotaSerial : public Stream {
|
|||
uint32_t m_out_pos;
|
||||
uint32_t serial_buffer_size = TM_SERIAL_BUFFER_SIZE;
|
||||
bool m_valid;
|
||||
bool m_tx_enable_valid;
|
||||
bool m_nwmode;
|
||||
bool m_hardserial;
|
||||
bool m_hardswap;
|
||||
|
|
|
@ -27,9 +27,15 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D
|
|||
|
||||
//#define TASMOTAMODBUSDEBUG
|
||||
|
||||
#define TASMOTA_MODBUS_TX_ENABLE // Use local Tx enable on write buffer
|
||||
|
||||
TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin, int tx_enable_pin) : TasmotaSerial(receive_pin, transmit_pin, 2)
|
||||
{
|
||||
setTransmitEnablePin(tx_enable_pin);
|
||||
#ifdef TASMOTA_MODBUS_TX_ENABLE
|
||||
mb_tx_enable_pin = tx_enable_pin; // Use local Tx enable on write buffer
|
||||
#else
|
||||
setTransmitEnablePin(tx_enable_pin); // Use TasmotaSerial Tx enable on write byte
|
||||
#endif // TASMOTA_MODBUS_TX_ENABLE
|
||||
mb_address = 0;
|
||||
}
|
||||
|
||||
|
@ -58,6 +64,12 @@ int TasmotaModbus::Begin(long speed, uint32_t config)
|
|||
if (begin(speed, config)) {
|
||||
result = 1;
|
||||
if (hardwareSerial()) { result = 2; }
|
||||
#ifdef TASMOTA_MODBUS_TX_ENABLE
|
||||
if (mb_tx_enable_pin > -1) {
|
||||
pinMode(mb_tx_enable_pin, OUTPUT);
|
||||
digitalWrite(mb_tx_enable_pin, LOW);
|
||||
}
|
||||
#endif // TASMOTA_MODBUS_TX_ENABLE
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -143,14 +155,25 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
|
|||
buf = (uint8_t *)malloc(bufsize);
|
||||
memset(buf, 0, bufsize);
|
||||
uint16_t i;
|
||||
for (i = 0; i < framepointer;i++)
|
||||
for (i = 0; i < framepointer;i++) {
|
||||
snprintf((char *)&buf[i*3], (bufsize-i*3), "%02X ",frame[i]);
|
||||
}
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: %s"), buf);
|
||||
free(buf);
|
||||
#endif
|
||||
|
||||
flush();
|
||||
#ifdef TASMOTA_MODBUS_TX_ENABLE
|
||||
if (mb_tx_enable_pin > -1) {
|
||||
digitalWrite(mb_tx_enable_pin, HIGH);
|
||||
}
|
||||
#endif // TASMOTA_MODBUS_TX_ENABLE
|
||||
write(frame, framepointer);
|
||||
#ifdef TASMOTA_MODBUS_TX_ENABLE
|
||||
if (mb_tx_enable_pin > -1) {
|
||||
digitalWrite(mb_tx_enable_pin, LOW);
|
||||
}
|
||||
#endif // TASMOTA_MODBUS_TX_ENABLE
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ class TasmotaModbus : public TasmotaSerial {
|
|||
uint8_t ReceiveCount(void) { return mb_len; }
|
||||
|
||||
private:
|
||||
int mb_tx_enable_pin;
|
||||
uint8_t mb_address;
|
||||
uint8_t mb_len;
|
||||
};
|
||||
|
|
|
@ -86,6 +86,10 @@ void Renderer::Begin(int16_t p1,int16_t p2,int16_t p3) {
|
|||
|
||||
}
|
||||
|
||||
void Renderer::Sleep(void) {
|
||||
|
||||
}
|
||||
|
||||
void Renderer::Updateframe() {
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ typedef struct LVGL_PARAMS {
|
|||
uint8_t use_dma : 1;
|
||||
uint8_t swap_color : 1;
|
||||
uint8_t async_dma : 1; // force DMA completion before returning, avoid conflict with other devices on same bus. If set you should make sure the display is the only device on the bus
|
||||
uint8_t resvd_1 : 1;
|
||||
uint8_t busy_invert : 1;
|
||||
uint8_t resvd_2 : 1;
|
||||
uint8_t resvd_3 : 1;
|
||||
uint8_t resvd_4 : 1;
|
||||
|
@ -86,6 +86,7 @@ public:
|
|||
virtual uint16_t bgcol(void);
|
||||
virtual int8_t color_type(void);
|
||||
virtual void Splash(void);
|
||||
virtual void Sleep(void);
|
||||
virtual char *devname(void);
|
||||
virtual LVGL_PARAMS *lvgl_pars(void);
|
||||
virtual void ep_update_mode(uint8_t mode);
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
#include "epd2in9.h"
|
||||
|
||||
|
||||
#define EPD_29_V2
|
||||
|
||||
//#define BUSY_PIN 16
|
||||
|
||||
|
||||
Epd::Epd(int16_t width, int16_t height) :
|
||||
Paint(width,height) {
|
||||
}
|
||||
|
@ -36,30 +41,35 @@ void Epd::DisplayOnff(int8_t on) {
|
|||
}
|
||||
|
||||
void Epd::Updateframe() {
|
||||
#ifdef EPD_29_V2
|
||||
if (mode == DISPLAY_INIT_PARTIAL) {
|
||||
SetFrameMemory_Partial(framebuffer, 0, 0, EPD_WIDTH,EPD_HEIGHT);
|
||||
DisplayFrame_Partial();
|
||||
} else {
|
||||
SetFrameMemory(framebuffer, 0, 0, EPD_WIDTH,EPD_HEIGHT);
|
||||
DisplayFrame();
|
||||
}
|
||||
#else
|
||||
SetFrameMemory(framebuffer, 0, 0, EPD_WIDTH,EPD_HEIGHT);
|
||||
DisplayFrame();
|
||||
#endif
|
||||
//Serial.printf("update\n");
|
||||
}
|
||||
|
||||
#define DISPLAY_INIT_MODE 0
|
||||
#define DISPLAY_INIT_PARTIAL 1
|
||||
#define DISPLAY_INIT_FULL 2
|
||||
|
||||
|
||||
void Epd::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
|
||||
// ignore update mode
|
||||
if (p==DISPLAY_INIT_PARTIAL) {
|
||||
if (p == DISPLAY_INIT_PARTIAL) {
|
||||
Init(lut_partial_update);
|
||||
//ClearFrameMemory(0xFF); // bit set = white, bit reset = black
|
||||
DisplayFrame();
|
||||
delay(500);
|
||||
delay_busy(500);
|
||||
return;
|
||||
//Serial.printf("partial\n");
|
||||
} else if (p==DISPLAY_INIT_FULL) {
|
||||
} else if (p == DISPLAY_INIT_FULL) {
|
||||
Init(lut_full_update);
|
||||
//ClearFrameMemory(0xFF); // bit set = white, bit reset = black
|
||||
DisplayFrame();
|
||||
delay(3500);
|
||||
delay_busy(3500);
|
||||
//Serial.printf("full\n");
|
||||
return;
|
||||
} else {
|
||||
|
@ -78,25 +88,31 @@ void Epd::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
|
|||
disp_bpp = 1;
|
||||
}
|
||||
|
||||
void Epd::Begin(int16_t cs,int16_t mosi,int16_t sclk) {
|
||||
cs_pin=cs;
|
||||
mosi_pin=mosi;
|
||||
sclk_pin=sclk;
|
||||
void Epd::Begin(int16_t cs,int16_t mosi,int16_t sclk, int16_t rst, int16_t busy) {
|
||||
cs_pin = cs;
|
||||
mosi_pin = mosi;
|
||||
sclk_pin = sclk;
|
||||
rst_pin = rst;
|
||||
busy_pin = busy;
|
||||
#ifdef BUSY_PIN
|
||||
busy_pin = BUSY_PIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Epd::Init(int8_t p) {
|
||||
if (p==DISPLAY_INIT_PARTIAL) {
|
||||
if (p == DISPLAY_INIT_PARTIAL) {
|
||||
Init(lut_partial_update);
|
||||
} else {
|
||||
Init(lut_full_update);
|
||||
}
|
||||
mode = p;
|
||||
ClearFrameMemory(0xFF);
|
||||
DisplayFrame();
|
||||
if (p==DISPLAY_INIT_PARTIAL) {
|
||||
delay(350);
|
||||
if (p == DISPLAY_INIT_PARTIAL) {
|
||||
delay_busy(350);
|
||||
} else {
|
||||
delay(3500);
|
||||
delay_busy(3500);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,6 +128,9 @@ int Epd::Init(const unsigned char* lut) {
|
|||
sclk_pin=pin[GPIO_SSPI_SCLK];
|
||||
*/
|
||||
|
||||
if (framebuffer) {
|
||||
// free(framebuffer);
|
||||
}
|
||||
framebuffer = (uint8_t*)malloc(EPD_WIDTH * EPD_HEIGHT / 8);
|
||||
if (!framebuffer) return -1;
|
||||
|
||||
|
@ -123,9 +142,46 @@ int Epd::Init(const unsigned char* lut) {
|
|||
digitalWrite(mosi_pin,LOW);
|
||||
digitalWrite(sclk_pin,LOW);
|
||||
|
||||
if (rst_pin >= 0) {
|
||||
pinMode(rst_pin, OUTPUT);
|
||||
digitalWrite(rst_pin, HIGH);
|
||||
}
|
||||
|
||||
if (busy_pin >= 0) {
|
||||
pinMode(busy_pin, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
width = EPD_WIDTH;
|
||||
height = EPD_HEIGHT;
|
||||
|
||||
#ifdef EPD_29_V2
|
||||
/* EPD hardware init start */
|
||||
Reset();
|
||||
|
||||
SendCommand(0x12); //SWRESET
|
||||
delay_busy(100);
|
||||
|
||||
SendCommand(0x01); //Driver output control
|
||||
SendData(0x27);
|
||||
SendData(0x01);
|
||||
SendData(0x00);
|
||||
|
||||
SendCommand(0x11); //data entry mode
|
||||
SendData(0x03);
|
||||
|
||||
SetMemoryArea(0, 0, width-1, height-1);
|
||||
|
||||
SendCommand(0x21); // Display update control
|
||||
SendData(0x00);
|
||||
SendData(0x80);
|
||||
|
||||
SetMemoryPointer(0, 0);
|
||||
delay_busy(10);
|
||||
|
||||
SetLut_by_host(lut_full_update);
|
||||
mode = DISPLAY_INIT_FULL;
|
||||
|
||||
#else
|
||||
/* EPD hardware init start */
|
||||
this->lut = lut;
|
||||
Reset();
|
||||
|
@ -146,6 +202,7 @@ int Epd::Init(const unsigned char* lut) {
|
|||
SendCommand(DATA_ENTRY_MODE_SETTING);
|
||||
SendData(0x03); // X increment; Y increment
|
||||
SetLut(this->lut);
|
||||
#endif
|
||||
/* EPD hardware init end */
|
||||
return 0;
|
||||
}
|
||||
|
@ -168,28 +225,63 @@ void Epd::SendData(unsigned char data) {
|
|||
// SpiTransfer(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief: Wait until the busy_pin goes LOW
|
||||
*/
|
||||
void Epd::WaitUntilIdle(void) {
|
||||
return;
|
||||
//while(DigitalRead(busy_pin) == HIGH) { //LOW: idle, HIGH: busy
|
||||
// DelayMs(100);
|
||||
//}
|
||||
|
||||
|
||||
void Epd::delay_busy(uint32_t wait) {
|
||||
if (busy_pin >= 0) {
|
||||
while (digitalRead(busy_pin) == HIGH) { //LOW: idle, HIGH: busy
|
||||
delay(10);
|
||||
}
|
||||
} else {
|
||||
delay(wait);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief: module reset.
|
||||
* often used to awaken the module in deep sleep,
|
||||
* see Epd::Sleep();
|
||||
*/
|
||||
void Epd::Reset(void) {
|
||||
//DigitalWrite(reset_pin, LOW); //module reset
|
||||
//delay(200);
|
||||
//DigitalWrite(reset_pin, HIGH);
|
||||
//delay(200);
|
||||
if (rst_pin >= 0) {
|
||||
digitalWrite(rst_pin, LOW); //module reset
|
||||
delay(200);
|
||||
digitalWrite(rst_pin, HIGH);
|
||||
delay(200);
|
||||
} else {
|
||||
SendCommand(0x12);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EPD_29_V2
|
||||
void Epd::SetLut(const unsigned char *lut) {
|
||||
unsigned char count;
|
||||
SendCommand(0x32);
|
||||
for(count=0; count<153; count++)
|
||||
SendData(lut[count]);
|
||||
delay_busy(50);
|
||||
}
|
||||
|
||||
|
||||
void Epd::SetLut_by_host(const unsigned char *lut) {
|
||||
SetLut((unsigned char *)lut);
|
||||
SendCommand(0x3f);
|
||||
SendData(*(lut+153));
|
||||
SendCommand(0x03); // gate voltage
|
||||
SendData(*(lut+154));
|
||||
SendCommand(0x04); // source voltage
|
||||
SendData(*(lut+155)); // VSH
|
||||
SendData(*(lut+156)); // VSH2
|
||||
SendData(*(lut+157)); // VSL
|
||||
SendCommand(0x2c); // VCOM
|
||||
SendData(*(lut+158));
|
||||
}
|
||||
#else
|
||||
|
||||
void Epd::SetLut_by_host(const unsigned char *lut) {
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief: set the look-up table register
|
||||
*/
|
||||
|
@ -201,6 +293,7 @@ void Epd::SetLut(const unsigned char* lut) {
|
|||
SendData(this->lut[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief: put an image buffer to the frame memory.
|
||||
|
@ -213,6 +306,7 @@ void Epd::SetFrameMemory(
|
|||
uint16_t image_width,
|
||||
uint16_t image_height
|
||||
) {
|
||||
|
||||
uint16_t x_end;
|
||||
uint16_t y_end;
|
||||
|
||||
|
@ -303,13 +397,118 @@ void Epd::ClearFrameMemory(unsigned char color) {
|
|||
* set the other memory area.
|
||||
*/
|
||||
void Epd::DisplayFrame(void) {
|
||||
SendCommand(DISPLAY_UPDATE_CONTROL_2);
|
||||
SendCommand(DISPLAY_UPDATE_CONTROL_2); // 0x22
|
||||
#ifdef EPD_29_V2
|
||||
SendData(0xC7);
|
||||
#else
|
||||
SendData(0xC4);
|
||||
SendCommand(MASTER_ACTIVATION);
|
||||
#endif
|
||||
SendCommand(MASTER_ACTIVATION); // 0x20
|
||||
#ifndef EPD_29_V2
|
||||
SendCommand(TERMINATE_FRAME_READ_WRITE);
|
||||
WaitUntilIdle();
|
||||
#endif
|
||||
delay_busy(10);
|
||||
}
|
||||
|
||||
void Epd::DisplayFrame_Partial(void) {
|
||||
SendCommand(0x22);
|
||||
SendData(0x0F);
|
||||
SendCommand(0x20);
|
||||
delay_busy(10);
|
||||
}
|
||||
|
||||
#ifdef EPD_29_V2
|
||||
|
||||
void Epd::SetFrameMemory_Partial(const unsigned char* image_buffer, int x, int y, int image_width, int image_height) {
|
||||
int x_end;
|
||||
int y_end;
|
||||
|
||||
if (
|
||||
image_buffer == NULL ||
|
||||
x < 0 || image_width < 0 ||
|
||||
y < 0 || image_height < 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
/* x point must be the multiple of 8 or the last 3 bits will be ignored */
|
||||
x &= 0xF8;
|
||||
image_width &= 0xF8;
|
||||
if (x + image_width >= this->width) {
|
||||
x_end = this->width - 1;
|
||||
} else {
|
||||
x_end = x + image_width - 1;
|
||||
}
|
||||
if (y + image_height >= this->height) {
|
||||
y_end = this->height - 1;
|
||||
} else {
|
||||
y_end = y + image_height - 1;
|
||||
}
|
||||
|
||||
if (rst_pin >= 0) {
|
||||
digitalWrite(rst_pin, LOW);
|
||||
delay(2);
|
||||
digitalWrite(rst_pin, HIGH);
|
||||
delay(2);
|
||||
} else {
|
||||
SendCommand(0x12);
|
||||
}
|
||||
SetLut(lut_partial_update);
|
||||
SendCommand(0x37);
|
||||
SendData(0x00);
|
||||
SendData(0x00);
|
||||
SendData(0x00);
|
||||
SendData(0x00);
|
||||
SendData(0x00);
|
||||
SendData(0x40);
|
||||
SendData(0x00);
|
||||
SendData(0x00);
|
||||
SendData(0x00);
|
||||
SendData(0x00);
|
||||
|
||||
SendCommand(0x3C); //BorderWavefrom
|
||||
SendData(0x80);
|
||||
|
||||
SendCommand(0x22);
|
||||
SendData(0xC0);
|
||||
SendCommand(0x20);
|
||||
delay_busy(100);
|
||||
|
||||
SetMemoryArea(x, y, x_end, y_end);
|
||||
SetMemoryPointer(x, y);
|
||||
SendCommand(0x24);
|
||||
/* send the image data */
|
||||
for (int j = 0; j < y_end - y + 1; j++) {
|
||||
for (int i = 0; i < (x_end - x + 1) / 8; i++) {
|
||||
SendData(image_buffer[i + j * (image_width / 8)]^0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief: private function to specify the memory area for data R/W
|
||||
*/
|
||||
void Epd::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) {
|
||||
SendCommand(0x44);
|
||||
/* x point must be the multiple of 8 or the last 3 bits will be ignored */
|
||||
SendData((x_start >> 3) & 0xFF);
|
||||
SendData((x_end >> 3) & 0xFF);
|
||||
SendCommand(0x45);
|
||||
SendData(y_start & 0xFF);
|
||||
SendData((y_start >> 8) & 0xFF);
|
||||
SendData(y_end & 0xFF);
|
||||
SendData((y_end >> 8) & 0xFF);
|
||||
}
|
||||
#else
|
||||
|
||||
void Epd::SetFrameMemory_Partial(
|
||||
const unsigned char* image_buffer,
|
||||
int x,
|
||||
int y,
|
||||
int image_width,
|
||||
int image_height
|
||||
) {
|
||||
}
|
||||
/**
|
||||
* @brief: private function to specify the memory area for data R/W
|
||||
*/
|
||||
|
@ -324,7 +523,24 @@ void Epd::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) {
|
|||
SendData(y_end & 0xFF);
|
||||
SendData((y_end >> 8) & 0xFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef EPD_29_V2
|
||||
|
||||
/**
|
||||
* @brief: private function to specify the start point for data R/W
|
||||
*/
|
||||
void Epd::SetMemoryPointer(int x, int y) {
|
||||
SendCommand(0x4E);
|
||||
/* x point must be the multiple of 8 or the last 3 bits will be ignored */
|
||||
SendData((x >> 3) & 0xFF);
|
||||
SendCommand(0x4F);
|
||||
SendData(y & 0xFF);
|
||||
SendData((y >> 8) & 0xFF);
|
||||
delay_busy(10);
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* @brief: private function to specify the start point for data R/W
|
||||
*/
|
||||
|
@ -335,8 +551,9 @@ void Epd::SetMemoryPointer(int x, int y) {
|
|||
SendCommand(SET_RAM_Y_ADDRESS_COUNTER);
|
||||
SendData(y & 0xFF);
|
||||
SendData((y >> 8) & 0xFF);
|
||||
WaitUntilIdle();
|
||||
delay_busy(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief: After this command is transmitted, the chip would enter the
|
||||
|
@ -346,9 +563,59 @@ void Epd::SetMemoryPointer(int x, int y) {
|
|||
*/
|
||||
void Epd::Sleep() {
|
||||
SendCommand(DEEP_SLEEP_MODE);
|
||||
WaitUntilIdle();
|
||||
delay_busy(10);
|
||||
}
|
||||
|
||||
#ifdef EPD_29_V2
|
||||
|
||||
const unsigned char lut_partial_update[159] =
|
||||
{
|
||||
0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0A,0x0,0x0,0x0,0x0,0x0,0x2,
|
||||
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0,
|
||||
0x22,0x17,0x41,0xB0,0x32,0x36,
|
||||
};
|
||||
|
||||
const unsigned char lut_full_update[159] =
|
||||
{
|
||||
0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0,
|
||||
0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
|
||||
0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0,
|
||||
0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x14, 0x8, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0xA, 0xA, 0x0, 0xA, 0xA, 0x0, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x14, 0x8, 0x0, 0x1, 0x0, 0x0, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x0, 0x0, 0x0,
|
||||
0x22, 0x17, 0x41, 0x0, 0x32, 0x36
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
const unsigned char lut_full_update[] =
|
||||
{
|
||||
0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22,
|
||||
|
@ -364,7 +631,7 @@ const unsigned char lut_partial_update[] =
|
|||
0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
#endif // EPD_29_V2
|
||||
|
||||
#define PIN_OUT_SET 0x60000304
|
||||
#define PIN_OUT_CLEAR 0x60000308
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
#include "epdpaint.h"
|
||||
|
||||
|
||||
#define DISPLAY_INIT_MODE 0
|
||||
#define DISPLAY_INIT_PARTIAL 1
|
||||
#define DISPLAY_INIT_FULL 2
|
||||
|
||||
// Display resolution
|
||||
#define EPD_WIDTH 128
|
||||
#define EPD_HEIGHT 296
|
||||
|
@ -91,21 +95,27 @@ public:
|
|||
|
||||
void DisplayOnff(int8_t on);
|
||||
void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font);
|
||||
void Begin(int16_t p1,int16_t p2,int16_t p3);
|
||||
void Begin(int16_t cs,int16_t mosi,int16_t sclk, int16_t rst = -1, int16_t busy = -1);
|
||||
|
||||
void Updateframe();
|
||||
|
||||
private:
|
||||
unsigned int reset_pin;
|
||||
unsigned int dc_pin;
|
||||
unsigned int busy_pin;
|
||||
const unsigned char* lut;
|
||||
unsigned int cs_pin;
|
||||
signed int rst_pin;
|
||||
signed int busy_pin;
|
||||
unsigned int mosi_pin;
|
||||
unsigned int sclk_pin;
|
||||
|
||||
unsigned char mode;
|
||||
void delay_busy(uint32_t wait);
|
||||
void SetLut(const unsigned char* lut);
|
||||
void SetMemoryArea(int x_start, int y_start, int x_end, int y_end);
|
||||
void SetMemoryPointer(int x, int y);
|
||||
void SetLut_by_host(const unsigned char* lut);
|
||||
void SetFrameMemory_Partial(const unsigned char* image_buffer,int x,int y,int image_width,int image_height);
|
||||
void DisplayFrame_Partial(void);
|
||||
//void fastSPIwrite(uint8_t d,uint8_t dc);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
#include <Arduino.h>
|
||||
#include <stdint.h>
|
||||
#include "GT911.h"
|
||||
|
||||
#undef log_d
|
||||
#define log_d
|
||||
#undef log_e
|
||||
#define log_e
|
||||
|
||||
#ifdef ESP8266
|
||||
#define ESP_OK 0
|
||||
#define ESP_FAIL -1
|
||||
#endif
|
||||
|
||||
//#define log_d Serial.printf
|
||||
|
||||
GT911::GT911() {}
|
||||
|
||||
volatile uint8_t gt911_irq_trigger = 0;
|
||||
void ICACHE_RAM_ATTR ___GT911IRQ___()
|
||||
{
|
||||
noInterrupts();
|
||||
gt911_irq_trigger = 1;
|
||||
interrupts();
|
||||
}
|
||||
|
||||
int32_t GT911::begin(TwoWire *use_wire, int8_t pin_int, int8_t pin_res, uint16_t xs, uint16_t ys)
|
||||
{
|
||||
log_d("GT911: Initialization");
|
||||
|
||||
if (pin_int >= 0) {
|
||||
pinMode(pin_int, INPUT); // Startup sequence PIN part
|
||||
}
|
||||
if (pin_res >= 0) {
|
||||
pinMode(pin_res, OUTPUT); // Startup sequence PIN part
|
||||
digitalWrite(pin_res, 0);
|
||||
delay(1);
|
||||
digitalWrite(pin_res, 1);
|
||||
}
|
||||
delay(100);
|
||||
wire = use_wire;
|
||||
|
||||
wire->beginTransmission(0x14);
|
||||
if (wire->endTransmission())
|
||||
{
|
||||
wire->beginTransmission(0x5D);
|
||||
if (wire->endTransmission())
|
||||
{
|
||||
log_e("Touch screen IIC connection error");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
_iic_addr = 0x5D;
|
||||
}
|
||||
|
||||
if (pin_int >= 0) {
|
||||
attachInterrupt(pin_int, ___GT911IRQ___, FALLING);
|
||||
}
|
||||
|
||||
readBlockData(configBuf, GT911_CONFIG_START, GT911_CONFIG_SIZE);
|
||||
|
||||
uint16_t curx = configBuf[GT911_X_OUTPUT_MAX_LOW - GT911_CONFIG_START] | (configBuf[GT911_X_OUTPUT_MAX_HIGH - GT911_CONFIG_START] << 8);
|
||||
uint16_t cury = configBuf[GT911_Y_OUTPUT_MAX_LOW - GT911_CONFIG_START] | (configBuf[GT911_Y_OUTPUT_MAX_HIGH - GT911_CONFIG_START] << 8);
|
||||
|
||||
if (curx != xs || cury != ys) {
|
||||
setResolution(xs, ys);
|
||||
}
|
||||
|
||||
log_d("GT911: initialized");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
void GT911::write(uint16_t addr, uint8_t data)
|
||||
{
|
||||
wire->beginTransmission(_iic_addr);
|
||||
wire->write((uint8_t)(addr >> 8));
|
||||
wire->write((uint8_t)addr);
|
||||
wire->write(data);
|
||||
wire->endTransmission(true);
|
||||
}
|
||||
|
||||
void GT911::write(uint16_t addr, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
wire->beginTransmission(_iic_addr);
|
||||
wire->write((uint8_t)(addr >> 8));
|
||||
wire->write((uint8_t)addr);
|
||||
wire->write(data, len);
|
||||
wire->endTransmission(true);
|
||||
}
|
||||
|
||||
uint8_t GT911::read(uint16_t addr)
|
||||
{
|
||||
wire->flush();
|
||||
wire->beginTransmission(_iic_addr);
|
||||
wire->write((uint8_t)(addr >> 8));
|
||||
wire->write((uint8_t)addr);
|
||||
wire->endTransmission(false);
|
||||
wire->requestFrom((uint8_t)_iic_addr, (uint8_t)1);
|
||||
return wire->read();
|
||||
}
|
||||
|
||||
void GT911::read(uint16_t addr, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
wire->flush();
|
||||
wire->beginTransmission(_iic_addr);
|
||||
wire->write((uint8_t)(addr >> 8));
|
||||
wire->write((uint8_t)addr);
|
||||
wire->endTransmission(false);
|
||||
wire->requestFrom((int)_iic_addr, (int)len);
|
||||
wire->readBytes(buf, len);
|
||||
}
|
||||
|
||||
void GT911::readBlockData(uint8_t *buf, uint16_t reg, uint8_t size) {
|
||||
wire->beginTransmission(_iic_addr);
|
||||
wire->write(highByte(reg));
|
||||
wire->write(lowByte(reg));
|
||||
wire->endTransmission();
|
||||
wire->requestFrom(_iic_addr, size);
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
buf[i] = wire->read();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GT911::calculateChecksum() {
|
||||
uint8_t checksum = 0;
|
||||
for (uint8_t i = 0; i < GT911_CONFIG_SIZE - 1 ; i++) {
|
||||
checksum += configBuf[i];
|
||||
}
|
||||
checksum = (~checksum) + 1;
|
||||
configBuf[GT911_CONFIG_CHKSUM - GT911_CONFIG_START] = checksum;
|
||||
}
|
||||
|
||||
void GT911::reflashConfig() {
|
||||
calculateChecksum();
|
||||
write(GT911_X_OUTPUT_MAX_LOW, configBuf[GT911_X_OUTPUT_MAX_LOW - GT911_CONFIG_START]);
|
||||
write(GT911_X_OUTPUT_MAX_HIGH, configBuf[GT911_X_OUTPUT_MAX_HIGH - GT911_CONFIG_START]);
|
||||
write(GT911_Y_OUTPUT_MAX_LOW, configBuf[GT911_Y_OUTPUT_MAX_LOW - GT911_CONFIG_START]);
|
||||
write(GT911_Y_OUTPUT_MAX_HIGH, configBuf[GT911_Y_OUTPUT_MAX_HIGH - GT911_CONFIG_START]);
|
||||
write(GT911_CONFIG_CHKSUM, configBuf[GT911_CONFIG_CHKSUM - GT911_CONFIG_START]);
|
||||
write(GT911_CONFIG_FRESH, 1);
|
||||
}
|
||||
|
||||
void GT911::setResolution(uint16_t _width, uint16_t _height) {
|
||||
configBuf[GT911_X_OUTPUT_MAX_LOW - GT911_CONFIG_START] = lowByte(_width);
|
||||
configBuf[GT911_X_OUTPUT_MAX_HIGH - GT911_CONFIG_START] = highByte(_width);
|
||||
configBuf[GT911_Y_OUTPUT_MAX_LOW - GT911_CONFIG_START] = lowByte(_height);
|
||||
configBuf[GT911_Y_OUTPUT_MAX_HIGH - GT911_CONFIG_START] = highByte(_height);
|
||||
reflashConfig();
|
||||
}
|
||||
|
||||
bool GT911::avaliable()
|
||||
{
|
||||
if(gt911_irq_trigger == 1)
|
||||
{
|
||||
gt911_irq_trigger = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GT911::flush(void)
|
||||
{
|
||||
write(0x814E, 0x00);
|
||||
gt911_irq_trigger = 0;
|
||||
_num = 0;
|
||||
_is_finger_up = 0;
|
||||
}
|
||||
|
||||
void GT911::update()
|
||||
{
|
||||
uint8_t r814e = read(0x814E);
|
||||
uint8_t num = r814e & 0x0F;
|
||||
if(r814e & 0x80)
|
||||
{
|
||||
if(num != 0)
|
||||
{
|
||||
_is_finger_up = false;
|
||||
_num = num;
|
||||
uint8_t data[num * 8];
|
||||
read(0x8150, data, num * 8);
|
||||
for(int j = 0; j < num; j++)
|
||||
{
|
||||
uint8_t *buf = data + j * 8;
|
||||
|
||||
if(_rotate == ROTATE_0)
|
||||
{
|
||||
_fingers[j].x = (buf[3] << 8) | buf[2];
|
||||
_fingers[j].y = 540 - ((buf[1] << 8) | buf[0]);
|
||||
}
|
||||
else if(_rotate == ROTATE_180)
|
||||
{
|
||||
_fingers[j].x = 960 - ((buf[3] << 8) | buf[2]);
|
||||
_fingers[j].y = (buf[1] << 8) | buf[0];
|
||||
}
|
||||
else if(_rotate == ROTATE_270)
|
||||
{
|
||||
_fingers[j].x = 540 - ((buf[1] << 8) | buf[0]);
|
||||
_fingers[j].y = 960 - ((buf[3] << 8) | buf[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fingers[j].x = (buf[1] << 8) | buf[0];
|
||||
_fingers[j].y = (buf[3] << 8) | buf[2];
|
||||
}
|
||||
|
||||
_fingers[j].size = (buf[5] << 8) | buf[4];
|
||||
_fingers[j].id = buf[7];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_is_finger_up = true;
|
||||
}
|
||||
write(0x814E, 0x00);
|
||||
}
|
||||
else
|
||||
{
|
||||
_is_finger_up = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool GT911::isFingerUp(void)
|
||||
{
|
||||
if(_is_finger_up == 1)
|
||||
{
|
||||
_is_finger_up = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GT911::SetRotation(uint16_t rotate)
|
||||
{
|
||||
if(rotate < 4)
|
||||
{
|
||||
this->_rotate = rotate;
|
||||
}
|
||||
else if(rotate < 90)
|
||||
{
|
||||
this->_rotate = ROTATE_0;
|
||||
}
|
||||
else if(rotate < 180)
|
||||
{
|
||||
this->_rotate = ROTATE_90;
|
||||
}
|
||||
else if(rotate < 270)
|
||||
{
|
||||
this->_rotate = ROTATE_180;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_rotate = ROTATE_270;
|
||||
}
|
||||
}
|
||||
|
||||
tp_finger_t GT911::readFinger(uint8_t num)
|
||||
{
|
||||
if(num > 2)
|
||||
{
|
||||
num = 1;
|
||||
}
|
||||
return this->_fingers[num];
|
||||
}
|
||||
|
||||
uint16_t GT911::readFingerID(uint8_t num)
|
||||
{
|
||||
return this->_fingers[num].id;
|
||||
}
|
||||
|
||||
uint16_t GT911::readFingerSize(uint8_t num)
|
||||
{
|
||||
return this->_fingers[num].size;
|
||||
}
|
||||
|
||||
uint16_t GT911::readFingerX(uint8_t num)
|
||||
{
|
||||
return this->_fingers[num].x;
|
||||
}
|
||||
|
||||
uint16_t GT911::readFingerY(uint8_t num)
|
||||
{
|
||||
return this->_fingers[num].y;
|
||||
}
|
||||
|
||||
uint8_t GT911::getFingerNum(void)
|
||||
{
|
||||
return _num;
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
#ifndef GT911_H
|
||||
#define GT911_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <Wire.h>
|
||||
|
||||
|
||||
// Real-time command (Write only)
|
||||
#define GT911_COMMAND (uint16_t)0x8040
|
||||
#define GT911_ESD_CHECK (uint16_t)0x8041
|
||||
#define GT911_COMMAND_CHECK (uint16_t)0x8046
|
||||
|
||||
// Configuration information (R/W)
|
||||
#define GT911_CONFIG_START (uint16_t)0x8047
|
||||
#define GT911_CONFIG_VERSION (uint16_t)0x8047
|
||||
#define GT911_X_OUTPUT_MAX_LOW (uint16_t)0x8048
|
||||
#define GT911_X_OUTPUT_MAX_HIGH (uint16_t)0x8049
|
||||
#define GT911_Y_OUTPUT_MAX_LOW (uint16_t)0x804A
|
||||
#define GT911_Y_OUTPUT_MAX_HIGH (uint16_t)0x804B
|
||||
#define GT911_TOUCH_NUMBER (uint16_t)0x804C
|
||||
#define GT911_MODULE_SWITCH_1 (uint16_t)0x804D
|
||||
#define GT911_MODULE_SWITCH_2 (uint16_t)0x804E
|
||||
#define GT911_SHAKE_COUNT (uint16_t)0x804F
|
||||
#define GT911_FILTER (uint16_t)0x8050
|
||||
#define GT911_LARGE_TOUCH (uint16_t)0x8051
|
||||
#define GT911_NOISE_REDUCTION (uint16_t)0x8052
|
||||
#define GT911_SCREEN_TOUCH_LEVEL (uint16_t)0x8053
|
||||
#define GT911_SCREEN_RELEASE_LEVEL (uint16_t)0x8054
|
||||
#define GT911_LOW_POWER_CONTROL (uint16_t)0x8055
|
||||
#define GT911_REFRESH_RATE (uint16_t)0x8056
|
||||
#define GT911_X_THRESHOLD (uint16_t)0x8057
|
||||
#define GT911_Y_THRESHOLD (uint16_t)0x8058
|
||||
#define GT911_X_SPEED_LIMIT (uint16_t)0x8059 //Reserve
|
||||
#define GT911_Y_SPEED_LIMIT (uint16_t)0x805A //Reserve
|
||||
#define GT911_SPACE_TOP_BOTTOM (uint16_t)0x805B
|
||||
#define GT911_SPACE_LEFT_RIGHT (uint16_t)0x805C
|
||||
#define GT911_MINI_FILTER (uint16_t)0x805D
|
||||
#define GT911_STRETCH_R0 (uint16_t)0x805E
|
||||
#define GT911_STRETCH_R1 (uint16_t)0x805F
|
||||
#define GT911_STRETCH_R2 (uint16_t)0x8060
|
||||
#define GT911_STRETCH_RM (uint16_t)0x8061
|
||||
#define GT911_DRV_GROUPA_NUM (uint16_t)0x8062
|
||||
#define GT911_DRV_GROUPB_NUM (uint16_t)0x8063
|
||||
#define GT911_SENSOR_NUM (uint16_t)0x8064
|
||||
#define GT911_FREQ_A_FACTOR (uint16_t)0x8065
|
||||
#define GT911_FREQ_B_FACTOR (uint16_t)0x8066
|
||||
#define GT911_PANEL_BIT_FREQ_L (uint16_t)0x8067
|
||||
#define GT911_PANEL_BIT_FREQ_H (uint16_t)0x8068
|
||||
#define GT911_PANEL_SENSOR_TIME_L (uint16_t)0x8069 //Reserve
|
||||
#define GT911_PANEL_SENSOR_TIME_H (uint16_t)0x806A
|
||||
#define GT911_PANEL_TX_GAIN (uint16_t)0x806B
|
||||
#define GT911_PANEL_RX_GAIN (uint16_t)0x806C
|
||||
#define GT911_PANEL_DUMP_SHIFT (uint16_t)0x806D
|
||||
#define GT911_DRV_FRAME_CONTROL (uint16_t)0x806E
|
||||
#define GT911_CHARGING_LEVEL_UP (uint16_t)0x806F
|
||||
#define GT911_MODULE_SWITCH3 (uint16_t)0x8070
|
||||
#define GT911_GESTURE_DIS (uint16_t)0X8071
|
||||
#define GT911_GESTURE_LONG_PRESS_TIME (uint16_t)0x8072
|
||||
#define GT911_X_Y_SLOPE_ADJUST (uint16_t)0X8073
|
||||
#define GT911_GESTURE_CONTROL (uint16_t)0X8074
|
||||
#define GT911_GESTURE_SWITCH1 (uint16_t)0X8075
|
||||
#define GT911_GESTURE_SWITCH2 (uint16_t)0X8076
|
||||
#define GT911_GESTURE_REFRESH_RATE (uint16_t)0x8077
|
||||
#define GT911_GESTURE_TOUCH_LEVEL (uint16_t)0x8078
|
||||
#define GT911_NEWGREENWAKEUPLEVEL (uint16_t)0x8079
|
||||
#define GT911_FREQ_HOPPING_START (uint16_t)0x807A
|
||||
#define GT911_FREQ_HOPPING_END (uint16_t)0X807B
|
||||
#define GT911_NOISE_DETECT_TIMES (uint16_t)0x807C
|
||||
#define GT911_HOPPING_FLAG (uint16_t)0X807D
|
||||
#define GT911_HOPPING_THRESHOLD (uint16_t)0X807E
|
||||
#define GT911_NOISE_THRESHOLD (uint16_t)0X807F //Reserve
|
||||
#define GT911_NOISE_MIN_THRESHOLD (uint16_t)0X8080
|
||||
#define GT911_HOPPING_SENSOR_GROUP (uint16_t)0X8082
|
||||
#define GT911_HOPPING_SEG1_NORMALIZE (uint16_t)0X8083
|
||||
#define GT911_HOPPING_SEG1_FACTOR (uint16_t)0X8084
|
||||
#define GT911_MAIN_CLOCK_AJDUST (uint16_t)0X8085
|
||||
#define GT911_HOPPING_SEG2_NORMALIZE (uint16_t)0X8086
|
||||
#define GT911_HOPPING_SEG2_FACTOR (uint16_t)0X8087
|
||||
#define GT911_HOPPING_SEG3_NORMALIZE (uint16_t)0X8089
|
||||
#define GT911_HOPPING_SEG3_FACTOR (uint16_t)0X808A
|
||||
#define GT911_HOPPING_SEG4_NORMALIZE (uint16_t)0X808C
|
||||
#define GT911_HOPPING_SEG4_FACTOR (uint16_t)0X808D
|
||||
#define GT911_HOPPING_SEG5_NORMALIZE (uint16_t)0X808F
|
||||
#define GT911_HOPPING_SEG5_FACTOR (uint16_t)0X8090
|
||||
#define GT911_HOPPING_SEG6_NORMALIZE (uint16_t)0X8092
|
||||
#define GT911_KEY_1 (uint16_t)0X8093
|
||||
#define GT911_KEY_2 (uint16_t)0X8094
|
||||
#define GT911_KEY_3 (uint16_t)0X8095
|
||||
#define GT911_KEY_4 (uint16_t)0X8096
|
||||
#define GT911_KEY_AREA (uint16_t)0X8097
|
||||
#define GT911_KEY_TOUCH_LEVEL (uint16_t)0X8098
|
||||
#define GT911_KEY_LEAVE_LEVEL (uint16_t)0X8099
|
||||
#define GT911_KEY_SENS_1_2 (uint16_t)0X809A
|
||||
#define GT911_KEY_SENS_3_4 (uint16_t)0X809B
|
||||
#define GT911_KEY_RESTRAIN (uint16_t)0X809C
|
||||
#define GT911_KEY_RESTRAIN_TIME (uint16_t)0X809D
|
||||
#define GT911_GESTURE_LARGE_TOUCH (uint16_t)0X809E
|
||||
#define GT911_HOTKNOT_NOISE_MAP (uint16_t)0X80A1
|
||||
#define GT911_LINK_THRESHOLD (uint16_t)0X80A2
|
||||
#define GT911_PXY_THRESHOLD (uint16_t)0X80A3
|
||||
#define GT911_GHOT_DUMP_SHIFT (uint16_t)0X80A4
|
||||
#define GT911_GHOT_RX_GAIN (uint16_t)0X80A5
|
||||
#define GT911_FREQ_GAIN0 (uint16_t)0X80A6
|
||||
#define GT911_FREQ_GAIN1 (uint16_t)0X80A7
|
||||
#define GT911_FREQ_GAIN2 (uint16_t)0X80A8
|
||||
#define GT911_FREQ_GAIN3 (uint16_t)0X80A9
|
||||
#define GT911_COMBINE_DIS (uint16_t)0X80B3
|
||||
#define GT911_SPLIT_SET (uint16_t)0X80B4
|
||||
#define GT911_SENSOR_CH0 (uint16_t)0X80B7
|
||||
#define GT911_DRIVER_CH0 (uint16_t)0X80D5
|
||||
#define GT911_CONFIG_CHKSUM (uint16_t)0X80FF
|
||||
#define GT911_CONFIG_FRESH (uint16_t)0X8100
|
||||
#define GT911_CONFIG_SIZE (uint16_t)0xFF-0x46
|
||||
// Coordinate information
|
||||
#define GT911_PRODUCT_ID (uint16_t)0X8140
|
||||
#define GT911_FIRMWARE_VERSION (uint16_t)0X8140
|
||||
#define GT911_RESOLUTION (uint16_t)0X8140
|
||||
#define GT911_VENDOR_ID (uint16_t)0X8140
|
||||
#define GT911_IMFORMATION (uint16_t)0X8140
|
||||
#define GT911_POINT_INFO (uint16_t)0X814E
|
||||
#define GT911_POINT_1 (uint16_t)0X814F
|
||||
#define GT911_POINT_2 (uint16_t)0X8157
|
||||
#define GT911_POINT_3 (uint16_t)0X815F
|
||||
#define GT911_POINT_4 (uint16_t)0X8167
|
||||
#define GT911_POINT_5 (uint16_t)0X816F
|
||||
#define GT911_POINTS_REG {GT911_POINT_1, GT911_POINT_2, GT911_POINT_3, GT911_POINT_4, GT911_POINT_5}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t id;
|
||||
uint16_t size;
|
||||
}tp_finger_t;
|
||||
|
||||
class GT911
|
||||
{
|
||||
public:
|
||||
static const uint8_t ROTATE_0 = 0;
|
||||
static const uint8_t ROTATE_90 = 1;
|
||||
static const uint8_t ROTATE_180 = 2;
|
||||
static const uint8_t ROTATE_270 = 3;
|
||||
|
||||
public:
|
||||
GT911();
|
||||
int32_t begin(TwoWire *use_wire, int8_t pin_int, int8_t pin_res, uint16_t xs, uint16_t ys);
|
||||
bool avaliable();
|
||||
void update();
|
||||
void SetRotation(uint16_t rotate);
|
||||
tp_finger_t readFinger(uint8_t num);
|
||||
uint16_t readFingerX(uint8_t num);
|
||||
uint16_t readFingerY(uint8_t num);
|
||||
uint16_t readFingerID(uint8_t num);
|
||||
uint16_t readFingerSize(uint8_t num);
|
||||
uint8_t getFingerNum(void);
|
||||
bool isFingerUp(void);
|
||||
void flush(void);
|
||||
|
||||
private:
|
||||
void write(uint16_t addr, uint8_t data);
|
||||
void write(uint16_t addr, const uint8_t *data, uint16_t len);
|
||||
uint8_t read(uint16_t addr);
|
||||
void read(uint16_t addr, uint8_t *buf, uint16_t len);
|
||||
uint8_t calcChecksum(const uint8_t *buf, uint8_t len);
|
||||
void reflashConfig();
|
||||
void calculateChecksum();
|
||||
void setResolution(uint16_t _width, uint16_t _height);
|
||||
void readBlockData(uint8_t *buf, uint16_t reg, uint8_t size);
|
||||
|
||||
bool _is_finger_up = false;
|
||||
uint8_t _num = 0;
|
||||
uint8_t _rotate = ROTATE_90;
|
||||
tp_finger_t _fingers[2];
|
||||
uint8_t _iic_addr = 0x14;
|
||||
TwoWire *wire;
|
||||
uint8_t configBuf[GT911_CONFIG_SIZE];
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -31,16 +31,25 @@ static inline volatile uint32_t* get_gpio_lo_reg(int_fast8_t pin) { return (pin
|
|||
static inline bool gpio_in(int_fast8_t pin) { return ((pin & 32) ? GPIO.in1.data : GPIO.in) & (1 << (pin & 31)); }
|
||||
static inline void gpio_hi(int_fast8_t pin) { if (pin >= 0) *get_gpio_hi_reg(pin) = 1 << (pin & 31); } // ESP_LOGI("LGFX", "gpio_hi: %d", pin); }
|
||||
static inline void gpio_lo(int_fast8_t pin) { if (pin >= 0) *get_gpio_lo_reg(pin) = 1 << (pin & 31); } // ESP_LOGI("LGFX", "gpio_lo: %d", pin); }
|
||||
#endif
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_panel_rgb.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include <hal/dma_types.h>
|
||||
#include <rom/cache.h>
|
||||
#endif // USE_ESP32_S3
|
||||
|
||||
#define _UDSP_I2C 1
|
||||
#define _UDSP_SPI 2
|
||||
#define _UDSP_PAR8 3
|
||||
#define _UDSP_PAR16 4
|
||||
#define _UDSP_RGB 5
|
||||
|
||||
#define UDISP1_WHITE 1
|
||||
#define UDISP1_BLACK 0
|
||||
|
||||
#define MAX_LUTS 5
|
||||
|
||||
#define DISPLAY_INIT_MODE 0
|
||||
#define DISPLAY_INIT_PARTIAL 1
|
||||
#define DISPLAY_INIT_FULL 2
|
||||
|
@ -100,7 +109,6 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
|
|||
#define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR_SLOW(spi_dc);
|
||||
#define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc);
|
||||
|
||||
#define LUTMAXSIZE 64
|
||||
|
||||
#ifdef USE_ESP32_S3
|
||||
struct esp_lcd_i80_bus_t {
|
||||
|
@ -115,6 +123,39 @@ struct esp_lcd_i80_bus_t {
|
|||
size_t resolution_hz; // LCD_CLK resolution, determined by selected clock source
|
||||
gdma_channel_handle_t dma_chan; // DMA channel handle
|
||||
};
|
||||
|
||||
// extract from esp-idf esp_lcd_rgb_panel.c
|
||||
struct esp_rgb_panel_t
|
||||
{
|
||||
esp_lcd_panel_t base; // Base class of generic lcd panel
|
||||
int panel_id; // LCD panel ID
|
||||
lcd_hal_context_t hal; // Hal layer object
|
||||
size_t data_width; // Number of data lines (e.g. for RGB565, the data width is 16)
|
||||
size_t sram_trans_align; // Alignment for framebuffer that allocated in SRAM
|
||||
size_t psram_trans_align; // Alignment for framebuffer that allocated in PSRAM
|
||||
int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off"
|
||||
intr_handle_t intr; // LCD peripheral interrupt handle
|
||||
esp_pm_lock_handle_t pm_lock; // Power management lock
|
||||
size_t num_dma_nodes; // Number of DMA descriptors that used to carry the frame buffer
|
||||
uint8_t *fb; // Frame buffer
|
||||
size_t fb_size; // Size of frame buffer
|
||||
int data_gpio_nums[SOC_LCD_RGB_DATA_WIDTH]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color"
|
||||
size_t resolution_hz; // Peripheral clock resolution
|
||||
esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
|
||||
gdma_channel_handle_t dma_chan; // DMA channel handle
|
||||
esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done; // Callback, invoked after frame trans done
|
||||
void *user_ctx; // Reserved user's data of callback functions
|
||||
int x_gap; // Extra gap in x coordinate, it's used when calculate the flush window
|
||||
int y_gap; // Extra gap in y coordinate, it's used when calculate the flush window
|
||||
struct
|
||||
{
|
||||
unsigned int disp_en_level : 1; // The level which can turn on the screen by `disp_gpio_num`
|
||||
unsigned int stream_mode : 1; // If set, the LCD transfers data continuously, otherwise, it stops refreshing the LCD when transaction done
|
||||
unsigned int fb_in_psram : 1; // Whether the frame buffer is in PSRAM
|
||||
} flags;
|
||||
dma_descriptor_t dma_nodes[]; // DMA descriptor pool of size `num_dma_nodes`
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -205,7 +246,7 @@ class uDisplay : public Renderer {
|
|||
uint8_t i2c_page_start;
|
||||
uint8_t i2c_page_end;
|
||||
int8_t reset;
|
||||
uint8_t dsp_cmds[128];
|
||||
uint8_t dsp_cmds[256];
|
||||
uint8_t dsp_ncmds;
|
||||
uint8_t dsp_on;
|
||||
uint8_t dsp_off;
|
||||
|
@ -249,16 +290,28 @@ class uDisplay : public Renderer {
|
|||
uint8_t dim_op;
|
||||
uint8_t lutfsize;
|
||||
uint8_t lutpsize;
|
||||
uint16_t lutftime;
|
||||
int16_t lutftime;
|
||||
int8_t busy_pin;
|
||||
uint16_t lutptime;
|
||||
uint16_t lut3time;
|
||||
uint16_t lut_num;
|
||||
uint8_t ep_mode;
|
||||
uint8_t lut_full[LUTMAXSIZE];
|
||||
uint8_t lut_partial[LUTMAXSIZE];
|
||||
uint8_t lut_array[LUTMAXSIZE][5];
|
||||
uint8_t lut_cnt[5];
|
||||
uint8_t lut_cmd[5];
|
||||
uint8_t ep_update_mode;
|
||||
uint8_t *lut_full;
|
||||
uint8_t lut_siz_full;
|
||||
uint8_t *lut_partial;
|
||||
uint8_t lut_siz_partial;
|
||||
uint8_t *frame_buffer;
|
||||
|
||||
uint8_t epcoffs_full;
|
||||
uint8_t epc_full_cnt;
|
||||
uint8_t epcoffs_part;
|
||||
uint8_t epc_part_cnt;
|
||||
|
||||
uint8_t *lut_array[MAX_LUTS];
|
||||
uint8_t lut_cnt[MAX_LUTS];
|
||||
uint8_t lut_cmd[MAX_LUTS];
|
||||
uint8_t lut_siz[MAX_LUTS];
|
||||
uint16_t seta_xp1;
|
||||
uint16_t seta_xp2;
|
||||
uint16_t seta_yp1;
|
||||
|
@ -268,6 +321,11 @@ class uDisplay : public Renderer {
|
|||
int16_t rotmap_ymin;
|
||||
int16_t rotmap_ymax;
|
||||
void pushColorsMono(uint16_t *data, uint16_t len, bool rgb16_swap = false);
|
||||
void delay_sync(int32_t time);
|
||||
void reset_pin(int32_t delayl, int32_t delayh);
|
||||
void delay_arg(uint32_t arg);
|
||||
void Send_EP_Data(void);
|
||||
void send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size);
|
||||
|
||||
#ifdef USE_ESP32_S3
|
||||
int8_t par_cs;
|
||||
|
@ -278,6 +336,26 @@ class uDisplay : public Renderer {
|
|||
int8_t par_dbl[8];
|
||||
int8_t par_dbh[8];
|
||||
|
||||
int8_t de;
|
||||
int8_t vsync;
|
||||
int8_t hsync;
|
||||
int8_t pclk;
|
||||
|
||||
uint16_t hsync_polarity;
|
||||
uint16_t hsync_front_porch;
|
||||
uint16_t hsync_pulse_width;
|
||||
uint16_t hsync_back_porch;
|
||||
uint16_t vsync_polarity;
|
||||
uint16_t vsync_front_porch;
|
||||
uint16_t vsync_pulse_width;
|
||||
uint16_t vsync_back_porch;
|
||||
uint16_t pclk_active_neg;
|
||||
|
||||
esp_lcd_panel_handle_t _panel_handle = NULL;
|
||||
esp_rgb_panel_t *_rgb_panel;
|
||||
uint16_t *rgb_fb;
|
||||
|
||||
|
||||
esp_lcd_i80_bus_handle_t _i80_bus = nullptr;
|
||||
gdma_channel_handle_t _dma_chan;
|
||||
lldesc_t *_dmadesc = nullptr;
|
||||
|
@ -304,6 +382,7 @@ class uDisplay : public Renderer {
|
|||
uint8_t _align_data;
|
||||
void cs_control(bool level);
|
||||
uint32_t get_sr_touch(uint32_t xp, uint32_t xm, uint32_t yp, uint32_t ym);
|
||||
void drawPixel_RGB(int16_t x, int16_t y, uint16_t color);
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#include "Cosem.h"
|
||||
#include "lwip/def.h"
|
||||
#include "TimeLib.h"
|
||||
|
||||
|
||||
time_t decodeCosemDateTime(CosemDateTime timestamp) {
|
||||
tmElements_t tm;
|
||||
uint16_t year = ntohs(timestamp.year);
|
||||
if(year < 1970) return 0;
|
||||
tm.Year = year - 1970;
|
||||
tm.Month = timestamp.month;
|
||||
tm.Day = timestamp.dayOfMonth;
|
||||
tm.Hour = timestamp.hour;
|
||||
tm.Minute = timestamp.minute;
|
||||
tm.Second = timestamp.second;
|
||||
|
||||
//Serial.printf("\nY: %d, M: %d, D: %d, h: %d, m: %d, s: %d, deviation: 0x%2X, status: 0x%1X\n", tm.Year, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second, timestamp.deviation, timestamp.status);
|
||||
|
||||
time_t time = makeTime(tm);
|
||||
int16_t deviation = ntohs(timestamp.deviation);
|
||||
if(deviation >= -720 && deviation <= 720) {
|
||||
time -= deviation * 60;
|
||||
}
|
||||
return time;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#ifndef _COSEM_H
|
||||
#define _COSEM_H
|
||||
|
||||
#include "lwip/def.h"
|
||||
|
||||
// Blue book, Table 2
|
||||
enum CosemType {
|
||||
CosemTypeNull = 0x00,
|
||||
CosemTypeArray = 0x01,
|
||||
CosemTypeStructure = 0x02,
|
||||
CosemTypeOctetString = 0x09,
|
||||
CosemTypeString = 0x0A,
|
||||
CosemTypeDLongSigned = 0x05,
|
||||
CosemTypeDLongUnsigned = 0x06,
|
||||
CosemTypeLongSigned = 0x10,
|
||||
CosemTypeLongUnsigned = 0x12,
|
||||
CosemTypeLong64Signed = 0x14,
|
||||
CosemTypeLong64Unsigned = 0x15,
|
||||
CosemTypeDateTime = 0x19
|
||||
};
|
||||
|
||||
struct CosemBasic {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CosemString {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
uint8_t data[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CosemLongSigned {
|
||||
uint8_t type;
|
||||
int16_t data;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CosemLongUnsigned {
|
||||
uint8_t type;
|
||||
uint16_t data;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CosemDLongSigned {
|
||||
uint8_t type;
|
||||
int32_t data;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CosemDLongUnsigned {
|
||||
uint8_t type;
|
||||
uint32_t data;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CosemLong64Signed {
|
||||
uint8_t type;
|
||||
int64_t data;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CosemLong64Unsigned {
|
||||
uint8_t type;
|
||||
uint64_t data;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CosemDateTime {
|
||||
uint8_t type;
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t dayOfMonth;
|
||||
uint8_t dayOfWeek;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t hundredths;
|
||||
int16_t deviation;
|
||||
uint8_t status;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef union {
|
||||
struct CosemBasic base;
|
||||
struct CosemString str;
|
||||
struct CosemString oct;
|
||||
struct CosemLongSigned ls;
|
||||
struct CosemLongUnsigned lu;
|
||||
struct CosemDLongSigned dls;
|
||||
struct CosemDLongUnsigned dlu;
|
||||
struct CosemLong64Signed l64s;
|
||||
struct CosemLong64Unsigned l64u;
|
||||
struct CosemDateTime dt;
|
||||
} CosemData;
|
||||
|
||||
time_t decodeCosemDateTime(CosemDateTime timestamp);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _DATAPASERSER_H
|
||||
#define _DATAPASERSER_H
|
||||
|
||||
#define DATA_TAG_NONE 0x00
|
||||
#define DATA_TAG_AUTO 0x01
|
||||
#define DATA_TAG_HDLC 0x7E
|
||||
#define DATA_TAG_LLC 0xE6
|
||||
#define DATA_TAG_DLMS 0x0F
|
||||
#define DATA_TAG_DSMR 0x2F
|
||||
#define DATA_TAG_MBUS 0x68
|
||||
#define DATA_TAG_GBT 0xE0
|
||||
#define DATA_TAG_GCM 0xDB
|
||||
|
||||
#define DATA_PARSE_OK 0
|
||||
#define DATA_PARSE_FAIL -1
|
||||
#define DATA_PARSE_INCOMPLETE -2
|
||||
#define DATA_PARSE_BOUNDRY_FLAG_MISSING -3
|
||||
#define DATA_PARSE_HEADER_CHECKSUM_ERROR -4
|
||||
#define DATA_PARSE_FOOTER_CHECKSUM_ERROR -5
|
||||
#define DATA_PARSE_INTERMEDIATE_SEGMENT -6
|
||||
#define DATA_PARSE_FINAL_SEGMENT -7
|
||||
#define DATA_PARSE_UNKNOWN_DATA -9
|
||||
|
||||
struct DataParserContext {
|
||||
uint8_t type;
|
||||
uint16_t length;
|
||||
time_t timestamp;
|
||||
uint8_t system_title[8];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef _DATAPASERSERS_H
|
||||
#define _DATAPASERSERS_H
|
||||
|
||||
#include "HdlcParser.h"
|
||||
#include "DlmsParser.h"
|
||||
#include "DsmrParser.h"
|
||||
#include "MbusParser.h"
|
||||
#include "GbtParser.h"
|
||||
#include "GcmParser.h"
|
||||
#include "LlcParser.h"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#include "DlmsParser.h"
|
||||
#include "Cosem.h"
|
||||
|
||||
int8_t DLMSParser::parse(uint8_t *buf, DataParserContext &ctx) {
|
||||
if(ctx.length < 6) return DATA_PARSE_INCOMPLETE;
|
||||
|
||||
uint8_t* ptr = buf+1;
|
||||
ptr += 4; // Skip invoke ID and priority
|
||||
|
||||
CosemData* item = (CosemData*) ptr;
|
||||
if(item->base.type == CosemTypeOctetString) {
|
||||
if(item->base.length == 0x0C) {
|
||||
CosemDateTime* dateTime = (CosemDateTime*) (ptr+1);
|
||||
ctx.timestamp = decodeCosemDateTime(*dateTime);
|
||||
}
|
||||
uint8_t len = 5+14;
|
||||
ctx.length -= len;
|
||||
return len;
|
||||
} else if(item->base.type == CosemTypeNull) {
|
||||
ctx.timestamp = 0;
|
||||
uint8_t len = 5+1;
|
||||
ctx.length -= len;
|
||||
return len;
|
||||
} else if(item->base.type == CosemTypeDateTime) {
|
||||
CosemDateTime* dateTime = (CosemDateTime*) (ptr);
|
||||
ctx.timestamp = decodeCosemDateTime(*dateTime);
|
||||
uint8_t len = 5+13;
|
||||
ctx.length -= len;
|
||||
return len;
|
||||
} else if(item->base.type == 0x0C) { // Kamstrup bug...
|
||||
CosemDateTime* dateTime = (CosemDateTime*) (ptr);
|
||||
ctx.timestamp = decodeCosemDateTime(*dateTime);
|
||||
uint8_t len = 5+13;
|
||||
ctx.length -= len;
|
||||
return len;
|
||||
}
|
||||
return DATA_PARSE_UNKNOWN_DATA;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef _DLMSPARSER_H
|
||||
#define _DLMSPARSER_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "DataParser.h"
|
||||
|
||||
class DLMSParser {
|
||||
public:
|
||||
int8_t parse(uint8_t *buf, DataParserContext &ctx);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#include "DsmrParser.h"
|
||||
#include "crc.h"
|
||||
#include "hexutils.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
int8_t DSMRParser::parse(uint8_t *buf, DataParserContext &ctx, bool verified) {
|
||||
uint16_t crcPos = 0;
|
||||
bool reachedEnd = verified;
|
||||
uint8_t lastByte = 0x00;
|
||||
for(int pos = 0; pos < ctx.length; pos++) {
|
||||
uint8_t b = *(buf+pos);
|
||||
if(pos == 0 && b != '/') return DATA_PARSE_BOUNDRY_FLAG_MISSING;
|
||||
if(pos > 0 && b == '!' && lastByte == '\n') crcPos = pos+1;
|
||||
if(crcPos > 0 && b == '\n') reachedEnd = true;
|
||||
lastByte = b;
|
||||
}
|
||||
if(!reachedEnd) return DATA_PARSE_INCOMPLETE;
|
||||
buf[ctx.length+1] = '\0';
|
||||
if(crcPos > 0) {
|
||||
uint16_t crc_calc = AMS_crc16(buf, crcPos);
|
||||
uint16_t crc = 0x0000;
|
||||
AMS_fromHex((uint8_t*) &crc, String((char*) buf+crcPos), 2);
|
||||
crc = ntohs(crc);
|
||||
|
||||
if(crc != crc_calc)
|
||||
return DATA_PARSE_FOOTER_CHECKSUM_ERROR;
|
||||
}
|
||||
return DATA_PARSE_OK;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef _DSMRPARSER_H
|
||||
#define _DSMRPARSER_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "DataParser.h"
|
||||
|
||||
class DSMRParser {
|
||||
public:
|
||||
int8_t parse(uint8_t *buf, DataParserContext &ctx, bool verified);
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
#include "GbtParser.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
GBTParser::~GBTParser(void) {
|
||||
if (buf) free(buf);
|
||||
}
|
||||
|
||||
int8_t GBTParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
GBTHeader* h = (GBTHeader*) (d);
|
||||
uint16_t sequence = ntohs(h->sequence);
|
||||
|
||||
if(h->flag != GBT_TAG) return DATA_PARSE_BOUNDRY_FLAG_MISSING;
|
||||
|
||||
if(sequence == 1) {
|
||||
if(buf == NULL) buf = (uint8_t *)malloc((size_t)1024); // TODO find out from first package ?
|
||||
pos = 0;
|
||||
} else if(lastSequenceNumber != sequence-1) {
|
||||
return DATA_PARSE_FAIL;
|
||||
}
|
||||
|
||||
if(buf == NULL) return DATA_PARSE_FAIL;
|
||||
|
||||
uint8_t* ptr = (uint8_t*) &h[1];
|
||||
memcpy(buf + pos, ptr, h->size);
|
||||
pos += h->size;
|
||||
lastSequenceNumber = sequence;
|
||||
|
||||
if((h->control & 0x80) == 0x00) {
|
||||
return DATA_PARSE_INTERMEDIATE_SEGMENT;
|
||||
} else {
|
||||
memcpy((uint8_t *) d, buf, pos);
|
||||
}
|
||||
ctx.length = pos;
|
||||
return DATA_PARSE_OK;
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef _GBTPARSER_H
|
||||
#define _GBTPARSER_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "DataParser.h"
|
||||
|
||||
#define GBT_TAG 0xE0
|
||||
|
||||
typedef struct GBTHeader {
|
||||
uint8_t flag;
|
||||
uint8_t control;
|
||||
uint16_t sequence;
|
||||
uint16_t sequenceAck;
|
||||
uint8_t size;
|
||||
} __attribute__((packed)) GBTHeader;
|
||||
|
||||
class GBTParser {
|
||||
public:
|
||||
int8_t parse(uint8_t *buf, DataParserContext &ctx);
|
||||
~GBTParser(void);
|
||||
private:
|
||||
uint8_t lastSequenceNumber = 0;
|
||||
uint16_t pos = 0;
|
||||
uint8_t *buf = NULL;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,104 @@
|
|||
|
||||
#include "GcmParser.h"
|
||||
#include "tasmota_options.h"
|
||||
|
||||
#ifdef USE_TLS
|
||||
#include "lwip/def.h"
|
||||
#include <t_bearssl.h>
|
||||
|
||||
GCMParser::GCMParser(uint8_t *encryption_key, uint8_t *authentication_key) {
|
||||
memcpy(this->encryption_key, encryption_key, 16);
|
||||
memcpy(this->authentication_key, authentication_key, 16);
|
||||
use_auth = 0;
|
||||
for (uint16_t cnt = 0; cnt < 16; cnt++) {
|
||||
if (authentication_key[cnt]) {
|
||||
use_auth |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8_t GCMParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
if(ctx.length < 12) return DATA_PARSE_INCOMPLETE;
|
||||
|
||||
uint8_t* ptr = (uint8_t*) d;
|
||||
if(*ptr != GCM_TAG) return DATA_PARSE_BOUNDRY_FLAG_MISSING;
|
||||
ptr++;
|
||||
// Encrypted APDU
|
||||
// http://www.weigu.lu/tutorials/sensors2bus/04_encryption/index.html
|
||||
|
||||
uint8_t systemTitleLength = *ptr;
|
||||
ptr++;
|
||||
|
||||
uint8_t initialization_vector[12];
|
||||
memcpy(ctx.system_title, ptr, systemTitleLength);
|
||||
memcpy(initialization_vector, ctx.system_title, systemTitleLength);
|
||||
|
||||
int len = 0;
|
||||
int headersize = 2 + systemTitleLength;
|
||||
ptr += systemTitleLength;
|
||||
if(((*ptr) & 0xFF) == 0x81) {
|
||||
ptr++;
|
||||
len = *ptr;
|
||||
// 1-byte payload length
|
||||
ptr++;
|
||||
headersize += 2;
|
||||
} else if(((*ptr) & 0xFF) == 0x82) {
|
||||
GCMSizeDef* h = (GCMSizeDef*) ptr;
|
||||
|
||||
// 2-byte payload length
|
||||
len = (ntohs(h->format) & 0xFFFF);
|
||||
|
||||
ptr += 3;
|
||||
headersize += 3;
|
||||
} else if(((*ptr) & 0xFF) == 0x4f) {
|
||||
// ???????? single frame did only decode with this compare
|
||||
ptr++;
|
||||
headersize++;
|
||||
}
|
||||
if(len + headersize > ctx.length)
|
||||
return DATA_PARSE_INCOMPLETE;
|
||||
|
||||
uint8_t additional_authenticated_data[17];
|
||||
memcpy(additional_authenticated_data, ptr, 1);
|
||||
|
||||
// Security tag
|
||||
uint8_t sec = *ptr;
|
||||
ptr++;
|
||||
headersize++;
|
||||
|
||||
// Frame counter
|
||||
memcpy(initialization_vector + 8, ptr, 4);
|
||||
ptr += 4;
|
||||
headersize += 4;
|
||||
|
||||
int footersize = 0;
|
||||
|
||||
// Authentication enabled
|
||||
uint8_t authentication_tag[12];
|
||||
uint8_t authkeylen = 0, aadlen = 0;
|
||||
if((sec & 0x10) == 0x10) {
|
||||
authkeylen = 12;
|
||||
aadlen = 17;
|
||||
footersize += authkeylen;
|
||||
memcpy(additional_authenticated_data + 1, authentication_key, 16);
|
||||
memcpy(authentication_tag, ptr + len - footersize - 5, authkeylen);
|
||||
}
|
||||
|
||||
br_gcm_context gcm_ctx;
|
||||
br_aes_small_ctr_keys ctr_ctx;
|
||||
br_aes_small_ctr_init(&ctr_ctx, encryption_key, 16);
|
||||
br_gcm_init(&gcm_ctx, &ctr_ctx.vtable, &br_ghash_ctmul32);
|
||||
br_gcm_reset(&gcm_ctx, initialization_vector, 12);
|
||||
if (use_auth && authkeylen > 0) {
|
||||
br_gcm_aad_inject(&gcm_ctx, additional_authenticated_data, aadlen);
|
||||
}
|
||||
br_gcm_flip(&gcm_ctx);
|
||||
br_gcm_run(&gcm_ctx, 0, ptr , ctx.length - headersize);
|
||||
if (use_auth && authkeylen > 0 && br_gcm_check_tag_trunc(&gcm_ctx, authentication_tag, authkeylen) != 1) {
|
||||
return GCM_AUTH_FAILED;
|
||||
}
|
||||
|
||||
ctx.length -= footersize + headersize;
|
||||
return ptr - d;
|
||||
}
|
||||
#endif // USE_TLS
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef _GCMPARSER_H
|
||||
#define _GCMPARSER_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "DataParser.h"
|
||||
|
||||
#define GCM_TAG 0xDB
|
||||
#define GCM_AUTH_FAILED -51
|
||||
#define GCM_DECRYPT_FAILED -52
|
||||
#define GCM_ENCRYPTION_KEY_FAILED -53
|
||||
|
||||
typedef struct GCMSizeDef {
|
||||
uint8_t flag;
|
||||
uint16_t format;
|
||||
} __attribute__((packed)) GCMSizeDef;
|
||||
|
||||
|
||||
class GCMParser {
|
||||
public:
|
||||
GCMParser(uint8_t *encryption_key, uint8_t *authentication_key);
|
||||
int8_t parse(uint8_t *buf, DataParserContext &ctx);
|
||||
private:
|
||||
uint8_t encryption_key[16];
|
||||
uint8_t authentication_key[16];
|
||||
uint8_t use_auth = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
#include "HdlcParser.h"
|
||||
#include "lwip/def.h"
|
||||
#include "crc.h"
|
||||
|
||||
int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
int len;
|
||||
|
||||
uint8_t* ptr;
|
||||
if(ctx.length < 3)
|
||||
return DATA_PARSE_INCOMPLETE;
|
||||
|
||||
HDLCHeader* h = (HDLCHeader*) d;
|
||||
ptr = (uint8_t*) &h[1];
|
||||
|
||||
// Frame format type 3
|
||||
if((h->format & 0xF0) == 0xA0) {
|
||||
// Length field (11 lsb of format)
|
||||
len = (ntohs(h->format) & 0x7FF) + 2;
|
||||
if(len > ctx.length)
|
||||
return DATA_PARSE_INCOMPLETE;
|
||||
|
||||
HDLCFooter* f = (HDLCFooter*) (d + len - sizeof *f);
|
||||
|
||||
// First and last byte should be HDLC_FLAG
|
||||
if(h->flag != HDLC_FLAG || f->flag != HDLC_FLAG)
|
||||
return DATA_PARSE_BOUNDRY_FLAG_MISSING;
|
||||
|
||||
// Verify FCS
|
||||
if(ntohs(f->fcs) != AMS_crc16_x25(d + 1, len - sizeof *f - 1))
|
||||
return DATA_PARSE_FOOTER_CHECKSUM_ERROR;
|
||||
|
||||
// Skip destination address, LSB marks last byte
|
||||
while(((*ptr) & 0x01) == 0x00) {
|
||||
ptr++;
|
||||
}
|
||||
ptr++;
|
||||
|
||||
// Skip source address, LSB marks last byte
|
||||
while(((*ptr) & 0x01) == 0x00) {
|
||||
ptr++;
|
||||
}
|
||||
ptr++;
|
||||
|
||||
HDLC3CtrlHcs* t3 = (HDLC3CtrlHcs*) (ptr);
|
||||
|
||||
// Verify HCS
|
||||
if(ntohs(t3->hcs) != AMS_crc16_x25(d + 1, ptr-d))
|
||||
return DATA_PARSE_HEADER_CHECKSUM_ERROR;
|
||||
ptr += 3;
|
||||
|
||||
// Exclude all of header and 3 byte footer
|
||||
ctx.length -= ptr-d+3;
|
||||
return ptr-d;
|
||||
}
|
||||
return DATA_PARSE_UNKNOWN_DATA;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef _HDLCPARSER_H
|
||||
#define _HDLCPARSER_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "DataParser.h"
|
||||
|
||||
#define HDLC_FLAG 0x7E
|
||||
|
||||
typedef struct HDLCHeader {
|
||||
uint8_t flag;
|
||||
uint16_t format;
|
||||
} __attribute__((packed)) HDLCHeader;
|
||||
|
||||
typedef struct HDLCFooter {
|
||||
uint16_t fcs;
|
||||
uint8_t flag;
|
||||
} __attribute__((packed)) HDLCFooter;
|
||||
|
||||
typedef struct HDLC3CtrlHcs {
|
||||
uint8_t control;
|
||||
uint16_t hcs;
|
||||
} __attribute__((packed)) HDLC3CtrlHcs;
|
||||
|
||||
class HDLCParser {
|
||||
public:
|
||||
int8_t parse(uint8_t *buf, DataParserContext &ctx);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
#include "LlcParser.h"
|
||||
|
||||
int8_t LLCParser::parse(uint8_t *buf, DataParserContext &ctx) {
|
||||
ctx.length -= 3;
|
||||
return 3;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _LLCPARSER_H
|
||||
#define _LLCPARSER_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "DataParser.h"
|
||||
|
||||
typedef struct LLCHeader {
|
||||
uint8_t dst;
|
||||
uint8_t src;
|
||||
uint8_t control;
|
||||
} __attribute__((packed)) LLCHeader;
|
||||
|
||||
class LLCParser {
|
||||
public:
|
||||
int8_t parse(uint8_t *buf, DataParserContext &ctx);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,91 @@
|
|||
#include "MbusParser.h"
|
||||
|
||||
|
||||
MBUSParser::~MBUSParser(void) {
|
||||
if (buf) free(buf);
|
||||
}
|
||||
int8_t MBUSParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
int len;
|
||||
int headersize = 3;
|
||||
int footersize = 1;
|
||||
|
||||
uint8_t* ptr;
|
||||
|
||||
// https://m-bus.com/documentation-wired/06-application-layer
|
||||
if(ctx.length < 4)
|
||||
return DATA_PARSE_INCOMPLETE;
|
||||
|
||||
MbusHeader* mh = (MbusHeader*) d;
|
||||
if(mh->flag1 != MBUS_START || mh->flag2 != MBUS_START)
|
||||
return DATA_PARSE_BOUNDRY_FLAG_MISSING;
|
||||
|
||||
// First two bytes is 1-byte length value repeated. Only used for last segment
|
||||
if(mh->len1 != mh->len2)
|
||||
return MBUS_FRAME_LENGTH_NOT_EQUAL;
|
||||
len = mh->len1;
|
||||
ptr = (uint8_t*) &mh[1];
|
||||
headersize = 4;
|
||||
footersize = 2;
|
||||
|
||||
if(len == 0x00)
|
||||
len = ctx.length - headersize - footersize;
|
||||
// Payload can max be 255 bytes, so I think the following case is only valid for austrian meters
|
||||
if(len < headersize)
|
||||
len += 256;
|
||||
|
||||
if((headersize + footersize + len) > ctx.length)
|
||||
return DATA_PARSE_INCOMPLETE;
|
||||
|
||||
MbusFooter* mf = (MbusFooter*) (d + len + headersize);
|
||||
if(mf->flag != MBUS_END)
|
||||
return DATA_PARSE_BOUNDRY_FLAG_MISSING;
|
||||
if(checksum(d + headersize, len) != mf->fcs)
|
||||
return DATA_PARSE_FOOTER_CHECKSUM_ERROR;
|
||||
|
||||
ptr += 2; len -= 2;
|
||||
|
||||
// Control information field
|
||||
uint8_t ci = *ptr;
|
||||
|
||||
// Skip CI, STSAP and DTSAP
|
||||
ptr += 3; len -= 3;
|
||||
|
||||
// Bits 7 6 5 4 3 2 1 0
|
||||
// 0 0 0 Finished Sequence number
|
||||
uint8_t sequenceNumber = (ci & 0x0F);
|
||||
if((ci & 0x10) == 0x00) { // Not finished yet
|
||||
if(sequenceNumber == 0) {
|
||||
if(buf == NULL) buf = (uint8_t *)malloc((size_t)1024); // TODO find out from first package ?
|
||||
pos = 0;
|
||||
} else if(buf == NULL || pos + len > 1024 || sequenceNumber != (lastSequenceNumber + 1)) {
|
||||
return DATA_PARSE_FAIL;
|
||||
}
|
||||
memcpy(buf+pos, ptr, len);
|
||||
pos += len;
|
||||
lastSequenceNumber = sequenceNumber;
|
||||
return DATA_PARSE_INTERMEDIATE_SEGMENT;
|
||||
} else if(sequenceNumber > 0) { // This is the last frame of multiple, assembly needed
|
||||
if(buf == NULL || pos + len > 1024 || sequenceNumber != (lastSequenceNumber + 1)) {
|
||||
return DATA_PARSE_FAIL;
|
||||
}
|
||||
memcpy(buf+pos, ptr, len);
|
||||
pos += len;
|
||||
return DATA_PARSE_FINAL_SEGMENT;
|
||||
}
|
||||
return ptr-d;
|
||||
}
|
||||
|
||||
uint16_t MBUSParser::write(const uint8_t* d, DataParserContext &ctx) {
|
||||
if(buf != NULL) {
|
||||
memcpy((uint8_t *) d, buf, pos);
|
||||
ctx.length = pos;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t MBUSParser::checksum(const uint8_t* p, int len) {
|
||||
uint8_t ret = 0;
|
||||
while(len--)
|
||||
ret += *p++;
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef _MBUSPARSER_H
|
||||
#define _MBUSPARSER_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "DataParser.h"
|
||||
|
||||
#define MBUS_START 0x68
|
||||
#define MBUS_END 0x16
|
||||
#define MBUS_FRAME_LENGTH_NOT_EQUAL -41
|
||||
|
||||
typedef struct MbusHeader {
|
||||
uint8_t flag1;
|
||||
uint8_t len1;
|
||||
uint8_t len2;
|
||||
uint8_t flag2;
|
||||
} __attribute__((packed)) MbusHeader;
|
||||
|
||||
typedef struct MbusFooter {
|
||||
uint8_t fcs;
|
||||
uint8_t flag;
|
||||
} __attribute__((packed)) MbusFooter;
|
||||
|
||||
class MBUSParser {
|
||||
public:
|
||||
int8_t parse(uint8_t *buf, DataParserContext &ctx);
|
||||
~MBUSParser(void);
|
||||
uint16_t write(const uint8_t* d, DataParserContext &ctx);
|
||||
private:
|
||||
uint8_t lastSequenceNumber = 0;
|
||||
uint16_t pos = 0;
|
||||
uint8_t *buf = NULL;
|
||||
uint8_t checksum(const uint8_t* p, int len);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
time.c - low level time and date functions
|
||||
Copyright (c) Michael Margolis 2009-2014
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
1.0 6 Jan 2010 - initial release
|
||||
1.1 12 Feb 2010 - fixed leap year calculation error
|
||||
1.2 1 Nov 2010 - fixed setTime bug (thanks to Korman for this)
|
||||
1.3 24 Mar 2012 - many edits by Paul Stoffregen: fixed timeStatus() to update
|
||||
status, updated examples for Arduino 1.0, fixed ARM
|
||||
compatibility issues, added TimeArduinoDue and TimeTeensy3
|
||||
examples, add error checking and messages to RTC examples,
|
||||
add examples to DS1307RTC library.
|
||||
1.4 5 Sep 2014 - compatibility with Arduino 1.5.7
|
||||
*/
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include "TimeLib.h"
|
||||
|
||||
static tmElements_t tm; // a cache of time elements
|
||||
static time_t cacheTime; // the time the cache was updated
|
||||
static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds
|
||||
|
||||
void refreshCache(time_t t) {
|
||||
if (t != cacheTime) {
|
||||
breakTime(t, tm);
|
||||
cacheTime = t;
|
||||
}
|
||||
}
|
||||
|
||||
int hour() { // the hour now
|
||||
return hour(now());
|
||||
}
|
||||
|
||||
int hour(time_t t) { // the hour for the given time
|
||||
refreshCache(t);
|
||||
return tm.Hour;
|
||||
}
|
||||
|
||||
int hourFormat12() { // the hour now in 12 hour format
|
||||
return hourFormat12(now());
|
||||
}
|
||||
|
||||
int hourFormat12(time_t t) { // the hour for the given time in 12 hour format
|
||||
refreshCache(t);
|
||||
if( tm.Hour == 0 )
|
||||
return 12; // 12 midnight
|
||||
else if( tm.Hour > 12)
|
||||
return tm.Hour - 12 ;
|
||||
else
|
||||
return tm.Hour ;
|
||||
}
|
||||
|
||||
uint8_t isAM() { // returns true if time now is AM
|
||||
return !isPM(now());
|
||||
}
|
||||
|
||||
uint8_t isAM(time_t t) { // returns true if given time is AM
|
||||
return !isPM(t);
|
||||
}
|
||||
|
||||
uint8_t isPM() { // returns true if PM
|
||||
return isPM(now());
|
||||
}
|
||||
|
||||
uint8_t isPM(time_t t) { // returns true if PM
|
||||
return (hour(t) >= 12);
|
||||
}
|
||||
|
||||
int minute() {
|
||||
return minute(now());
|
||||
}
|
||||
|
||||
int minute(time_t t) { // the minute for the given time
|
||||
refreshCache(t);
|
||||
return tm.Minute;
|
||||
}
|
||||
|
||||
int second() {
|
||||
return second(now());
|
||||
}
|
||||
|
||||
int second(time_t t) { // the second for the given time
|
||||
refreshCache(t);
|
||||
return tm.Second;
|
||||
}
|
||||
|
||||
int day(){
|
||||
return(day(now()));
|
||||
}
|
||||
|
||||
int day(time_t t) { // the day for the given time (0-6)
|
||||
refreshCache(t);
|
||||
return tm.Day;
|
||||
}
|
||||
|
||||
int weekday() { // Sunday is day 1
|
||||
return weekday(now());
|
||||
}
|
||||
|
||||
int weekday(time_t t) {
|
||||
refreshCache(t);
|
||||
return tm.Wday;
|
||||
}
|
||||
|
||||
int month(){
|
||||
return month(now());
|
||||
}
|
||||
|
||||
int month(time_t t) { // the month for the given time
|
||||
refreshCache(t);
|
||||
return tm.Month;
|
||||
}
|
||||
|
||||
int year() { // as in Processing, the full four digit year: (2009, 2010 etc)
|
||||
return year(now());
|
||||
}
|
||||
|
||||
int year(time_t t) { // the year for the given time
|
||||
refreshCache(t);
|
||||
return tmYearToCalendar(tm.Year);
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
/* functions to convert to and from system time */
|
||||
/* These are for interfacing with time services and are not normally needed in a sketch */
|
||||
|
||||
// leap year calculator expects year argument as years offset from 1970
|
||||
#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) )
|
||||
|
||||
static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0
|
||||
|
||||
void breakTime(time_t timeInput, tmElements_t &tm){
|
||||
// break the given time_t into time components
|
||||
// this is a more compact version of the C library localtime function
|
||||
// note that year is offset from 1970 !!!
|
||||
|
||||
uint8_t year;
|
||||
uint8_t month, monthLength;
|
||||
uint32_t time;
|
||||
unsigned long days;
|
||||
|
||||
time = (uint32_t)timeInput;
|
||||
tm.Second = time % 60;
|
||||
time /= 60; // now it is minutes
|
||||
tm.Minute = time % 60;
|
||||
time /= 60; // now it is hours
|
||||
tm.Hour = time % 24;
|
||||
time /= 24; // now it is days
|
||||
tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1
|
||||
|
||||
year = 0;
|
||||
days = 0;
|
||||
while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
|
||||
year++;
|
||||
}
|
||||
tm.Year = year; // year is offset from 1970
|
||||
|
||||
days -= LEAP_YEAR(year) ? 366 : 365;
|
||||
time -= days; // now it is days in this year, starting at 0
|
||||
|
||||
days=0;
|
||||
month=0;
|
||||
monthLength=0;
|
||||
for (month=0; month<12; month++) {
|
||||
if (month==1) { // february
|
||||
if (LEAP_YEAR(year)) {
|
||||
monthLength=29;
|
||||
} else {
|
||||
monthLength=28;
|
||||
}
|
||||
} else {
|
||||
monthLength = monthDays[month];
|
||||
}
|
||||
|
||||
if (time >= monthLength) {
|
||||
time -= monthLength;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tm.Month = month + 1; // jan is month 1
|
||||
tm.Day = time + 1; // day of month
|
||||
}
|
||||
|
||||
time_t makeTime(const tmElements_t &tm){
|
||||
// assemble time elements into time_t
|
||||
// note year argument is offset from 1970 (see macros in time.h to convert to other formats)
|
||||
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
|
||||
|
||||
int i;
|
||||
uint32_t seconds;
|
||||
|
||||
// seconds from 1970 till 1 jan 00:00:00 of the given year
|
||||
seconds= tm.Year*(SECS_PER_DAY * 365);
|
||||
for (i = 0; i < tm.Year; i++) {
|
||||
if (LEAP_YEAR(i)) {
|
||||
seconds += SECS_PER_DAY; // add extra days for leap years
|
||||
}
|
||||
}
|
||||
|
||||
// add days for this year, months start from 1
|
||||
for (i = 1; i < tm.Month; i++) {
|
||||
if ( (i == 2) && LEAP_YEAR(tm.Year)) {
|
||||
seconds += SECS_PER_DAY * 29;
|
||||
} else {
|
||||
seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0
|
||||
}
|
||||
}
|
||||
seconds+= (tm.Day-1) * SECS_PER_DAY;
|
||||
seconds+= tm.Hour * SECS_PER_HOUR;
|
||||
seconds+= tm.Minute * SECS_PER_MIN;
|
||||
seconds+= tm.Second;
|
||||
return (time_t)seconds;
|
||||
}
|
||||
/*=====================================================*/
|
||||
/* Low level system time functions */
|
||||
|
||||
static uint32_t sysTime = 0;
|
||||
static uint32_t prevMillis = 0;
|
||||
static uint32_t nextSyncTime = 0;
|
||||
static timeStatus_t Status = timeNotSet;
|
||||
|
||||
getExternalTime getTimePtr; // pointer to external sync function
|
||||
//setExternalTime setTimePtr; // not used in this version
|
||||
|
||||
#ifdef TIME_DRIFT_INFO // define this to get drift data
|
||||
time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync
|
||||
#endif
|
||||
|
||||
|
||||
time_t now() {
|
||||
// calculate number of seconds passed since last call to now()
|
||||
while (millis() - prevMillis >= 1000) {
|
||||
// millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference
|
||||
sysTime++;
|
||||
prevMillis += 1000;
|
||||
#ifdef TIME_DRIFT_INFO
|
||||
sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift
|
||||
#endif
|
||||
}
|
||||
if (nextSyncTime <= sysTime) {
|
||||
if (getTimePtr != 0) {
|
||||
time_t t = getTimePtr();
|
||||
if (t != 0) {
|
||||
setTime(t);
|
||||
} else {
|
||||
nextSyncTime = sysTime + syncInterval;
|
||||
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (time_t)sysTime;
|
||||
}
|
||||
|
||||
void setTime(time_t t) {
|
||||
#ifdef TIME_DRIFT_INFO
|
||||
if(sysUnsyncedTime == 0)
|
||||
sysUnsyncedTime = t; // store the time of the first call to set a valid Time
|
||||
#endif
|
||||
|
||||
sysTime = (uint32_t)t;
|
||||
nextSyncTime = (uint32_t)t + syncInterval;
|
||||
Status = timeSet;
|
||||
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
||||
}
|
||||
|
||||
void setTime(int hr,int min,int sec,int dy, int mnth, int yr){
|
||||
// year can be given as full four digit year or two digts (2010 or 10 for 2010);
|
||||
//it is converted to years since 1970
|
||||
if( yr > 99)
|
||||
yr = yr - 1970;
|
||||
else
|
||||
yr += 30;
|
||||
tm.Year = yr;
|
||||
tm.Month = mnth;
|
||||
tm.Day = dy;
|
||||
tm.Hour = hr;
|
||||
tm.Minute = min;
|
||||
tm.Second = sec;
|
||||
setTime(makeTime(tm));
|
||||
}
|
||||
|
||||
void adjustTime(long adjustment) {
|
||||
sysTime += adjustment;
|
||||
}
|
||||
|
||||
// indicates if time has been set and recently synchronized
|
||||
timeStatus_t timeStatus() {
|
||||
now(); // required to actually update the status
|
||||
return Status;
|
||||
}
|
||||
|
||||
void setSyncProvider( getExternalTime getTimeFunction){
|
||||
getTimePtr = getTimeFunction;
|
||||
nextSyncTime = sysTime;
|
||||
now(); // this will sync the clock
|
||||
}
|
||||
|
||||
void setSyncInterval(time_t interval){ // set the number of seconds between re-sync
|
||||
syncInterval = (uint32_t)interval;
|
||||
nextSyncTime = sysTime + syncInterval;
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
time.h - low level time and date functions
|
||||
*/
|
||||
|
||||
/*
|
||||
July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this)
|
||||
- fixed daysToTime_t macro (thanks maniacbug)
|
||||
*/
|
||||
|
||||
#ifndef _Time_h
|
||||
#ifdef __cplusplus
|
||||
#define _Time_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#ifndef __AVR__
|
||||
#include <sys/types.h> // for __time_t_defined, but avr libc lacks sys/types.h
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc
|
||||
typedef unsigned long time_t;
|
||||
#endif
|
||||
|
||||
|
||||
// This ugly hack allows us to define C++ overloaded functions, when included
|
||||
// from within an extern "C", as newlib's sys/stat.h does. Actually it is
|
||||
// intended to include "time.h" from the C library (on ARM, but AVR does not
|
||||
// have that file at all). On Mac and Windows, the compiler will find this
|
||||
// "Time.h" instead of the C library "time.h", so we may cause other weird
|
||||
// and unpredictable effects by conflicting with the C library header "time.h",
|
||||
// but at least this hack lets us define C++ functions as intended. Hopefully
|
||||
// nothing too terrible will result from overriding the C library header?!
|
||||
extern "C++" {
|
||||
typedef enum {timeNotSet, timeNeedsSync, timeSet
|
||||
} timeStatus_t ;
|
||||
|
||||
typedef enum {
|
||||
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday
|
||||
} timeDayOfWeek_t;
|
||||
|
||||
typedef enum {
|
||||
tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields
|
||||
} tmByteFields;
|
||||
|
||||
typedef struct {
|
||||
uint8_t Second;
|
||||
uint8_t Minute;
|
||||
uint8_t Hour;
|
||||
uint8_t Wday; // day of week, sunday is day 1
|
||||
uint8_t Day;
|
||||
uint8_t Month;
|
||||
uint8_t Year; // offset from 1970;
|
||||
} tmElements_t, TimeElements, *tmElementsPtr_t;
|
||||
|
||||
//convenience macros to convert to and from tm years
|
||||
#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year
|
||||
#define CalendarYrToTm(Y) ((Y) - 1970)
|
||||
#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000
|
||||
#define y2kYearToTm(Y) ((Y) + 30)
|
||||
|
||||
typedef time_t(*getExternalTime)();
|
||||
//typedef void (*setExternalTime)(const time_t); // not used in this version
|
||||
|
||||
|
||||
/*==============================================================================*/
|
||||
/* Useful Constants */
|
||||
#define SECS_PER_MIN ((time_t)(60UL))
|
||||
#define SECS_PER_HOUR ((time_t)(3600UL))
|
||||
#define SECS_PER_DAY ((time_t)(SECS_PER_HOUR * 24UL))
|
||||
#define DAYS_PER_WEEK ((time_t)(7UL))
|
||||
#define SECS_PER_WEEK ((time_t)(SECS_PER_DAY * DAYS_PER_WEEK))
|
||||
#define SECS_PER_YEAR ((time_t)(SECS_PER_DAY * 365UL)) // TODO: ought to handle leap years
|
||||
#define SECS_YR_2000 ((time_t)(946684800UL)) // the time at the start of y2k
|
||||
|
||||
/* Useful Macros for getting elapsed time */
|
||||
#define numberOfSeconds(_time_) ((_time_) % SECS_PER_MIN)
|
||||
#define numberOfMinutes(_time_) (((_time_) / SECS_PER_MIN) % SECS_PER_MIN)
|
||||
#define numberOfHours(_time_) (((_time_) % SECS_PER_DAY) / SECS_PER_HOUR)
|
||||
#define dayOfWeek(_time_) ((((_time_) / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday
|
||||
#define elapsedDays(_time_) ((_time_) / SECS_PER_DAY) // this is number of days since Jan 1 1970
|
||||
#define elapsedSecsToday(_time_) ((_time_) % SECS_PER_DAY) // the number of seconds since last midnight
|
||||
// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971
|
||||
// Always set the correct time before setting alarms
|
||||
#define previousMidnight(_time_) (((_time_) / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day
|
||||
#define nextMidnight(_time_) (previousMidnight(_time_) + SECS_PER_DAY) // time at the end of the given day
|
||||
#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY)) // note that week starts on day 1
|
||||
#define previousSunday(_time_) ((_time_) - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time
|
||||
#define nextSunday(_time_) (previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time
|
||||
|
||||
|
||||
/* Useful Macros for converting elapsed time to a time_t */
|
||||
#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN)
|
||||
#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR)
|
||||
#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011
|
||||
#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK)
|
||||
|
||||
/*============================================================================*/
|
||||
/* time and date functions */
|
||||
int hour(); // the hour now
|
||||
int hour(time_t t); // the hour for the given time
|
||||
int hourFormat12(); // the hour now in 12 hour format
|
||||
int hourFormat12(time_t t); // the hour for the given time in 12 hour format
|
||||
uint8_t isAM(); // returns true if time now is AM
|
||||
uint8_t isAM(time_t t); // returns true the given time is AM
|
||||
uint8_t isPM(); // returns true if time now is PM
|
||||
uint8_t isPM(time_t t); // returns true the given time is PM
|
||||
int minute(); // the minute now
|
||||
int minute(time_t t); // the minute for the given time
|
||||
int second(); // the second now
|
||||
int second(time_t t); // the second for the given time
|
||||
int day(); // the day now
|
||||
int day(time_t t); // the day for the given time
|
||||
int weekday(); // the weekday now (Sunday is day 1)
|
||||
int weekday(time_t t); // the weekday for the given time
|
||||
int month(); // the month now (Jan is month 1)
|
||||
int month(time_t t); // the month for the given time
|
||||
int year(); // the full four digit year: (2009, 2010 etc)
|
||||
int year(time_t t); // the year for the given time
|
||||
|
||||
time_t now(); // return the current time as seconds since Jan 1 1970
|
||||
void setTime(time_t t);
|
||||
void setTime(int hr,int min,int sec,int day, int month, int yr);
|
||||
void adjustTime(long adjustment);
|
||||
|
||||
/* date strings */
|
||||
#define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null)
|
||||
char* monthStr(uint8_t month);
|
||||
char* dayStr(uint8_t day);
|
||||
char* monthShortStr(uint8_t month);
|
||||
char* dayShortStr(uint8_t day);
|
||||
|
||||
/* time sync functions */
|
||||
timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized
|
||||
void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider
|
||||
void setSyncInterval(time_t interval); // set the number of seconds between re-sync
|
||||
|
||||
/* low level functions to convert to and from system time */
|
||||
void breakTime(time_t time, tmElements_t &tm); // break time_t into elements
|
||||
time_t makeTime(const tmElements_t &tm); // convert time elements into time_t
|
||||
|
||||
} // extern "C++"
|
||||
#endif // __cplusplus
|
||||
#endif /* _Time_h */
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#include "crc.h"
|
||||
|
||||
uint16_t AMS_crc16_x25(const uint8_t* p, int len)
|
||||
{
|
||||
uint16_t crc = UINT16_MAX;
|
||||
|
||||
while(len--)
|
||||
for (uint16_t i = 0, d = 0xff & *p++; i < 8; i++, d >>= 1)
|
||||
crc = ((crc & 1) ^ (d & 1)) ? (crc >> 1) ^ 0x8408 : (crc >> 1);
|
||||
|
||||
return (~crc << 8) | (~crc >> 8 & 0xff);
|
||||
}
|
||||
|
||||
uint16_t AMS_crc16 (const uint8_t *p, int len) {
|
||||
uint16_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
int i;
|
||||
crc ^= *p++;
|
||||
for (i = 0 ; i < 8 ; ++i) {
|
||||
if (crc & 1)
|
||||
crc = (crc >> 1) ^ 0xa001;
|
||||
else
|
||||
crc = (crc >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef _CRC_H
|
||||
#define _CRC_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t AMS_crc16(const uint8_t* p, int len);
|
||||
uint16_t AMS_crc16_x25(const uint8_t* p, int len);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,273 @@
|
|||
#include "han_Parser.h"
|
||||
#include "Cosem.h"
|
||||
|
||||
|
||||
extern int SML_print(const char *, ...);
|
||||
#define han_debug SML_print
|
||||
|
||||
|
||||
Han_Parser::Han_Parser(uint16_t (dp)(uint8_t, uint8_t), uint8_t m, uint8_t *key, uint8_t *auth) {
|
||||
dispatch = dp;
|
||||
meter = m;
|
||||
memmove(encryptionKey, key, 16);
|
||||
if (auth) {
|
||||
memmove(authenticationKey, auth, 16);
|
||||
} else {
|
||||
memset(authenticationKey, 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
Han_Parser::~Han_Parser(void) {
|
||||
if (hdlcParser) delete hdlcParser;
|
||||
if (mbusParser) delete mbusParser;
|
||||
if (gbtParser) delete gbtParser;
|
||||
if (gcmParser) delete gcmParser;
|
||||
if (llcParser) delete llcParser;
|
||||
if (dlmsParser) delete dlmsParser;
|
||||
if (dsmrParser) delete dsmrParser;
|
||||
}
|
||||
|
||||
int Han_Parser::serial_available(void) {
|
||||
return dispatch(meter, 0);
|
||||
}
|
||||
int Han_Parser::serial_read(void) {
|
||||
return dispatch(meter, 1);
|
||||
}
|
||||
|
||||
int16_t Han_Parser::serial_readBytes(uint8_t *buf, uint16_t size) {
|
||||
if (size > serial_available()) {
|
||||
size = serial_available();
|
||||
}
|
||||
for (uint16_t cnt = 0; cnt < size; cnt++) {
|
||||
buf[cnt] = serial_read();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool Han_Parser::readHanPort(uint8_t **out, uint16_t *size) {
|
||||
|
||||
if (!serial_available()) return false;
|
||||
|
||||
// Before reading, empty serial buffer to increase chance of getting first byte of a data transfer
|
||||
if (!serialInit) {
|
||||
serial_readBytes(hanBuffer, BUF_SIZE_HAN);
|
||||
serialInit = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
DataParserContext ctx = {0};
|
||||
int pos = DATA_PARSE_INCOMPLETE;
|
||||
// For each byte received, check if we have a complete frame we can handle
|
||||
while (serial_available() && pos == DATA_PARSE_INCOMPLETE) {
|
||||
yield();
|
||||
// If buffer was overflowed, reset
|
||||
if (len >= BUF_SIZE_HAN) {
|
||||
serial_readBytes(hanBuffer, BUF_SIZE_HAN);
|
||||
len = 0;
|
||||
han_debug(PSTR("Buffer overflow, resetting"));
|
||||
return false;
|
||||
}
|
||||
hanBuffer[len++] = serial_read();
|
||||
ctx.length = len;
|
||||
pos = unwrapData((uint8_t *) hanBuffer, ctx);
|
||||
if(ctx.type > 0 && pos >= 0) {
|
||||
if(ctx.type == DATA_TAG_DLMS) {
|
||||
han_debug(PSTR("Received valid DLMS at %d"), pos);
|
||||
} else if(ctx.type == DATA_TAG_DSMR) {
|
||||
han_debug(PSTR("Received valid DSMR at %d"), pos);
|
||||
} else {
|
||||
// TODO: Move this so that payload is sent to MQTT
|
||||
han_debug(PSTR("Unknown tag %02X at pos %d"), ctx.type, pos);
|
||||
len = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pos == DATA_PARSE_INCOMPLETE) {
|
||||
return false;
|
||||
} else if(pos == DATA_PARSE_UNKNOWN_DATA) {
|
||||
han_debug(PSTR("Unknown data payload:"));
|
||||
len = len + serial_readBytes(hanBuffer + len, BUF_SIZE_HAN - len);
|
||||
//debugPrint(hanBuffer, 0, len);
|
||||
len = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pos == DATA_PARSE_INTERMEDIATE_SEGMENT) {
|
||||
len = 0;
|
||||
return false;
|
||||
} else if (pos < 0) {
|
||||
printHanReadError(pos);
|
||||
len += serial_readBytes(hanBuffer + len, BUF_SIZE_HAN - len);
|
||||
while (serial_available()) serial_read(); // Make sure it is all empty, in case we overflowed buffer above
|
||||
len = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Data is valid, clear the rest of the buffer to avoid tainted parsing
|
||||
for (int i = pos + ctx.length; i < BUF_SIZE_HAN; i++) {
|
||||
hanBuffer[i] = 0x00;
|
||||
}
|
||||
|
||||
//AmsData data;
|
||||
char* payload = ((char *) (hanBuffer)) + pos;
|
||||
if (ctx.type == DATA_TAG_DLMS) {
|
||||
han_debug(PSTR("Using application data:"));
|
||||
|
||||
//if (Debug.isActive(RemoteDebug::VERBOSE)) debugPrint((byte*) payload, 0, ctx.length);
|
||||
|
||||
// Rudimentary detector for L&G proprietary format
|
||||
if (payload[0] == CosemTypeStructure && payload[2] == CosemTypeArray && payload[1] == payload[3]) {
|
||||
//data = LNG(payload, meterState.getMeterType(), &meterConfig, ctx, &Debug);
|
||||
} else {
|
||||
// TODO: Split IEC6205675 into DataParserKaifa and DataParserObis. This way we can add other means of parsing, for those other proprietary formats
|
||||
//data = IEC6205675(payload, meterState.getMeterType(), &meterConfig, ctx);
|
||||
}
|
||||
} else if(ctx.type == DATA_TAG_DSMR) {
|
||||
//data = IEC6205621(payload);
|
||||
}
|
||||
|
||||
*out = hanBuffer + pos;
|
||||
*size = ctx.length;
|
||||
len = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int16_t Han_Parser::unwrapData(uint8_t *buf, DataParserContext &context) {
|
||||
int16_t ret = 0;
|
||||
bool doRet = false;
|
||||
uint16_t end = BUF_SIZE_HAN;
|
||||
uint8_t tag = (*buf);
|
||||
uint8_t lastTag = DATA_TAG_NONE;
|
||||
while (tag != DATA_TAG_NONE) {
|
||||
int16_t curLen = context.length;
|
||||
int8_t res = 0;
|
||||
switch(tag) {
|
||||
case DATA_TAG_HDLC:
|
||||
if (hdlcParser == NULL) hdlcParser = new HDLCParser();
|
||||
res = hdlcParser->parse(buf, context);
|
||||
break;
|
||||
case DATA_TAG_MBUS:
|
||||
if (mbusParser == NULL) mbusParser = new MBUSParser();
|
||||
res = mbusParser->parse(buf, context);
|
||||
break;
|
||||
case DATA_TAG_GBT:
|
||||
if (gbtParser == NULL) gbtParser = new GBTParser();
|
||||
res = gbtParser->parse(buf, context);
|
||||
break;
|
||||
case DATA_TAG_GCM:
|
||||
if (gcmParser == NULL) gcmParser = new GCMParser(encryptionKey, authenticationKey);
|
||||
res = gcmParser->parse(buf, context);
|
||||
break;
|
||||
case DATA_TAG_LLC:
|
||||
if (llcParser == NULL) llcParser = new LLCParser();
|
||||
res = llcParser->parse(buf, context);
|
||||
break;
|
||||
case DATA_TAG_DLMS:
|
||||
if (dlmsParser == NULL) dlmsParser = new DLMSParser();
|
||||
res = dlmsParser->parse(buf, context);
|
||||
if (res >= 0) doRet = true;
|
||||
break;
|
||||
case DATA_TAG_DSMR:
|
||||
if (dsmrParser == NULL) dsmrParser = new DSMRParser();
|
||||
res = dsmrParser->parse(buf, context, lastTag != DATA_TAG_NONE);
|
||||
if (res >= 0) doRet = true;
|
||||
break;
|
||||
default:
|
||||
han_debug(PSTR("Ended up in default case while unwrapping...(tag %02X)"), tag);
|
||||
return DATA_PARSE_UNKNOWN_DATA;
|
||||
}
|
||||
lastTag = tag;
|
||||
if (res == DATA_PARSE_INCOMPLETE) {
|
||||
return res;
|
||||
}
|
||||
if (context.length > end) return false;
|
||||
if (Debug) {
|
||||
switch(tag) {
|
||||
case DATA_TAG_HDLC:
|
||||
han_debug(PSTR("HDLC frame:"));
|
||||
break;
|
||||
case DATA_TAG_MBUS:
|
||||
han_debug(PSTR("MBUS frame:"));
|
||||
break;
|
||||
case DATA_TAG_GBT:
|
||||
han_debug(PSTR("GBT frame:"));
|
||||
break;
|
||||
case DATA_TAG_GCM:
|
||||
han_debug(PSTR("GCM frame:"));
|
||||
break;
|
||||
case DATA_TAG_LLC:
|
||||
han_debug(PSTR("LLC frame:"));
|
||||
break;
|
||||
case DATA_TAG_DLMS:
|
||||
han_debug(PSTR("DLMS frame:"));
|
||||
break;
|
||||
case DATA_TAG_DSMR:
|
||||
han_debug(PSTR("DSMR frame:"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res == DATA_PARSE_FINAL_SEGMENT) {
|
||||
if (tag == DATA_TAG_MBUS) {
|
||||
res = mbusParser->write(buf, context);
|
||||
}
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
buf += res;
|
||||
end -= res;
|
||||
ret += res;
|
||||
|
||||
// If we are ready to return, do that
|
||||
if (doRet) {
|
||||
context.type = tag;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Use start byte of new buffer position as tag for next round in loop
|
||||
tag = (*buf);
|
||||
}
|
||||
han_debug(PSTR("Got to end of unwrap method..."));
|
||||
return DATA_PARSE_UNKNOWN_DATA;
|
||||
}
|
||||
|
||||
void Han_Parser::printHanReadError(int16_t pos) {
|
||||
switch(pos) {
|
||||
case DATA_PARSE_BOUNDRY_FLAG_MISSING:
|
||||
han_debug(PSTR("Boundry flag missing"));
|
||||
break;
|
||||
case DATA_PARSE_HEADER_CHECKSUM_ERROR:
|
||||
han_debug(PSTR("Header checksum error"));
|
||||
break;
|
||||
case DATA_PARSE_FOOTER_CHECKSUM_ERROR:
|
||||
han_debug(PSTR("Frame checksum error"));
|
||||
break;
|
||||
case DATA_PARSE_INCOMPLETE:
|
||||
han_debug(PSTR("Received frame is incomplete"));
|
||||
break;
|
||||
case GCM_AUTH_FAILED:
|
||||
han_debug(PSTR("Decrypt authentication failed"));
|
||||
break;
|
||||
case GCM_ENCRYPTION_KEY_FAILED:
|
||||
han_debug(PSTR("Setting decryption key failed"));
|
||||
break;
|
||||
case GCM_DECRYPT_FAILED:
|
||||
han_debug(PSTR("Decryption failed"));
|
||||
break;
|
||||
case MBUS_FRAME_LENGTH_NOT_EQUAL:
|
||||
han_debug(PSTR("Frame length mismatch"));
|
||||
break;
|
||||
case DATA_PARSE_INTERMEDIATE_SEGMENT:
|
||||
han_debug(PSTR("Intermediate segment received"));
|
||||
break;
|
||||
case DATA_PARSE_UNKNOWN_DATA:
|
||||
han_debug(PSTR("Unknown data format %02X"), hanBuffer[0]);
|
||||
break;
|
||||
default:
|
||||
han_debug(PSTR("Unspecified error while reading data: %d"), pos);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
#ifndef _HAN_PARSER_H
|
||||
#define _HAN_PARSER_H
|
||||
#if defined __cplusplus
|
||||
#include "Arduino.h"
|
||||
#include "DataParsers.h"
|
||||
#include "DataParser.h"
|
||||
#include "Cosem.h"
|
||||
#include "ntohll.h"
|
||||
|
||||
#define BUF_SIZE_HAN (1280)
|
||||
|
||||
int16_t serial_available(void);
|
||||
uint8_t serial_read(void);
|
||||
|
||||
class Han_Parser
|
||||
{
|
||||
public:
|
||||
Han_Parser(uint16_t (*)(uint8_t, uint8_t), uint8_t, uint8_t *, uint8_t *);
|
||||
~Han_Parser(void);
|
||||
bool readHanPort(uint8_t **out, uint16_t *size);
|
||||
int16_t unwrapData(uint8_t *buf, DataParserContext &context);
|
||||
void printHanReadError(int16_t pos);
|
||||
uint8_t encryptionKey[16];
|
||||
uint8_t authenticationKey[16];
|
||||
uint8_t hanBuffer[BUF_SIZE_HAN];
|
||||
int len = 0;
|
||||
private:
|
||||
uint16_t (*dispatch)(uint8_t, uint8_t);
|
||||
int serial_available(void);
|
||||
int serial_read(void);
|
||||
int16_t serial_readBytes(uint8_t *, uint16_t);
|
||||
HDLCParser *hdlcParser = NULL;
|
||||
MBUSParser *mbusParser = NULL;
|
||||
GBTParser *gbtParser = NULL;
|
||||
GCMParser *gcmParser = NULL;
|
||||
LLCParser *llcParser = NULL;
|
||||
DLMSParser *dlmsParser = NULL;
|
||||
DSMRParser *dsmrParser = NULL;
|
||||
uint8_t encryption_key[16];
|
||||
uint8_t authentication_key[16];
|
||||
uint8_t meter;
|
||||
bool serialInit = true;
|
||||
bool Debug = true;
|
||||
};
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
#include "hexutils.h"
|
||||
|
||||
String AMS_toHex(uint8_t* in) {
|
||||
return AMS_toHex(in, sizeof(in)*2);
|
||||
}
|
||||
|
||||
String AMS_toHex(uint8_t* in, uint16_t size) {
|
||||
String hex;
|
||||
for(int i = 0; i < size; i++) {
|
||||
if(in[i] < 0x10) {
|
||||
hex += '0';
|
||||
}
|
||||
hex += String(in[i], HEX);
|
||||
}
|
||||
hex.toUpperCase();
|
||||
return hex;
|
||||
}
|
||||
|
||||
void AMS_fromHex(uint8_t *out, String in, uint16_t size) {
|
||||
for(int i = 0; i < size*2; i += 2) {
|
||||
out[i/2] = strtol(in.substring(i, i+2).c_str(), 0, 16);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef _HEXUTILS_H
|
||||
#define _HEXUTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
String AMS_toHex(uint8_t* in);
|
||||
String AMS_toHex(uint8_t* in, uint16_t size);
|
||||
void AMS_fromHex(uint8_t *out, String in, uint16_t size);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "ams",
|
||||
"version": "1.0",
|
||||
"description": "ESP8266 ESP32 library for Advanced utility meters",
|
||||
"license": "GPL",
|
||||
"homepage": "https://github.com/arendst/Tasmota",
|
||||
"frameworks": "*",
|
||||
"platforms": "*",
|
||||
"authors":
|
||||
{
|
||||
"name": "Gerhard Mutz",
|
||||
"maintainer": true
|
||||
},
|
||||
"build": {
|
||||
"flags": [ "-I$PROJECT_DIR/include" ]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
name=AMS Parser
|
||||
|
||||
version=1.2.0
|
||||
|
||||
author=Gunnar Skjold
|
||||
|
||||
maintainer=https://github.com/gskjold
|
||||
|
||||
sentence=Meter parsing Library for Espressif ESP32 and ESP8266 devices.
|
||||
|
||||
paragraph=This library allows the ESP32 and ESP8266 devices to parse several meter protocolls
|
||||
|
||||
category=Communication
|
||||
|
||||
url=https://github.com/UtilitechAS/amsreader-firmware
|
||||
|
||||
architectures=esp32,esp8266
|
|
@ -0,0 +1,5 @@
|
|||
#include "ntohll.h"
|
||||
|
||||
uint64_t ntohll(uint64_t x) {
|
||||
return (((uint64_t)ntohl((uint32_t)x)) << 32) + ntohl(x >> 32);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _NTOHLL_H
|
||||
#define _NTOHLL_H
|
||||
|
||||
#include "lwip/def.h"
|
||||
|
||||
uint64_t ntohll(uint64_t x);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 4
|
||||
AlignAfterOpenBracket: Align
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
IndentCaseLabels: true
|
||||
SpacesBeforeTrailingComments: 2
|
||||
PointerAlignment: Left
|
||||
AlignEscapedNewlines: Left
|
||||
ForEachMacros: ['TEST_GROUP', 'TEST']
|
||||
...
|
|
@ -0,0 +1,161 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_
|
||||
and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
|
||||
|
||||
`Unreleased`_
|
||||
-------------
|
||||
|
||||
|
||||
`0.6.0`_ 2022-06-22
|
||||
-------------------
|
||||
|
||||
- Fix compiler warnings in SensirionErrors.cpp
|
||||
- Allow drivers to choose CRC function
|
||||
|
||||
`0.5.3`_ 2021-10-19
|
||||
-------------------
|
||||
|
||||
- Add support for sensor specific errors
|
||||
- Update keywords.txt
|
||||
|
||||
|
||||
`0.5.2`_ 2021-08-03
|
||||
-------------------
|
||||
|
||||
Fixed
|
||||
.....
|
||||
|
||||
- Fix CRC insertion in ``SensirionI2CTxFrame`` when more then one parameter
|
||||
is sent to the sensor.
|
||||
|
||||
`0.5.1`_ 2021-07-08
|
||||
-------------------
|
||||
|
||||
Changed
|
||||
.......
|
||||
|
||||
- Adjusted deprecation warnings
|
||||
|
||||
`0.5.0`_ 2021-07-07
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Enable SensirionTxFrame to incorporate Uint8 and Uint16 commands
|
||||
|
||||
|
||||
`0.4.3`_ 2021-02-12
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Added ``const`` modifier to functions which process MOSI array data.
|
||||
|
||||
`0.4.2`_ 2021-01-29
|
||||
-------------------
|
||||
|
||||
Changed
|
||||
.......
|
||||
|
||||
- Renamed the library header from ``SensirionCoreArduinoLibrary.h`` to ``SensirionCore.h``.
|
||||
We keep the old header for legacy support.
|
||||
|
||||
`0.4.1`_ 2021-01-28
|
||||
-------------------
|
||||
|
||||
Fixed
|
||||
.....
|
||||
|
||||
- Properly handle I2C write errors
|
||||
|
||||
|
||||
`0.4.0`_ 2021-01-20
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Documentation for all functions.
|
||||
|
||||
Breaking
|
||||
........
|
||||
|
||||
- Change interface of ``errorToString()`` function to include length of the
|
||||
provided buffer.
|
||||
|
||||
Removed
|
||||
.......
|
||||
|
||||
- Removed ``reset()`` function from ``SensirionI2CTxFrame`` since the
|
||||
functionality is not needed.
|
||||
|
||||
|
||||
`0.3.0`_ 2021-01-13
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Core implementation for I2C communication. This includes a RX and TX frame
|
||||
and a I2C communication class.
|
||||
|
||||
Changed
|
||||
.......
|
||||
|
||||
- SHDLC and I2C RX frame inherit from a RX frame base class.
|
||||
- ESP8266 test board from esp8266:esp8266:arduino to esp8266:esp8266:generic.
|
||||
- Sorted errors into general, SHDLC and I2C errors.
|
||||
- Replace C style casts with ``static_cast``.
|
||||
|
||||
|
||||
`0.2.0`_ 2021-01-11
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Explanation what SHDLC is in README.
|
||||
- ``SensirionErrors.h`` to ``SensirionCoreArduinoLibrary.h``.
|
||||
- ``sendAndReceiveFrame()`` function to ``SensirionShdlcCommunication``. This
|
||||
function combines ``sendFrame()`` and ``receiveFrame()`` into one function and
|
||||
adds additional error checking.
|
||||
|
||||
Changed
|
||||
.......
|
||||
|
||||
- Rename DeviceError to ExecutionError.
|
||||
- Move check for execution error after the whole frame is read and checksum is
|
||||
checked. This prevents that a wrong checksum can't be displayed as an
|
||||
execution error.
|
||||
|
||||
Removed
|
||||
.......
|
||||
|
||||
- ``reset()`` function from ``SensirionShdlcTxFrame`` and ``SensirionShdlcRxFrame``,
|
||||
since one can just create a new frame object which has the same effect.
|
||||
|
||||
`0.1.0`_ 2021-01-07
|
||||
-------------------
|
||||
|
||||
- Initial release
|
||||
|
||||
|
||||
.. _Unreleased: https://github.com/Sensirion/arduino-core/compare/0.6.0...main
|
||||
.. _0.6.0: https://github.com/Sensirion/arduino-core/compare/0.6.0...0.5.3
|
||||
.. _0.5.3: https://github.com/Sensirion/arduino-core/compare/0.5.2...0.5.3
|
||||
.. _0.5.2: https://github.com/Sensirion/arduino-core/compare/0.5.1...0.5.2
|
||||
.. _0.5.1: https://github.com/Sensirion/arduino-core/compare/0.5.0...0.5.1
|
||||
.. _0.5.0: https://github.com/Sensirion/arduino-core/compare/0.4.3...0.5.0
|
||||
.. _0.4.3: https://github.com/Sensirion/arduino-core/compare/0.4.2...0.4.3
|
||||
.. _0.4.2: https://github.com/Sensirion/arduino-core/compare/0.4.1...0.4.2
|
||||
.. _0.4.1: https://github.com/Sensirion/arduino-core/compare/0.4.0...0.4.1
|
||||
.. _0.4.0: https://github.com/Sensirion/arduino-core/compare/0.3.0...0.4.0
|
||||
.. _0.3.0: https://github.com/Sensirion/arduino-core/compare/0.2.0...0.3.0
|
||||
.. _0.2.0: https://github.com/Sensirion/arduino-core/compare/0.1.0...0.2.0
|
||||
.. _0.1.0: https://github.com/Sensirion/arduino-core/releases/tag/0.1.0
|
|
@ -0,0 +1,29 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2020, Sensirion AG
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,139 @@
|
|||
<!-- Downloaded from https://github.com/Sensirion/arduino-core
|
||||
on 10/01/2023 at commit bd2d3ce9355a3a1997beeb820e59072ef9430d5e -->
|
||||
# Sensirion Arduino Core Library
|
||||
|
||||
This library provides SHDLC and I2C protocol implementations for Sensirion
|
||||
sensors. There shouldn't be a reason to use it directly, but is required by the
|
||||
sensor driver libraries provided here:
|
||||
|
||||
- [SCD4x](https://github.com/Sensirion/arduino-i2c-scd4x)
|
||||
- [SVM40-I2C](https://github.com/Sensirion/arduino-i2c-svm40)
|
||||
- [SVM40-UART](https://github.com/Sensirion/arduino-uart-svm40)
|
||||
- [SFA3x-I2C](https://github.com/Sensirion/arduino-i2c-sfa3x)
|
||||
- [SFA3x-UART](https://github.com/Sensirion/arduino-uart-sfa3x)
|
||||
|
||||
# More Drivers
|
||||
|
||||
Not looking for Arduino drivers? Check out our other drivers here:
|
||||
|
||||
- [Embedded](https://github.com/Sensirion/info#repositories)
|
||||
- [Python](https://github.com/Sensirion/info#python-drivers)
|
||||
|
||||
# Usage
|
||||
|
||||
## SHDLC
|
||||
|
||||
SHDLC (Sensirion High-Level Data Link Control) is a byte-oriented master-slave
|
||||
communication protocol based on [ISO
|
||||
HDLC](https://en.wikipedia.org/wiki/High-Level_Data_Link_Control). It is used
|
||||
to control some of Sensirion’s devices (for example mass flow controllers). The
|
||||
detailed protocol documentation is not publicly available (yet). If you need
|
||||
it, please contact our [customer
|
||||
support](https://www.sensirion.com/en/about-us/contact/).
|
||||
|
||||
This library provides the following classes for communication with Sensirion
|
||||
Sensors using the SHDLC protocol.
|
||||
- `SensirionShdlcTxFrame`
|
||||
- `SensirionShdlcRxFrame`
|
||||
- `SensirionShdlcCommunication`
|
||||
|
||||
### Example Usage
|
||||
First initialize an instance of `SensirionShdlcTxFrame` and
|
||||
`SensirionShdlcRxFrame` with a properly sized buffer. A good worst case
|
||||
estimation for the buffer size is `2 * (n+6)` where `n` is the number of bytes
|
||||
you want to send. After that you can build your frame by first calling
|
||||
`begin()`. Information about the correct COMMAND and ADDRESS can be found on
|
||||
the data sheet of your sensor. Then you can add data to the frame by using
|
||||
different add member functions. See the code below for examples. After adding
|
||||
your data finish the frame by calling `finish()`.
|
||||
|
||||
To send this frame to the sensor you first need to initialize the correct
|
||||
Stream object (Serial,UART,...) to talk to your sensor. Don't forget to also
|
||||
call the `.begin()` function with the right configuration. Then call the static
|
||||
function `sendAndReceiveFrame()` from `SensirionShdlcCommunication` as shown
|
||||
below. You need to replace `STREAMOBJECT` with the initialized Stream object of
|
||||
your choice. Additionally you need to provide a timeout for to receive data
|
||||
back, consult the data sheet of your sensor for information on the best timeout
|
||||
value.
|
||||
|
||||
You can decode the frame by using the different get members to convert the
|
||||
received data to desired data types.
|
||||
|
||||
All functions return a error code if an error occurs during execution and zero
|
||||
otherwise.
|
||||
|
||||
```cpp
|
||||
uint8_t txBuffer[256];
|
||||
uint8_t rxBuffer[256];
|
||||
|
||||
SensirionShdlcTxFrame txFrame(txBuffer, 256);
|
||||
SensirionShdlcRxFrame rxFrame(rxBuffer, 256);
|
||||
|
||||
txFrame.begin(COMMAND, ADDRESS, DATALENGTH);
|
||||
|
||||
txFrame.addUInt8(UINT8);
|
||||
txFrame.addUInt32(UINT32);
|
||||
|
||||
txFrame.finish();
|
||||
|
||||
SensirionShdlcCommunication::sendAndReceiveFrame(STREAMOBJECT, txFrame, rxFrame, TIMEOUT);
|
||||
|
||||
rxFrame.getUInt16(UINT16);
|
||||
rxFrame.getFloat(FLOAT);
|
||||
|
||||
```
|
||||
|
||||
## I2C
|
||||
|
||||
This library provides the following classes for communication with Sensirion
|
||||
Sensors using the I2C protocol.
|
||||
- `SensirionI2cTxFrame`
|
||||
- `SensirionI2cRxFrame`
|
||||
- `SensirionI2cCommunication`
|
||||
|
||||
### Example Usage
|
||||
|
||||
First initialize an instance of `SensirionI2CTxFrame` and `SensirionI2CRxFrame`
|
||||
with a buffer sized the amount of data to read times 1.5. This is needed to
|
||||
account for the CRC which is added after every second byte. After that you can
|
||||
build your frame by first calling `addCommand()` to add the command at the
|
||||
beginning of the frame. Information about the different COMMANDs can be found
|
||||
on the data sheet of your sensor. Then you can add data to the frame by using
|
||||
different add member functions. See the code below for examples.
|
||||
|
||||
To send this frame to the sensor you first need to initialize a Wire object.
|
||||
Don't forget to also call the `.begin()` function with the right configuration.
|
||||
Then call the static function `sendFrame()` form `SensirionI2CCommunication` as
|
||||
shown below. You can find the ADDRESS on the data sheet of the sensor. You also
|
||||
need to replace `WIREOBJECT` with the initialized Wire object. Then wait the in
|
||||
the data sheet documented `READ_DELAY` before receiving the reply from the
|
||||
sensor by calling `receiveFrame()` with the same Wire object.
|
||||
|
||||
You then can decode the frame by using the different get members to convert the
|
||||
received data to desired data types.
|
||||
|
||||
All functions return a error code if an error occurs during execution and zero
|
||||
otherwise.
|
||||
|
||||
```cpp
|
||||
uint8_t txBuffer[256];
|
||||
uint8_t rxBuffer[256];
|
||||
|
||||
SensirionShdlcTxFrame txFrame(txBuffer, 256);
|
||||
SensirionShdlcRxFrame rxFrame(rxBuffer, 256);
|
||||
|
||||
txFrame.addCommand(COMMAND);
|
||||
|
||||
txFrame.addUInt8(UINT8);
|
||||
txFrame.addUInt32(UINT32);
|
||||
|
||||
SensirionShdlcCommunication::sendFrame(ADDRESS, txFrame, WIREOBJECT);
|
||||
|
||||
delay(READ_DELAY);
|
||||
|
||||
SensirionShdlcCommunication::receiveFrame(ADDRESS, rxFrame, WIREOBJECT);
|
||||
|
||||
rxFrame.getUInt16(UINT16);
|
||||
rxFrame.getFloat(FLOAT);
|
||||
|
||||
```
|
|
@ -0,0 +1,62 @@
|
|||
#include <SensirionCore.h>
|
||||
#include <Wire.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t txBuffer[256];
|
||||
uint8_t rxBuffer[256];
|
||||
|
||||
SensirionI2CTxFrame txFrame(txBuffer, 256);
|
||||
SensirionI2CRxFrame rxFrame(rxBuffer, 256);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint16_t mockCommand = 42;
|
||||
uint16_t error = txFrame.addCommand(mockCommand);
|
||||
|
||||
uint32_t mockUInt32 = 42;
|
||||
error |= txFrame.addUInt32(mockUInt32);
|
||||
|
||||
int32_t mockInt32 = 42;
|
||||
error |= txFrame.addInt32(mockInt32);
|
||||
|
||||
uint16_t mockUInt16 = 42;
|
||||
error |= txFrame.addUInt16(mockUInt16);
|
||||
|
||||
int16_t mockInt16 = 42;
|
||||
error |= txFrame.addInt16(mockInt16);
|
||||
|
||||
uint8_t mockUInt8 = 42;
|
||||
error |= txFrame.addUInt8(mockUInt8);
|
||||
|
||||
int8_t mockInt8 = 42;
|
||||
error |= txFrame.addInt8(mockInt8);
|
||||
|
||||
float mockFloat = 42.0f;
|
||||
error |= txFrame.addFloat(mockFloat);
|
||||
|
||||
bool mockBool = true;
|
||||
error |= txFrame.addBool(mockBool);
|
||||
|
||||
uint8_t mockBytes[] = {42, 42, 42, 42};
|
||||
error |= txFrame.addBytes(mockBytes, 4);
|
||||
|
||||
uint8_t mockAddress = 42;
|
||||
|
||||
error |= SensirionI2CCommunication::sendFrame(mockAddress, txFrame, Wire);
|
||||
|
||||
size_t mockNumBytes = 42;
|
||||
error |= SensirionI2CCommunication::receiveFrame(mockAddress, mockNumBytes,
|
||||
rxFrame, Wire);
|
||||
|
||||
error |= rxFrame.getUInt32(mockUInt32);
|
||||
error |= rxFrame.getInt32(mockInt32);
|
||||
error |= rxFrame.getUInt16(mockUInt16);
|
||||
error |= rxFrame.getInt16(mockInt16);
|
||||
error |= rxFrame.getUInt8(mockUInt8);
|
||||
error |= rxFrame.getInt8(mockInt8);
|
||||
error |= rxFrame.getFloat(mockFloat);
|
||||
error |= rxFrame.getBytes(mockBytes, 4);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#include <SensirionCore.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t txBuffer[256];
|
||||
uint8_t rxBuffer[256];
|
||||
|
||||
SensirionShdlcTxFrame txFrame(txBuffer, 256);
|
||||
SensirionShdlcRxFrame rxFrame(rxBuffer, 256);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint8_t mockCommand = 42;
|
||||
uint8_t mockAddress = 42;
|
||||
uint8_t mockDataLength = 42;
|
||||
uint16_t error = txFrame.begin(mockCommand, mockAddress, mockDataLength);
|
||||
|
||||
uint32_t mockUInt32 = 42;
|
||||
error |= txFrame.addUInt32(mockUInt32);
|
||||
|
||||
int32_t mockInt32 = 42;
|
||||
error |= txFrame.addInt32(mockInt32);
|
||||
|
||||
uint16_t mockUInt16 = 42;
|
||||
error |= txFrame.addUInt16(mockUInt16);
|
||||
|
||||
int16_t mockInt16 = 42;
|
||||
error |= txFrame.addInt16(mockInt16);
|
||||
|
||||
uint8_t mockUInt8 = 42;
|
||||
error |= txFrame.addUInt8(mockUInt8);
|
||||
|
||||
int8_t mockInt8 = 42;
|
||||
error |= txFrame.addInt8(mockInt8);
|
||||
|
||||
float mockFloat = 42.0f;
|
||||
error |= txFrame.addFloat(mockFloat);
|
||||
|
||||
bool mockBool = true;
|
||||
error |= txFrame.addBool(mockBool);
|
||||
|
||||
uint8_t mockBytes[] = {42, 42, 42, 42};
|
||||
error |= txFrame.addBytes(mockBytes, 4);
|
||||
|
||||
error |= txFrame.finish();
|
||||
|
||||
error |= SensirionShdlcCommunication::sendFrame(txFrame, Serial);
|
||||
|
||||
error |= SensirionShdlcCommunication::sendAndReceiveFrame(
|
||||
Serial, txFrame, rxFrame, 10000000);
|
||||
|
||||
error |=
|
||||
SensirionShdlcCommunication::receiveFrame(rxFrame, Serial, 1000000);
|
||||
|
||||
error |= rxFrame.getUInt32(mockUInt32);
|
||||
error |= rxFrame.getInt32(mockInt32);
|
||||
error |= rxFrame.getUInt16(mockUInt16);
|
||||
error |= rxFrame.getInt16(mockInt16);
|
||||
error |= rxFrame.getUInt8(mockUInt8);
|
||||
error |= rxFrame.getInt8(mockInt8);
|
||||
error |= rxFrame.getFloat(mockFloat);
|
||||
error |= rxFrame.getBytes(mockBytes, 4);
|
||||
|
||||
mockCommand = rxFrame.getCommand();
|
||||
mockAddress = rxFrame.getAddress();
|
||||
mockDataLength = rxFrame.getDataLength();
|
||||
uint8_t mockState = rxFrame.getState();
|
||||
if (mockState) {
|
||||
// There is an error in the device.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
SensirionShdlcCommunication KEYWORD1
|
||||
SensirionShdlcRxFrame KEYWORD1
|
||||
SensirionShdlcTxFrame KEYWORD1
|
||||
SensirionI2CTxFrame KEYWORD1
|
||||
SensirionI2CRxFrame KEYWORD1
|
||||
SensirionI2CCommunication KEYWORD1
|
||||
|
||||
# SensirionErrors.h
|
||||
HighLevelError KEYWORD1
|
||||
LowLevelError KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
sendFrame KEYWORD2
|
||||
receiveFrame KEYWORD2
|
||||
sendAndReceiveFrame KEYWORD2
|
||||
addUInt32 KEYWORD2
|
||||
addInt32 KEYWORD2
|
||||
addUInt16 KEYWORD2
|
||||
addInt16 KEYWORD2
|
||||
addUInt8 KEYWORD2
|
||||
addInt8 KEYWORD2
|
||||
addFloat KEYWORD2
|
||||
addBytes KEYWORD2
|
||||
addBool KEYWORD2
|
||||
addCommand KEYWORD2
|
||||
begin KEYWORD2
|
||||
finish KEYWORD2
|
||||
reset KEYWORD2
|
||||
getUInt32 KEYWORD2
|
||||
getInt32 KEYWORD2
|
||||
getUInt16 KEYWORD2
|
||||
getInt16 KEYWORD2
|
||||
getUInt8 KEYWORD2
|
||||
getInt8 KEYWORD2
|
||||
getFloat KEYWORD2
|
||||
getBytes KEYWORD2
|
||||
getCommand KEYWORD2
|
||||
getAddress KEYWORD2
|
||||
getDataLength KEYWORD2
|
||||
getState KEYWORD2
|
||||
|
||||
# SensirionErrors.h
|
||||
errorToString KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
|
@ -0,0 +1,9 @@
|
|||
name=Sensirion Core
|
||||
version=0.6.0
|
||||
author=Sensirion
|
||||
maintainer=Sensirion
|
||||
sentence=Library containing code base for Sensirion Sensor Libraries.
|
||||
paragraph=All Libraries for Sensirion Sensors use this library as a code base. In this library the Sensirion specific parts for I2C and UART communication are implemented. It provides dynamic frame construction, checksum calculation and buffer handling.
|
||||
category=Communication
|
||||
url=https://github.com/Sensirion/arduino-core/
|
||||
includes=SensirionCore.h
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _SENSIRION_CORE_H_
|
||||
#define _SENSIRION_CORE_H_
|
||||
|
||||
#include "SensirionCrc.h"
|
||||
#include "SensirionErrors.h"
|
||||
#include "SensirionRxFrame.h"
|
||||
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
#include "SensirionShdlcRxFrame.h"
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
#include "SensirionI2CCommunication.h"
|
||||
#include "SensirionI2CRxFrame.h"
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
#endif /* _SENSIRION_CORE_H_ */
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
*
|
||||
* THIS IS A LEGACY FILE AND WILL BE REMOVED SOON.
|
||||
*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _SENSIRION_CORE_ARDUINO_LIBRARY_H_
|
||||
#define _SENSIRION_CORE_ARDUINO_LIBRARY_H_
|
||||
|
||||
#pragma GCC warning \
|
||||
"Legacy file SensirionCoreArdunioLibrary.h included. Please include SensirionCore.h instead."
|
||||
|
||||
#include "SensirionErrors.h"
|
||||
#include "SensirionRxFrame.h"
|
||||
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
#include "SensirionShdlcRxFrame.h"
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
#include "SensirionI2CCommunication.h"
|
||||
#include "SensirionI2CRxFrame.h"
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
#endif /* _SENSIRION_CORE_ARDUION_LIBRARY_H_ */
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SensirionCrc.h"
|
||||
|
||||
uint8_t generateCRCGeneric(const uint8_t* data, size_t count, uint8_t init,
|
||||
uint8_t polynomial) {
|
||||
uint8_t crc = init;
|
||||
|
||||
/* calculates 8-Bit checksum with given polynomial */
|
||||
for (size_t current_byte = 0; current_byte < count; ++current_byte) {
|
||||
crc ^= (data[current_byte]);
|
||||
for (uint8_t crc_bit = 8; crc_bit > 0; --crc_bit) {
|
||||
if (crc & 0x80)
|
||||
crc = (crc << 1) ^ polynomial;
|
||||
else
|
||||
crc = (crc << 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint8_t generateCRC31_ff(const uint8_t* data, size_t count) {
|
||||
return generateCRCGeneric(data, count, 0xff, 0x31);
|
||||
}
|
||||
|
||||
uint8_t generateCRC31_00(const uint8_t* data, size_t count) {
|
||||
return generateCRCGeneric(data, count, 0x00, 0x31);
|
||||
}
|
||||
|
||||
uint8_t generateCRC(const uint8_t* data, size_t count, CrcPolynomial type) {
|
||||
if (CRC31_00 == type) {
|
||||
return generateCRC31_00(data, count);
|
||||
}
|
||||
return generateCRC31_ff(data, count);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SENSIRION_CRC_H_
|
||||
#define _SENSIRION_CRC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum CrcPolynomial : uint8_t {
|
||||
CRC31_00 = 0x0,
|
||||
CRC31_ff = 0x1,
|
||||
};
|
||||
|
||||
uint8_t generateCRCGeneric(const uint8_t* data, size_t count, uint8_t init,
|
||||
uint8_t polynomial);
|
||||
|
||||
uint8_t generateCRC31_ff(const uint8_t* data, size_t count);
|
||||
|
||||
uint8_t generateCRC31_00(const uint8_t* data, size_t count);
|
||||
|
||||
/**
|
||||
* @brief Generate a crc for data given a polynomial type
|
||||
*
|
||||
* @param data data to calculate CRC for
|
||||
* @param count the array size of data
|
||||
* @param poly CRC polynomal to use
|
||||
*/
|
||||
uint8_t generateCRC(const uint8_t* data, size_t count, CrcPolynomial type);
|
||||
|
||||
#endif /* _SENSIRION_CRC_H_ */
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "SensirionErrors.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void errorToString(uint16_t error, char errorMessage[],
|
||||
size_t errorMessageSize) {
|
||||
|
||||
uint16_t highLevelError = error & 0xFF00;
|
||||
uint16_t lowLevelError = error & 0x00FF;
|
||||
|
||||
if (error & HighLevelError::SensorSpecificError) {
|
||||
snprintf(errorMessage, errorMessageSize, "Sensor specific error: 0x%2x",
|
||||
lowLevelError);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (highLevelError) {
|
||||
case HighLevelError::NoError:
|
||||
if (!error) {
|
||||
strncpy(errorMessage, "No error", errorMessageSize);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case HighLevelError::WriteError:
|
||||
switch (lowLevelError) {
|
||||
case LowLevelError::SerialWriteError:
|
||||
strncpy(errorMessage, "Error writing to serial",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::InternalBufferSizeError:
|
||||
strncpy(errorMessage,
|
||||
"Data too long to fit in transmit buffer",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::I2cAddressNack:
|
||||
strncpy(errorMessage,
|
||||
"Received NACK on transmit of address",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::I2cDataNack:
|
||||
strncpy(errorMessage, "Received NACK on transmit of data",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::I2cOtherError:
|
||||
strncpy(errorMessage, "Error writing to I2C bus",
|
||||
errorMessageSize);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case HighLevelError::ReadError:
|
||||
switch (lowLevelError) {
|
||||
case LowLevelError::NonemptyFrameError:
|
||||
strncpy(errorMessage, "Frame already contains data",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::TimeoutError:
|
||||
strncpy(errorMessage, "Timeout while reading data",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::ChecksumError:
|
||||
strncpy(errorMessage, "Checksum is wrong",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::CRCError:
|
||||
strncpy(errorMessage, "Wrong CRC found", errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::WrongNumberBytesError:
|
||||
strncpy(errorMessage, "Number of bytes not a multiple of 3",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::NotEnoughDataError:
|
||||
strncpy(errorMessage, "Not enough data received",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::InternalBufferSizeError:
|
||||
strncpy(errorMessage, "Internal I2C buffer too small",
|
||||
errorMessageSize);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case HighLevelError::ExecutionError: {
|
||||
char format[] = "Execution error, status register: 0x%x";
|
||||
snprintf(errorMessage, errorMessageSize, format, lowLevelError);
|
||||
return;
|
||||
}
|
||||
case HighLevelError::TxFrameError:
|
||||
switch (lowLevelError) {
|
||||
case LowLevelError::BufferSizeError:
|
||||
strncpy(errorMessage, "Not enough space in buffer",
|
||||
errorMessageSize);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case HighLevelError::RxFrameError:
|
||||
switch (lowLevelError) {
|
||||
case LowLevelError::BufferSizeError:
|
||||
strncpy(errorMessage, "Not enough space in buffer",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::NoDataError:
|
||||
strncpy(errorMessage, "No more data in frame",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::RxAddressError:
|
||||
strncpy(errorMessage, "Wrong address in return frame",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::RxCommandError:
|
||||
strncpy(errorMessage, "Wrong command in return frame",
|
||||
errorMessageSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
strncpy(errorMessage, "Error processing error", errorMessageSize);
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _SENSIRION_ERRORS_H_
|
||||
#define _SENSIRION_ERRORS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum HighLevelError : uint16_t {
|
||||
// general errors
|
||||
NoError = 0,
|
||||
WriteError = 0x0100,
|
||||
ReadError = 0x0200,
|
||||
TxFrameError = 0x0300,
|
||||
RxFrameError = 0x0400,
|
||||
// shdlc errors
|
||||
ExecutionError = 0x0500,
|
||||
// i2c errors
|
||||
|
||||
// Sensor specific errors. All errors higher than that are depending on the
|
||||
// sensor used.
|
||||
SensorSpecificError = 0x8000,
|
||||
};
|
||||
|
||||
enum LowLevelError : uint16_t {
|
||||
// general errors
|
||||
NonemptyFrameError,
|
||||
NoDataError,
|
||||
BufferSizeError,
|
||||
// shdlc errors
|
||||
StopByteError,
|
||||
ChecksumError,
|
||||
TimeoutError,
|
||||
RxCommandError,
|
||||
RxAddressError,
|
||||
SerialWriteError,
|
||||
// i2c errors
|
||||
WrongNumberBytesError,
|
||||
CRCError,
|
||||
I2cAddressNack,
|
||||
I2cDataNack,
|
||||
I2cOtherError,
|
||||
NotEnoughDataError,
|
||||
InternalBufferSizeError,
|
||||
};
|
||||
|
||||
/**
|
||||
* errorToString() - Convert error code to a human readable error message
|
||||
*
|
||||
* @param error Error code to be converted.
|
||||
* @param errorMessage String where the error text can be
|
||||
* stored.
|
||||
* @param errorMessageSize Size in bytes of the string buffer for the error
|
||||
* message.
|
||||
*/
|
||||
void errorToString(uint16_t error, char errorMessage[],
|
||||
size_t errorMessageSize);
|
||||
|
||||
#endif /* _SENSIRION_ERRORS_H_ */
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "SensirionI2CCommunication.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SensirionCrc.h"
|
||||
#include "SensirionErrors.h"
|
||||
#include "SensirionI2CRxFrame.h"
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
static void clearRxBuffer(TwoWire& i2cBus) {
|
||||
while (i2cBus.available()) {
|
||||
(void)i2cBus.read();
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CCommunication::sendFrame(uint8_t address,
|
||||
SensirionI2CTxFrame& frame,
|
||||
TwoWire& i2cBus) {
|
||||
i2cBus.beginTransmission(address);
|
||||
size_t writtenBytes = i2cBus.write(frame._buffer, frame._index);
|
||||
uint8_t i2c_error = i2cBus.endTransmission();
|
||||
if (writtenBytes != frame._index) {
|
||||
return WriteError | I2cOtherError;
|
||||
}
|
||||
// translate Arduino errors, see
|
||||
// https://www.arduino.cc/en/Reference/WireEndTransmission
|
||||
switch (i2c_error) {
|
||||
case 0:
|
||||
return NoError;
|
||||
case 1:
|
||||
return WriteError | InternalBufferSizeError;
|
||||
case 2:
|
||||
return WriteError | I2cAddressNack;
|
||||
case 3:
|
||||
return WriteError | I2cDataNack;
|
||||
default:
|
||||
return WriteError | I2cOtherError;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CCommunication::receiveFrame(uint8_t address,
|
||||
size_t numBytes,
|
||||
SensirionI2CRxFrame& frame,
|
||||
TwoWire& i2cBus,
|
||||
CrcPolynomial poly) {
|
||||
size_t readAmount;
|
||||
size_t i = 0;
|
||||
|
||||
#ifdef I2C_BUFFER_LENGTH
|
||||
const uint8_t sizeBuffer =
|
||||
(static_cast<uint8_t>(I2C_BUFFER_LENGTH) / static_cast<uint8_t>(3)) * 3;
|
||||
#elif defined(BUFFER_LENGTH)
|
||||
const uint8_t sizeBuffer =
|
||||
(static_cast<uint8_t>(BUFFER_LENGTH) / static_cast<uint8_t>(3)) * 3;
|
||||
#else
|
||||
const uint8_t sizeBuffer = 30;
|
||||
#endif
|
||||
|
||||
if (numBytes % 3) {
|
||||
return ReadError | WrongNumberBytesError;
|
||||
}
|
||||
if ((numBytes / 3) * 2 > frame._bufferSize) {
|
||||
return ReadError | BufferSizeError;
|
||||
}
|
||||
if (numBytes > sizeBuffer) {
|
||||
return ReadError | InternalBufferSizeError;
|
||||
}
|
||||
|
||||
readAmount = i2cBus.requestFrom(address, static_cast<uint8_t>(numBytes),
|
||||
static_cast<uint8_t>(true));
|
||||
if (numBytes != readAmount) {
|
||||
return ReadError | NotEnoughDataError;
|
||||
}
|
||||
do {
|
||||
frame._buffer[i++] = i2cBus.read();
|
||||
frame._buffer[i++] = i2cBus.read();
|
||||
uint8_t actualCRC = i2cBus.read();
|
||||
uint8_t expectedCRC = generateCRC(&frame._buffer[i - 2], 2, poly);
|
||||
if (actualCRC != expectedCRC) {
|
||||
clearRxBuffer(i2cBus);
|
||||
return ReadError | CRCError;
|
||||
}
|
||||
readAmount -= 3;
|
||||
} while (readAmount > 0);
|
||||
frame._numBytes = i;
|
||||
return NoError;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_I2C_COMMUNICATION_H_
|
||||
#define SENSIRION_I2C_COMMUNICATION_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
|
||||
#include "SensirionI2CRxFrame.h"
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
class SensirionI2CTxFrame;
|
||||
class SensirionI2CRxFrame;
|
||||
|
||||
/*
|
||||
* SensirionI2CCommunication - Class which is responsible for the communication
|
||||
* via a I2C bus. It provides functionality to send and receive frames from a
|
||||
* Sensirion sensor. The data is sent and received in a SensirionI2cTxFrame or
|
||||
* SensirionI2cRxFrame respectively.
|
||||
*/
|
||||
class SensirionI2CCommunication {
|
||||
public:
|
||||
/**
|
||||
* sendFrame() - Sends frame to sensor
|
||||
*
|
||||
* @param address I2C address of the sensor.
|
||||
* @param frame Tx frame object containing a finished frame to send to
|
||||
* the sensor.
|
||||
* @param i2cBus TwoWire object to communicate with the sensor.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t sendFrame(uint8_t address, SensirionI2CTxFrame& frame,
|
||||
TwoWire& i2cBus);
|
||||
|
||||
/**
|
||||
* receiveFrame() - Receive Frame from sensor
|
||||
*
|
||||
* @param address I2C address of the sensor.
|
||||
* @param numBytes Number of bytes to receive.
|
||||
* @param frame Rx frame to store the received data in.
|
||||
* @param i2cBus TwoWire object to communicate with the sensor.
|
||||
* @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t receiveFrame(uint8_t address, size_t numBytes,
|
||||
SensirionI2CRxFrame& frame, TwoWire& i2cBus,
|
||||
CrcPolynomial poly = CRC31_ff);
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_I2C_COMMUNICATION_H_ */
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_I2C_RX_FRAME_H_
|
||||
#define SENSIRION_I2C_RX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionI2CCommunication.h"
|
||||
#include "SensirionRxFrame.h"
|
||||
|
||||
/**
|
||||
* SenirionI2CRxFrame - Class which decodes the through I2C received data into
|
||||
* common data types. It contains a buffer which is filled by the
|
||||
* SensirionI2CCommunication class. By calling the different decode function
|
||||
* inherited from the SensirionRxFrame base class the raw data can be decoded
|
||||
* into different data types.
|
||||
*/
|
||||
class SensirionI2CRxFrame : public SensirionRxFrame {
|
||||
|
||||
friend class SensirionI2CCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the receive frame will be
|
||||
* stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the receive frame.
|
||||
*
|
||||
*/
|
||||
SensirionI2CRxFrame(uint8_t buffer[], size_t bufferSize)
|
||||
: SensirionRxFrame(buffer, bufferSize){};
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_I2C_RX_FRAME_H_ */
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionCrc.h"
|
||||
#include "SensirionErrors.h"
|
||||
|
||||
SensirionI2CTxFrame::SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize,
|
||||
size_t numCommandBytes,
|
||||
CrcPolynomial poly)
|
||||
: _buffer(buffer), _bufferSize(bufferSize), _index(numCommandBytes),
|
||||
_numCommandBytes(numCommandBytes), _polynomial_type(poly) {
|
||||
}
|
||||
|
||||
SensirionI2CTxFrame::SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize,
|
||||
CrcPolynomial poly)
|
||||
: SensirionI2CTxFrame(buffer, bufferSize, 2, poly) {
|
||||
}
|
||||
|
||||
SensirionI2CTxFrame SensirionI2CTxFrame::createWithUInt8Command(
|
||||
uint8_t command, uint8_t buffer[], size_t bufferSize, CrcPolynomial poly) {
|
||||
SensirionI2CTxFrame instance =
|
||||
SensirionI2CTxFrame(buffer, bufferSize, 1, poly);
|
||||
instance._buffer[0] = command;
|
||||
return instance;
|
||||
}
|
||||
|
||||
SensirionI2CTxFrame SensirionI2CTxFrame::createWithUInt16Command(
|
||||
uint16_t command, uint8_t buffer[], size_t bufferSize, CrcPolynomial poly) {
|
||||
SensirionI2CTxFrame instance =
|
||||
SensirionI2CTxFrame(buffer, bufferSize, 2, poly);
|
||||
instance._buffer[0] = static_cast<uint8_t>((command & 0xFF00) >> 8);
|
||||
instance._buffer[1] = static_cast<uint8_t>((command & 0x00FF) >> 0);
|
||||
return instance;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addCommand(uint16_t command) {
|
||||
if (_bufferSize < 2) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
_buffer[0] = static_cast<uint8_t>((command & 0xFF00) >> 8);
|
||||
_buffer[1] = static_cast<uint8_t>((command & 0x00FF) >> 0);
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addUInt32(uint32_t data) {
|
||||
uint16_t error = _addByte(static_cast<uint8_t>((data & 0xFF000000) >> 24));
|
||||
error |= _addByte(static_cast<uint8_t>((data & 0x00FF0000) >> 16));
|
||||
error |= _addByte(static_cast<uint8_t>((data & 0x0000FF00) >> 8));
|
||||
error |= _addByte(static_cast<uint8_t>((data & 0x000000FF) >> 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addInt32(int32_t data) {
|
||||
return addUInt32(static_cast<uint32_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addUInt16(uint16_t data) {
|
||||
uint16_t error = _addByte(static_cast<uint8_t>((data & 0xFF00) >> 8));
|
||||
error |= _addByte(static_cast<uint8_t>((data & 0x00FF) >> 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addInt16(int16_t data) {
|
||||
return addUInt16(static_cast<uint16_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addUInt8(uint8_t data) {
|
||||
return _addByte(data);
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addInt8(int8_t data) {
|
||||
return _addByte(static_cast<uint8_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addBool(bool data) {
|
||||
return _addByte(static_cast<uint8_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addFloat(float data) {
|
||||
union {
|
||||
uint32_t uInt32Data;
|
||||
float floatData;
|
||||
} convert;
|
||||
|
||||
convert.floatData = data;
|
||||
return addUInt32(convert.uInt32Data);
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addBytes(const uint8_t data[],
|
||||
size_t dataLength) {
|
||||
uint16_t error = 0;
|
||||
for (size_t i = 0; i < dataLength; i++) {
|
||||
error |= _addByte(data[i]);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::_addByte(uint8_t data) {
|
||||
if (_bufferSize <= _index) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
_buffer[_index++] = data;
|
||||
if ((_index - _numCommandBytes) % 3 == 2) {
|
||||
if (_bufferSize <= _index) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
uint8_t crc = generateCRC(&_buffer[_index - 2], 2, _polynomial_type);
|
||||
_buffer[_index++] = crc;
|
||||
}
|
||||
return NoError;
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_I2C_TX_FRAME_H_
|
||||
#define SENSIRION_I2C_TX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionCrc.h"
|
||||
#include "SensirionI2CCommunication.h"
|
||||
|
||||
/*
|
||||
* SensirionI2CTxFrame - Class which helps to build a correct I2C frame for
|
||||
* Sensirion Sensors. The different addDatatype() functions add the frame data
|
||||
* and the addCommand() function writes the command at the beginning. Using
|
||||
* these functions one can easily construct a I2C frame for Sensirion sensors.
|
||||
*/
|
||||
class SensirionI2CTxFrame {
|
||||
|
||||
friend class SensirionI2CCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Factory to create a SensirionI2CTxFrame using a UInt8 command.
|
||||
*
|
||||
* @param command Command to add to the send frame.
|
||||
* @param buffer Buffer in which the send frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the send frame.
|
||||
* @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF
|
||||
*
|
||||
* @return the constructed SensirionI2CTxFrame.
|
||||
*/
|
||||
static SensirionI2CTxFrame
|
||||
createWithUInt8Command(uint8_t command, uint8_t buffer[], size_t bufferSize,
|
||||
CrcPolynomial poly = CRC31_ff);
|
||||
|
||||
/**
|
||||
* Factory to create a SensirionI2CTxFrame using a UInt16 command.
|
||||
*
|
||||
* @param command Command to add to the send frame.
|
||||
* @param buffer Buffer in which the send frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the send frame.
|
||||
* @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF
|
||||
*
|
||||
* @return the constructed SensirionI2CTxFrame.
|
||||
*/
|
||||
static SensirionI2CTxFrame
|
||||
createWithUInt16Command(uint16_t command, uint8_t buffer[],
|
||||
size_t bufferSize, CrcPolynomial poly = CRC31_ff);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the send frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the send frame.
|
||||
* @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF
|
||||
*
|
||||
* @deprecated Use createWithUInt16Command() instead
|
||||
*/
|
||||
SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize,
|
||||
CrcPolynomial poly = CRC31_ff);
|
||||
|
||||
/**
|
||||
* addCommand() - Add command to the send frame.
|
||||
*
|
||||
* @param command Command to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*
|
||||
* @deprecated Use createWithUInt16Command() instead
|
||||
*/
|
||||
uint16_t addCommand(uint16_t command);
|
||||
|
||||
/**
|
||||
* addUInt32() - Add unsigned 32bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 32bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt32(uint32_t data);
|
||||
|
||||
/**
|
||||
* addInt32() - Add signed 32bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 32bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt32(int32_t data);
|
||||
|
||||
/**
|
||||
* addUInt16() - Add unsigned 16bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 16bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt16(uint16_t data);
|
||||
|
||||
/**
|
||||
* addInt16() - Add signed 16bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 16bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt16(int16_t data);
|
||||
|
||||
/**
|
||||
* addUInt8() - Add unsigned 8bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 8bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt8(uint8_t data);
|
||||
|
||||
/**
|
||||
* addInt8() - Add signed 8bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 8bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt8(int8_t data);
|
||||
|
||||
/**
|
||||
* addBool() - Add boolean to the send frame.
|
||||
*
|
||||
* @param data Boolean to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addBool(bool data);
|
||||
|
||||
/**
|
||||
* addFloat() - Add float to the send frame.
|
||||
*
|
||||
* @param data Float to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addFloat(float data);
|
||||
|
||||
/**
|
||||
* addBytes() - Add byte array to the send frame.
|
||||
*
|
||||
* @param data Byte array to add to the send frame.
|
||||
* @param dataLength Number of bytes to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addBytes(const uint8_t data[], size_t dataLength);
|
||||
|
||||
private:
|
||||
SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize,
|
||||
size_t numCommandBytes, CrcPolynomial poly = CRC31_ff);
|
||||
|
||||
uint16_t _addByte(uint8_t data);
|
||||
|
||||
uint8_t* _buffer;
|
||||
size_t _bufferSize;
|
||||
size_t _index;
|
||||
size_t _numCommandBytes;
|
||||
CrcPolynomial _polynomial_type;
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_I2C_TX_FRAME_H_ */
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SensirionRxFrame.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionErrors.h"
|
||||
|
||||
SensirionRxFrame::SensirionRxFrame(uint8_t buffer[], size_t bufferSize)
|
||||
: _buffer(buffer), _bufferSize(bufferSize), _index(0), _numBytes(0) {
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getUInt32(uint32_t& data) {
|
||||
if (_numBytes < 4) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = static_cast<uint32_t>(_buffer[_index++]) << 24;
|
||||
data |= static_cast<uint32_t>(_buffer[_index++]) << 16;
|
||||
data |= static_cast<uint32_t>(_buffer[_index++]) << 8;
|
||||
data |= static_cast<uint32_t>(_buffer[_index++]);
|
||||
_numBytes -= 4;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getInt32(int32_t& data) {
|
||||
uint32_t ret;
|
||||
uint16_t error = getUInt32(ret);
|
||||
data = static_cast<int32_t>(ret);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getUInt16(uint16_t& data) {
|
||||
if (_numBytes < 2) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = static_cast<uint16_t>(_buffer[_index++]) << 8;
|
||||
data |= static_cast<uint16_t>(_buffer[_index++]);
|
||||
_numBytes -= 2;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getInt16(int16_t& data) {
|
||||
uint16_t ret;
|
||||
uint16_t error = getUInt16(ret);
|
||||
data = static_cast<int16_t>(ret);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getUInt8(uint8_t& data) {
|
||||
if (_numBytes < 1) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = _buffer[_index++];
|
||||
_numBytes -= 1;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getInt8(int8_t& data) {
|
||||
if (_numBytes < 1) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = static_cast<int8_t>(_buffer[_index++]);
|
||||
_numBytes -= 1;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getBool(bool& data) {
|
||||
if (_numBytes < 1) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = static_cast<bool>(_buffer[_index++]);
|
||||
_numBytes -= 1;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getFloat(float& data) {
|
||||
union {
|
||||
uint32_t uInt32Data;
|
||||
float floatData;
|
||||
} convert;
|
||||
uint16_t error = getUInt32(convert.uInt32Data);
|
||||
data = convert.floatData;
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getBytes(uint8_t data[], size_t maxBytes) {
|
||||
if (_numBytes < 1) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
size_t readAmount = maxBytes;
|
||||
if (_numBytes < maxBytes) {
|
||||
readAmount = _numBytes;
|
||||
}
|
||||
for (size_t i = 0; i < readAmount; i++) {
|
||||
data[i] = _buffer[_index++];
|
||||
}
|
||||
_numBytes -= readAmount;
|
||||
return NoError;
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_RX_FRAME_H_
|
||||
#define SENSIRION_RX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* SenirionRxFrame - Base class for SensirionShdlcRxFrame and
|
||||
* SensirionI2cRxFrame. It decodes received data into common data types. The
|
||||
* data is contained in a buffer which is filled by the one of the two
|
||||
* communication classes. By calling the different decode function the raw data
|
||||
* can be decoded into different data types.
|
||||
*/
|
||||
class SensirionRxFrame {
|
||||
|
||||
friend class SensirionI2CCommunication;
|
||||
friend class SensirionShdlcCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the receive frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the receive frame.
|
||||
*/
|
||||
SensirionRxFrame(uint8_t buffer[], size_t bufferSize);
|
||||
|
||||
/**
|
||||
* getUInt32() - Get unsigned 32bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store unsigned 32bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getUInt32(uint32_t& data);
|
||||
|
||||
/**
|
||||
* getInt32() - Get signed 32bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store signed 32bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getInt32(int32_t& data);
|
||||
|
||||
/**
|
||||
* getUInt16() - Get unsigned 16bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store unsigned 16bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getUInt16(uint16_t& data);
|
||||
|
||||
/**
|
||||
* getInt16() - Get signed 16bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store signed 16bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getInt16(int16_t& data);
|
||||
|
||||
/**
|
||||
* getUInt8() - Get unsigned 8bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store unsigned 8bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getUInt8(uint8_t& data);
|
||||
|
||||
/**
|
||||
* getInt8() - Get signed 8bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store signed 8bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getInt8(int8_t& data);
|
||||
|
||||
/**
|
||||
* getBool() - Get Boolean from the received data.
|
||||
*
|
||||
* @param data Memory to store boolean in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getBool(bool& data);
|
||||
|
||||
/**
|
||||
* getFloat() - Get float from the received data.
|
||||
*
|
||||
* @param data Memory to store float in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getFloat(float& data);
|
||||
|
||||
/**
|
||||
* getBytes() - Get an array of bytes from the received data.
|
||||
*
|
||||
* @param data Buffer to store the bytes in.
|
||||
* @param maxBytes Maximal amount of bytes to read from the received data.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getBytes(uint8_t data[], size_t maxBytes);
|
||||
|
||||
private:
|
||||
uint8_t* _buffer = 0;
|
||||
size_t _bufferSize = 0;
|
||||
size_t _index = 0;
|
||||
size_t _numBytes = 0;
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_RX_FRAME_H_ */
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SensirionErrors.h"
|
||||
#include "SensirionShdlcRxFrame.h"
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
static uint16_t readByte(uint8_t& data, Stream& serial, unsigned long startTime,
|
||||
unsigned long timeoutMicros) {
|
||||
do {
|
||||
if (micros() - startTime > timeoutMicros) {
|
||||
return ReadError | TimeoutError;
|
||||
}
|
||||
} while (!serial.available());
|
||||
data = serial.read();
|
||||
return NoError;
|
||||
}
|
||||
|
||||
static uint16_t unstuffByte(uint8_t& data, Stream& serial,
|
||||
unsigned long startTime,
|
||||
unsigned long timeoutMicros) {
|
||||
uint16_t error = readByte(data, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (data == 0x7d) {
|
||||
error = readByte(data, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
data = data ^ (1 << 5);
|
||||
}
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcCommunication::sendFrame(SensirionShdlcTxFrame& frame,
|
||||
Stream& serial) {
|
||||
size_t writtenBytes = serial.write(&frame._buffer[0], frame._index);
|
||||
if (writtenBytes != frame._index) {
|
||||
return WriteError | SerialWriteError;
|
||||
}
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcCommunication::receiveFrame(
|
||||
SensirionShdlcRxFrame& frame, Stream& serial, unsigned long timeoutMicros) {
|
||||
unsigned long startTime = micros();
|
||||
uint16_t error;
|
||||
uint8_t dataLength;
|
||||
uint8_t current = 0;
|
||||
|
||||
if (frame._numBytes) {
|
||||
return ReadError | NonemptyFrameError;
|
||||
}
|
||||
|
||||
// Wait for start byte and ignore all other bytes in case a partial frame
|
||||
// is still in the receive buffer due to a previous error.
|
||||
do {
|
||||
error = readByte(current, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} while (current != 0x7e);
|
||||
|
||||
// Handle a repeated start byte which may happen
|
||||
do {
|
||||
error = unstuffByte(current, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} while (current == 0x7e);
|
||||
|
||||
frame._address = current;
|
||||
error = unstuffByte(frame._command, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
error = unstuffByte(frame._state, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
error = unstuffByte(dataLength, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t checksum =
|
||||
frame._address + frame._command + frame._state + dataLength;
|
||||
|
||||
if (dataLength > frame._bufferSize) {
|
||||
return RxFrameError | BufferSizeError;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
while (i < dataLength) {
|
||||
error = unstuffByte(current, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
frame._buffer[i] = current;
|
||||
checksum += current;
|
||||
i++;
|
||||
}
|
||||
|
||||
uint8_t expectedChecksum = ~checksum;
|
||||
uint8_t actualChecksum;
|
||||
error = unstuffByte(actualChecksum, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (expectedChecksum != actualChecksum) {
|
||||
return ReadError | ChecksumError;
|
||||
}
|
||||
|
||||
uint8_t stop;
|
||||
error = readByte(stop, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (stop != 0x7e) {
|
||||
return ReadError | StopByteError;
|
||||
}
|
||||
if (frame._state & 0x7F) {
|
||||
return ExecutionError | frame._state;
|
||||
}
|
||||
frame._dataLength = dataLength;
|
||||
frame._numBytes = dataLength;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcCommunication::sendAndReceiveFrame(
|
||||
Stream& serial, SensirionShdlcTxFrame& txFrame,
|
||||
SensirionShdlcRxFrame& rxFrame, unsigned long rxTimeoutMicros) {
|
||||
uint16_t error;
|
||||
error = SensirionShdlcCommunication::sendFrame(txFrame, serial);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
error = SensirionShdlcCommunication::receiveFrame(rxFrame, serial,
|
||||
rxTimeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (rxFrame.getCommand() != txFrame.getCommand()) {
|
||||
return RxFrameError | RxCommandError;
|
||||
}
|
||||
if (rxFrame.getAddress() != txFrame.getAddress()) {
|
||||
return RxFrameError | RxAddressError;
|
||||
}
|
||||
return NoError;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_SHDLC_COMMUNICATION_H_
|
||||
#define SENSIRION_SHDLC_COMMUNICATION_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "SensirionShdlcRxFrame.h"
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
class SensirionShdlcTxFrame;
|
||||
class SensirionShdlcRxFrame;
|
||||
|
||||
/*
|
||||
* SensirionShdlcCommunication - Class which is responsible for the
|
||||
* communication via a UART (Serial) interface. It provides functionality to
|
||||
* send and receive frames from a Sensirion sensor. The data is sent and
|
||||
* received in a SensirionShdlcTxFrame or SensirionShdlcRxFrame respectively.
|
||||
*/
|
||||
class SensirionShdlcCommunication {
|
||||
|
||||
public:
|
||||
/**
|
||||
* sendFrame() - Sends frame to sensor
|
||||
*
|
||||
* @param frame Tx frame object containing a finished frame to send to the
|
||||
* sensor.
|
||||
* @param serial Stream object to communicate with the sensor.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t sendFrame(SensirionShdlcTxFrame& frame, Stream& serial);
|
||||
|
||||
/**
|
||||
* receiveFrame() - Receive Frame from sensor
|
||||
*
|
||||
* @param frame Rx frame to store the received data in.
|
||||
* @param serial Stream object to communicate with the sensor.
|
||||
* @param timeoutMicros Timeout in micro seconds for the receive operation.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t receiveFrame(SensirionShdlcRxFrame& frame, Stream& serial,
|
||||
unsigned long timeoutMicros);
|
||||
|
||||
/**
|
||||
* sendAndReceiveFrame() - Send and receive a frame from sensor.
|
||||
*
|
||||
* @param serial Stream object to communicate with the sensor.
|
||||
* @param txFrame Tx frame object containing a finished frame to
|
||||
* send to the sensor.
|
||||
* @param rxFrame Rx frame to store the received data in.
|
||||
* @param rxTimeoutMicros Timeout in micro seconds for the receive
|
||||
* operation.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t sendAndReceiveFrame(Stream& serial,
|
||||
SensirionShdlcTxFrame& txFrame,
|
||||
SensirionShdlcRxFrame& rxFrame,
|
||||
unsigned long rxTimeoutMicros);
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_SHDLC_COMMUNICATION_H_ */
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_SHDLC_RX_FRAME_H_
|
||||
#define SENSIRION_SHDLC_RX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionRxFrame.h"
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
|
||||
/**
|
||||
* SenirionShdlcRxFrame - Class which decodes the through UART received data
|
||||
* into common data types. It contains a buffer which is filled by the
|
||||
* SensirionShdlcCommunication class. By calling the different decode function
|
||||
* inherited from the SensirionRxFrame base class the raw data can be decoded
|
||||
* into different data types. In addition to that it also stores the four
|
||||
* header bytes defined by the SHDLC protocol state, command, address,
|
||||
* datalength. These bytes can be read out by the corresponding getter method.
|
||||
*/
|
||||
class SensirionShdlcRxFrame : public SensirionRxFrame {
|
||||
|
||||
friend class SensirionShdlcCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the receive frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the receive frame.
|
||||
*/
|
||||
SensirionShdlcRxFrame(uint8_t buffer[], size_t bufferSize)
|
||||
: SensirionRxFrame(buffer, bufferSize){};
|
||||
|
||||
uint8_t getAddress(void) const {
|
||||
return _address;
|
||||
};
|
||||
|
||||
uint8_t getCommand(void) const {
|
||||
return _command;
|
||||
};
|
||||
|
||||
uint8_t getState(void) const {
|
||||
return _state;
|
||||
};
|
||||
|
||||
uint8_t getDataLength(void) const {
|
||||
return _dataLength;
|
||||
};
|
||||
|
||||
private:
|
||||
uint8_t _address = 0;
|
||||
uint8_t _command = 0;
|
||||
uint8_t _state = 0;
|
||||
uint8_t _dataLength = 0;
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_SHDLC_RX_FRAME_H_ */
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionErrors.h"
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::begin(uint8_t command, uint8_t address,
|
||||
uint8_t dataLength) {
|
||||
_buffer[_index++] = 0x7e;
|
||||
uint16_t error = addUInt8(address);
|
||||
error |= addUInt8(command);
|
||||
error |= addUInt8(dataLength);
|
||||
_command = command;
|
||||
_address = address;
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::finish(void) {
|
||||
uint16_t error = addUInt8(~_checksum);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (_index + 1 > _bufferSize) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
_buffer[_index++] = 0x7e;
|
||||
_isFinished = true;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addUInt32(uint32_t data) {
|
||||
uint16_t error = addUInt8(static_cast<uint8_t>((data & 0xFF000000) >> 24));
|
||||
error |= addUInt8(static_cast<uint8_t>((data & 0x00FF0000) >> 16));
|
||||
error |= addUInt8(static_cast<uint8_t>((data & 0x0000FF00) >> 8));
|
||||
error |= addUInt8(static_cast<uint8_t>((data & 0x000000FF) >> 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addInt32(int32_t data) {
|
||||
return addUInt32(static_cast<uint32_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addUInt16(uint16_t data) {
|
||||
uint16_t error = addUInt8(static_cast<uint8_t>((data & 0xFF00) >> 8));
|
||||
error |= addUInt8(static_cast<uint8_t>((data & 0x00FF) >> 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addInt16(int16_t data) {
|
||||
return addUInt16(static_cast<uint16_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addUInt8(uint8_t data) {
|
||||
if (_index + 2 > _bufferSize) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
switch (data) {
|
||||
case 0x11:
|
||||
case 0x13:
|
||||
case 0x7d:
|
||||
case 0x7e:
|
||||
// byte stuffing is done by inserting 0x7d and inverting bit 5
|
||||
_buffer[_index++] = 0x7d;
|
||||
_buffer[_index++] = data ^ (1 << 5);
|
||||
break;
|
||||
default:
|
||||
_buffer[_index++] = data;
|
||||
}
|
||||
_checksum += data;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addInt8(int8_t data) {
|
||||
return addUInt8(static_cast<uint8_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addBool(bool data) {
|
||||
return addUInt8(static_cast<uint8_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addFloat(float data) {
|
||||
union {
|
||||
uint32_t uInt32Data;
|
||||
float floatData;
|
||||
} convert;
|
||||
|
||||
convert.floatData = data;
|
||||
return addUInt32(convert.uInt32Data);
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addBytes(const uint8_t data[],
|
||||
size_t dataLength) {
|
||||
uint16_t error = 0;
|
||||
for (size_t i = 0; i < dataLength; i++) {
|
||||
error |= addUInt8(data[i]);
|
||||
}
|
||||
return error;
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_SHDLC_TX_FRAME_H_
|
||||
#define SENSIRION_SHDLC_TX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
|
||||
/*
|
||||
* SensirionShdlcTxFrame - Class which helps to build a correct SHDLC frame.
|
||||
* The begin() functions writes the header. The different addDatatype()
|
||||
* functions add the frame data and the finish() function writes the tail.
|
||||
* Using these functions one can easily construct a SHDLC frame.
|
||||
*/
|
||||
class SensirionShdlcTxFrame {
|
||||
|
||||
friend class SensirionShdlcCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the send frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the send frame.
|
||||
*/
|
||||
SensirionShdlcTxFrame(uint8_t buffer[], size_t bufferSize)
|
||||
: _buffer(buffer), _bufferSize(bufferSize) {
|
||||
}
|
||||
|
||||
/**
|
||||
* begin() - Begin frame and write header.
|
||||
*
|
||||
* @note This function needs to be called before calling other
|
||||
* data add functions to write the header at the beginning.
|
||||
*
|
||||
* @param command Command byte to add to the send frame.
|
||||
* @param address Address byte to add to the send frame.
|
||||
* @param dataLength Data length byte to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t begin(uint8_t command, uint8_t address, uint8_t dataLength);
|
||||
|
||||
/**
|
||||
* finish() - Finish frame and write tail.
|
||||
*
|
||||
* @note This function needs to be called last, after adding all
|
||||
* data to frame and before sending the frame to the sensor.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t finish(void);
|
||||
|
||||
/**
|
||||
* addUInt32() - Add unsigned 32bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 32bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt32(uint32_t data);
|
||||
|
||||
/**
|
||||
* addInt32() - Add signed 32bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 32bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt32(int32_t data);
|
||||
|
||||
/**
|
||||
* addUInt16() - Add unsigned 16bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 16bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt16(uint16_t data);
|
||||
|
||||
/**
|
||||
* addInt16() - Add signed 16bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 16bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt16(int16_t data);
|
||||
|
||||
/**
|
||||
* addUInt8() - Add unsigned 8bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 8bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt8(uint8_t data);
|
||||
|
||||
/**
|
||||
* addInt8() - Add signed 8bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 8bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt8(int8_t data);
|
||||
|
||||
/**
|
||||
* addBool() - Add boolean to the send frame.
|
||||
*
|
||||
* @param data Boolean to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addBool(bool data);
|
||||
|
||||
/**
|
||||
* addFloat() - Add float to the send frame.
|
||||
*
|
||||
* @param data Float to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addFloat(float data);
|
||||
|
||||
/**
|
||||
* addBytes() - Add byte array to the send frame.
|
||||
*
|
||||
* @param data Byte array to add to the send frame.
|
||||
* @param dataLength Number of bytes to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addBytes(const uint8_t data[], size_t dataLength);
|
||||
|
||||
uint8_t getCommand(void) const {
|
||||
return _command;
|
||||
};
|
||||
|
||||
uint8_t getAddress(void) const {
|
||||
return _address;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t* _buffer;
|
||||
size_t _bufferSize;
|
||||
size_t _index = 0;
|
||||
uint8_t _checksum = 0;
|
||||
bool _isFinished = false;
|
||||
uint8_t _command = 0;
|
||||
uint8_t _address = 0;
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_SHDLC_TX_FRAME_H_ */
|
|
@ -0,0 +1,45 @@
|
|||
#! /usr/bin/env python3
|
||||
import subprocess
|
||||
import json
|
||||
import argparse
|
||||
import sys
|
||||
import logging
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.description = u'Compile test a sketch for all available boards'
|
||||
parser.add_argument(u'-s', u'--sketch', dest=u'sketch',
|
||||
required=True, help=u'Path to sketch')
|
||||
args = parser.parse_args()
|
||||
test_all_boards(args.sketch)
|
||||
|
||||
|
||||
def test_all_boards(sketch):
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
format='%(asctime)s [%(levelname)s] %(message)s')
|
||||
log = logging.getLogger('arduino-compile-test')
|
||||
process = subprocess.run("arduino-cli board listall --format json".split(),
|
||||
stdout=subprocess.PIPE)
|
||||
board_list_json = process.stdout.decode('utf-8')
|
||||
board_list = json.loads(board_list_json)
|
||||
test_list = ["arduino:samd:mkrzero", "arduino:avr:mega",
|
||||
"arduino:avr:nano", "arduino:avr:uno",
|
||||
"esp32:esp32:esp32", "esp8266:esp8266:generic"]
|
||||
for board in test_list:
|
||||
if board in (b['fqbn'] for b in board_list['boards']):
|
||||
log.info('Test compilation for board {}'.format(board))
|
||||
command = 'arduino-cli compile --libraries="." --warnings all'\
|
||||
' --fqbn {board} {sketch}'.format(board=board,
|
||||
sketch=sketch)
|
||||
process = subprocess.run(command.split(), stdout=subprocess.PIPE)
|
||||
if process.returncode:
|
||||
log.error(process.stdout.decode('utf-8'))
|
||||
sys.exit(process.returncode)
|
||||
else:
|
||||
log.error('Board not installed: {}'.format(board))
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
cppcheck --std=c++11 --language=c++ --error-exitcode=1 --enable=warning,style,performance,portability src/*
|
|
@ -0,0 +1,5 @@
|
|||
#! /bin/bash
|
||||
set -euxo pipefail
|
||||
editorconfig-checker
|
||||
flake8
|
||||
find . -type f -iregex ".*\.\(c\|h\|cpp\|ino\)" -exec clang-format-6.0 -i -style=file {} \; && git diff --exit-code
|
|
@ -0,0 +1,20 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
## [0.2.0] - 2022-03-30
|
||||
|
||||
Add support for SEN50
|
||||
|
||||
## [0.1.0] - 2022-01-05
|
||||
|
||||
Initial release
|
||||
|
||||
[0.2.0]: https://github.com/Sensirion/embedded-i2c-sen5x/compare/0.1.0...0.2.0
|
||||
[0.1.0]: https://github.com/Sensirion/arduino-i2c-sen5x/releases/tag/0.1.0
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, Sensirion AG
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,97 @@
|
|||
<!-- Downloaded from https://github.com/Sensirion/arduino-i2c-sen5x
|
||||
on 10/01/2023 at commit d7a73c86073cca34b84cde83814f5c17b87aad6d -->
|
||||
# Sensirion I2C SEN5X Arduino Library
|
||||
|
||||
This is the Sensirion SEN5X library for Arduino using the
|
||||
modules I2C interface.
|
||||
|
||||
<center><img src="images/SEN5x.png" width="500px"></center>
|
||||
|
||||
## Supported sensors
|
||||
|
||||
- SEN50 (only particulate matter signals available)
|
||||
- SEN54 (no NOx signal available)
|
||||
- SEN55 (full feature set)
|
||||
|
||||
# Installation
|
||||
|
||||
To install, download the latest release as .zip file and add it to your
|
||||
[Arduino IDE](http://www.arduino.cc/en/main/software) via
|
||||
|
||||
Sketch => Include Library => Add .ZIP Library...
|
||||
|
||||
Don't forget to **install the dependencies** listed below the same way via `Add
|
||||
.ZIP Library`
|
||||
|
||||
Note: Installation via the Arduino Library Manager is coming soon.
|
||||
|
||||
# Dependencies
|
||||
|
||||
* [Sensirion Core](https://github.com/Sensirion/arduino-core)
|
||||
|
||||
|
||||
# Quick Start
|
||||
|
||||
1. Connect the SEN5X Sensor to your Arduino board's standard
|
||||
I2C bus. Check the pinout of your Arduino board to find the correct pins.
|
||||
The pinout of the SEN5X Sensor board can be found in the
|
||||
data sheet.
|
||||
|
||||
| *SEN5X* | *Arduino* | *Jumper Wire* |
|
||||
| ------- | ----------- | ------------- |
|
||||
| VCC | 5V | Red |
|
||||
| GND | GND | Black |
|
||||
| SDA | SDA | Green |
|
||||
| SCL | SCL | Yellow |
|
||||
| SEL | GND for I2C | Blue |
|
||||
|
||||
<center><img src="images/SEN5X_pinout.png" width="300px"></center>
|
||||
|
||||
| *Pin* | *Name* | *Description* | *Comments* |
|
||||
| ----- | ------ | ------------------------------- | -------------------------------- |
|
||||
| 1 | VCC | Supply Voltage | 5V ±10% |
|
||||
| 2 | GND | Ground |
|
||||
| 3 | SDA | I2C: Serial data input / output | TTL 5V and LVTTL 3.3V compatible |
|
||||
| 4 | SCL | I2C: Serial clock input | TTL 5V and LVTTL 3.3V compatible |
|
||||
| 5 | SEL | Interface select | Pull to GND to select I2C |
|
||||
| 6 | NC | Do not connect |
|
||||
|
||||
2. Open the `exampleUsage` sample project within the Arduino IDE
|
||||
|
||||
File => Examples => Sensirion I2C SEN5X => exampleUsage
|
||||
|
||||
3. Click the `Upload` button in the Arduino IDE or
|
||||
|
||||
Sketch => Upload
|
||||
|
||||
4. When the upload process has finished, open the `Serial Monitor` or `Serial
|
||||
Plotter` via the `Tools` menu to observe the measurement values. Note that
|
||||
the `Baud Rate` in the corresponding window has to be set to `115200 baud`.
|
||||
|
||||
# Contributing
|
||||
|
||||
**Contributions are welcome!**
|
||||
|
||||
We develop and test this driver using our company internal tools (version
|
||||
control, continuous integration, code review etc.) and automatically
|
||||
synchronize the master branch with GitHub. But this doesn't mean that we don't
|
||||
respond to issues or don't accept pull requests on GitHub. In fact, you're very
|
||||
welcome to open issues or create pull requests :)
|
||||
|
||||
This Sensirion library uses
|
||||
[`clang-format`](https://releases.llvm.org/download.html) to standardize the
|
||||
formatting of all our `.cpp` and `.h` files. Make sure your contributions are
|
||||
formatted accordingly:
|
||||
|
||||
The `-i` flag will apply the format changes to the files listed.
|
||||
|
||||
```bash
|
||||
clang-format -i src/*.cpp src/*.h
|
||||
```
|
||||
|
||||
Note that differences from this formatting will result in a failed build until
|
||||
they are fixed.
|
||||
|
||||
# License
|
||||
|
||||
See [LICENSE](LICENSE).
|
|
@ -0,0 +1,249 @@
|
|||
|
||||
/*
|
||||
* I2C-Generator: 0.3.0
|
||||
* Yaml Version: 2.1.3
|
||||
* Template Version: 0.7.0-112-g190ecaa
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SensirionI2CSen5x.h>
|
||||
#include <Wire.h>
|
||||
|
||||
// The used commands use up to 48 bytes. On some Arduino's the default buffer
|
||||
// space is not large enough
|
||||
#define MAXBUF_REQUIREMENT 48
|
||||
|
||||
#if (defined(I2C_BUFFER_LENGTH) && \
|
||||
(I2C_BUFFER_LENGTH >= MAXBUF_REQUIREMENT)) || \
|
||||
(defined(BUFFER_LENGTH) && BUFFER_LENGTH >= MAXBUF_REQUIREMENT)
|
||||
#define USE_PRODUCT_INFO
|
||||
#endif
|
||||
|
||||
SensirionI2CSen5x sen5x;
|
||||
|
||||
void printModuleVersions() {
|
||||
uint16_t error;
|
||||
char errorMessage[256];
|
||||
|
||||
unsigned char productName[32];
|
||||
uint8_t productNameSize = 32;
|
||||
|
||||
error = sen5x.getProductName(productName, productNameSize);
|
||||
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute getProductName(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("ProductName:");
|
||||
Serial.println((char*)productName);
|
||||
}
|
||||
|
||||
uint8_t firmwareMajor;
|
||||
uint8_t firmwareMinor;
|
||||
bool firmwareDebug;
|
||||
uint8_t hardwareMajor;
|
||||
uint8_t hardwareMinor;
|
||||
uint8_t protocolMajor;
|
||||
uint8_t protocolMinor;
|
||||
|
||||
error = sen5x.getVersion(firmwareMajor, firmwareMinor, firmwareDebug,
|
||||
hardwareMajor, hardwareMinor, protocolMajor,
|
||||
protocolMinor);
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute getVersion(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("Firmware: ");
|
||||
Serial.print(firmwareMajor);
|
||||
Serial.print(".");
|
||||
Serial.print(firmwareMinor);
|
||||
Serial.print(", ");
|
||||
|
||||
Serial.print("Hardware: ");
|
||||
Serial.print(hardwareMajor);
|
||||
Serial.print(".");
|
||||
Serial.println(hardwareMinor);
|
||||
}
|
||||
}
|
||||
|
||||
void printSerialNumber() {
|
||||
uint16_t error;
|
||||
char errorMessage[256];
|
||||
unsigned char serialNumber[32];
|
||||
uint8_t serialNumberSize = 32;
|
||||
|
||||
error = sen5x.getSerialNumber(serialNumber, serialNumberSize);
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute getSerialNumber(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("SerialNumber:");
|
||||
Serial.println((char*)serialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
while (!Serial) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
Wire.begin();
|
||||
|
||||
sen5x.begin(Wire);
|
||||
|
||||
uint16_t error;
|
||||
char errorMessage[256];
|
||||
error = sen5x.deviceReset();
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute deviceReset(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
}
|
||||
|
||||
// Print SEN55 module information if i2c buffers are large enough
|
||||
#ifdef USE_PRODUCT_INFO
|
||||
printSerialNumber();
|
||||
printModuleVersions();
|
||||
#endif
|
||||
|
||||
// set a temperature offset in degrees celsius
|
||||
// Note: supported by SEN54 and SEN55 sensors
|
||||
// By default, the temperature and humidity outputs from the sensor
|
||||
// are compensated for the modules self-heating. If the module is
|
||||
// designed into a device, the temperature compensation might need
|
||||
// to be adapted to incorporate the change in thermal coupling and
|
||||
// self-heating of other device components.
|
||||
//
|
||||
// A guide to achieve optimal performance, including references
|
||||
// to mechanical design-in examples can be found in the app note
|
||||
// “SEN5x – Temperature Compensation Instruction” at www.sensirion.com.
|
||||
// Please refer to those application notes for further information
|
||||
// on the advanced compensation settings used
|
||||
// in `setTemperatureOffsetParameters`, `setWarmStartParameter` and
|
||||
// `setRhtAccelerationMode`.
|
||||
//
|
||||
// Adjust tempOffset to account for additional temperature offsets
|
||||
// exceeding the SEN module's self heating.
|
||||
float tempOffset = 0.0;
|
||||
error = sen5x.setTemperatureOffsetSimple(tempOffset);
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute setTemperatureOffsetSimple(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("Temperature Offset set to ");
|
||||
Serial.print(tempOffset);
|
||||
Serial.println(" deg. Celsius (SEN54/SEN55 only");
|
||||
}
|
||||
|
||||
// Start Measurement
|
||||
error = sen5x.startMeasurement();
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute startMeasurement(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint16_t error;
|
||||
char errorMessage[256];
|
||||
|
||||
delay(1000);
|
||||
|
||||
// Read Measurement
|
||||
float massConcentrationPm1p0;
|
||||
float massConcentrationPm2p5;
|
||||
float massConcentrationPm4p0;
|
||||
float massConcentrationPm10p0;
|
||||
float ambientHumidity;
|
||||
float ambientTemperature;
|
||||
float vocIndex;
|
||||
float noxIndex;
|
||||
|
||||
error = sen5x.readMeasuredValues(
|
||||
massConcentrationPm1p0, massConcentrationPm2p5, massConcentrationPm4p0,
|
||||
massConcentrationPm10p0, ambientHumidity, ambientTemperature, vocIndex,
|
||||
noxIndex);
|
||||
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute readMeasuredValues(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("MassConcentrationPm1p0:");
|
||||
Serial.print(massConcentrationPm1p0);
|
||||
Serial.print("\t");
|
||||
Serial.print("MassConcentrationPm2p5:");
|
||||
Serial.print(massConcentrationPm2p5);
|
||||
Serial.print("\t");
|
||||
Serial.print("MassConcentrationPm4p0:");
|
||||
Serial.print(massConcentrationPm4p0);
|
||||
Serial.print("\t");
|
||||
Serial.print("MassConcentrationPm10p0:");
|
||||
Serial.print(massConcentrationPm10p0);
|
||||
Serial.print("\t");
|
||||
Serial.print("AmbientHumidity:");
|
||||
if (isnan(ambientHumidity)) {
|
||||
Serial.print("n/a");
|
||||
} else {
|
||||
Serial.print(ambientHumidity);
|
||||
}
|
||||
Serial.print("\t");
|
||||
Serial.print("AmbientTemperature:");
|
||||
if (isnan(ambientTemperature)) {
|
||||
Serial.print("n/a");
|
||||
} else {
|
||||
Serial.print(ambientTemperature);
|
||||
}
|
||||
Serial.print("\t");
|
||||
Serial.print("VocIndex:");
|
||||
if (isnan(vocIndex)) {
|
||||
Serial.print("n/a");
|
||||
} else {
|
||||
Serial.print(vocIndex);
|
||||
}
|
||||
Serial.print("\t");
|
||||
Serial.print("NoxIndex:");
|
||||
if (isnan(noxIndex)) {
|
||||
Serial.println("n/a");
|
||||
} else {
|
||||
Serial.println(noxIndex);
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
Binary file not shown.
After Width: | Height: | Size: 440 KiB |
|
@ -0,0 +1,55 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
SensirionI2CSen5x KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
startMeasurement KEYWORD2
|
||||
startMeasurementWithoutPm KEYWORD2
|
||||
stopMeasurement KEYWORD2
|
||||
readDataReady KEYWORD2
|
||||
readMeasuredValues KEYWORD2
|
||||
readMeasuredValuesAsIntegers KEYWORD2
|
||||
readMeasuredValuesSen50 KEYWORD2
|
||||
readMeasuredRawValues KEYWORD2
|
||||
readMeasuredPmValues KEYWORD2
|
||||
readMeasuredPmValuesAsIntegers KEYWORD2
|
||||
startFanCleaning KEYWORD2
|
||||
setTemperatureOffsetSimple KEYWORD2
|
||||
getTemperatureOffsetSimple KEYWORD2
|
||||
setTemperatureOffsetParameters KEYWORD2
|
||||
getTemperatureOffsetParameters KEYWORD2
|
||||
setWarmStartParameter KEYWORD2
|
||||
getWarmStartParameter KEYWORD2
|
||||
setVocAlgorithmTuningParameters KEYWORD2
|
||||
getVocAlgorithmTuningParameters KEYWORD2
|
||||
setNoxAlgorithmTuningParameters KEYWORD2
|
||||
getNoxAlgorithmTuningParameters KEYWORD2
|
||||
setRhtAccelerationMode KEYWORD2
|
||||
getRhtAccelerationMode KEYWORD2
|
||||
setVocAlgorithmState KEYWORD2
|
||||
getVocAlgorithmState KEYWORD2
|
||||
setFanAutoCleaningInterval KEYWORD2
|
||||
getFanAutoCleaningInterval KEYWORD2
|
||||
getProductName KEYWORD2
|
||||
getSerialNumber KEYWORD2
|
||||
getVersion KEYWORD2
|
||||
readDeviceStatus KEYWORD2
|
||||
readAndClearDeviceStatus KEYWORD2
|
||||
deviceReset KEYWORD2
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
sen5x KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
|
@ -0,0 +1,10 @@
|
|||
name=Sensirion I2C SEN5X
|
||||
version=0.2.0
|
||||
author=Sensirion
|
||||
maintainer=Sensirion
|
||||
sentence=Library for the SEN5X sensor family by Sensirion
|
||||
paragraph=Enables you to use the SEN50, SEN54 and SEN55 via I2C.
|
||||
url=https://github.com/Sensirion/arduino-i2c-sen5x
|
||||
category=Sensors
|
||||
depends=Sensirion Core
|
||||
includes=SensirionI2CSen5x.h
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue