mirror of https://github.com/arendst/Tasmota.git
commit
4de7185321
|
@ -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 on Tasmota core ESP8266 V.2.7.4.9
|
||||
- [ ] The code change is tested and works on Tasmota core ESP32 V.1.0.5-rc4
|
||||
- [ ] The code change is tested and works on Tasmota core ESP32 V.1.0.5-rc6
|
||||
- [ ] 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**_
|
||||
|
|
|
@ -64,6 +64,26 @@ jobs:
|
|||
name: firmware
|
||||
path: ./build_output/firmware
|
||||
|
||||
tasmota32-core2:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
platformio upgrade --dev
|
||||
platformio update
|
||||
- name: Run PlatformIO
|
||||
run: |
|
||||
platformio run -e tasmota32-core2
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output/firmware
|
||||
|
||||
tasmota32-minimal:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
|
|
@ -898,6 +898,29 @@ jobs:
|
|||
path: ./build_output/firmware
|
||||
|
||||
|
||||
tasmota32-core2:
|
||||
needs: tasmota_pull
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
platformio upgrade --dev
|
||||
platformio update
|
||||
- name: Run PlatformIO
|
||||
run: |
|
||||
platformio run -e tasmota32-core2
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output/firmware
|
||||
|
||||
|
||||
tasmota32-knx:
|
||||
needs: tasmota_pull
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -1600,11 +1623,10 @@ jobs:
|
|||
[ ! -f ./mv_firmware/tasmota32-display.* ] || mv ./mv_firmware/tasmota32-display.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-web*.* ] || mv ./mv_firmware/tasmota32-web*.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-odroidgo.* ] || mv ./mv_firmware/tasmota32-odroidgo.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-core2.* ] || mv ./mv_firmware/tasmota32-core2.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-knx.* ] || mv ./mv_firmware/tasmota32-knx.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32* ] || mv ./mv_firmware/tasmota32* ./firmware/tasmota32/languages/
|
||||
[ ! -f ./mv_firmware/* ] || mv ./mv_firmware/* ./firmware/tasmota/languages/
|
||||
rm ./firmware/tasmota32/*.gz
|
||||
rm ./firmware/tasmota32/languages/*.gz
|
||||
[ ! -f ./tools/Esptool/ESP32/*.* ] || mv ./tools/Esptool/ESP32/*.* ./firmware/tasmota32/ESP32_needed_files/
|
||||
[ ! -f ./tools/Esptool/Odroid_go/*.* ] || mv ./tools/Esptool/Odroid_go/*.* ./firmware/tasmota32/Odroid_go_needed_files/
|
||||
[ ! -f ./FIRMWARE.md ] || mv -f ./FIRMWARE.md ./README.md
|
||||
|
|
|
@ -898,6 +898,29 @@ jobs:
|
|||
path: ./build_output/firmware
|
||||
|
||||
|
||||
tasmota32-core2:
|
||||
needs: tasmota_pull
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
platformio upgrade --dev
|
||||
platformio update
|
||||
- name: Run PlatformIO
|
||||
run: |
|
||||
platformio run -e tasmota32-core2
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output/firmware
|
||||
|
||||
|
||||
tasmota32-knx:
|
||||
needs: tasmota_pull
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -1600,11 +1623,10 @@ jobs:
|
|||
[ ! -f ./mv_firmware/tasmota32-display.* ] || mv ./mv_firmware/tasmota32-display.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-web*.* ] || mv ./mv_firmware/tasmota32-web*.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-odroidgo.* ] || mv ./mv_firmware/tasmota32-odroidgo.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-core2.* ] || mv ./mv_firmware/tasmota32-core2.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-knx.* ] || mv ./mv_firmware/tasmota32-knx.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32* ] || mv ./mv_firmware/tasmota32* ./firmware/tasmota32/languages/
|
||||
[ ! -f ./mv_firmware/* ] || mv ./mv_firmware/* ./firmware/tasmota/languages/
|
||||
rm ./firmware/tasmota32/*.gz
|
||||
rm ./firmware/tasmota32/languages/*.gz
|
||||
[ ! -f ./tools/Esptool/ESP32/*.* ] || mv ./tools/Esptool/ESP32/*.* ./firmware/tasmota32/ESP32_needed_files/
|
||||
[ ! -f ./tools/Esptool/Odroid_go/*.* ] || mv ./tools/Esptool/Odroid_go/*.* ./firmware/tasmota32/Odroid_go_needed_files/
|
||||
[ ! -f ./FIRMWARE.md ] || mv -f ./RELEASENOTES.md ./README.md
|
||||
|
|
|
@ -2,13 +2,13 @@ name: "Mark or close stale issues and PRs"
|
|||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "15 05 * * *"
|
||||
- cron: "30 * * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v3.0.14
|
||||
- uses: actions/stale@v3.0.15
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 25
|
||||
|
|
|
@ -149,6 +149,7 @@
|
|||
| USE_EZORGB | - | - | - | - | - | - | - |
|
||||
| USE_EZORTD | - | - | - | - | - | - | - |
|
||||
| USE_SEESAW_SOIL | - | - | - | - | - | - | - |
|
||||
| USE_TOF10120 | - | - | - | - | - | - | - |
|
||||
| | | | | | | | |
|
||||
| Feature or Sensor | minimal | lite | tasmota | knx | sensors | ir | display | Remarks
|
||||
| USE_SPI | - | - | - | - | - | - | x |
|
||||
|
@ -193,6 +194,7 @@
|
|||
| USE_RF_SENSOR | - | - | - | - | x | - | - | AlectoV2 only
|
||||
| USE_HRE | - | - | - | - | x | - | - |
|
||||
| USE_A4988_STEPPER | - | - | - | - | - | - | - |
|
||||
| USE_NEOPOOL | - | - | - | - | - | - | - |
|
||||
| | | | | | | | |
|
||||
| Feature or Sensor | minimal | lite | tasmota | knx | sensors | ir | display | Remarks
|
||||
| USE_DISPLAY | - | - | - | - | - | - | x |
|
||||
|
|
32
CHANGELOG.md
32
CHANGELOG.md
|
@ -3,7 +3,23 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
## [Unreleased] - Development
|
||||
|
||||
## [9.2.0.3]
|
||||
## [9.2.0.4]
|
||||
### Added
|
||||
- Function ``AddLog`` to provide logging for up to 128 (LOGSZ) characters to save stack space
|
||||
- Commands ``ChannelRemap``, ``MultiPWM``, ``AlexaCTRange``, ``PowerOnFade``, ``PWMCT``, ``WhiteBlend`` and ``VirtualCT`` as synonyms for ``SetOption37, 68, 82, 91, 92, 105`` and ``106``
|
||||
- Commands ``ZbNameKey``, ``ZbDeviceTopic``, ``ZbNoPrefix``, ``ZbEndpointSuffix``, ``ZbNoAutoBind`` and ``ZbNameTopic`` as synonyms for ``SetOption83, 89, 100, 101, 110`` and ``112``
|
||||
- Commands ``ZbNoAutoBind``, ``ZbReceivedTopic`` and ``ZbOmitDevice`` as synonyms for ``SetOption116, 118`` and ``119``
|
||||
- Commands ``BuzzerActive`` and ``BuzzerPwm`` as synonyms for ``SetOption67`` and ``111``
|
||||
- Support for ESP32 ``Module 5`` Wireless Tag Eth01 (#9496)
|
||||
- Support trailing silence in buzzer tune (#10694)
|
||||
- Command ``L1MusicSync <0|Off>|<1|On>|<2|Toggle>, 1..10, 1..100>`` to control Sonoff L1 Music Sync mode sensitivity and speed (#10722)
|
||||
- Command ``Speed2`` to control a once off fade (#10741)
|
||||
- Zigbee command ``SetOption120 1`` or ``ZbEndpointTopic 1`` to add the endpoint as suffix in topic when using ``SetOption89 1``
|
||||
|
||||
### Changed
|
||||
- Maximum chars in ``AddLog_P`` logging restored from 128 to 700 (MAX_LOGSZ) to solve broken error messages
|
||||
|
||||
## [9.2.0.3] 20210122
|
||||
### Added
|
||||
- Support for time proportioned (``#define USE_TIMEPROP``) and optional PID (``#define USE_PID``) relay control (#10412)
|
||||
- Support rotary encoder on Shelly Dimmer (#10407)
|
||||
|
@ -12,6 +28,14 @@ All notable changes to this project will be documented in this file.
|
|||
- Support for up to 4 I2C SEESAW_SOIL Capacitance & Temperature sensors by Peter Franck (#10481)
|
||||
- ESP8266 Support for 2MB and up linker files with 1MB and up LittleFS
|
||||
- ESP32 support for TLS MQTT using BearSSL (same as ESP8266)
|
||||
- Support for 24/26/32/34 bit RFID Wiegand interface (D0/D1) by Sigurd Leuther (#3647)
|
||||
- Compile time option ``USE_MQTT_TLS_DROP_OLD_FINGERPRINT`` to drop old (less secure) TLS fingerprint
|
||||
- Command ``SetOption40 0..250`` to disable button functionality if activated for over 0.1 second re-introduced
|
||||
- Support for SM2135 current selection using GPIO ``SM2135 DAT`` index (#10634)
|
||||
- Support for ESP32 ``Module 7`` M5stack core2 16MB binary tasmota32-core2.bin (#10635)
|
||||
- Support for Sugar Valley NeoPool Controller by Norbert Richter (#10637)
|
||||
- Rule trigger string comparisons for EndsWith ``$>``, StartsWith ``$<`` and Contains ``$|`` (#10538)
|
||||
- Support for TOF10120 time of flight sensor by Cyril Pawelko (#10190)
|
||||
|
||||
### Breaking Changed
|
||||
- ESP32 switch from default SPIFFS to default LittleFS file system loosing current (zigbee) files
|
||||
|
@ -20,10 +44,12 @@ All notable changes to this project will be documented in this file.
|
|||
### Changed
|
||||
- Force initial default state ``SetOption57 1`` to scan wifi network every 44 minutes for strongest signal (#10395)
|
||||
- Command ``Sleep 0`` removes any sleep from wifi modem except when ESP32 BLE is active
|
||||
- PubSubClient MQTT_SOCKET_TIMEOUT from 15 to 4 seconds
|
||||
- Domoticz fixed 2 decimals resolution by user selectable ``TempRes``, ``HumRes`` and ``PressRes`` resolutions
|
||||
|
||||
## [9.2.0.2] 20210105
|
||||
### Added
|
||||
- Basic support for ESP32 Odroid Go 16MB binary tasmota32-odroidgo.bin (#8630)
|
||||
- Support for ESP32 ``Module 3`` Odroid Go 16MB binary tasmota32-odroidgo.bin (#8630)
|
||||
- Command ``CTRange`` to specify the visible CT range the bulb is capable of (#10311)
|
||||
- Command ``VirtualCT`` to simulate or fine tune CT bulbs with 3,4,5 channels (#10311)
|
||||
- Command ``SetOption118 1`` to move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default (#10353)
|
||||
|
@ -45,7 +71,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Replaced RA8876 GPIO selection from ``SPI CS`` by ``RA8876 CS``
|
||||
|
||||
### Changed
|
||||
- Maximum chars in AddLog_P logging reduced from 700 to 128 (LOGSZ) to enhance stability
|
||||
- Maximum chars in ``AddLog_P`` logging reduced from 700 to 128 (LOGSZ) to enhance stability
|
||||
- Disabled ``USE_LIGHT`` light support for ZBBridge saving 17.6kB (#10374)
|
||||
|
||||
## [9.2.0.1] 20201229
|
||||
|
|
|
@ -90,3 +90,4 @@ Index | Define | Driver | Device | Address(es) | Description
|
|||
55 | USE_EZORGB | xsns_78 | EZORGB | 0x61 - 0x70 | Color sensor
|
||||
55 | USE_EZOPMP | xsns_78 | EZOPMP | 0x61 - 0x70 | Peristaltic Pump
|
||||
56 | USE_SEESAW_SOIL | xsns_81 | SEESOIL | 0x36 - 0x39 | Adafruit seesaw soil moisture sensor
|
||||
57 | USE_TOF10120 | xsns_84 | TOF10120 | 0x52 | Time-of-flight (ToF) distance sensor
|
||||
|
|
|
@ -56,14 +56,22 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
|
|||
|
||||
[Complete list](BUILDS.md) of available feature and sensors.
|
||||
|
||||
## Changelog v9.2.0.3
|
||||
## Changelog v9.2.0.4
|
||||
### Added
|
||||
- Command ``CTRange`` to specify the visible CT range the bulb is capable of [#10311](https://github.com/arendst/Tasmota/issues/10311)
|
||||
- Command ``L1MusicSync <0|Off>|<1|On>|<2|Toggle>, 1..10, 1..100>`` to control Sonoff L1 Music Sync mode sensitivity and speed [#10722](https://github.com/arendst/Tasmota/issues/10722)
|
||||
- Command ``RuleTimer0`` to access all RuleTimers at once [#10352](https://github.com/arendst/Tasmota/issues/10352)
|
||||
- Command ``Speed2`` to control a once off fade [#10741](https://github.com/arendst/Tasmota/issues/10741)
|
||||
- Command ``VirtualCT`` to simulate or fine tune CT bulbs with 3,4,5 channels [#10311](https://github.com/arendst/Tasmota/issues/10311)
|
||||
- Command ``SetOption40 0..250`` to disable button functionality if activated for over 0.1 second re-introduced
|
||||
- Command ``SetOption43 1..255`` to control Rotary step (#10407)
|
||||
- Command ``SetOption118 1`` to move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default [#10353](https://github.com/arendst/Tasmota/issues/10353)
|
||||
- Command ``SetOption119 1`` to remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic [#10355](https://github.com/arendst/Tasmota/issues/10355)
|
||||
- Zigbee command ``SetOption120 1`` or ``ZbEndpointTopic 1`` to add the zigbee endpoint as suffix in topic when using ``SetOption89 1``
|
||||
- Commands ``ChannelRemap``, ``MultiPWM``, ``AlexaCTRange``, ``PowerOnFade``, ``PWMCT``, ``WhiteBlend`` and ``VirtualCT`` as synonyms for ``SetOption37, 68, 82, 91, 92, 105`` and ``106``
|
||||
- Commands ``ZbNameKey``, ``ZbDeviceTopic``, ``ZbNoPrefix``, ``ZbEndpointSuffix``, ``ZbNoAutoBind`` and ``ZbNameTopic`` as synonyms for ``SetOption83, 89, 100, 101, 110`` and ``112``
|
||||
- Commands ``ZbNoAutoBind``, ``ZbReceivedTopic`` and ``ZbOmitDevice`` as synonyms for ``SetOption116, 118`` and ``119``
|
||||
- Commands ``BuzzerActive`` and ``BuzzerPwm`` as synonyms for ``SetOption67`` and ``111``
|
||||
- Milliseconds to console output [#10152](https://github.com/arendst/Tasmota/issues/10152)
|
||||
- Gpio ``Option_a1`` enabling PWM2 high impedance if powered off as used by Wyze bulbs [#10196](https://github.com/arendst/Tasmota/issues/10196)
|
||||
- Rotary No Pullup GPIO selection ``Rotary A/B_n`` [#10407](https://github.com/arendst/Tasmota/issues/10407)
|
||||
|
@ -73,15 +81,24 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
|
|||
- Support for FTC532 8-button touch controller by Peter Franck [#10222](https://github.com/arendst/Tasmota/issues/10222)
|
||||
- Support for BS814A-2 8-button touch buttons by Peter Franck [#10447](https://github.com/arendst/Tasmota/issues/10447)
|
||||
- Support for up to 4 I2C SEESAW_SOIL Capacitance & Temperature sensors by Peter Franck [#10481](https://github.com/arendst/Tasmota/issues/10481)
|
||||
- Support for TOF10120 time of flight sensor by Cyril Pawelko [#10190](https://github.com/arendst/Tasmota/issues/10190)
|
||||
- Support for Afrikaans language translations by Christiaan Heerze
|
||||
- Support for IR inverted leds using ``#define IR_SEND_INVERTED true`` [#10301](https://github.com/arendst/Tasmota/issues/10301)
|
||||
- Support for disabling 38kHz IR modulation using ``#define IR_SEND_USE_MODULATION false`` [#10301](https://github.com/arendst/Tasmota/issues/10301)
|
||||
- Support for SPI display driver for ST7789 TFT by Gerhard Mutz [#9037](https://github.com/arendst/Tasmota/issues/9037)
|
||||
- Support for time proportioned (``#define USE_TIMEPROP``) and optional PID (``#define USE_PID``) relay control [#10412](https://github.com/arendst/Tasmota/issues/10412)
|
||||
- Support for 24/26/32/34 bit RFID Wiegand interface (D0/D1) by Sigurd Leuther [#3647](https://github.com/arendst/Tasmota/issues/3647)
|
||||
- Support for SM2135 current selection using GPIO ``SM2135 DAT`` index [#10634](https://github.com/arendst/Tasmota/issues/10634)
|
||||
- Support for Sugar Valley NeoPool Controller by Norbert Richter [#10637](https://github.com/arendst/Tasmota/issues/10637)
|
||||
- Support for ESP32 ``Module 3`` Odroid Go 16MB binary tasmota32-odroidgo.bin [#8630](https://github.com/arendst/Tasmota/issues/8630)
|
||||
- Support for ESP32 ``Module 5`` Wireless Tag Eth01 [#9496](https://github.com/arendst/Tasmota/issues/9496)
|
||||
- Support for ESP32 ``Module 7`` M5stack core2 16MB binary tasmota32-core2.bin [#10635](https://github.com/arendst/Tasmota/issues/10635)
|
||||
- Support rotary encoder on Shelly Dimmer [#10407](https://github.com/arendst/Tasmota/issues/10407#issuecomment-756240920)
|
||||
- Support character `#` to be replaced by `space`-character in command ``Publish`` topic [#10258](https://github.com/arendst/Tasmota/issues/10258)
|
||||
- Basic support for ESP32 Odroid Go 16MB binary tasmota32-odroidgo.bin [#8630](https://github.com/arendst/Tasmota/issues/8630)
|
||||
- Support trailing silence in buzzer tune [#10694](https://github.com/arendst/Tasmota/issues/10694)
|
||||
- Rule trigger string comparisons for EndsWith ``$>``, StartsWith ``$<`` and Contains ``$|`` [#10538](https://github.com/arendst/Tasmota/issues/10538)
|
||||
- SPI display driver SSD1331 Color oled by Jeroen Vermeulen [#10376](https://github.com/arendst/Tasmota/issues/10376)
|
||||
- Compile time option ``USE_MQTT_TLS_DROP_OLD_FINGERPRINT`` to drop old (less secure) TLS fingerprint
|
||||
|
||||
### Breaking Changed
|
||||
- ESP32 switch from default SPIFFS to default LittleFS file system loosing current (zigbee) files
|
||||
|
@ -100,6 +117,8 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
|
|||
- Logging from heap to stack freeing 700 bytes RAM
|
||||
- Disabled ``USE_LIGHT`` light support for ZBBridge saving 17.6kB [#10374](https://github.com/arendst/Tasmota/issues/10374)
|
||||
- Force initial default state ``SetOption57 1`` to scan wifi network every 44 minutes for strongest signal [#10395](https://github.com/arendst/Tasmota/issues/10395)
|
||||
- PubSubClient MQTT_SOCKET_TIMEOUT from 15 to 4 seconds
|
||||
- Domoticz fixed 2 decimals resolution by user selectable ``TempRes``, ``HumRes`` and ``PressRes`` resolutions
|
||||
|
||||
### Fixed
|
||||
- Redesign syslog and mqttlog using log buffer [#10164](https://github.com/arendst/Tasmota/issues/10164)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
name=Ext-printf
|
||||
version=1.0
|
||||
author=Stephan Hadinger
|
||||
maintainer=Stephan <stephan.hadinger@gmail.com>
|
||||
sentence=Extension of snprintf() and vsnprintf()
|
||||
paragraph=This library provides extended types support for snprintf (float, uint64_t)
|
||||
architectures=esp8266, esp32
|
|
@ -237,6 +237,21 @@ public:
|
|||
return buf2;
|
||||
}
|
||||
|
||||
// nullptr accepted
|
||||
static bool equalsSBuffer(const class SBuffer * buf1, const class SBuffer * buf2) {
|
||||
if (buf1 == buf2) { return true; }
|
||||
if (!buf1 && (buf2->len() == 0)) { return true; }
|
||||
if (!buf2 && (buf1->len() == 0)) { return true; }
|
||||
if (!buf1 || !buf2) { return false; } // at least one buf is not empty
|
||||
// we know that both buf1 and buf2 are non-null
|
||||
if (buf1->len() != buf2->len()) { return false; }
|
||||
size_t len = buf1->len();
|
||||
for (uint32_t i=0; i<len; i++) {
|
||||
if (buf1->get8(i) != buf2->get8(i)) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static uint8_t asc2byte(char chr) {
|
||||
|
@ -269,18 +284,3 @@ public:
|
|||
_buf = nullptr;
|
||||
}
|
||||
} PreAllocatedSBuffer;
|
||||
|
||||
// nullptr accepted
|
||||
bool equalsSBuffer(const class SBuffer * buf1, const class SBuffer * buf2) {
|
||||
if (buf1 == buf2) { return true; }
|
||||
if (!buf1 && (buf2->len() == 0)) { return true; }
|
||||
if (!buf2 && (buf1->len() == 0)) { return true; }
|
||||
if (!buf1 || !buf2) { return false; } // at least one buf is not empty
|
||||
// we know that both buf1 and buf2 are non-null
|
||||
if (buf1->len() != buf2->len()) { return false; }
|
||||
size_t len = buf1->len();
|
||||
for (uint32_t i=0; i<len; i++) {
|
||||
if (buf1->get8(i) != buf2->get8(i)) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
ext_printf.ino - Extended printf for Arduino objects
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ext_printf.h"
|
||||
#include <Arduino.h>
|
||||
#include <IPAddress.h>
|
||||
#include <SBuffer.hpp>
|
||||
|
||||
/*********************************************************************************************\
|
||||
* va_list extended support
|
||||
*
|
||||
* va_list allows to get the next argument but not to get the address of this argument in the stack.
|
||||
*
|
||||
* We add `va_cur_ptr(va, TYPE)` to get a pointer to the current argument.
|
||||
* This will allow to modify it in place and call back printf with altered arguments
|
||||
\*********************************************************************************************/
|
||||
|
||||
// This code is heavily inspired by the gcc implementation of va_list
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/gcc/config/xtensa/xtensa.c
|
||||
|
||||
// Here is the va_list structure:
|
||||
// struct va_list {
|
||||
// void * __va_stk; // offset 0 - pointer to arguments on the stack
|
||||
// void * __va_reg; // offset 4 - pointer to arguments from registers
|
||||
// uint32_t __va_ndx; // offset 8 - index in bytes of the argument (overshoot by sizeof(T))
|
||||
// }
|
||||
//
|
||||
// When `va_start()` is called, the first 6 arguments are passed through registers r2-r7 and
|
||||
// are saved on the stack like local variables
|
||||
|
||||
// The algorightm used by `va_arg()` is the following:
|
||||
// /* Implement `va_arg'. */
|
||||
// /* First align __va_ndx if necessary for this arg:
|
||||
// orig_ndx = (AP).__va_ndx;
|
||||
// if (__alignof__ (TYPE) > 4 )
|
||||
// orig_ndx = ((orig_ndx + __alignof__ (TYPE) - 1)
|
||||
// & -__alignof__ (TYPE)); */
|
||||
// /* Increment __va_ndx to point past the argument:
|
||||
// (AP).__va_ndx = orig_ndx + __va_size (TYPE); */
|
||||
// /* Check if the argument is in registers:
|
||||
// if ((AP).__va_ndx <= __MAX_ARGS_IN_REGISTERS * 4
|
||||
// && !must_pass_in_stack (type))
|
||||
// __array = (AP).__va_reg; */
|
||||
// /* ...otherwise, the argument is on the stack (never split between
|
||||
// registers and the stack -- change __va_ndx if necessary):
|
||||
// else
|
||||
// {
|
||||
// if (orig_ndx <= __MAX_ARGS_IN_REGISTERS * 4)
|
||||
// (AP).__va_ndx = 32 + __va_size (TYPE);
|
||||
// __array = (AP).__va_stk;
|
||||
// } */
|
||||
// /* Given the base array pointer (__array) and index to the subsequent
|
||||
// argument (__va_ndx), find the address:
|
||||
// __array + (AP).__va_ndx - (BYTES_BIG_ENDIAN && sizeof (TYPE) < 4
|
||||
// ? sizeof (TYPE)
|
||||
// : __va_size (TYPE))
|
||||
// The results are endian-dependent because values smaller than one word
|
||||
// are aligned differently. */
|
||||
|
||||
// So we can simply get the argument address
|
||||
#define MAX_ARGS_IN_REGISTERS 6 // ESP8266 passes 6 arguments by register, then on stack
|
||||
|
||||
// #define va_cur_ptr(va,T) ( (T*) __va_cur_ptr(va,sizeof(T)) ) // we only support 4 bytes aligned arguments, so we don't need this one
|
||||
|
||||
// void * __va_cur_ptr(va_list &va, size_t size) {
|
||||
// size = (size + 3) & 0xFFFFFFFC; // round to upper 4 bytes boundary
|
||||
|
||||
// uintptr_t * va_stk = (uintptr_t*) &va;
|
||||
// uintptr_t * va_reg = 1 + (uintptr_t*) &va;
|
||||
// uintptr_t * va_ndx = 2 + (uintptr_t*) &va;
|
||||
// uintptr_t arr;
|
||||
|
||||
// if (*va_ndx <= MAX_ARGS_IN_REGISTERS * 4) {
|
||||
// arr = *va_reg;
|
||||
// } else {
|
||||
// arr = *va_stk;
|
||||
// }
|
||||
// return (void*) (arr + *va_ndx - size);
|
||||
// }
|
||||
|
||||
// reduced version when arguments are always 4 bytes
|
||||
#define va_cur_ptr4(va,T) ( (T*) __va_cur_ptr4(va) )
|
||||
void * __va_cur_ptr4(va_list &va) {
|
||||
uintptr_t * va_stk = (uintptr_t*) &va;
|
||||
uintptr_t * va_reg = 1 + (uintptr_t*) &va;
|
||||
uintptr_t * va_ndx = 2 + (uintptr_t*) &va;
|
||||
uintptr_t arr;
|
||||
|
||||
if (*va_ndx <= MAX_ARGS_IN_REGISTERS * 4) {
|
||||
arr = *va_reg;
|
||||
} else {
|
||||
arr = *va_stk;
|
||||
}
|
||||
return (void*) (arr + *va_ndx - 4);
|
||||
}
|
||||
|
||||
// Example of logs with 8 arguments (+1 static argument)
|
||||
// We see that the first 5 are from low in the stack (local variables)
|
||||
// while the last 8 are upper in the stack pushed by caller
|
||||
//
|
||||
// Note 64 bits arguments cannot be split between registers and stack
|
||||
//
|
||||
// >>> Reading a_ptr=0x3FFFFD44 *a_ptr=1
|
||||
// >>> Reading a_ptr=0x3FFFFD48 *a_ptr=2
|
||||
// >>> Reading a_ptr=0x3FFFFD4C *a_ptr=3
|
||||
// >>> Reading a_ptr=0x3FFFFD50 *a_ptr=4
|
||||
// >>> Reading a_ptr=0x3FFFFD54 *a_ptr=5
|
||||
// >>> Reading a_ptr=0x3FFFFD70 *a_ptr=6
|
||||
// >>> Reading a_ptr=0x3FFFFD74 *a_ptr=7
|
||||
// >>> Reading a_ptr=0x3FFFFD78 *a_ptr=8
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Genral function to convert u64 to hex
|
||||
\*********************************************************************************************/
|
||||
// Simple function to print a 64 bits unsigned int
|
||||
char * U64toHex(uint64_t value, char *str) {
|
||||
// str must be at least 17 bytes long
|
||||
str[16] = 0; // end of string
|
||||
for (uint32_t i=0; i<16; i++) { // 16 digits
|
||||
uint32_t n = value & 0x0F;
|
||||
str[15 - i] = (n < 10) ? (char)n+'0' : (char)n-10+'A';
|
||||
value = value >> 4;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// see https://stackoverflow.com/questions/6357031/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-in-c
|
||||
// char* ToHex_P(unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween = '\0'); in tasmota_globals.h
|
||||
char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween = '\0') {
|
||||
// ToHex_P(in, insz, out, outz) -> "12345667"
|
||||
// ToHex_P(in, insz, out, outz, ' ') -> "12 34 56 67"
|
||||
// ToHex_P(in, insz, out, outz, ':') -> "12:34:56:67"
|
||||
static const char * hex PROGMEM = "0123456789ABCDEF";
|
||||
int between = (inbetween) ? 3 : 2;
|
||||
const unsigned char * pin = in;
|
||||
char * pout = out;
|
||||
for (; pin < in+insz; pout += between, pin++) {
|
||||
pout[0] = pgm_read_byte(&hex[(pgm_read_byte(pin)>>4) & 0xF]);
|
||||
pout[1] = pgm_read_byte(&hex[ pgm_read_byte(pin) & 0xF]);
|
||||
if (inbetween) { pout[2] = inbetween; }
|
||||
if (pout + 3 - out > outsz) { break; } // Better to truncate output string than overflow buffer
|
||||
}
|
||||
pout[(inbetween && insz) ? -1 : 0] = 0; // Discard last inbetween if any input
|
||||
return out;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* snprintf extended
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
|
||||
// get a fresh malloc allocated string based on the current pointer (can be in PROGMEM)
|
||||
// It is the caller's responsibility to free the memory
|
||||
char * copyStr(const char * str) {
|
||||
if (str == nullptr) { return nullptr; }
|
||||
char * cpy = (char*) malloc(strlen_P(str) + 1);
|
||||
strcpy_P(cpy, str);
|
||||
return cpy;
|
||||
}
|
||||
|
||||
int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list va) {
|
||||
va_list va_cpy;
|
||||
va_copy(va_cpy, va);
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32) // this works only for xtensa, other platforms needs va_list to be adapted
|
||||
// iterate on fmt to extract arguments and patch them in place
|
||||
char * fmt_cpy = copyStr(fmt_P);
|
||||
if (fmt_cpy == nullptr) { return 0; }
|
||||
char * fmt = fmt_cpy;
|
||||
|
||||
const uint32_t ALLOC_SIZE = 12;
|
||||
static char * allocs[ALLOC_SIZE] = {}; // initialized to zeroes
|
||||
uint32_t alloc_idx = 0;
|
||||
static char hex[20]; // buffer used for 64 bits, favor RAM instead of stack to remove pressure
|
||||
|
||||
for (; *fmt != 0; ++fmt) {
|
||||
int32_t decimals = -2; // default to 2 decimals and remove trailing zeros
|
||||
int32_t * decimals_ptr = nullptr;
|
||||
if (alloc_idx >= ALLOC_SIZE) { break; } // buffer is full, don't continue parsing
|
||||
if (*fmt == '%') {
|
||||
fmt++;
|
||||
char * fmt_start = fmt;
|
||||
if (*fmt == '\0') { break; } // end of string
|
||||
if (*fmt == '%') { continue; } // actual '%' char
|
||||
if (*fmt == '*') {
|
||||
decimals = va_arg(va, int32_t); // skip width argument as int
|
||||
decimals_ptr = va_cur_ptr4(va, int32_t); // pointer to value on stack
|
||||
const char ** cur_val_ptr = va_cur_ptr4(va, const char*); // pointer to value on stack
|
||||
fmt++;
|
||||
// Serial.printf("> decimals=%d, decimals_ptr=0x%08X\n", decimals, decimals_ptr);
|
||||
}
|
||||
if (*fmt < 'A') {
|
||||
decimals = strtol(fmt, nullptr, 10);
|
||||
}
|
||||
while (*fmt < 'A') { // brutal way to munch anything that is not a letter or '-' (or anything else)
|
||||
// while ((*fmt >= '0' && *fmt <= '9') || (*fmt == '.') || (*fmt == '*') || (*fmt == '-' || (*fmt == ' ' || (*fmt == '+') || (*fmt == '#')))) {
|
||||
fmt++;
|
||||
}
|
||||
|
||||
if (*fmt == '_') { // extension
|
||||
if (decimals_ptr) {
|
||||
// Serial.printf(">2 decimals=%d, decimals_ptr=0x%08X\n", decimals, decimals_ptr);
|
||||
*decimals_ptr = 0; // if '*' was used, make sure we replace the value with zero for snprintf()
|
||||
*(fmt_start++) = '-'; // in this case replace with `%-*s`
|
||||
*(fmt_start++) = '*';
|
||||
}
|
||||
for (; fmt_start <= fmt; fmt_start++) {
|
||||
*fmt_start = '0';
|
||||
}
|
||||
// *fmt = '0';
|
||||
fmt++;
|
||||
uint32_t cur_val = va_arg(va, uint32_t); // current value
|
||||
const char ** cur_val_ptr = va_cur_ptr4(va, const char*); // pointer to value on stack
|
||||
char * new_val_str = (char*) "";
|
||||
switch (*fmt) {
|
||||
case 'H': // Hex, decimals indicates the length, default 2
|
||||
{
|
||||
if (decimals < 0) { decimals = 0; }
|
||||
if (decimals > 0) {
|
||||
char * hex_char = (char*) malloc(decimals*2 + 2);
|
||||
ToHex_P((const uint8_t *)cur_val, decimals, hex_char, decimals*2 + 2);
|
||||
new_val_str = hex_char;
|
||||
allocs[alloc_idx++] = new_val_str;
|
||||
// Serial.printf("> hex=%s\n", hex_char);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'B': // Pointer to SBuffer
|
||||
{
|
||||
const SBuffer & buf = *(const SBuffer*)cur_val;
|
||||
size_t buf_len = (&buf != nullptr) ? buf.len() : 0;
|
||||
if (buf_len) {
|
||||
char * hex_char = (char*) malloc(buf_len*2 + 2);
|
||||
ToHex_P(buf.getBuffer(), buf_len, hex_char, buf_len*2 + 2);
|
||||
new_val_str = hex_char;
|
||||
allocs[alloc_idx++] = new_val_str;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// case 'D':
|
||||
// decimals = *(int32_t*)cur_val_ptr;
|
||||
// break;
|
||||
|
||||
// `%_I` ouputs an IPv4 32 bits address passed as u32 into a decimal dotted format
|
||||
case 'I': // Input is `uint32_t` 32 bits IP address, output is decimal dotted address
|
||||
{
|
||||
char * ip_str = (char*) malloc(16);
|
||||
snprintf_P(ip_str, 16, PSTR("%u.%u.%u.%u"), cur_val & 0xFF, (cur_val >> 8) & 0xFF, (cur_val >> 16) & 0xFF, (cur_val >> 24) & 0xFF);
|
||||
new_val_str = ip_str;
|
||||
allocs[alloc_idx++] = new_val_str;
|
||||
}
|
||||
break;
|
||||
|
||||
// `%_f` or `%*_f` outputs a float with optionan number of decimals passed as first argument if `*` is present
|
||||
// positive number of decimals means an exact number of decimals, can be `0` terminate
|
||||
// negative number of decimals will suppress
|
||||
// Ex:
|
||||
// char c[128];
|
||||
// float f = 3.141f;
|
||||
// ext_vsnprintf_P(c; szeof(c), "%_f %*_f %*_f", &f, 4, 1f, -4, %f);
|
||||
// --> c will be "3.14 3.1410 3.141"
|
||||
// Note: float MUST be passed by address, because C alsays promoted float to double when in vararg
|
||||
case 'f': // input is `float`, printed to float with 2 decimals
|
||||
{
|
||||
bool truncate = false;
|
||||
if (decimals < 0) {
|
||||
decimals = -decimals;
|
||||
truncate = true;
|
||||
}
|
||||
float number = *(float*)cur_val;
|
||||
if (isnan(number) || isinf(number)) {
|
||||
new_val_str = (char*) "null";
|
||||
} else {
|
||||
dtostrf(*(float*)cur_val, (decimals + 2), decimals, hex);
|
||||
|
||||
if (truncate) {
|
||||
uint32_t last = strlen(hex) - 1;
|
||||
// remove trailing zeros
|
||||
while (hex[last] == '0') {
|
||||
hex[last--] = 0; // remove last char
|
||||
}
|
||||
// remove trailing dot
|
||||
if (hex[last] == '.') {
|
||||
hex[last] = 0;
|
||||
}
|
||||
}
|
||||
new_val_str = copyStr(hex);
|
||||
allocs[alloc_idx++] = new_val_str;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// '%_X' outputs a 64 bits unsigned int to uppercase HEX with 16 digits
|
||||
case 'X': // input is `uint64_t*`, printed as 16 hex digits (no prefix 0x)
|
||||
{
|
||||
U64toHex(*(uint64_t*)cur_val, hex);
|
||||
new_val_str = copyStr(hex);
|
||||
allocs[alloc_idx++] = new_val_str;
|
||||
}
|
||||
break;
|
||||
// Trying to do String allocation alternatives, but not as interesting as I thought in the beginning
|
||||
// case 's':
|
||||
// {
|
||||
// new_val_str = copyStr(((String*)cur_val)->c_str());
|
||||
// allocs[alloc_idx++] = new_val_str;
|
||||
// }
|
||||
// break;
|
||||
// case 'S':
|
||||
// {
|
||||
// funcString_t * func_str = (funcString_t*) cur_val;
|
||||
// new_val_str = copyStr((*func_str)().c_str());
|
||||
// allocs[alloc_idx++] = new_val_str;
|
||||
// }
|
||||
// break;
|
||||
}
|
||||
*cur_val_ptr = new_val_str;
|
||||
*fmt = 's'; // replace `%_X` with `%0s` to display a string instead
|
||||
|
||||
} else {
|
||||
va_arg(va, int32_t); // munch one 32 bits argument and leave it unchanged
|
||||
// we take the hypothesis here that passing 64 bits arguments is always unsupported in ESP8266
|
||||
}
|
||||
}
|
||||
}
|
||||
#else // defined(ESP8266) || defined(ESP32)
|
||||
#error "ext_printf is not suppoerted on this platform"
|
||||
#endif // defined(ESP8266) || defined(ESP32)
|
||||
// Serial.printf("> format_final=%s\n", fmt_cpy); Serial.flush();
|
||||
int32_t ret = vsnprintf_P(buf, buf_len, fmt_cpy, va_cpy);
|
||||
|
||||
va_end(va_cpy);
|
||||
|
||||
// disallocated all temporary strings
|
||||
for (uint32_t i = 0; i < alloc_idx; i++) {
|
||||
free(allocs[i]); // it is ok to call free() on nullptr so we don't test for nullptr first
|
||||
allocs[i] = nullptr;
|
||||
}
|
||||
free(fmt_cpy); // free the local copy of the format string
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t ext_snprintf_P(char * buf, size_t buf_len, const char * fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
|
||||
int32_t ret = ext_vsnprintf_P(buf, buf_len, fmt, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
ext_printf.ino - Extended printf for Arduino objects
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EXT_PRINTF_H
|
||||
#define EXT_PRINTF_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdarg>
|
||||
|
||||
int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list va);
|
||||
int32_t ext_snprintf_P(char * buf, size_t buf_len, const char * fmt, ...);
|
||||
|
||||
char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween);
|
||||
|
||||
// void test_ext_snprintf_P(void);
|
||||
|
||||
#endif // EXT_PRINTF_H
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
ext_printf.ino - Extended printf for Arduino objects
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ext_printf.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
// DEBUG only
|
||||
|
||||
// String test_string(void) {
|
||||
// String s("This is the string");
|
||||
|
||||
// return s;
|
||||
// }
|
||||
|
||||
// String f_str(void) { return String("foobar"); }
|
||||
// String k_str("foobar");
|
||||
|
||||
// void f1(String s) {
|
||||
// Serial.printf("> %s\n", s.c_str());
|
||||
// }
|
||||
// void f2(void) {
|
||||
// f1(f_str());
|
||||
// }
|
||||
|
||||
// void test_snprintf1(void) {
|
||||
// char c[100];
|
||||
// snprintf_P(c, sizeof(c), PSTR("s1=%s, s2=%s"), k_str.c_str(), f_str().c_str());
|
||||
// }
|
||||
// void test_snprintf2(void) {
|
||||
// char c[100];
|
||||
// ext_snprintf_P(c, sizeof(c), PSTR("s1=%_s, s2=%_S"), &k_str, &f_str, &ResponseAppendTHD);
|
||||
// }
|
||||
void test_ext_snprintf_P(void) {
|
||||
// test_snprintf1();
|
||||
// test_snprintf2();
|
||||
// if (0) {
|
||||
// // testVarArg2("", 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
char c[128];
|
||||
float fpi=-3333.1415926535f;
|
||||
float f3 = 3333;
|
||||
float f31 = 3333.1;
|
||||
ext_snprintf_P(c, sizeof(c), "Int1 = %d, ip=%_I", 1, 0x10203040);
|
||||
Serial.printf("--> out=%s\n", c);
|
||||
|
||||
ext_snprintf_P(c, sizeof(c), "Float default=%_f %_f", &f3, &fpi);
|
||||
Serial.printf("--> out=%s\n", c);
|
||||
|
||||
ext_snprintf_P(c, sizeof(c), "Float default=%1_f, int(3)=%4_f, int(3)=%-4_f, int(3)=%-4_f, 6dec=%-8_f", &fpi, &f3, &f3, &f31, &fpi);
|
||||
Serial.printf("--> out=%s\n", c);
|
||||
ext_snprintf_P(c, sizeof(c), "Float default=%*_f, int(3)=%*_f, int(3)=%*_f, int(3)=%*_f, 6dec=%*_f", 1, &fpi, 4, &f3, -4, &f3, -4, &f31, -8, &fpi);
|
||||
Serial.printf("--> out=%s\n", c);
|
||||
uint64_t u641 = 0x1122334455667788LL;
|
||||
uint64_t u642 = 0x0123456789ABCDEFLL;
|
||||
uint64_t u643 = 0xFEDCBA9876543210LL;
|
||||
ext_snprintf_P(c, sizeof(c), "Int64 0x%_X 0x%_X 0x%_X", &u641, &u642, &u643);
|
||||
Serial.printf("--> out=%s\n", c);
|
||||
|
||||
// ext_snprintf_P(c, sizeof(c), "Float default=%*_f, int(3)=%*_f, int(3)=%*_f, int(3)=%*_f, 6dec=%*_f", &fpi, &f3, &f3, &f31, &fpi);
|
||||
|
||||
// String string("Foobar");
|
||||
// ext_snprintf_P(c, sizeof(c), "String 0x%08X %_s", &string, &string);
|
||||
// Serial.printf("--> out=%s\n", c);
|
||||
|
||||
// ext_snprintf_P(c, sizeof(c), "StringFunc 0x%08X %_S", &test_string, &test_string);
|
||||
// Serial.printf("--> out=%s\n", c);
|
||||
|
||||
// uint64_t u64 = 0x123456789ABCDEFLL;
|
||||
// testVarArg2("", u64, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
// // Serial.printf("+++ ld=%ld, lld=%lld\n", 1,2,3,4);
|
||||
// // testVarArg("", 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
// }
|
||||
// tprintf("%s", 12, "14");
|
||||
}
|
||||
|
||||
|
||||
// void tprintf(const char* format) // base function
|
||||
// {
|
||||
// Serial.printf("%s\n", format);
|
||||
// }
|
||||
|
||||
// template<typename T, typename... Targs>
|
||||
// void tprintf(const char* format, T value, Targs... Fargs) // recursive variadic function
|
||||
// {
|
||||
// for ( ; *format != '\0'; format++ ) {
|
||||
// if ( *format == '%' ) {
|
||||
// Serial.printf("%d", (uint32_t) value);
|
||||
// tprintf(format+1, Fargs...); // recursive call
|
||||
// return;
|
||||
// }
|
||||
// Serial.printf("%s", format);
|
||||
// }
|
||||
// }
|
|
@ -10,8 +10,5 @@
|
|||
"exclude": "tests",
|
||||
"examples": "examples/*/*.ino",
|
||||
"frameworks": "arduino",
|
||||
"platforms": [
|
||||
"atmelavr",
|
||||
"espressif"
|
||||
]
|
||||
"platforms": ["espressif8266", "espressif32"]
|
||||
}
|
||||
|
|
|
@ -25,19 +25,20 @@
|
|||
#ifndef MQTT_MAX_PACKET_SIZE
|
||||
//#define MQTT_MAX_PACKET_SIZE 128
|
||||
//#define MQTT_MAX_PACKET_SIZE 1000 // Tasmota v5.11.1c
|
||||
#define MQTT_MAX_PACKET_SIZE 1200 // Tasmota v8.1.0.8
|
||||
#define MQTT_MAX_PACKET_SIZE 1200 // Tasmota v8.1.0.8
|
||||
#endif
|
||||
|
||||
// MQTT_KEEPALIVE : keepAlive interval in Seconds
|
||||
// Keepalive timeout for default MQTT Broker is 10s
|
||||
#ifndef MQTT_KEEPALIVE
|
||||
//#define MQTT_KEEPALIVE 10
|
||||
#define MQTT_KEEPALIVE 30 // Tasmota v6.5.0.14 enabling AWS-iot
|
||||
#define MQTT_KEEPALIVE 30 // Tasmota v6.5.0.14 enabling AWS-iot
|
||||
#endif
|
||||
|
||||
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
|
||||
#ifndef MQTT_SOCKET_TIMEOUT
|
||||
#define MQTT_SOCKET_TIMEOUT 15
|
||||
//#define MQTT_SOCKET_TIMEOUT 15
|
||||
#define MQTT_SOCKET_TIMEOUT 4 // Tasmota 20210120
|
||||
#endif
|
||||
|
||||
// MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client
|
||||
|
|
|
@ -32,7 +32,7 @@ extern String EscapeJSONString(const char *str);
|
|||
class JsonGeneratorArray {
|
||||
public:
|
||||
|
||||
JsonGeneratorArray(): val("[]") {} // start with empty array
|
||||
JsonGeneratorArray(): val(F("[]")) {} // start with empty array
|
||||
|
||||
void add(uint32_t uval32);
|
||||
void add(int32_t uval32);
|
||||
|
@ -53,7 +53,7 @@ protected:
|
|||
class JsonGeneratorObject {
|
||||
public:
|
||||
|
||||
JsonGeneratorObject(): val("{}") {} // start with empty object
|
||||
JsonGeneratorObject(): val(F("{}")) {} // start with empty object
|
||||
|
||||
void add(const char* key, uint32_t uval32);
|
||||
void add(const char* key, int32_t uval32);
|
||||
|
|
|
@ -6,5 +6,5 @@ sentence=Access 1-wire temperature sensors, memory and other chips.
|
|||
paragraph= Mod of Paul Stoffregen code to support ESP32
|
||||
category=Communication
|
||||
url=http://www.pjrc.com/teensy/td_libs_OneWire.html
|
||||
architectures=esp32
|
||||
architectures=esp8266,esp32
|
||||
|
||||
|
|
|
@ -11,5 +11,5 @@
|
|||
"url": "https://github.com/arendst/Tasmota/lib/TasmotaModbus"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": "espressif8266"
|
||||
"platforms": ["espressif8266", "espressif32"]
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ sentence=Basic modbus wrapper for TasmotaSerial for ESP8266.
|
|||
paragraph=
|
||||
category=Signal Input/Output
|
||||
url=
|
||||
architectures=esp8266
|
||||
architectures=esp8266,esp32
|
||||
|
|
|
@ -24,7 +24,7 @@ TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin) : TasmotaSerial(
|
|||
mb_address = 0;
|
||||
}
|
||||
|
||||
uint16_t CalculateCRC(uint8_t *frame, uint8_t num)
|
||||
uint16_t TasmotaModbus::CalculateCRC(uint8_t *frame, uint8_t num)
|
||||
{
|
||||
uint16_t crc = 0xFFFF;
|
||||
|
||||
|
@ -81,30 +81,37 @@ bool TasmotaModbus::ReceiveReady()
|
|||
uint8_t TasmotaModbus::ReceiveBuffer(uint8_t *buffer, uint8_t register_count)
|
||||
{
|
||||
mb_len = 0;
|
||||
uint32_t last = millis();
|
||||
while ((available() > 0) && (mb_len < (register_count *2) + 5) && (millis() - last < 10)) {
|
||||
uint8_t data = (uint8_t)read();
|
||||
if (!mb_len) { // Skip leading data as provided by hardware serial
|
||||
if (mb_address == data) {
|
||||
uint32_t timeout = millis() + 10;
|
||||
while ((mb_len < (register_count *2) + 5) && (millis() < timeout)) {
|
||||
if (available()) {
|
||||
uint8_t data = (uint8_t)read();
|
||||
if (!mb_len) { // Skip leading data as provided by hardware serial
|
||||
if (mb_address == data) {
|
||||
buffer[mb_len++] = data;
|
||||
}
|
||||
} else {
|
||||
buffer[mb_len++] = data;
|
||||
}
|
||||
} else {
|
||||
buffer[mb_len++] = data;
|
||||
if (3 == mb_len) {
|
||||
if (buffer[1] & 0x80) { // 01 84 02 f2 f1
|
||||
return buffer[2]; // 1 = Illegal Function,
|
||||
// 2 = Illegal Data Address,
|
||||
// 3 = Illegal Data Value,
|
||||
// 4 = Slave Error
|
||||
// 5 = Acknowledge but not finished (no error)
|
||||
// 6 = Slave Busy
|
||||
// 8 = Memory Parity error
|
||||
// 10 = Gateway Path Unavailable
|
||||
// 11 = Gateway Target device failed to respond
|
||||
if (3 == mb_len) {
|
||||
if (buffer[1] & 0x80) { // 01 84 02 f2 f1
|
||||
if (0 == buffer[2]) {
|
||||
return 3; // 3 = Illegal Data Value,
|
||||
}
|
||||
return buffer[2]; // 1 = Illegal Function,
|
||||
// 2 = Illegal Data Address,
|
||||
// 3 = Illegal Data Value,
|
||||
// 4 = Slave Error
|
||||
// 5 = Acknowledge but not finished (no error)
|
||||
// 6 = Slave Busy
|
||||
// 8 = Memory Parity error
|
||||
// 10 = Gateway Path Unavailable
|
||||
// 11 = Gateway Target device failed to respond
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timeout = millis() + 10;
|
||||
|
||||
}
|
||||
last = millis();
|
||||
}
|
||||
|
||||
if (mb_len < 7) { return 7; } // 7 = Not enough data
|
||||
|
|
|
@ -32,6 +32,8 @@ class TasmotaModbus : public TasmotaSerial {
|
|||
|
||||
int Begin(long speed = TM_MODBUS_BAUDRATE, int stop_bits = 1);
|
||||
|
||||
uint16_t CalculateCRC(uint8_t *frame, uint8_t num);
|
||||
|
||||
void Send(uint8_t device_address, uint8_t function_code, uint16_t start_address, uint16_t register_count);
|
||||
|
||||
bool ReceiveReady();
|
||||
|
|
|
@ -7,4 +7,3 @@ paragraph=Arduino library for FT5206 chip. Tested with ESP32
|
|||
category=Communication
|
||||
url=https://github.com/lewisxhe/FT5206_Library
|
||||
architectures=*
|
||||
architectures=esp32
|
|
@ -10,6 +10,6 @@
|
|||
"frameworks": "arduino",
|
||||
"platforms":
|
||||
[
|
||||
"atmelavr"
|
||||
"*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ sentence=ESP8266 library for Waveshare e-paper display.
|
|||
paragraph=
|
||||
category=Display
|
||||
url=https://github.com/gemu2015/Sonoff-Tasmota/tree/displays/lib/esp-epaper-29-ws-20171230-gemu-1.0#
|
||||
architectures=esp8266
|
||||
architectures=*
|
||||
|
|
|
@ -338,7 +338,15 @@ float Adafruit_TSL2591::calculateLux(uint16_t ch0, uint16_t ch1)
|
|||
|
||||
// Alternate lux calculation 1
|
||||
// See: https://github.com/adafruit/Adafruit_TSL2591_Library/issues/14
|
||||
lux = ( ((float)ch0 - (float)ch1 )) * (1.0F - ((float)ch1/(float)ch0) ) / cpl;
|
||||
if(ch0 > 0)
|
||||
{
|
||||
lux = ( ((float)ch0 - (float)ch1 )) * (1.0F - ((float)ch1/(float)ch0) ) / cpl;
|
||||
}
|
||||
else
|
||||
{
|
||||
lux = 0.0F;
|
||||
}
|
||||
|
||||
|
||||
// Alternate lux calculation 2
|
||||
//lux = ( (float)ch0 - ( 1.7F * (float)ch1 ) ) / cpl;
|
||||
|
|
|
@ -6,4 +6,4 @@ sentence=Sensor driver for BME680 sensor
|
|||
paragraph=Sensor driver for BME680 sensor
|
||||
category=Sensor
|
||||
url=
|
||||
architectures=esp8266
|
||||
architectures=esp8266,esp32
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"type": "git"
|
||||
},
|
||||
"platforms": [
|
||||
"atmelavr"
|
||||
"*"
|
||||
],
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
|
@ -28,4 +28,4 @@
|
|||
],
|
||||
"id": 11,
|
||||
"description": "The I2C Device Library (I2Cdevlib) is a collection of uniform and well-documented classes to provide simple and intuitive interfaces to I2C devices."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
"url": "https://github.com/jrowberg/i2cdevlib.git"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": "atmelavr"
|
||||
"platforms": "*"
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ sentence=.
|
|||
paragraph=
|
||||
category=
|
||||
url=
|
||||
architectures=esp8266
|
||||
architectures=esp8266,esp32
|
||||
|
|
|
@ -6,4 +6,4 @@ sentence=BearSSL implementation of the SSL/TLS protocol optimized for ESP8266 by
|
|||
paragraph=
|
||||
category=Other
|
||||
url=https://github.com/earlephilhower/bearssl-esp8266.git
|
||||
architectures=esp8266
|
||||
architectures=esp8266,esp32
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
name=M5 Stack Core2 library
|
||||
version=1.0
|
||||
author=Gerhard Mutz
|
||||
maintainer=Gerhard Mutz
|
||||
sentence=Allows Tasmota to use Core2
|
||||
paragraph=Allows Tasmota to Core2 for esp32
|
||||
category=ESP32
|
||||
url=
|
||||
architectures=*
|
|
@ -2,6 +2,75 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [1.1.0] - 2021-01-20
|
||||
|
||||
### Added
|
||||
- `NimBLEDevice::setOwnAddrType` added to enable the use of random and random-resolvable addresses, by asukiaaa
|
||||
|
||||
- New examples for securing and authenticating client/server connections, by mblasee.
|
||||
|
||||
- `NimBLEAdvertiseing::SetMinPreferred` and `NimBLEAdvertiseing::SetMinPreferred` re-added.
|
||||
|
||||
- Conditional checks added for command line config options in `nimconfig.h` to support custom configuration in platformio.
|
||||
|
||||
- `NimBLEClient::setValue` Now takes an extra bool parameter `response` to enable the use of write with response (default = false).
|
||||
|
||||
- `NimBLEClient::getCharacteristic(uint16_t handle)` Enabling the use of the characteristic handle to be used to find
|
||||
the NimBLERemoteCharacteristic object.
|
||||
|
||||
- `NimBLEHIDDevice` class added by wakwak-koba.
|
||||
|
||||
- `NimBLEServerCallbacks::onDisconnect` overloaded callback added to provide a ble_gap_conn_desc parameter for the application
|
||||
to obtain information about the disconnected client.
|
||||
|
||||
- Conditional checks in `nimconfig.h` for command line defined macros to support platformio config settings.
|
||||
|
||||
### Changed
|
||||
- `NimBLEAdvertising::start` now returns a bool value to indicate success/failure.
|
||||
|
||||
- Some asserts were removed in `NimBLEAdvertising::start` and replaced with better return code handling and logging.
|
||||
|
||||
- If a host reset event occurs, scanning and advertising will now only be restarted if their previous duration was indefinite.
|
||||
|
||||
- `NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::registerForNotify` will now set the callback
|
||||
regardless of the existance of the CCCD and return true unless the descriptor write operation failed.
|
||||
|
||||
- Advertising tx power level is now sent in the advertisement packet instead of scan response.
|
||||
|
||||
- `NimBLEScan` When the scan ends the scan stopped flag is now set before calling the scan complete callback (if used)
|
||||
this allows the starting of a new scan from the callback function.
|
||||
|
||||
### Fixed
|
||||
- Sometimes `NimBLEClient::connect` would hang on the task block if no event arrived to unblock.
|
||||
A time limit has been added to timeout appropriately.
|
||||
|
||||
- When getting descriptors for a characterisic the end handle of the service was used as a proxy for the characteristic end
|
||||
handle. This would be rejected by some devices and has been changed to use the next characteristic handle as the end when possible.
|
||||
|
||||
- An exception could occur when deleting a client instance if a notification arrived while the attribute vectors were being
|
||||
deleted. A flag has been added to prevent this.
|
||||
|
||||
- An exception could occur after a host reset event when the host re-synced if the tasks that were stopped during the event did
|
||||
not finish processing. A yield has been added after re-syncing to allow tasks to finish before proceeding.
|
||||
|
||||
- Occasionally the controller would fail to send a disconnected event causing the client to indicate it is connected
|
||||
and would be unable to reconnect. A timer has been added to reset the host/controller if it expires.
|
||||
|
||||
- Occasionally the call to start scanning would get stuck in a loop on BLE_HS_EBUSY, this loop has been removed.
|
||||
|
||||
- 16bit and 32bit UUID's in some cases were not discovered or compared correctly if the device
|
||||
advertised them as 16/32bit but resolved them to 128bits. Both are now checked.
|
||||
|
||||
- `FreeRTOS` compile errors resolved in latest Ardruino core and IDF v3.3.
|
||||
|
||||
- Multiple instances of `time()` called inside critical sections caused sporadic crashes, these have been moved out of critical regions.
|
||||
|
||||
- Advertisement type now correctly set when using non-connectable (advertiser only) mode.
|
||||
|
||||
- Advertising payload length correction, now accounts for appearance.
|
||||
|
||||
- (Arduino) Ensure controller mode is set to BLE Only.
|
||||
|
||||
## [1.0.2] - 2020-09-13
|
||||
|
||||
### Changed
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
[Latest release ![Release Version](https://img.shields.io/github/release/h2zero/NimBLE-Arduino.svg?style=plastic)
|
||||
![Release Date](https://img.shields.io/github/release-date/h2zero/NimBLE-Arduino.svg?style=plastic)](https://github.com/h2zero/NimBLE-Arduino/releases/latest/)
|
||||
|
||||
Need help? Have questions or suggestions? Join the [![Gitter](https://badges.gitter.im/NimBLE-Arduino/community.svg)](https://gitter.im/NimBLE-Arduino/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
<br/>
|
||||
|
||||
# NimBLE-Arduino
|
||||
|
@ -57,6 +59,8 @@ Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for inform
|
|||
|
||||
[Full API documentation and class list can be found here.](https://h2zero.github.io/esp-nimble-cpp/)
|
||||
|
||||
For added performance and optimizations see [Usage tips](docs/Usage_tips.md).
|
||||
|
||||
Check the Refactored_original_examples in the examples folder for highlights of the differences with the original library.
|
||||
|
||||
More advanced examples highlighting many available features are in examples/ NimBLE_Server, NimBLE_Client.
|
||||
|
@ -68,9 +72,9 @@ such as increasing max connections, default is 3, absolute maximum connections i
|
|||
<br/>
|
||||
|
||||
# Development Status
|
||||
This Library is tracking the esp-nimble repo, nimble-1.2.0-idf master branch, currently [@95bd864.](https://github.com/espressif/esp-nimble)
|
||||
This Library is tracking the esp-nimble repo, nimble-1.2.0-idf master branch, currently [@f4ae049.](https://github.com/espressif/esp-nimble)
|
||||
|
||||
Also tracking the NimBLE related changes in ESP-IDF, master branch, currently [@2ef4890.](https://github.com/espressif/esp-idf/tree/master/components/bt/host/nimble)
|
||||
Also tracking the NimBLE related changes in ESP-IDF, master branch, currently [@3caa969.](https://github.com/espressif/esp-idf/tree/master/components/bt/host/nimble)
|
||||
<br/>
|
||||
|
||||
# Acknowledgments
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
# Arduino command line and platformio config options
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED`
|
||||
|
||||
If defined, NimBLE Client functions will not be included.
|
||||
- Reduces flash size by approx. 7kB.
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED`
|
||||
|
||||
If defined, NimBLE Scan functions will not be included.
|
||||
- Reduces flash size by approx. 26kB.
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED`
|
||||
|
||||
If defined NimBLE Server functions will not be included.
|
||||
- Reduces flash size by approx. 16kB.
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED`
|
||||
|
||||
If defined, NimBLE Advertising functions will not be included.
|
||||
- Reduces flash size by approx. 5kB.
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_DEBUG`
|
||||
|
||||
If defined, enables debug log messages from the NimBLE host
|
||||
- Uses approx. 32kB of flash memory.
|
||||
<br>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT`
|
||||
|
||||
If defined, NimBLE host return codes will be printed as text in debug log messages.
|
||||
- Uses approx. 7kB of flash memory.
|
||||
<br>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT`
|
||||
|
||||
If defined, GAP event codes will be printed as text in debug log messages.
|
||||
- Uses approx. 1kB of flash memory.
|
||||
<br>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT`
|
||||
|
||||
If defined, advertisment types will be printed as text while scanning in debug log messages.
|
||||
- Uses approx. 250 bytes of flash memory.
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_PINNED_TO_CORE`
|
||||
|
||||
Sets the core the NimBLE host stack will run on
|
||||
- Options: 0 or 1
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_TASK_STACK_SIZE`
|
||||
|
||||
Set the task stack size for the NimBLE core.
|
||||
- Default is 4096
|
||||
<br>
|
||||
|
||||
|
||||
`CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL`
|
||||
|
||||
Sets the NimBLE stack to use external PSRAM will be loaded
|
||||
- Must be defined with a value of 1; Default is CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_CONNECTIONS`
|
||||
|
||||
Sets the number of simultaneous connections (esp controller max is 9)
|
||||
- Default value is 3
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_BONDS`
|
||||
|
||||
Sets the number of devices allowed to store/bond with
|
||||
- Default value is 3
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_CCCDS`
|
||||
|
||||
Sets the maximum number of CCCD subscriptions to store
|
||||
- Default value is 8
|
||||
<br>
|
||||
|
||||
`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME`
|
||||
|
||||
Set the default device name
|
||||
- Default value is "nimble"
|
||||
<br>
|
||||
|
|
@ -79,27 +79,24 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
|
|||
return;
|
||||
}
|
||||
|
||||
uint8_t *payLoad = advertisedDevice->getPayload();
|
||||
BLEUUID eddyUUID = (uint16_t)0xfeaa;
|
||||
|
||||
BLEUUID checkUrlUUID = (uint16_t)0xfeaa;
|
||||
|
||||
if (advertisedDevice->getServiceUUID().equals(checkUrlUUID))
|
||||
if (advertisedDevice->getServiceUUID().equals(eddyUUID))
|
||||
{
|
||||
if (payLoad[11] == 0x10)
|
||||
std::string serviceData = advertisedDevice->getServiceData(eddyUUID);
|
||||
if (serviceData[0] == 0x10)
|
||||
{
|
||||
Serial.println("Found an EddystoneURL beacon!");
|
||||
BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
|
||||
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
||||
|
||||
foundEddyURL.setData(eddyContent);
|
||||
foundEddyURL.setData(serviceData);
|
||||
std::string bareURL = foundEddyURL.getURL();
|
||||
if (bareURL[0] == 0x00)
|
||||
{
|
||||
size_t payLoadLen = advertisedDevice->getPayloadLength();
|
||||
Serial.println("DATA-->");
|
||||
for (int idx = 0; idx < payLoadLen; idx++)
|
||||
for (int idx = 0; idx < serviceData.length(); idx++)
|
||||
{
|
||||
Serial.printf("0x%08X ", payLoad[idx]);
|
||||
Serial.printf("0x%08X ", serviceData[idx]);
|
||||
}
|
||||
Serial.println("\nInvalid Data");
|
||||
return;
|
||||
|
@ -110,23 +107,15 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
|
|||
Serial.printf("TX power %d\n", foundEddyURL.getPower());
|
||||
Serial.println("\n");
|
||||
}
|
||||
else if (payLoad[11] == 0x20)
|
||||
else if (serviceData[0] == 0x20)
|
||||
{
|
||||
Serial.println("Found an EddystoneTLM beacon!");
|
||||
BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
|
||||
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
||||
foundEddyURL.setData(serviceData);
|
||||
|
||||
eddyContent = "01234567890123";
|
||||
|
||||
for (int idx = 0; idx < 14; idx++)
|
||||
{
|
||||
eddyContent[idx] = payLoad[idx + 11];
|
||||
}
|
||||
|
||||
foundEddyURL.setData(eddyContent);
|
||||
Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
|
||||
Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
|
||||
int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
|
||||
int temp = (int)serviceData[5] + (int)(serviceData[4] << 8);
|
||||
float calcTemp = temp / 256.0f;
|
||||
Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
|
||||
Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
/** NimBLE_Server Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE client library.
|
||||
*
|
||||
*
|
||||
* Created: on March 24 2020
|
||||
* Author: H2zero
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
@ -19,15 +19,15 @@ static uint32_t scanTime = 0; /** 0 = scan forever */
|
|||
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
** Remove as you see fit for your needs */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) {
|
||||
Serial.println("Connected");
|
||||
/** After connection we should change the parameters if we don't need fast response times.
|
||||
* These settings are 150ms interval, 0 latency, 450ms timout.
|
||||
* These settings are 150ms interval, 0 latency, 450ms timout.
|
||||
* Timeout should be a multiple of the interval, minimum is 100ms.
|
||||
* I find a multiple of 3-5 * the interval works best for quick response/reconnect.
|
||||
* Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 60 * 10ms = 600ms timeout
|
||||
* Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 60 * 10ms = 600ms timeout
|
||||
*/
|
||||
pClient->updateConnParams(120,120,0,60);
|
||||
};
|
||||
|
@ -37,9 +37,9 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
|||
Serial.println(" Disconnected - Starting scan");
|
||||
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||
};
|
||||
|
||||
|
||||
/** Called when the peripheral requests a change to the connection parameters.
|
||||
* Return true to accept and apply them or false to reject and keep
|
||||
* Return true to accept and apply them or false to reject and keep
|
||||
* the currently used parameters. Default will return true.
|
||||
*/
|
||||
bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) {
|
||||
|
@ -55,7 +55,7 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
|||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/********************* Security handled here **********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyRequest(){
|
||||
|
@ -85,7 +85,7 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
|||
|
||||
/** Define a class to handle the callbacks when advertisments are received */
|
||||
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
||||
|
||||
|
||||
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
Serial.print("Advertised Device found: ");
|
||||
Serial.println(advertisedDevice->toString().c_str());
|
||||
|
@ -94,9 +94,9 @@ class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
|||
Serial.println("Found Our Service");
|
||||
/** stop scan before connecting */
|
||||
NimBLEDevice::getScan()->stop();
|
||||
/** Save the device reference in a global for the client to use*/
|
||||
/** Save the device reference in a global for the client to use*/
|
||||
advDevice = advertisedDevice;
|
||||
/** Ready to connect now */
|
||||
/** Ready to connect now */
|
||||
doConnect = true;
|
||||
}
|
||||
};
|
||||
|
@ -105,7 +105,7 @@ class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
|||
|
||||
/** Notification / Indication receiving handler callback */
|
||||
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){
|
||||
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
||||
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
||||
str += " from ";
|
||||
/** NimBLEAddress and NimBLEUUID have std::string operators */
|
||||
str += std::string(pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress());
|
||||
|
@ -128,10 +128,10 @@ static ClientCallbacks clientCB;
|
|||
/** Handles the provisioning of clients and connects / interfaces with the server */
|
||||
bool connectToServer() {
|
||||
NimBLEClient* pClient = nullptr;
|
||||
|
||||
|
||||
/** Check if we have a client we should reuse first **/
|
||||
if(NimBLEDevice::getClientListSize()) {
|
||||
/** Special case when we already know this device, we send false as the
|
||||
/** Special case when we already know this device, we send false as the
|
||||
* second argument in connect() to prevent refreshing the service database.
|
||||
* This saves considerable time and power.
|
||||
*/
|
||||
|
@ -142,7 +142,7 @@ bool connectToServer() {
|
|||
return false;
|
||||
}
|
||||
Serial.println("Reconnected client");
|
||||
}
|
||||
}
|
||||
/** We don't already have a client that knows this device,
|
||||
* we will check for a client that is disconnected that we can use.
|
||||
*/
|
||||
|
@ -150,28 +150,28 @@ bool connectToServer() {
|
|||
pClient = NimBLEDevice::getDisconnectedClient();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** No client to reuse? Create a new one. */
|
||||
if(!pClient) {
|
||||
if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) {
|
||||
Serial.println("Max clients reached - no more connections available");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
pClient = NimBLEDevice::createClient();
|
||||
|
||||
|
||||
Serial.println("New client created");
|
||||
|
||||
|
||||
pClient->setClientCallbacks(&clientCB, false);
|
||||
/** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout.
|
||||
* These settings are safe for 3 clients to connect reliably, can go faster if you have less
|
||||
/** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout.
|
||||
* These settings are safe for 3 clients to connect reliably, can go faster if you have less
|
||||
* connections. Timeout should be a multiple of the interval, minimum is 100ms.
|
||||
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 51 * 10ms = 510ms timeout
|
||||
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 51 * 10ms = 510ms timeout
|
||||
*/
|
||||
pClient->setConnectionParams(12,12,0,51);
|
||||
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
|
||||
pClient->setConnectTimeout(5);
|
||||
|
||||
|
||||
|
||||
if (!pClient->connect(advDevice)) {
|
||||
/** Created a client but failed to connect, don't need to keep it as it has no data */
|
||||
|
@ -179,149 +179,147 @@ bool connectToServer() {
|
|||
Serial.println("Failed to connect, deleted client");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!pClient->isConnected()) {
|
||||
if (!pClient->connect(advDevice)) {
|
||||
Serial.println("Failed to connect");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Serial.print("Connected to: ");
|
||||
Serial.println(pClient->getPeerAddress().toString().c_str());
|
||||
Serial.print("RSSI: ");
|
||||
Serial.println(pClient->getRssi());
|
||||
|
||||
|
||||
/** Now we can read/write/subscribe the charateristics of the services we are interested in */
|
||||
NimBLERemoteService* pSvc = nullptr;
|
||||
NimBLERemoteCharacteristic* pChr = nullptr;
|
||||
NimBLERemoteDescriptor* pDsc = nullptr;
|
||||
|
||||
|
||||
pSvc = pClient->getService("DEAD");
|
||||
if(pSvc) { /** make sure it's not null */
|
||||
pChr = pSvc->getCharacteristic("BEEF");
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("Tasty")) {
|
||||
Serial.print("Wrote new value to: ");
|
||||
Serial.println(pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
Serial.print("The value of: ");
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" is now: ");
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("Tasty")) {
|
||||
Serial.print("Wrote new value to: ");
|
||||
Serial.println(pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr->canRead()) {
|
||||
Serial.print("The value of: ");
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" is now: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
|
||||
} else {
|
||||
Serial.println("DEAD service not found.");
|
||||
}
|
||||
|
||||
|
||||
pSvc = pClient->getService("BAAD");
|
||||
if(pSvc) { /** make sure it's not null */
|
||||
pChr = pSvc->getCharacteristic("F00D");
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
||||
if(pDsc) { /** make sure it's not null */
|
||||
Serial.print("Descriptor: ");
|
||||
Serial.print(pDsc->getUUID().toString().c_str());
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pDsc->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("No tip!")) {
|
||||
Serial.print("Wrote new value to: ");
|
||||
Serial.println(pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
Serial.print("The value of: ");
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" is now: ");
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
||||
if(pDsc) { /** make sure it's not null */
|
||||
Serial.print("Descriptor: ");
|
||||
Serial.print(pDsc->getUUID().toString().c_str());
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pDsc->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("No tip!")) {
|
||||
Serial.print("Wrote new value to: ");
|
||||
Serial.println(pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr->canRead()) {
|
||||
Serial.print("The value of: ");
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" is now: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Serial.println("BAAD service not found.");
|
||||
}
|
||||
|
||||
|
||||
Serial.println("Done with this device!");
|
||||
return true;
|
||||
}
|
||||
|
@ -331,7 +329,7 @@ void setup (){
|
|||
Serial.println("Starting NimBLE Client");
|
||||
/** Initialize NimBLE, no device name spcified as we are not advertising */
|
||||
NimBLEDevice::init("");
|
||||
|
||||
|
||||
/** Set the IO capabilities of the device, each option will trigger a different pairing method.
|
||||
* BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing
|
||||
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
||||
|
@ -339,37 +337,37 @@ void setup (){
|
|||
*/
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
|
||||
/** 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, secure connections.
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
|
||||
|
||||
/** Optional: set the transmit power, default is 3db */
|
||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */
|
||||
|
||||
|
||||
/** Optional: set any devices you don't want to get advertisments from */
|
||||
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
|
||||
|
||||
/** create new scan */
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
|
||||
|
||||
/** create new scan */
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
/** create a callback that gets called when advertisers are found */
|
||||
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
|
||||
|
||||
|
||||
/** Set scan interval (how often) and window (how long) in milliseconds */
|
||||
pScan->setInterval(45);
|
||||
pScan->setWindow(15);
|
||||
|
||||
|
||||
/** Active scan will gather scan response data from advertisers
|
||||
* but will use more energy from both devices
|
||||
*/
|
||||
pScan->setActiveScan(true);
|
||||
/** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever
|
||||
* Optional callback for when scanning stops.
|
||||
* Optional callback for when scanning stops.
|
||||
*/
|
||||
pScan->start(scanTime, scanEndedCB);
|
||||
}
|
||||
|
@ -380,15 +378,15 @@ void loop (){
|
|||
while(!doConnect){
|
||||
delay(1);
|
||||
}
|
||||
|
||||
|
||||
doConnect = false;
|
||||
|
||||
|
||||
/** Found a device we want to connect to, do it now */
|
||||
if(connectToServer()) {
|
||||
Serial.println("Success! we should now be getting notifications, scanning for more!");
|
||||
} else {
|
||||
Serial.println("Failed to connect, starting scan");
|
||||
}
|
||||
|
||||
|
||||
NimBLEDevice::getScan()->start(scanTime,scanEndedCB);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/** NimBLE_Secure_Client Demo:
|
||||
*
|
||||
* This example demonstrates the secure passkey protected conenction and communication between an esp32 server and an esp32 client.
|
||||
* Please note that esp32 stores auth info in nvs memory. After a successful connection it is possible that a passkey change will be ineffective.
|
||||
* To avoid this clear the memory of the esp32's between security testings. esptool.py is capable of this, example: esptool.py --port /dev/ttyUSB0 erase_flash.
|
||||
*
|
||||
* Created: on Jan 08 2021
|
||||
* Author: mblasee
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
class ClientCallbacks : public NimBLEClientCallbacks
|
||||
{
|
||||
uint32_t onPassKeyRequest()
|
||||
{
|
||||
Serial.println("Client Passkey Request");
|
||||
/** return the passkey to send to the server */
|
||||
/** Change this to be different from NimBLE_Secure_Server if you want to test what happens on key mismatch */
|
||||
return 123456;
|
||||
};
|
||||
};
|
||||
static ClientCallbacks clientCB;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println("Starting NimBLE Client");
|
||||
|
||||
NimBLEDevice::init("");
|
||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
|
||||
NimBLEDevice::setSecurityAuth(true, true, true);
|
||||
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY);
|
||||
NimBLEScan *pScan = NimBLEDevice::getScan();
|
||||
NimBLEScanResults results = pScan->start(5);
|
||||
|
||||
NimBLEUUID serviceUuid("ABCD");
|
||||
|
||||
for (int i = 0; i < results.getCount(); i++)
|
||||
{
|
||||
NimBLEAdvertisedDevice device = results.getDevice(i);
|
||||
Serial.println(device.getName().c_str());
|
||||
|
||||
if (device.isAdvertisingService(serviceUuid))
|
||||
{
|
||||
NimBLEClient *pClient = NimBLEDevice::createClient();
|
||||
pClient->setClientCallbacks(&clientCB, false);
|
||||
|
||||
if (pClient->connect(&device))
|
||||
{
|
||||
pClient->secureConnection();
|
||||
NimBLERemoteService *pService = pClient->getService(serviceUuid);
|
||||
if (pService != nullptr)
|
||||
{
|
||||
NimBLERemoteCharacteristic *pNonSecureCharacteristic = pService->getCharacteristic("1234");
|
||||
|
||||
if (pNonSecureCharacteristic != nullptr)
|
||||
{
|
||||
// Testing to read a non secured characteristic, you should be able to read this even if you have mismatching passkeys.
|
||||
std::string value = pNonSecureCharacteristic->readValue();
|
||||
// print or do whatever you need with the value
|
||||
Serial.println(value.c_str());
|
||||
}
|
||||
|
||||
NimBLERemoteCharacteristic *pSecureCharacteristic = pService->getCharacteristic("1235");
|
||||
|
||||
if (pSecureCharacteristic != nullptr)
|
||||
{
|
||||
// Testing to read a secured characteristic, you should be able to read this only if you have matching passkeys, otherwise you should
|
||||
// get an error like this. E NimBLERemoteCharacteristic: "<< readValue rc=261"
|
||||
// This means you are trying to do something without the proper permissions.
|
||||
std::string value = pSecureCharacteristic->readValue();
|
||||
// print or do whatever you need with the value
|
||||
Serial.println(value.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to connect
|
||||
Serial.println("failed to connect");
|
||||
}
|
||||
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/** NimBLE_Secure_Server Demo:
|
||||
*
|
||||
* This example demonstrates the secure passkey protected conenction and communication between an esp32 server and an esp32 client.
|
||||
* Please note that esp32 stores auth info in nvs memory. After a successful connection it is possible that a passkey change will be ineffective.
|
||||
* To avoid this clear the memory of the esp32's between security testings. esptool.py is capable of this, example: esptool.py --port /dev/ttyUSB0 erase_flash.
|
||||
*
|
||||
* Created: on Jan 08 2021
|
||||
* Author: mblasee
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Starting NimBLE Server");
|
||||
NimBLEDevice::init("NimBLE");
|
||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
|
||||
|
||||
NimBLEDevice::setSecurityAuth(true, true, true);
|
||||
NimBLEDevice::setSecurityPasskey(123456);
|
||||
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
|
||||
NimBLEServer *pServer = NimBLEDevice::createServer();
|
||||
NimBLEService *pService = pServer->createService("ABCD");
|
||||
NimBLECharacteristic *pNonSecureCharacteristic = pService->createCharacteristic("1234", NIMBLE_PROPERTY::READ );
|
||||
NimBLECharacteristic *pSecureCharacteristic = pService->createCharacteristic("1235", NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::READ_AUTHEN);
|
||||
|
||||
pService->start();
|
||||
pNonSecureCharacteristic->setValue("Hello Non Secure BLE");
|
||||
pSecureCharacteristic->setValue("Hello Secure BLE");
|
||||
|
||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID("ABCD");
|
||||
pAdvertising->start();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
|
@ -116,9 +116,9 @@ void setup() {
|
|||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(false);
|
||||
/**This method is removed as it was no longer useful and consumed advertising space
|
||||
* pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
|
||||
*/
|
||||
/** Note, this could be left out as that is the default value */
|
||||
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
|
||||
|
||||
BLEDevice::startAdvertising();
|
||||
Serial.println("Waiting a client connection to notify...");
|
||||
}
|
||||
|
|
|
@ -44,10 +44,9 @@ void setup() {
|
|||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(true);
|
||||
/**These methods are removed as they are no longer useful and consumed advertising space
|
||||
* pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
|
||||
* pAdvertising->setMinPreferred(0x12);
|
||||
*/
|
||||
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
|
||||
pAdvertising->setMaxPreferred(0x12);
|
||||
|
||||
BLEDevice::startAdvertising();
|
||||
Serial.println("Characteristic defined! Now you can read it in your phone!");
|
||||
}
|
||||
|
|
|
@ -120,9 +120,9 @@ void setup() {
|
|||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(false);
|
||||
/**This method is removed it was no longer useful and consumed advertising space
|
||||
* pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
|
||||
*/
|
||||
/** Note, this could be left out as that is the default value */
|
||||
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
|
||||
|
||||
BLEDevice::startAdvertising();
|
||||
Serial.println("Waiting a client connection to notify...");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name=NimBLE-Arduino
|
||||
version=1.0.2
|
||||
version=1.1.0
|
||||
author=h2zero
|
||||
maintainer=h2zero <powellperalta@gmail.com>
|
||||
sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE.
|
||||
|
|
|
@ -264,10 +264,14 @@ void FreeRTOS::Semaphore::setName(std::string name) {
|
|||
* @param [in] length The amount of storage to allocate for the ring buffer.
|
||||
* @param [in] type The type of buffer. One of RINGBUF_TYPE_NOSPLIT, RINGBUF_TYPE_ALLOWSPLIT, RINGBUF_TYPE_BYTEBUF.
|
||||
*/
|
||||
#if defined(ESP_IDF_VERSION) && !defined(ESP_IDF_VERSION_VAL) //Quick hack to detect if using IDF version that replaced ringbuf_type_t, ESP_IDF_VERSION_VAL is for IDF>4.0.0
|
||||
Ringbuffer::Ringbuffer(size_t length, RingbufferType_t type) {
|
||||
#ifdef ESP_IDF_VERSION //Quick hack to detect if using IDF version that replaced ringbuf_type_t
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
Ringbuffer::Ringbuffer(size_t length, RingbufferType_t type) {
|
||||
#else
|
||||
Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type) {
|
||||
Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type) {
|
||||
#endif
|
||||
#else
|
||||
Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type) {
|
||||
#endif
|
||||
m_handle = ::xRingbufferCreate(length, type);
|
||||
} // Ringbuffer
|
||||
|
|
|
@ -68,8 +68,12 @@ public:
|
|||
*/
|
||||
class Ringbuffer {
|
||||
public:
|
||||
#if defined(ESP_IDF_VERSION) && !defined(ESP_IDF_VERSION_VAL) //Quick hack to detect if using IDF version that replaced ringbuf_type_t, ESP_IDF_VERSION_VAL is for IDF>4.0.0
|
||||
#ifdef ESP_IDF_VERSION //Quick hack to detect if using IDF version that replaced ringbuf_type_t
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
Ringbuffer(size_t length, RingbufferType_t type = RINGBUF_TYPE_NOSPLIT);
|
||||
#else
|
||||
Ringbuffer(size_t length, ringbuf_type_t type = RINGBUF_TYPE_NOSPLIT);
|
||||
#endif
|
||||
#else
|
||||
Ringbuffer(size_t length, ringbuf_type_t type = RINGBUF_TYPE_NOSPLIT);
|
||||
#endif
|
||||
|
|
|
@ -37,7 +37,7 @@ NimBLE2904::NimBLE2904(NimBLECharacteristic* pCharacterisitic)
|
|||
m_data.m_unit = 0;
|
||||
m_data.m_description = 0;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // BLE2902
|
||||
} // BLE2904
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,7 +32,7 @@ static const char* LOG_TAG = "NimBLEAdvertising";
|
|||
/**
|
||||
* @brief Construct a default advertising object.
|
||||
*/
|
||||
NimBLEAdvertising::NimBLEAdvertising() {
|
||||
NimBLEAdvertising::NimBLEAdvertising() : m_slaveItvl() {
|
||||
memset(&m_advData, 0, sizeof m_advData);
|
||||
memset(&m_scanData, 0, sizeof m_scanData);
|
||||
memset(&m_advParams, 0, sizeof m_advParams);
|
||||
|
@ -41,15 +41,20 @@ NimBLEAdvertising::NimBLEAdvertising() {
|
|||
m_advData.name = (uint8_t *)name;
|
||||
m_advData.name_len = strlen(name);
|
||||
m_advData.name_is_complete = 1;
|
||||
m_scanData.tx_pwr_lvl_is_present = 1;
|
||||
m_scanData.tx_pwr_lvl = NimBLEDevice::getPower();
|
||||
m_advData.tx_pwr_lvl_is_present = 1;
|
||||
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
|
||||
m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
|
||||
m_advData.appearance = 0;
|
||||
m_advData.appearance_is_present = 0;
|
||||
m_advData.mfg_data_len = 0;
|
||||
m_advData.mfg_data = nullptr;
|
||||
m_advData.slave_itvl_range = nullptr;
|
||||
|
||||
#if !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
m_advParams.conn_mode = BLE_GAP_CONN_MODE_NON;
|
||||
#else
|
||||
m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
#endif
|
||||
m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
m_advParams.itvl_min = 0;
|
||||
m_advParams.itvl_max = 0;
|
||||
|
@ -58,6 +63,8 @@ NimBLEAdvertising::NimBLEAdvertising() {
|
|||
m_customScanResponseData = false;
|
||||
m_scanResp = true;
|
||||
m_advDataSet = false;
|
||||
// Set this to non-zero to prevent auto start if host reset before started by app.
|
||||
m_duration = BLE_HS_FOREVER;
|
||||
|
||||
} // NimBLEAdvertising
|
||||
|
||||
|
@ -86,7 +93,6 @@ void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) {
|
|||
* @param [in] serviceUUID The UUID of the service to expose.
|
||||
*/
|
||||
void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID &serviceUUID) {
|
||||
//m_serviceUUIDs.erase(std::remove_if(m_serviceUUIDs.begin(), m_serviceUUIDs.end(),[serviceUUID](const NimBLEUUID &s) {return serviceUUID == s;}), m_serviceUUIDs.end());
|
||||
for(auto it = m_serviceUUIDs.begin(); it != m_serviceUUIDs.end(); ++it) {
|
||||
if((*it) == serviceUUID) {
|
||||
m_serviceUUIDs.erase(it);
|
||||
|
@ -112,11 +118,9 @@ void NimBLEAdvertising::setAppearance(uint16_t appearance) {
|
|||
/**
|
||||
* @brief Set the type of advertisment to use.
|
||||
* @param [in] adv_type:
|
||||
* * BLE_HCI_ADV_TYPE_ADV_IND (0) - indirect advertising
|
||||
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD (1) - direct advertisng - high duty cycle
|
||||
* * BLE_HCI_ADV_TYPE_ADV_SCAN_IND (2) - indirect scan response
|
||||
* * BLE_HCI_ADV_TYPE_ADV_NONCONN_IND (3) - indirect advertisng - not connectable
|
||||
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD (4) - direct advertising - low duty cycle
|
||||
* * BLE_GAP_CONN_MODE_NON (0) - not connectable advertising
|
||||
* * BLE_GAP_CONN_MODE_DIR (1) - directed connectable advertising
|
||||
* * BLE_GAP_CONN_MODE_UND (2) - undirected connectable advertising
|
||||
*/
|
||||
void NimBLEAdvertising::setAdvertisementType(uint8_t adv_type){
|
||||
m_advParams.conn_mode = adv_type;
|
||||
|
@ -141,6 +145,64 @@ void NimBLEAdvertising::setMaxInterval(uint16_t maxinterval) {
|
|||
} // setMaxInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertised min connection interval preferred by this device.
|
||||
* @param [in] mininterval the max interval value. Range = 0x0006 to 0x0C80.
|
||||
* @details Values not within the range will cancel advertising of this data.\n
|
||||
* Consumes 6 bytes of advertising space (combined with max interval).
|
||||
*/
|
||||
void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
||||
// invalid paramters, set the slave interval to null
|
||||
if(mininterval < 0x0006 || mininterval > 0x0C80) {
|
||||
m_advData.slave_itvl_range = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_advData.slave_itvl_range == nullptr) {
|
||||
m_advData.slave_itvl_range = m_slaveItvl;
|
||||
}
|
||||
|
||||
m_slaveItvl[0] = mininterval;
|
||||
m_slaveItvl[1] = mininterval >> 8;
|
||||
|
||||
uint16_t maxinterval = *(uint16_t*)(m_advData.slave_itvl_range+2);
|
||||
|
||||
// If mininterval is higher than the maxinterval make them the same
|
||||
if(mininterval > maxinterval) {
|
||||
m_slaveItvl[2] = m_slaveItvl[0];
|
||||
m_slaveItvl[3] = m_slaveItvl[1];
|
||||
}
|
||||
} // setMinPreferred
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertised max connection interval preferred by this device.
|
||||
* @param [in] maxinterval the max interval value. Range = 0x0006 to 0x0C80.
|
||||
* @details Values not within the range will cancel advertising of this data.\n
|
||||
* Consumes 6 bytes of advertising space (combined with min interval).
|
||||
*/
|
||||
void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
|
||||
// invalid paramters, set the slave interval to null
|
||||
if(maxinterval < 0x0006 || maxinterval > 0x0C80) {
|
||||
m_advData.slave_itvl_range = nullptr;
|
||||
return;
|
||||
}
|
||||
if(m_advData.slave_itvl_range == nullptr) {
|
||||
m_advData.slave_itvl_range = m_slaveItvl;
|
||||
}
|
||||
m_slaveItvl[2] = maxinterval;
|
||||
m_slaveItvl[3] = maxinterval >> 8;
|
||||
|
||||
uint16_t mininterval = *(uint16_t*)(m_advData.slave_itvl_range);
|
||||
|
||||
// If mininterval is higher than the maxinterval make them the same
|
||||
if(mininterval > maxinterval) {
|
||||
m_slaveItvl[0] = m_slaveItvl[2];
|
||||
m_slaveItvl[1] = m_slaveItvl[3];
|
||||
}
|
||||
} // setMaxPreferred
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set if scan response is available.
|
||||
* @param [in] set true = scan response available.
|
||||
|
@ -156,7 +218,8 @@ void NimBLEAdvertising::setScanResponse(bool set) {
|
|||
* @param [in] connectWhitelistOnly If true, only allow connections from those on the white list.
|
||||
*/
|
||||
void NimBLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly);
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d",
|
||||
scanRequestWhitelistOnly, connectWhitelistOnly);
|
||||
if (!scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||
m_advParams.filter_policy = BLE_HCI_ADV_FILT_NONE;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
|
@ -194,7 +257,8 @@ void NimBLEAdvertising::setAdvertisementData(NimBLEAdvertisementData& advertisem
|
|||
(uint8_t*)advertisementData.getPayload().data(),
|
||||
advertisementData.getPayload().length());
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_set_data: %d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_set_data: %d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
m_customAdvData = true; // Set the flag that indicates we are using custom advertising data.
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setAdvertisementData");
|
||||
|
@ -213,7 +277,8 @@ void NimBLEAdvertising::setScanResponseData(NimBLEAdvertisementData& advertiseme
|
|||
(uint8_t*)advertisementData.getPayload().data(),
|
||||
advertisementData.getPayload().length());
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_rsp_set_data: %d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_rsp_set_data: %d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data.
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setScanResponseData");
|
||||
|
@ -225,13 +290,14 @@ void NimBLEAdvertising::setScanResponseData(NimBLEAdvertisementData& advertiseme
|
|||
* @param [in] duration The duration, in seconds, to advertise, 0 == advertise forever.
|
||||
* @param [in] advCompleteCB A pointer to a callback to be invoked when advertising ends.
|
||||
*/
|
||||
void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdvertising *pAdv)) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> Advertising start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData);
|
||||
bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdvertising *pAdv)) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> Advertising start: customAdvData: %d, customScanResponseData: %d",
|
||||
m_customAdvData, m_customScanResponseData);
|
||||
|
||||
// If Host is not synced we cannot start advertising.
|
||||
if(!NimBLEDevice::m_synced) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
@ -240,17 +306,21 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
if(!pServer->m_gattsStarted){
|
||||
pServer->start();
|
||||
} else if(pServer->getConnectedCount() >= NIMBLE_MAX_CONNECTIONS) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Max connections reached - not advertising");
|
||||
return;
|
||||
NIMBLE_LOGE(LOG_TAG, "Max connections reached - not advertising");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// If already advertising just return
|
||||
if(ble_gap_adv_active()) {
|
||||
return;
|
||||
NIMBLE_LOGW(LOG_TAG, "Advertising already active");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the duration incase of host reset so we can restart with the same params
|
||||
m_duration = duration;
|
||||
|
||||
if(duration == 0){
|
||||
duration = BLE_HS_FOREVER;
|
||||
}
|
||||
|
@ -260,16 +330,31 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
|
||||
m_advCompCB = advCompleteCB;
|
||||
|
||||
m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
|
||||
if(m_advParams.conn_mode == BLE_GAP_CONN_MODE_NON) {
|
||||
if(!m_scanResp) {
|
||||
m_advParams.disc_mode = BLE_GAP_DISC_MODE_NON;
|
||||
m_advData.flags = BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
}
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
|
||||
if (!m_customAdvData && !m_advDataSet) {
|
||||
//start with 3 bytes for the flags data
|
||||
uint8_t payloadLen = 3;
|
||||
uint8_t payloadLen = (2 + 1);
|
||||
if(m_advData.appearance_is_present)
|
||||
payloadLen += (2 + BLE_HS_ADV_APPEARANCE_LEN);
|
||||
if(m_advData.tx_pwr_lvl_is_present)
|
||||
payloadLen += (2 + 1);
|
||||
if(m_advData.slave_itvl_range != nullptr)
|
||||
payloadLen += (2 + 4);
|
||||
|
||||
for(auto &it : m_serviceUUIDs) {
|
||||
if(it.getNative()->u.type == BLE_UUID_TYPE_16) {
|
||||
int add = (m_advData.num_uuids16 > 0) ? 2 : 4;
|
||||
if((payloadLen + add) > 31){
|
||||
if((payloadLen + add) > BLE_HS_ADV_MAX_SZ){
|
||||
m_advData.uuids16_is_complete = 0;
|
||||
continue;
|
||||
}
|
||||
|
@ -278,7 +363,7 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
if(nullptr == (m_advData.uuids16 = (ble_uuid16_t*)realloc(m_advData.uuids16,
|
||||
(m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t))))
|
||||
{
|
||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
||||
NIMBLE_LOGC(LOG_TAG, "Error, no mem");
|
||||
abort();
|
||||
}
|
||||
memcpy(&m_advData.uuids16[m_advData.num_uuids16].value,
|
||||
|
@ -290,7 +375,7 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
}
|
||||
if(it.getNative()->u.type == BLE_UUID_TYPE_32) {
|
||||
int add = (m_advData.num_uuids32 > 0) ? 4 : 6;
|
||||
if((payloadLen + add) > 31){
|
||||
if((payloadLen + add) > BLE_HS_ADV_MAX_SZ){
|
||||
m_advData.uuids32_is_complete = 0;
|
||||
continue;
|
||||
}
|
||||
|
@ -299,7 +384,7 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
if(nullptr == (m_advData.uuids32 = (ble_uuid32_t*)realloc(m_advData.uuids32,
|
||||
(m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t))))
|
||||
{
|
||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
||||
NIMBLE_LOGC(LOG_TAG, "Error, no mem");
|
||||
abort();
|
||||
}
|
||||
memcpy(&m_advData.uuids32[m_advData.num_uuids32].value,
|
||||
|
@ -311,7 +396,7 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
}
|
||||
if(it.getNative()->u.type == BLE_UUID_TYPE_128){
|
||||
int add = (m_advData.num_uuids128 > 0) ? 16 : 18;
|
||||
if((payloadLen + add) > 31){
|
||||
if((payloadLen + add) > BLE_HS_ADV_MAX_SZ){
|
||||
m_advData.uuids128_is_complete = 0;
|
||||
continue;
|
||||
}
|
||||
|
@ -320,7 +405,7 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc(m_advData.uuids128,
|
||||
(m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t))))
|
||||
{
|
||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
||||
NIMBLE_LOGC(LOG_TAG, "Error, no mem");
|
||||
abort();
|
||||
}
|
||||
memcpy(&m_advData.uuids128[m_advData.num_uuids128].value,
|
||||
|
@ -333,54 +418,74 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
}
|
||||
|
||||
// check if there is room for the name, if not put it in scan data
|
||||
if((payloadLen + m_advData.name_len) > 29) {
|
||||
if((payloadLen + (2 + m_advData.name_len)) > BLE_HS_ADV_MAX_SZ) {
|
||||
if(m_scanResp){
|
||||
m_scanData.name = m_advData.name;
|
||||
m_scanData.name_len = m_advData.name_len;
|
||||
m_scanData.name_is_complete = m_advData.name_is_complete;
|
||||
if(m_scanData.name_len > BLE_HS_ADV_MAX_SZ - 2) {
|
||||
m_scanData.name_len = BLE_HS_ADV_MAX_SZ - 2;
|
||||
m_scanData.name_is_complete = 0;
|
||||
} else {
|
||||
m_scanData.name_is_complete = 1;
|
||||
}
|
||||
m_advData.name = nullptr;
|
||||
m_advData.name_len = 0;
|
||||
m_advData.name_is_complete = 0;
|
||||
} else {
|
||||
if(m_advData.tx_pwr_lvl_is_present) {
|
||||
m_advData.tx_pwr_lvl = 0;
|
||||
m_advData.tx_pwr_lvl_is_present = 0;
|
||||
payloadLen -= (2 + 1);
|
||||
}
|
||||
// if not using scan response just cut the name down
|
||||
// leaving 2 bytes for the data specifier.
|
||||
m_advData.name_len = (29 - payloadLen);
|
||||
if(m_advData.name_len > (BLE_HS_ADV_MAX_SZ - payloadLen - 2)) {
|
||||
m_advData.name_len = (BLE_HS_ADV_MAX_SZ - payloadLen - 2);
|
||||
m_advData.name_is_complete = 0;
|
||||
}
|
||||
}
|
||||
m_advData.name_is_complete = 0;
|
||||
}
|
||||
|
||||
if(m_advData.name_len > 0) {
|
||||
payloadLen += (m_advData.name_len + 2);
|
||||
}
|
||||
|
||||
if(m_scanResp) {
|
||||
// name length + type byte + length byte + tx power type + length + data
|
||||
if((m_scanData.name_len + 5) > 31) {
|
||||
// prioritize name data over tx power
|
||||
m_scanData.tx_pwr_lvl_is_present = 0;
|
||||
m_scanData.tx_pwr_lvl = 0;
|
||||
// limit name to 29 to leave room for the data specifiers
|
||||
if(m_scanData.name_len > 29) {
|
||||
m_scanData.name_len = 29;
|
||||
m_scanData.name_is_complete = false;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ble_gap_adv_rsp_set_fields(&m_scanData);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGC(LOG_TAG, "error setting scan response data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
abort();
|
||||
switch(rc) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case BLE_HS_EBUSY:
|
||||
NIMBLE_LOGE(LOG_TAG, "Already advertising");
|
||||
break;
|
||||
|
||||
case BLE_HS_EMSGSIZE:
|
||||
NIMBLE_LOGE(LOG_TAG, "Scan data too long");
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Error setting scan response data; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
// if not using scan response and there is room,
|
||||
// put the tx power data into the advertisment
|
||||
} else if (payloadLen < 29) {
|
||||
m_advData.tx_pwr_lvl_is_present = 1;
|
||||
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
|
||||
}
|
||||
|
||||
rc = ble_gap_adv_set_fields(&m_advData);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGC(LOG_TAG, "error setting advertisement data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
abort();
|
||||
if(rc == 0) {
|
||||
rc = ble_gap_adv_set_fields(&m_advData);
|
||||
switch(rc) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case BLE_HS_EBUSY:
|
||||
NIMBLE_LOGE(LOG_TAG, "Already advertising");
|
||||
break;
|
||||
|
||||
case BLE_HS_EMSGSIZE:
|
||||
NIMBLE_LOGE(LOG_TAG, "Advertisement data too long");
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Error setting advertisement data; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_advData.num_uuids128 > 0) {
|
||||
|
@ -401,24 +506,54 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
m_advData.num_uuids16 = 0;
|
||||
}
|
||||
|
||||
if(rc !=0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_advDataSet = true;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
rc = ble_gap_adv_start(0, NULL, duration,
|
||||
rc = ble_gap_adv_start(NimBLEDevice::m_own_addr_type, NULL, duration,
|
||||
&m_advParams,
|
||||
(pServer != nullptr) ? NimBLEServer::handleGapEvent : NimBLEAdvertising::handleGapEvent,
|
||||
(pServer != nullptr) ? NimBLEServer::handleGapEvent :
|
||||
NimBLEAdvertising::handleGapEvent,
|
||||
(pServer != nullptr) ? (void*)pServer : (void*)this);
|
||||
#else
|
||||
rc = ble_gap_adv_start(0, NULL, duration,
|
||||
rc = ble_gap_adv_start(NimBLEDevice::m_own_addr_type, NULL, duration,
|
||||
&m_advParams, NimBLEAdvertising::handleGapEvent, this);
|
||||
#endif
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGC(LOG_TAG, "Error enabling advertising; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
abort();
|
||||
switch(rc) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case BLE_HS_EINVAL:
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Duration too long");
|
||||
break;
|
||||
|
||||
case BLE_HS_EPREEMPTED:
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - busy");
|
||||
break;
|
||||
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Host Reset");
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Error enabling advertising; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
|
||||
if(rc != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< Advertising start");
|
||||
return true;
|
||||
} // start
|
||||
|
||||
|
||||
|
@ -427,9 +562,11 @@ void NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
|||
*/
|
||||
void NimBLEAdvertising::stop() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> stop");
|
||||
|
||||
int rc = ble_gap_adv_stop();
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_stop rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_stop rc=%d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -460,8 +597,17 @@ bool NimBLEAdvertising::isAdvertising() {
|
|||
* Host reset seems to clear advertising data,
|
||||
* we need clear the flag so it reloads it.
|
||||
*/
|
||||
void NimBLEAdvertising::onHostReset() {
|
||||
void NimBLEAdvertising::onHostSync() {
|
||||
NIMBLE_LOGD(LOG_TAG, "Host re-synced");
|
||||
|
||||
m_advDataSet = false;
|
||||
// If we were advertising forever, restart it now
|
||||
if(m_duration == 0) {
|
||||
start(m_duration, m_advCompCB);
|
||||
} else {
|
||||
// Otherwise we should tell the app that advertising stopped.
|
||||
advCompleteCB();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -475,6 +621,19 @@ int NimBLEAdvertising::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
|||
NimBLEAdvertising *pAdv = (NimBLEAdvertising*)arg;
|
||||
|
||||
if(event->type == BLE_GAP_EVENT_ADV_COMPLETE) {
|
||||
switch(event->adv_complete.reason) {
|
||||
// Don't call the callback if host reset, we want to
|
||||
// preserve the active flag until re-sync to restart advertising.
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGC(LOG_TAG, "host reset, rc=%d", event->adv_complete.reason);
|
||||
NimBLEDevice::onReset(event->adv_complete.reason);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pAdv->advCompleteCB();
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -77,7 +77,7 @@ public:
|
|||
void addServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
void addServiceUUID(const char* serviceUUID);
|
||||
void removeServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
void start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr);
|
||||
bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr);
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setAdvertisementType(uint8_t adv_type);
|
||||
|
@ -87,13 +87,15 @@ public:
|
|||
void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
|
||||
void setScanResponseData(NimBLEAdvertisementData& advertisementData);
|
||||
void setScanResponse(bool);
|
||||
void setMinPreferred(uint16_t);
|
||||
void setMaxPreferred(uint16_t);
|
||||
void advCompleteCB();
|
||||
bool isAdvertising();
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
|
||||
void onHostReset();
|
||||
void onHostSync();
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
|
||||
ble_hs_adv_fields m_advData;
|
||||
|
@ -104,8 +106,9 @@ private:
|
|||
bool m_customScanResponseData;
|
||||
bool m_scanResp;
|
||||
bool m_advDataSet;
|
||||
void (*m_advCompCB)(NimBLEAdvertising *pAdv);
|
||||
|
||||
void (*m_advCompCB)(NimBLEAdvertising *pAdv);
|
||||
uint8_t m_slaveItvl[4];
|
||||
uint32_t m_duration;
|
||||
};
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
|
|
@ -473,9 +473,10 @@ void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
|||
return;
|
||||
}
|
||||
|
||||
time_t t = time(nullptr);
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
m_value = std::string((char*)data, length);
|
||||
m_timestamp = time(nullptr);
|
||||
m_timestamp = t;
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "nimble/nimble_port.h"
|
||||
|
||||
|
||||
static const char* LOG_TAG = "NimBLEClient";
|
||||
static NimBLEClientCallbacks defaultCallbacks;
|
||||
|
||||
|
@ -56,11 +59,10 @@ static NimBLEClientCallbacks defaultCallbacks;
|
|||
NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(peerAddress) {
|
||||
m_pClientCallbacks = &defaultCallbacks;
|
||||
m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
m_isConnected = false;
|
||||
m_waitingToConnect = false;
|
||||
m_connectTimeout = 30000;
|
||||
m_deleteCallbacks = false;
|
||||
m_pTaskData = nullptr;
|
||||
m_connEstablished = false;
|
||||
|
||||
m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
|
||||
m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
|
||||
|
@ -70,6 +72,9 @@ NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(pee
|
|||
m_pConnParams.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; // timeout = 400*10ms = 4000ms
|
||||
m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
|
||||
m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
|
||||
|
||||
ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(),
|
||||
NimBLEClient::dcTimerCb, this);
|
||||
} // NimBLEClient
|
||||
|
||||
|
||||
|
@ -89,6 +94,20 @@ NimBLEClient::~NimBLEClient() {
|
|||
} // ~NimBLEClient
|
||||
|
||||
|
||||
/**
|
||||
* @brief If we have asked to disconnect and the event does not
|
||||
* occur within the supervision timeout + added delay, this will
|
||||
* be called to reset the host in the case of a stalled controller.
|
||||
*/
|
||||
void NimBLEClient::dcTimerCb(ble_npl_event *event) {
|
||||
/* NimBLEClient *pClient = (NimBLEClient*)event->arg;
|
||||
NIMBLE_LOGC(LOG_TAG, "Timed out disconnecting from %s - resetting host",
|
||||
std::string(pClient->getPeerAddress()).c_str());
|
||||
*/
|
||||
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete all service objects created by this client and clear the vector.
|
||||
*/
|
||||
|
@ -164,70 +183,119 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(ble_gap_conn_active()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection in progress - must wait.");
|
||||
if(isConnected() || m_connEstablished || m_pTaskData != nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, id=%d",
|
||||
std::string(m_peerAddress).c_str(), getConnId());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!NimBLEDevice::getScan()->stop()) {
|
||||
ble_addr_t peerAddr_t;
|
||||
memcpy(&peerAddr_t.val, address.getNative(),6);
|
||||
peerAddr_t.type = address.getType();
|
||||
if(ble_gap_conn_find_by_addr(&peerAddr_t, NULL) == 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists",
|
||||
address.toString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(address == NimBLEAddress("")) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid peer address;(NULL)");
|
||||
return false;
|
||||
} else if(m_peerAddress != address) {
|
||||
} else {
|
||||
m_peerAddress = address;
|
||||
}
|
||||
|
||||
ble_addr_t peerAddrt;
|
||||
memcpy(&peerAddrt.val, m_peerAddress.getNative(),6);
|
||||
peerAddrt.type = m_peerAddress.getType();
|
||||
|
||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||
m_pTaskData = &taskData;
|
||||
|
||||
int rc = 0;
|
||||
|
||||
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
||||
* timeout (default value of m_connectTimeout).
|
||||
* Loop on BLE_HS_EBUSY if the scan hasn't stopped yet.
|
||||
*/
|
||||
do{
|
||||
rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &peerAddrt, m_connectTimeout, &m_pConnParams,
|
||||
NimBLEClient::handleGapEvent, this);
|
||||
if(rc == BLE_HS_EBUSY) {
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}while(rc == BLE_HS_EBUSY);
|
||||
do {
|
||||
rc = ble_gap_connect(NimBLEDevice::m_own_addr_type, &peerAddr_t,
|
||||
m_connectTimeout, &m_pConnParams,
|
||||
NimBLEClient::handleGapEvent, this);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
if (rc != 0 && rc != BLE_HS_EDONE) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to connect to device; "
|
||||
"addr=%s, rc=%d; %s",
|
||||
std::string(m_peerAddress).c_str(),
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
case BLE_HS_EBUSY:
|
||||
// Scan was still running, stop it and try again
|
||||
if (!NimBLEDevice::getScan()->stop()) {
|
||||
rc = BLE_HS_EUNKNOWN;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_HS_EDONE:
|
||||
// A connection to this device already exists, do not connect twice.
|
||||
NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s",
|
||||
std::string(m_peerAddress).c_str());
|
||||
break;
|
||||
|
||||
case BLE_HS_EALREADY:
|
||||
// Already attemting to connect to this device, cancel the previous
|
||||
// attempt and report failure here so we don't get 2 connections.
|
||||
NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling",
|
||||
std::string(m_peerAddress).c_str());
|
||||
ble_gap_conn_cancel();
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to connect to %s, rc=%d; %s",
|
||||
std::string(m_peerAddress).c_str(),
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
|
||||
} while (rc == BLE_HS_EBUSY);
|
||||
|
||||
if(rc != 0) {
|
||||
m_pTaskData = nullptr;
|
||||
m_waitingToConnect = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_waitingToConnect = true;
|
||||
// Wait for the connect timeout time +1 second for the connection to complete
|
||||
if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
||||
m_pTaskData = nullptr;
|
||||
// If a connection was made but no response from MTU exchange; disconnect
|
||||
if(isConnected()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connect timeout - no response");
|
||||
disconnect();
|
||||
} else {
|
||||
// workaround; if the controller doesn't cancel the connection
|
||||
// at the timeout, cancel it here.
|
||||
NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling");
|
||||
ble_gap_conn_cancel();
|
||||
}
|
||||
|
||||
// Wait for the connection to complete.
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if(taskData.rc != 0){
|
||||
return false;
|
||||
|
||||
} else if(taskData.rc != 0){
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s",
|
||||
taskData.rc,
|
||||
NimBLEUtils::returnCodeToString(taskData.rc));
|
||||
// If the failure was not a result of a disconnection
|
||||
// make sure we disconnect now to avoid dangling connections
|
||||
if(isConnected()) {
|
||||
disconnect();
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
NIMBLE_LOGI(LOG_TAG, "Connection established");
|
||||
}
|
||||
|
||||
if(deleteAttibutes) {
|
||||
deleteServices();
|
||||
}
|
||||
|
||||
m_connEstablished = true;
|
||||
m_pClientCallbacks->onConnect(this);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< connect()");
|
||||
return true;
|
||||
// Check if still connected before returning
|
||||
return isConnected();
|
||||
} // connect
|
||||
|
||||
|
||||
|
@ -268,12 +336,39 @@ bool NimBLEClient::secureConnection() {
|
|||
int NimBLEClient::disconnect(uint8_t reason) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
|
||||
int rc = 0;
|
||||
if(m_isConnected){
|
||||
rc = ble_gap_terminate(m_conn_id, reason);
|
||||
if(rc != 0){
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc,
|
||||
NimBLEUtils::returnCodeToString(rc));
|
||||
if(isConnected()) {
|
||||
// If the timer was already started, ignore this call.
|
||||
if(ble_npl_callout_is_active(&m_dcTimer)) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Already disconnecting, timer started");
|
||||
return BLE_HS_EALREADY;
|
||||
}
|
||||
|
||||
ble_gap_conn_desc desc;
|
||||
if(ble_gap_conn_find(m_conn_id, &desc) != 0){
|
||||
NIMBLE_LOGI(LOG_TAG, "Connection ID not found");
|
||||
return BLE_HS_EALREADY;
|
||||
}
|
||||
|
||||
// We use a timer to detect a controller error in the event that it does
|
||||
// not inform the stack when disconnection is complete.
|
||||
// This is a common error in certain esp-idf versions.
|
||||
// The disconnect timeout time is the supervison timeout time + 1 second.
|
||||
// In the case that the event happenss shortly after the supervision timeout
|
||||
// we don't want to prematurely reset the host.
|
||||
ble_npl_time_t ticks;
|
||||
ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks);
|
||||
ble_npl_callout_reset(&m_dcTimer, ticks);
|
||||
|
||||
rc = ble_gap_terminate(m_conn_id, reason);
|
||||
if (rc != 0) {
|
||||
if(rc != BLE_HS_EALREADY) {
|
||||
ble_npl_callout_stop(&m_dcTimer);
|
||||
}
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
} else {
|
||||
NIMBLE_LOGD(LOG_TAG, "Not connected to any peers");
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
||||
|
@ -283,12 +378,12 @@ int NimBLEClient::disconnect(uint8_t reason) {
|
|||
|
||||
/**
|
||||
* @brief Set the connection paramaters to use when connecting to a server.
|
||||
* @param [in] minInterval minimum connection interval in 0.625ms units.
|
||||
* @param [in] maxInterval maximum connection interval in 0.625ms units.
|
||||
* @param [in] latency number of packets allowed to skip (extends max interval)
|
||||
* @param [in] timeout the timeout time in 10ms units before disconnecting
|
||||
* @param [in] scanInterval the scan interval to use when attempting to connect in 0.625ms units.
|
||||
* @param [in] scanWindow the scan window to use when attempting to connect in 0.625ms units.
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
* @param [in] scanInterval The scan interval to use when attempting to connect in 0.625ms units.
|
||||
* @param [in] scanWindow The scan window to use when attempting to connect in 0.625ms units.
|
||||
*/
|
||||
void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout,
|
||||
|
@ -315,10 +410,10 @@ void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterva
|
|||
/**
|
||||
* @brief Update the connection parameters:
|
||||
* * Can only be used after a connection has been established.
|
||||
* @param [in] minInterval minimum connection interval in 0.625ms units.
|
||||
* @param [in] maxInterval maximum connection interval in 0.625ms units.
|
||||
* @param [in] latency number of packets allowed to skip (extends max interval)
|
||||
* @param [in] timeout the timeout time in 10ms units before disconnecting
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
*/
|
||||
void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout)
|
||||
|
@ -454,6 +549,16 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
|
|||
if(m_servicesVector.size() > prev_size) {
|
||||
return m_servicesVector.back();
|
||||
}
|
||||
|
||||
// If the request was successful but 16/32 bit service not found
|
||||
// try again with the 128 bit uuid.
|
||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||
{
|
||||
NimBLEUUID uuid128(uuid);
|
||||
uuid128.to128();
|
||||
return getService(uuid128);
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getService: not found");
|
||||
|
@ -510,7 +615,7 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
|
|||
|
||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveServices");
|
||||
|
||||
if(!m_isConnected){
|
||||
if(!isConnected()){
|
||||
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting");
|
||||
return false;
|
||||
}
|
||||
|
@ -618,10 +723,11 @@ std::string NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUU
|
|||
* @param [in] serviceUUID The service that owns the characteristic.
|
||||
* @param [in] characteristicUUID The characteristic whose value we wish to write.
|
||||
* @param [in] value The value to write to the characteristic.
|
||||
* @param [in] response If true, uses write with response operation.
|
||||
* @returns true if successful otherwise false
|
||||
*/
|
||||
bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||
const std::string &value)
|
||||
const std::string &value, bool response)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s",
|
||||
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
|
@ -632,7 +738,7 @@ bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &cha
|
|||
if(pService != nullptr) {
|
||||
NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID);
|
||||
if(pChar != nullptr) {
|
||||
ret = pChar->writeValue(value);
|
||||
ret = pChar->writeValue(value, response);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,6 +747,31 @@ bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &cha
|
|||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the remote characteristic with the specified handle.
|
||||
* @param [in] handle The handle of the desired characteristic.
|
||||
* @returns The matching remote characteristic, nullptr otherwise.
|
||||
*/
|
||||
NimBLERemoteCharacteristic* NimBLEClient::getCharacteristic(const uint16_t handle)
|
||||
{
|
||||
NimBLERemoteService *pService = nullptr;
|
||||
for(auto it = m_servicesVector.begin(); it != m_servicesVector.end(); ++it) {
|
||||
if ((*it)->getStartHandle() <= handle && handle <= (*it)->getEndHandle()) {
|
||||
pService = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pService != nullptr) {
|
||||
for (auto it = pService->begin(); it != pService->end(); ++it) {
|
||||
if ((*it)->getHandle() == handle) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current mtu of this connection.
|
||||
|
@ -656,7 +787,8 @@ uint16_t NimBLEClient::getMTU() {
|
|||
* @param [in] event The event structure sent by the NimBLE stack.
|
||||
* @param [in] arg A pointer to the client instance that registered for this callback.
|
||||
*/
|
||||
/*STATIC*/ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
/*STATIC*/
|
||||
int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
NimBLEClient* client = (NimBLEClient*)arg;
|
||||
int rc;
|
||||
|
||||
|
@ -665,61 +797,67 @@ uint16_t NimBLEClient::getMTU() {
|
|||
switch(event->type) {
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT: {
|
||||
if(!client->m_isConnected)
|
||||
return 0;
|
||||
|
||||
if(client->m_conn_id != event->disconnect.conn.conn_handle)
|
||||
return 0;
|
||||
|
||||
client->m_isConnected = false;
|
||||
client->m_waitingToConnect=false;
|
||||
// Remove the device from ignore list so we will scan it again
|
||||
NimBLEDevice::removeIgnored(client->m_peerAddress);
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", event->disconnect.reason,
|
||||
NimBLEUtils::returnCodeToString(event->disconnect.reason));
|
||||
|
||||
rc = event->disconnect.reason;
|
||||
// If Host reset tell the device now before returning to prevent
|
||||
// any errors caused by calling host functions before resyncing.
|
||||
switch(event->disconnect.reason) {
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
switch(rc) {
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGC(LOG_TAG, "Disconnect - host reset, rc=%d", event->disconnect.reason);
|
||||
NimBLEDevice::onReset(event->disconnect.reason);
|
||||
case BLE_HS_EOS:
|
||||
NIMBLE_LOGC(LOG_TAG, "Disconnect - host reset, rc=%d", rc);
|
||||
NimBLEDevice::onReset(rc);
|
||||
break;
|
||||
default:
|
||||
// Check that the event is for this client.
|
||||
if(client->m_conn_id != event->disconnect.conn.conn_handle) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
// Stop the disconnect timer since we are now disconnected.
|
||||
ble_npl_callout_stop(&client->m_dcTimer);
|
||||
|
||||
// Remove the device from ignore list so we will scan it again
|
||||
NimBLEDevice::removeIgnored(client->m_peerAddress);
|
||||
|
||||
// No longer connected, clear the connection ID.
|
||||
client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
|
||||
// If we received a connected event but did not get established (no PDU)
|
||||
// then a disconnect event will be sent but we should not send it to the
|
||||
// app for processing. Instead we will ensure the task is released
|
||||
// and report the error.
|
||||
if(!client->m_connEstablished)
|
||||
break;
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
|
||||
client->m_connEstablished = false;
|
||||
client->m_pClientCallbacks->onDisconnect(client);
|
||||
rc = event->disconnect.reason;
|
||||
break;
|
||||
} // BLE_GAP_EVENT_DISCONNECT
|
||||
|
||||
case BLE_GAP_EVENT_CONNECT: {
|
||||
|
||||
if(!client->m_waitingToConnect)
|
||||
// If we aren't waiting for this connection response
|
||||
// we should drop the connection immediately.
|
||||
if(client->isConnected() || client->m_pTaskData == nullptr) {
|
||||
ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//if(client->m_conn_id != BLE_HS_CONN_HANDLE_NONE)
|
||||
// return 0;
|
||||
|
||||
client->m_waitingToConnect=false;
|
||||
|
||||
if (event->connect.status == 0) {
|
||||
client->m_isConnected = true;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Connection established");
|
||||
rc = event->connect.status;
|
||||
if (rc == 0) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Connected event");
|
||||
|
||||
client->m_conn_id = event->connect.conn_handle;
|
||||
|
||||
rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL,NULL);
|
||||
if(rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_exchange_mtu: rc=%d %s",rc,
|
||||
NimBLEUtils::returnCodeToString(rc));
|
||||
NIMBLE_LOGE(LOG_TAG, "MTU exchange error; rc=%d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -727,14 +865,10 @@ uint16_t NimBLEClient::getMTU() {
|
|||
// scanning since we are already connected to it
|
||||
NimBLEDevice::addIgnored(client->m_peerAddress);
|
||||
} else {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Connection failed; status=%d %s",
|
||||
event->connect.status,
|
||||
NimBLEUtils::returnCodeToString(event->connect.status));
|
||||
|
||||
client->m_isConnected = false;
|
||||
rc = event->connect.status;
|
||||
client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_CONNECT
|
||||
|
||||
|
@ -742,7 +876,14 @@ uint16_t NimBLEClient::getMTU() {
|
|||
if(client->m_conn_id != event->notify_rx.conn_handle)
|
||||
return 0;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",event->notify_rx.attr_handle);
|
||||
// If a notification comes before this flag is set we might
|
||||
// access a vector while it is being cleared in connect()
|
||||
if(!client->m_connEstablished) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",
|
||||
event->notify_rx.attr_handle);
|
||||
|
||||
for(auto &it: client->m_servicesVector) {
|
||||
// Dont waste cycles searching services without this handle in its range
|
||||
|
@ -752,8 +893,8 @@ uint16_t NimBLEClient::getMTU() {
|
|||
|
||||
auto cVector = &it->m_characteristicVector;
|
||||
NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d",
|
||||
it->getUUID().toString().c_str(),
|
||||
event->notify_rx.attr_handle);
|
||||
it->getUUID().toString().c_str(),
|
||||
event->notify_rx.attr_handle);
|
||||
|
||||
auto characteristic = cVector->cbegin();
|
||||
for(; characteristic != cVector->cend(); ++characteristic) {
|
||||
|
@ -762,16 +903,19 @@ uint16_t NimBLEClient::getMTU() {
|
|||
}
|
||||
|
||||
if(characteristic != cVector->cend()) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str());
|
||||
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s",
|
||||
(*characteristic)->toString().c_str());
|
||||
|
||||
time_t t = time(nullptr);
|
||||
portENTER_CRITICAL(&(*characteristic)->m_valMux);
|
||||
(*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data, event->notify_rx.om->om_len);
|
||||
(*characteristic)->m_timestamp = time(nullptr);
|
||||
(*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data,
|
||||
event->notify_rx.om->om_len);
|
||||
(*characteristic)->m_timestamp = t;
|
||||
portEXIT_CRITICAL(&(*characteristic)->m_valMux);
|
||||
|
||||
if ((*characteristic)->m_notifyCallback != nullptr) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
|
||||
(*characteristic)->toString().c_str());
|
||||
(*characteristic)->toString().c_str());
|
||||
(*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data,
|
||||
event->notify_rx.om->om_len,
|
||||
!event->notify_rx.indication);
|
||||
|
@ -790,10 +934,10 @@ uint16_t NimBLEClient::getMTU() {
|
|||
}
|
||||
NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters");
|
||||
NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d",
|
||||
event->conn_update_req.peer_params->itvl_min,
|
||||
event->conn_update_req.peer_params->itvl_max,
|
||||
event->conn_update_req.peer_params->latency,
|
||||
event->conn_update_req.peer_params->supervision_timeout);
|
||||
event->conn_update_req.peer_params->itvl_min,
|
||||
event->conn_update_req.peer_params->itvl_max,
|
||||
event->conn_update_req.peer_params->latency,
|
||||
event->conn_update_req.peer_params->supervision_timeout);
|
||||
|
||||
rc = client->m_pClientCallbacks->onConnParamsUpdateRequest(client,
|
||||
event->conn_update_req.peer_params) ? 0 : BLE_ERR_CONN_PARMS;
|
||||
|
@ -827,7 +971,9 @@ uint16_t NimBLEClient::getMTU() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if(event->enc_change.status == 0 || event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) {
|
||||
if(event->enc_change.status == 0 ||
|
||||
event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING))
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
|
@ -922,7 +1068,9 @@ uint16_t NimBLEClient::getMTU() {
|
|||
|
||||
if(client->m_pTaskData != nullptr) {
|
||||
client->m_pTaskData->rc = rc;
|
||||
xTaskNotifyGive(client->m_pTaskData->task);
|
||||
if(client->m_pTaskData->task) {
|
||||
xTaskNotifyGive(client->m_pTaskData->task);
|
||||
}
|
||||
client->m_pTaskData = nullptr;
|
||||
}
|
||||
|
||||
|
@ -935,7 +1083,7 @@ uint16_t NimBLEClient::getMTU() {
|
|||
* @return True if we are connected and false if we are not connected.
|
||||
*/
|
||||
bool NimBLEClient::isConnected() {
|
||||
return m_isConnected;
|
||||
return m_conn_id != BLE_HS_CONN_HANDLE_NONE;
|
||||
} // isConnected
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <string>
|
||||
|
||||
class NimBLERemoteService;
|
||||
class NimBLERemoteCharacteristic;
|
||||
class NimBLEClientCallbacks;
|
||||
class NimBLEAdvertisedDevice;
|
||||
|
||||
|
@ -54,7 +55,8 @@ public:
|
|||
size_t deleteService(const NimBLEUUID &uuid);
|
||||
std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
|
||||
bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||
const std::string &value);
|
||||
const std::string &value, bool response = false);
|
||||
NimBLERemoteCharacteristic* getCharacteristic(const uint16_t handle);
|
||||
bool isConnected();
|
||||
void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks,
|
||||
bool deleteCallbacks = true);
|
||||
|
@ -82,16 +84,17 @@ private:
|
|||
const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_svc *service,
|
||||
void *arg);
|
||||
static void dcTimerCb(ble_npl_event *event);
|
||||
bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr);
|
||||
|
||||
NimBLEAddress m_peerAddress;
|
||||
uint16_t m_conn_id;
|
||||
bool m_isConnected;
|
||||
bool m_waitingToConnect;
|
||||
bool m_connEstablished;
|
||||
bool m_deleteCallbacks;
|
||||
int32_t m_connectTimeout;
|
||||
NimBLEClientCallbacks* m_pClientCallbacks;
|
||||
ble_task_data_t *m_pTaskData;
|
||||
ble_task_data_t* m_pTaskData;
|
||||
ble_npl_callout m_dcTimer;
|
||||
|
||||
std::vector<NimBLERemoteService*> m_servicesVector;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_hs_pvcy.h"
|
||||
#include "host/util/util.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
@ -60,6 +61,7 @@ std::list <NimBLEClient*> NimBLEDevice::m_cList;
|
|||
#endif
|
||||
std::list <NimBLEAddress> NimBLEDevice::m_ignoreList;
|
||||
NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr;
|
||||
uint8_t NimBLEDevice::m_own_addr_type = BLE_OWN_ADDR_PUBLIC;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -144,8 +146,8 @@ void NimBLEDevice::stopAdvertising() {
|
|||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
/* STATIC */ NimBLEClient* NimBLEDevice::createClient(NimBLEAddress peerAddress) {
|
||||
if(m_cList.size() >= NIMBLE_MAX_CONNECTIONS) {
|
||||
NIMBLE_LOGW("Number of clients exceeds Max connections. Max=(%d)",
|
||||
NIMBLE_MAX_CONNECTIONS);
|
||||
NIMBLE_LOGW(LOG_TAG,"Number of clients exceeds Max connections. Cur=%d Max=%d",
|
||||
m_cList.size(), NIMBLE_MAX_CONNECTIONS);
|
||||
}
|
||||
|
||||
NimBLEClient* pClient = new NimBLEClient(peerAddress);
|
||||
|
@ -165,26 +167,31 @@ void NimBLEDevice::stopAdvertising() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Set the connection established flag to false to stop notifications
|
||||
// from accessing the attribute vectors while they are being deleted.
|
||||
pClient->m_connEstablished = false;
|
||||
int rc =0;
|
||||
|
||||
if(pClient->m_isConnected) {
|
||||
if(pClient->isConnected()) {
|
||||
rc = pClient->disconnect();
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY && rc != BLE_HS_ENOTCONN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while(pClient->m_isConnected) {
|
||||
vTaskDelay(10);
|
||||
while(pClient->isConnected()) {
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
// Since we set the flag to false the app will not get a callback
|
||||
// in the disconnect event so we call it here for good measure.
|
||||
pClient->m_pClientCallbacks->onDisconnect(pClient);
|
||||
|
||||
if(pClient->m_waitingToConnect) {
|
||||
} else if(pClient->m_pTaskData != nullptr) {
|
||||
rc = ble_gap_conn_cancel();
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
return false;
|
||||
}
|
||||
while(pClient->m_waitingToConnect) {
|
||||
vTaskDelay(10);
|
||||
while(pClient->m_pTaskData != nullptr) {
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,30 +412,16 @@ void NimBLEDevice::stopAdvertising() {
|
|||
|
||||
m_synced = false;
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
if(m_pScan != nullptr) {
|
||||
m_pScan->onHostReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Not needed
|
||||
if(m_pServer != nullptr) {
|
||||
m_pServer->onHostReset();
|
||||
}
|
||||
|
||||
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
||||
(*it)->onHostReset();
|
||||
}
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
if(m_bleAdvertising != nullptr) {
|
||||
m_bleAdvertising->onHostReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
NIMBLE_LOGC(LOG_TAG, "Resetting state; reason=%d, %s", reason,
|
||||
NimBLEUtils::returnCodeToString(reason));
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
if(initialized) {
|
||||
if(m_pScan != nullptr) {
|
||||
m_pScan->onHostReset();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // onReset
|
||||
|
||||
|
||||
|
@ -448,20 +441,22 @@ void NimBLEDevice::stopAdvertising() {
|
|||
int rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
// Yield for houskeeping before returning to operations.
|
||||
// Occasionally triggers exception without.
|
||||
taskYIELD();
|
||||
|
||||
m_synced = true;
|
||||
|
||||
if(initialized) {
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
if(m_pScan != nullptr) {
|
||||
// Restart scanning with the last values sent, allow to clear results.
|
||||
m_pScan->start(m_pScan->m_duration, m_pScan->m_scanCompleteCB);
|
||||
m_pScan->onHostSync();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
if(m_bleAdvertising != nullptr) {
|
||||
// Restart advertisng, parameters should already be set.
|
||||
m_bleAdvertising->start();
|
||||
m_bleAdvertising->onHostSync();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -705,6 +700,35 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
|
|||
} // setSecurityCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the own address type.
|
||||
* @param [in] own_addr_type Own Bluetooth Device address type.\n
|
||||
* The available bits are defined as:
|
||||
* * 0x00: BLE_OWN_ADDR_PUBLIC
|
||||
* * 0x01: BLE_OWN_ADDR_RANDOM
|
||||
* * 0x02: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT
|
||||
* * 0x03: BLE_OWN_ADDR_RPA_RANDOM_DEFAULT
|
||||
* @param [in] useNRPA If true, and address type is random, uses a non-resolvable random address.
|
||||
*/
|
||||
void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
|
||||
m_own_addr_type = own_addr_type;
|
||||
switch (own_addr_type) {
|
||||
case BLE_OWN_ADDR_PUBLIC:
|
||||
ble_hs_pvcy_rpa_config(NIMBLE_HOST_DISABLE_PRIVACY);
|
||||
break;
|
||||
case BLE_OWN_ADDR_RANDOM:
|
||||
setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
|
||||
ble_hs_pvcy_rpa_config(useNRPA ? NIMBLE_HOST_ENABLE_NRPA : NIMBLE_HOST_ENABLE_RPA);
|
||||
break;
|
||||
case BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT:
|
||||
case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT:
|
||||
setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
|
||||
ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA);
|
||||
break;
|
||||
}
|
||||
} // setOwnAddrType
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start the connection securing and authorization for this connection.
|
||||
* @param conn_id The connection id of the peer device.
|
||||
|
|
|
@ -116,6 +116,7 @@ public:
|
|||
static void setSecurityPasskey(uint32_t pin);
|
||||
static uint32_t getSecurityPasskey();
|
||||
static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks);
|
||||
static void setOwnAddrType(uint8_t own_addr_type, bool useNRPA=false);
|
||||
static int startSecurity(uint16_t conn_id);
|
||||
static int setMTU(uint16_t mtu);
|
||||
static uint16_t getMTU();
|
||||
|
@ -182,6 +183,7 @@ private:
|
|||
static uint32_t m_passkey;
|
||||
static ble_gap_event_listener m_listener;
|
||||
static gap_event_handler m_customGapHandler;
|
||||
static uint8_t m_own_addr_type;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* NimBLEHIDDevice.cpp
|
||||
*
|
||||
* Created: on Oct 06 2020
|
||||
* Author wakwak-koba
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEHIDDevice.cpp
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEHIDDevice.h"
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
/**
|
||||
* @brief Construct a default NimBLEHIDDevice object.
|
||||
* @param [in] server A pointer to the server instance this HID Device will use.
|
||||
*/
|
||||
NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
|
||||
/*
|
||||
* Here we create mandatory services described in bluetooth specification
|
||||
*/
|
||||
m_deviceInfoService = server->createService(NimBLEUUID((uint16_t) 0x180a));
|
||||
m_hidService = server->createService(NimBLEUUID((uint16_t) 0x1812), 40);
|
||||
m_batteryService = server->createService(NimBLEUUID((uint16_t) 0x180f));
|
||||
|
||||
/*
|
||||
* Mandatory characteristic for device info service
|
||||
*/
|
||||
m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, NIMBLE_PROPERTY::READ);
|
||||
|
||||
/*
|
||||
* Mandatory characteristics for HID service
|
||||
*/
|
||||
m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, NIMBLE_PROPERTY::READ);
|
||||
m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, NIMBLE_PROPERTY::READ);
|
||||
m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, NIMBLE_PROPERTY::WRITE_NR);
|
||||
m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ);
|
||||
|
||||
/*
|
||||
* Mandatory battery level characteristic with notification and presence descriptor
|
||||
*/
|
||||
m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
|
||||
NimBLE2904* batteryLevelDescriptor = (NimBLE2904*)m_batteryLevelCharacteristic->createDescriptor((uint16_t) 0x2904);
|
||||
batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
|
||||
batteryLevelDescriptor->setNamespace(1);
|
||||
batteryLevelDescriptor->setUnit(0x27ad);
|
||||
|
||||
/*
|
||||
* This value is setup here because its default value in most usage cases, its very rare to use boot mode
|
||||
* and we want to simplify library using as much as possible
|
||||
*/
|
||||
const uint8_t pMode[] = { 0x01 };
|
||||
protocolMode()->setValue((uint8_t*) pMode, 1);
|
||||
}
|
||||
|
||||
NimBLEHIDDevice::~NimBLEHIDDevice() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the report map data formatting information.
|
||||
* @param [in] map A pointer to an array with the values to set.
|
||||
* @param [in] size The number of values in the array.
|
||||
*/
|
||||
void NimBLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
|
||||
m_reportMapCharacteristic->setValue(map, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start the HID device services.\n
|
||||
* This function called when all the services have been created.
|
||||
*/
|
||||
void NimBLEHIDDevice::startServices() {
|
||||
m_deviceInfoService->start();
|
||||
m_hidService->start();
|
||||
m_batteryService->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a manufacturer characteristic (this characteristic is optional).
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::manufacturer() {
|
||||
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, NIMBLE_PROPERTY::READ);
|
||||
return m_manufacturerCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer name
|
||||
* @param [in] name The manufacturer name of this HID device.
|
||||
*/
|
||||
void NimBLEHIDDevice::manufacturer(std::string name) {
|
||||
m_manufacturerCharacteristic->setValue(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the Plug n Play characterisc value.
|
||||
* @param [in] sig The vendor ID source number.
|
||||
* @param [in[ vid The vendor ID number.
|
||||
* @param [in] pid The product ID number.
|
||||
* @param [in] version The produce version number.
|
||||
*/
|
||||
void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
|
||||
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
|
||||
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the HID Information characteristic value.
|
||||
* @param [in] country The country code for the device.
|
||||
* @param [in] flags The HID Class Specification release number to use.
|
||||
*/
|
||||
void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
|
||||
uint8_t info[] = { 0x11, 0x1, country, flags };
|
||||
m_hidInfoCharacteristic->setValue(info, sizeof(info));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create input report characteristic
|
||||
* @param [in] reportID input report ID, the same as in report map for input object related to the characteristic
|
||||
* @return pointer to new input report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
|
||||
NimBLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
|
||||
NimBLEDescriptor* inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t) 0x2908);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x01 };
|
||||
inputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
|
||||
return inputReportCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create output report characteristic
|
||||
* @param [in] reportID Output report ID, the same as in report map for output object related to the characteristic
|
||||
* @return Pointer to new output report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
|
||||
NimBLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
NimBLEDescriptor* outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t) 0x2908);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x02 };
|
||||
outputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
|
||||
return outputReportCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create feature report characteristic.
|
||||
* @param [in] reportID Feature report ID, the same as in report map for feature object related to the characteristic
|
||||
* @return Pointer to new feature report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
|
||||
NimBLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
NimBLEDescriptor* featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t) 0x2908);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x03 };
|
||||
featureReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
|
||||
return featureReportCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a keyboard boot input report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::bootInput() {
|
||||
return m_hidService->createCharacteristic((uint16_t) 0x2a22, NIMBLE_PROPERTY::NOTIFY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a keyboard boot output report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::bootOutput() {
|
||||
return m_hidService->createCharacteristic((uint16_t) 0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the HID control point characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::hidControl() {
|
||||
return m_hidControlCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the protocol mode characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::protocolMode() {
|
||||
return m_protocolModeCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the battery level characteristic value.
|
||||
* @param [in] level The battery level value.
|
||||
*/
|
||||
void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
|
||||
m_batteryLevelCharacteristic->setValue(&level, 1);
|
||||
}
|
||||
/*
|
||||
* @brief Returns battery level characteristic
|
||||
* @ return battery level characteristic
|
||||
*//*
|
||||
BLECharacteristic* BLEHIDDevice::batteryLevel() {
|
||||
return m_batteryLevelCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::reportMap() {
|
||||
return m_reportMapCharacteristic;
|
||||
}
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::pnp() {
|
||||
return m_pnpCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::hidInfo() {
|
||||
return m_hidInfoCharacteristic;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the device information service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::deviceInfo() {
|
||||
return m_deviceInfoService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the HID service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::hidService() {
|
||||
return m_hidService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief @brief Returns a pointer to the battery service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::batteryService() {
|
||||
return m_batteryService;
|
||||
}
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif // #if defined(CONFIG_BT_ENABLED)
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* NimBLEHIDDevice.h
|
||||
*
|
||||
* Created: on Oct 06 2020
|
||||
* Author wakwak-koba
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEHIDDevice.h
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#ifndef _BLEHIDDEVICE_H_
|
||||
#define _BLEHIDDEVICE_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
#include "NimBLECharacteristic.h"
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLEDescriptor.h"
|
||||
#include "HIDTypes.h"
|
||||
|
||||
#define GENERIC_HID 0x03C0
|
||||
#define HID_KEYBOARD 0x03C1
|
||||
#define HID_MOUSE 0x03C2
|
||||
#define HID_JOYSTICK 0x03C3
|
||||
#define HID_GAMEPAD 0x03C4
|
||||
#define HID_TABLET 0x03C5
|
||||
#define HID_CARD_READER 0x03C6
|
||||
#define HID_DIGITAL_PEN 0x03C7
|
||||
#define HID_BARCODE 0x03C8
|
||||
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE Human Interface Device.
|
||||
*/
|
||||
class NimBLEHIDDevice {
|
||||
public:
|
||||
NimBLEHIDDevice(NimBLEServer*);
|
||||
virtual ~NimBLEHIDDevice();
|
||||
|
||||
void reportMap(uint8_t* map, uint16_t);
|
||||
void startServices();
|
||||
|
||||
NimBLEService* deviceInfo();
|
||||
NimBLEService* hidService();
|
||||
NimBLEService* batteryService();
|
||||
|
||||
NimBLECharacteristic* manufacturer();
|
||||
void manufacturer(std::string name);
|
||||
//NimBLECharacteristic* pnp();
|
||||
void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version);
|
||||
//NimBLECharacteristic* hidInfo();
|
||||
void hidInfo(uint8_t country, uint8_t flags);
|
||||
//NimBLECharacteristic* batteryLevel();
|
||||
void setBatteryLevel(uint8_t level);
|
||||
|
||||
|
||||
//NimBLECharacteristic* reportMap();
|
||||
NimBLECharacteristic* hidControl();
|
||||
NimBLECharacteristic* inputReport(uint8_t reportID);
|
||||
NimBLECharacteristic* outputReport(uint8_t reportID);
|
||||
NimBLECharacteristic* featureReport(uint8_t reportID);
|
||||
NimBLECharacteristic* protocolMode();
|
||||
NimBLECharacteristic* bootInput();
|
||||
NimBLECharacteristic* bootOutput();
|
||||
|
||||
private:
|
||||
NimBLEService* m_deviceInfoService; //0x180a
|
||||
NimBLEService* m_hidService; //0x1812
|
||||
NimBLEService* m_batteryService = 0; //0x180f
|
||||
|
||||
NimBLECharacteristic* m_manufacturerCharacteristic; //0x2a29
|
||||
NimBLECharacteristic* m_pnpCharacteristic; //0x2a50
|
||||
NimBLECharacteristic* m_hidInfoCharacteristic; //0x2a4a
|
||||
NimBLECharacteristic* m_reportMapCharacteristic; //0x2a4b
|
||||
NimBLECharacteristic* m_hidControlCharacteristic; //0x2a4c
|
||||
NimBLECharacteristic* m_protocolModeCharacteristic; //0x2a4e
|
||||
NimBLECharacteristic* m_batteryLevelCharacteristic; //0x2a19
|
||||
};
|
||||
#endif // CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* _BLEHIDDEVICE_H_ */
|
|
@ -38,7 +38,7 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
|||
NimBLERemoteCharacteristic::NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteService,
|
||||
const struct ble_gatt_chr *chr)
|
||||
{
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteCharacteristic()");
|
||||
switch (chr->uuid.u.type) {
|
||||
case BLE_UUID_TYPE_16:
|
||||
m_uuid = NimBLEUUID(chr->uuid.u16.value);
|
||||
|
@ -50,7 +50,6 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
|||
m_uuid = NimBLEUUID(const_cast<ble_uuid128_t*>(&chr->uuid.u128));
|
||||
break;
|
||||
default:
|
||||
m_uuid = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -61,6 +60,8 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
|||
m_notifyCallback = nullptr;
|
||||
m_timestamp = 0;
|
||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteCharacteristic(): %s", m_uuid.toString().c_str());
|
||||
} // NimBLERemoteCharacteristic
|
||||
|
||||
|
||||
|
@ -208,15 +209,21 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
|||
bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filter) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str());
|
||||
|
||||
uint16_t endHandle = getRemoteService()->getEndHandle(this);
|
||||
if(m_handle >= endHandle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||
desc_filter_t filter = {uuid_filter, &taskData};
|
||||
|
||||
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
|
||||
m_handle,
|
||||
getRemoteService()->getEndHandle(),
|
||||
endHandle,
|
||||
NimBLERemoteCharacteristic::descriptorDiscCB,
|
||||
&filter);
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
|
@ -225,12 +232,13 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
|||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if(taskData.rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: startHandle:%d endHandle:%d taskData.rc=%d %s", m_handle, endHandle, taskData.rc, NimBLEUtils::returnCodeToString(0x0100+taskData.rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size());
|
||||
} // getDescriptors
|
||||
} // retrieveDescriptors
|
||||
|
||||
|
||||
/**
|
||||
|
@ -243,7 +251,7 @@ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUU
|
|||
|
||||
for(auto &it: m_descriptorVector) {
|
||||
if(it->getUUID() == uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found");
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found the descriptor with uuid: %s", uuid.toString().c_str());
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +261,18 @@ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUU
|
|||
if(m_descriptorVector.size() > prev_size) {
|
||||
return m_descriptorVector.back();
|
||||
}
|
||||
|
||||
// If the request was successful but 16/32 bit descriptor not found
|
||||
// try again with the 128 bit uuid.
|
||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||
{
|
||||
NimBLEUUID uuid128(uuid);
|
||||
uuid128.to128();
|
||||
return getDescriptor(uuid128);
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found");
|
||||
return nullptr;
|
||||
} // getDescriptor
|
||||
|
@ -447,9 +466,10 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
|||
}
|
||||
} while(rc != 0 && retryCount--);
|
||||
|
||||
time_t t = time(nullptr);
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
m_value = value;
|
||||
m_timestamp = time(nullptr);
|
||||
m_timestamp = t;
|
||||
if(timestamp != nullptr) {
|
||||
*timestamp = m_timestamp;
|
||||
}
|
||||
|
@ -506,19 +526,19 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
|
|||
* @param [in] notifyCallback A callback to be invoked for a notification.
|
||||
* @param [in] response If write response required set this to true.
|
||||
* If NULL is provided then no callback is performed.
|
||||
* @return true if successful.
|
||||
* @return false if writing to the descriptor failed.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyCallback, bool response) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setNotify(): %s, %02x", toString().c_str(), val);
|
||||
|
||||
m_notifyCallback = notifyCallback;
|
||||
|
||||
NimBLERemoteDescriptor* desc = getDescriptor(NimBLEUUID((uint16_t)0x2902));
|
||||
if(desc == nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "<< setNotify(): Could not get descriptor");
|
||||
return false;
|
||||
NIMBLE_LOGW(LOG_TAG, "<< setNotify(): Callback set, CCCD not found");
|
||||
return true;
|
||||
}
|
||||
|
||||
m_notifyCallback = notifyCallback;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setNotify()");
|
||||
|
||||
return desc->writeValue((uint8_t *)&val, 2, response);
|
||||
|
@ -531,7 +551,7 @@ bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyC
|
|||
* @param [in] notifyCallback A callback to be invoked for a notification.
|
||||
* @param [in] response If true, require a write response from the descriptor write operation.
|
||||
* If NULL is provided then no callback is performed.
|
||||
* @return true if successful.
|
||||
* @return false if writing to the descriptor failed.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback notifyCallback, bool response) {
|
||||
if(notifications) {
|
||||
|
@ -545,7 +565,7 @@ bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback n
|
|||
/**
|
||||
* @brief Unsubscribe for notifications or indications.
|
||||
* @param [in] response bool if true, require a write response from the descriptor write operation.
|
||||
* @return true if successful.
|
||||
* @return false if writing to the descriptor failed.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::unsubscribe(bool response) {
|
||||
return setNotify(0x00, nullptr, response);
|
||||
|
|
|
@ -31,6 +31,7 @@ static const char* LOG_TAG = "NimBLERemoteDescriptor";
|
|||
NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemoteCharacteristic,
|
||||
const struct ble_gatt_dsc *dsc)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteDescriptor()");
|
||||
switch (dsc->uuid.u.type) {
|
||||
case BLE_UUID_TYPE_16:
|
||||
m_uuid = NimBLEUUID(dsc->uuid.u16.value);
|
||||
|
@ -42,12 +43,13 @@ NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemo
|
|||
m_uuid = NimBLEUUID(const_cast<ble_uuid128_t*>(&dsc->uuid.u128));
|
||||
break;
|
||||
default:
|
||||
m_uuid = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
m_handle = dsc->handle;
|
||||
m_pRemoteCharacteristic = pRemoteCharacteristic;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteDescriptor(): %s", m_uuid.toString().c_str());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -44,12 +44,11 @@ NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const struct ble
|
|||
m_uuid = NimBLEUUID(const_cast<ble_uuid128_t*>(&service->uuid.u128));
|
||||
break;
|
||||
default:
|
||||
m_uuid = nullptr;
|
||||
break;
|
||||
}
|
||||
m_startHandle = service->start_handle;
|
||||
m_endHandle = service->end_handle;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteService()");
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteService(): %s", m_uuid.toString().c_str());
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,8 +94,11 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* u
|
|||
* @return A pointer to the characteristic object, or nullptr if not found.
|
||||
*/
|
||||
NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID &uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> getCharacteristic: uuid: %s", uuid.toString().c_str());
|
||||
|
||||
for(auto &it: m_characteristicVector) {
|
||||
if(it->getUUID() == uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: found the characteristic with uuid: %s", uuid.toString().c_str());
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
@ -106,8 +108,19 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEU
|
|||
if(m_characteristicVector.size() > prev_size) {
|
||||
return m_characteristicVector.back();
|
||||
}
|
||||
|
||||
// If the request was successful but 16/32 bit characteristic not found
|
||||
// try again with the 128 bit uuid.
|
||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||
{
|
||||
NimBLEUUID uuid128(uuid);
|
||||
uuid128.to128();
|
||||
return getCharacteristic(uuid128);
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: not found");
|
||||
return nullptr;
|
||||
} // getCharacteristic
|
||||
|
||||
|
@ -236,6 +249,23 @@ uint16_t NimBLERemoteService::getEndHandle() {
|
|||
return m_endHandle;
|
||||
} // getEndHandle
|
||||
|
||||
/**
|
||||
* @brief Get the end handle of specified NimBLERemoteCharacteristic.
|
||||
*/
|
||||
|
||||
uint16_t NimBLERemoteService::getEndHandle(NimBLERemoteCharacteristic *pCharacteristic) {
|
||||
uint16_t endHandle = m_endHandle;
|
||||
|
||||
for(auto &it: m_characteristicVector) {
|
||||
uint16_t defHandle = it->getDefHandle() - 1;
|
||||
if(defHandle > pCharacteristic->getDefHandle() && endHandle > defHandle) {
|
||||
endHandle = defHandle;
|
||||
}
|
||||
}
|
||||
|
||||
return endHandle;
|
||||
} // getEndHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service start handle.
|
||||
|
|
|
@ -70,6 +70,7 @@ private:
|
|||
|
||||
uint16_t getStartHandle();
|
||||
uint16_t getEndHandle();
|
||||
uint16_t getEndHandle(NimBLERemoteCharacteristic *pCharacteristic);
|
||||
void releaseSemaphores();
|
||||
|
||||
// Properties
|
||||
|
|
|
@ -30,7 +30,6 @@ static const char* LOG_TAG = "NimBLEScan";
|
|||
* @brief Scan constuctor.
|
||||
*/
|
||||
NimBLEScan::NimBLEScan() {
|
||||
m_own_addr_type = 0;
|
||||
m_scan_params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL;
|
||||
m_scan_params.passive = 1; // If set, don’t send scan requests to advertisers (i.e., don’t request additional advertising data).
|
||||
m_scan_params.itvl = 0; // This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec)
|
||||
|
@ -38,9 +37,10 @@ NimBLEScan::NimBLEScan() {
|
|||
m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode.
|
||||
m_scan_params.filter_duplicates = 0; // If set, the controller ignores all but the first advertisement from each device.
|
||||
m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
m_stopped = true;
|
||||
m_ignoreResults = false;
|
||||
m_wantDuplicates = false;
|
||||
m_pTaskData = nullptr;
|
||||
m_duration = BLE_HS_FOREVER; // make sure this is non-zero in the event of a host reset
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,8 +63,8 @@ NimBLEScan::~NimBLEScan() {
|
|||
switch(event->type) {
|
||||
|
||||
case BLE_GAP_EVENT_DISC: {
|
||||
if(pScan->m_stopped) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Scan stop called, ignoring results.");
|
||||
if(pScan->m_ignoreResults) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Scan op in progress - ignoring results");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,6 @@ NimBLEScan::~NimBLEScan() {
|
|||
pScan->m_scanCompleteCB(pScan->m_scanResults);
|
||||
}
|
||||
|
||||
pScan->m_stopped = true;
|
||||
if(pScan->m_pTaskData != nullptr) {
|
||||
pScan->m_pTaskData->rc = event->disc_complete.reason;
|
||||
xTaskNotifyGive(pScan->m_pTaskData->task);
|
||||
|
@ -238,7 +237,7 @@ void NimBLEScan::setWindow(uint16_t windowMSecs) {
|
|||
* @return true if scanning or scan starting.
|
||||
*/
|
||||
bool NimBLEScan::isScanning() {
|
||||
return !m_stopped;
|
||||
return ble_gap_disc_active();
|
||||
}
|
||||
|
||||
|
||||
|
@ -252,25 +251,6 @@ bool NimBLEScan::isScanning() {
|
|||
bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> start(duration=%d)", duration);
|
||||
|
||||
// If Host is not synced we cannot start scanning.
|
||||
if(!NimBLEDevice::m_synced) {
|
||||
NIMBLE_LOGC(LOG_TAG, "Host reset, wait for sync.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ble_gap_conn_active()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection in progress - must wait.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we are already scanning don't start again or we will get stuck on the semaphore.
|
||||
if(!m_stopped || ble_gap_disc_active()) { // double check - can cause host reset.
|
||||
NIMBLE_LOGE(LOG_TAG, "Scan already in progress");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_stopped = false;
|
||||
|
||||
// Save the callback to be invoked when the scan completes.
|
||||
m_scanCompleteCB = scanCompleteCB;
|
||||
// Save the duration in the case that the host is reset so we can reuse it.
|
||||
|
@ -281,32 +261,51 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
|
|||
duration = BLE_HS_FOREVER;
|
||||
}
|
||||
else{
|
||||
duration = duration*1000; // convert duration to milliseconds
|
||||
// convert duration to milliseconds
|
||||
duration = duration * 1000;
|
||||
}
|
||||
|
||||
// if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals
|
||||
// then we should not clear vector or we will connect the same device few times
|
||||
// Set the flag to ignore the results while we are deleting the vector
|
||||
if(!is_continue) {
|
||||
clearResults();
|
||||
m_ignoreResults = true;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
do{
|
||||
rc = ble_gap_disc(m_own_addr_type, duration, &m_scan_params,
|
||||
NimBLEScan::handleGapEvent, this);
|
||||
if(rc == BLE_HS_EBUSY) {
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
}
|
||||
} while(rc == BLE_HS_EBUSY);
|
||||
int rc = ble_gap_disc(NimBLEDevice::m_own_addr_type, duration, &m_scan_params,
|
||||
NimBLEScan::handleGapEvent, this);
|
||||
|
||||
if (rc != 0 && rc != BLE_HS_EDONE) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
m_stopped = true;
|
||||
switch(rc) {
|
||||
case 0:
|
||||
if(!is_continue) {
|
||||
clearResults();
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_HS_EALREADY:
|
||||
break;
|
||||
|
||||
case BLE_HS_EBUSY:
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to scan - connection in progress.");
|
||||
break;
|
||||
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGC(LOG_TAG, "Unable to scan - Host Reset");
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
|
||||
m_ignoreResults = false;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< start()");
|
||||
|
||||
if(rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< start()");
|
||||
return true;
|
||||
} // start
|
||||
|
||||
|
@ -347,8 +346,6 @@ bool NimBLEScan::stop() {
|
|||
return false;
|
||||
}
|
||||
|
||||
m_stopped = true;
|
||||
|
||||
if (rc != BLE_HS_EALREADY && m_scanCompleteCB != nullptr) {
|
||||
m_scanCompleteCB(m_scanResults);
|
||||
}
|
||||
|
@ -381,13 +378,25 @@ void NimBLEScan::erase(const NimBLEAddress &address) {
|
|||
|
||||
|
||||
/**
|
||||
* @brief If the host reset the scan will have stopped so we should set the flag as stopped.
|
||||
* @brief Called when host reset, we set a flag to stop scanning until synced.
|
||||
*/
|
||||
void NimBLEScan::onHostReset() {
|
||||
m_stopped = true;
|
||||
m_ignoreResults = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief If the host reset and re-synced this is called.
|
||||
* If the application was scanning indefinitely with a callback, restart it.
|
||||
*/
|
||||
void NimBLEScan::onHostSync() {
|
||||
m_ignoreResults = false;
|
||||
|
||||
if(m_duration == 0 && m_pAdvertisedDeviceCallbacks != nullptr) {
|
||||
start(m_duration, m_scanCompleteCB);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the results of the scan.
|
||||
* @return NimBLEScanResults object.
|
||||
|
|
|
@ -83,12 +83,12 @@ private:
|
|||
~NimBLEScan();
|
||||
static int handleGapEvent(ble_gap_event* event, void* arg);
|
||||
void onHostReset();
|
||||
void onHostSync();
|
||||
|
||||
NimBLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
void (*m_scanCompleteCB)(NimBLEScanResults scanResults);
|
||||
ble_gap_disc_params m_scan_params;
|
||||
uint8_t m_own_addr_type;
|
||||
bool m_stopped;
|
||||
bool m_ignoreResults;
|
||||
bool m_wantDuplicates;
|
||||
NimBLEScanResults m_scanResults;
|
||||
uint32_t m_duration;
|
||||
|
|
|
@ -296,6 +296,7 @@ size_t NimBLEServer::getConnectedCount() {
|
|||
}
|
||||
|
||||
server->m_pServerCallbacks->onDisconnect(server);
|
||||
server->m_pServerCallbacks->onDisconnect(server, &event->disconnect.conn);
|
||||
|
||||
if(server->m_advertiseOnDisconnect) {
|
||||
server->startAdvertising();
|
||||
|
@ -620,7 +621,13 @@ uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
|||
|
||||
|
||||
/**
|
||||
* Update connection parameters can be called only after connection has been established
|
||||
* @brief Request an Update the connection parameters:
|
||||
* * Can only be used after a connection has been established.
|
||||
* @param [in] conn_handle The connection handle of the peer to send the request to.
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
*/
|
||||
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
||||
uint16_t minInterval, uint16_t maxInterval,
|
||||
|
@ -658,6 +665,10 @@ void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer) {
|
|||
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
|
||||
} // onDisconnect
|
||||
|
||||
void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
|
||||
} // onDisconnect
|
||||
|
||||
uint32_t NimBLEServerCallbacks::onPassKeyRequest(){
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyRequest: default: 123456");
|
||||
return 123456;
|
||||
|
|
|
@ -114,6 +114,15 @@ public:
|
|||
*/
|
||||
virtual void onDisconnect(NimBLEServer* pServer);
|
||||
|
||||
/**
|
||||
* @brief Handle a client disconnection.
|
||||
* This is called when a client discconnects.
|
||||
* @param [in] pServer A pointer to the %BLE server that received the client disconnection.
|
||||
* @param [in] desc A pointer to the connection description structure containig information
|
||||
* about the connection.
|
||||
*/
|
||||
virtual void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc);
|
||||
|
||||
/**
|
||||
* @brief Called when a client requests a passkey for pairing.
|
||||
* @return The passkey to be sent to the client.
|
||||
|
|
|
@ -264,6 +264,37 @@ std::string NimBLEUUID::toString() const {
|
|||
*/
|
||||
bool NimBLEUUID::operator ==(const NimBLEUUID & rhs) const {
|
||||
if(m_valueSet && rhs.m_valueSet) {
|
||||
NIMBLE_LOGD(LOG_TAG,"Comparing UUIDs; type %u to %u; UUID %s to %s",
|
||||
m_uuid.u.type, rhs.m_uuid.u.type,
|
||||
this->toString().c_str(), rhs.toString().c_str());
|
||||
|
||||
if(m_uuid.u.type != rhs.m_uuid.u.type) {
|
||||
uint8_t uuidBase[16] = {
|
||||
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
|
||||
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
if(m_uuid.u.type == BLE_UUID_TYPE_128){
|
||||
if(rhs.m_uuid.u.type == BLE_UUID_TYPE_16){
|
||||
memcpy(uuidBase+12, &rhs.m_uuid.u16.value, 2);
|
||||
} else if (rhs.m_uuid.u.type == BLE_UUID_TYPE_32){
|
||||
memcpy(uuidBase+12, &rhs.m_uuid.u32.value, 4);
|
||||
}
|
||||
return memcmp(m_uuid.u128.value,uuidBase,16) == 0;
|
||||
|
||||
} else if(rhs.m_uuid.u.type == BLE_UUID_TYPE_128) {
|
||||
if(m_uuid.u.type == BLE_UUID_TYPE_16){
|
||||
memcpy(uuidBase+12, &m_uuid.u16.value, 2);
|
||||
} else if (m_uuid.u.type == BLE_UUID_TYPE_32){
|
||||
memcpy(uuidBase+12, &m_uuid.u32.value, 4);
|
||||
}
|
||||
return memcmp(rhs.m_uuid.u128.value,uuidBase,16) == 0;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return ble_uuid_cmp(&m_uuid.u, &rhs.m_uuid.u) == 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file has been modified by Ryan Powell, aka h2zero.
|
||||
* The modifications are for the purpose of improving performance and support
|
||||
* for Esprssif versions used by the ardruino-esp32 core that are less current
|
||||
* than the esp-idf releases.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "sysinit/sysinit.h"
|
||||
#include "nimble/hci_common.h"
|
||||
|
@ -30,8 +37,10 @@
|
|||
#include "esp_bt.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_compiler.h"
|
||||
/* IPC is used to improve performance when calls come from a processor not running the NimBLE stack */
|
||||
/* but does not exist for solo */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
#include "esp_ipc.h"
|
||||
#include "esp_ipc.h"
|
||||
#endif
|
||||
|
||||
#define NIMBLE_VHCI_TIMEOUT_MS 2000
|
||||
|
@ -81,31 +90,40 @@ void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
|
|||
ble_hci_rx_acl_hs_arg = acl_arg;
|
||||
}
|
||||
|
||||
void ble_hci_trans_hs_cmd_tx_on_core_0(void *arg)
|
||||
/* Added; Called from the core NimBLE is running on, not used for unicore */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
void ble_hci_trans_hs_cmd_tx_on_core(void *arg)
|
||||
{
|
||||
uint8_t *cmd = arg;
|
||||
uint16_t len = BLE_HCI_CMD_HDR_LEN + cmd[3] + 1;
|
||||
esp_vhci_host_send_packet(cmd, len);
|
||||
// Ugly but necessary as the arduino core does not provide enough IPC stack for variables.
|
||||
esp_vhci_host_send_packet((uint8_t*)arg, *((uint8_t*)arg + 3) + 1 + BLE_HCI_CMD_HDR_LEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Modified to use ipc calls in arduino to correct performance issues */
|
||||
int ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
|
||||
{
|
||||
uint16_t len;
|
||||
uint8_t rc = 0;
|
||||
|
||||
assert(cmd != NULL);
|
||||
*cmd = BLE_HCI_UART_H4_CMD;
|
||||
len = BLE_HCI_CMD_HDR_LEN + cmd[3] + 1;
|
||||
if (!esp_vhci_host_check_send_available()) {
|
||||
ESP_LOGD(TAG, "Controller not ready to receive packets");
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) {
|
||||
if (xPortGetCoreID() != 0) {
|
||||
/* esp_ipc_call_blocking does not exist for solo */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
esp_ipc_call_blocking(0, ble_hci_trans_hs_cmd_tx_on_core_0, cmd);
|
||||
#endif
|
||||
if (xPortGetCoreID() != CONFIG_BT_NIMBLE_PINNED_TO_CORE) {
|
||||
esp_ipc_call_blocking(CONFIG_BT_NIMBLE_PINNED_TO_CORE,
|
||||
ble_hci_trans_hs_cmd_tx_on_core, cmd);
|
||||
} else {
|
||||
ble_hci_trans_hs_cmd_tx_on_core_0(cmd);
|
||||
esp_vhci_host_send_packet(cmd, len);
|
||||
}
|
||||
#else /* Unicore */
|
||||
esp_vhci_host_send_packet(cmd, len);
|
||||
#endif
|
||||
} else {
|
||||
rc = BLE_HS_ETIMEOUT_HCI;
|
||||
}
|
||||
|
@ -124,21 +142,21 @@ int ble_hci_trans_ll_evt_tx(uint8_t *hci_ev)
|
|||
return rc;
|
||||
}
|
||||
|
||||
void ble_hci_trans_hs_acl_tx_on_core_0(void *arg)
|
||||
/* Added; Called from the core NimBLE is running on, not used for unicore */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
void ble_hci_trans_hs_acl_tx_on_core(void *arg)
|
||||
{
|
||||
uint8_t data[MYNEWT_VAL(BLE_ACL_BUF_SIZE) + 1];
|
||||
struct os_mbuf *om = arg;
|
||||
uint16_t len = 1 + OS_MBUF_PKTLEN(om);
|
||||
|
||||
data[0] = BLE_HCI_UART_H4_ACL;
|
||||
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]);
|
||||
|
||||
esp_vhci_host_send_packet(data, len);
|
||||
// Ugly but necessary as the arduino core does not provide enough IPC stack for variables.
|
||||
esp_vhci_host_send_packet((uint8_t*)arg + 2, *(uint16_t*)arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Modified to use ipc calls in arduino to correct performance issues */
|
||||
int ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
|
||||
{
|
||||
uint8_t rc = 0;
|
||||
uint16_t len = 0;
|
||||
uint8_t data[MYNEWT_VAL(BLE_ACL_BUF_SIZE) + 3], rc = 0;
|
||||
bool tx_using_nimble_core = 0;
|
||||
/* If this packet is zero length, just free it */
|
||||
if (OS_MBUF_PKTLEN(om) == 0) {
|
||||
os_mbuf_free_chain(om);
|
||||
|
@ -149,14 +167,36 @@ int ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
|
|||
ESP_LOGD(TAG, "Controller not ready to receive packets");
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) {
|
||||
if (xPortGetCoreID() != 0) {
|
||||
len = 1 + OS_MBUF_PKTLEN(om);
|
||||
/* Don't check core ID if unicore */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
esp_ipc_call_blocking(0, ble_hci_trans_hs_acl_tx_on_core_0, om);
|
||||
tx_using_nimble_core = xPortGetCoreID() != CONFIG_BT_NIMBLE_PINNED_TO_CORE;
|
||||
if (tx_using_nimble_core) {
|
||||
data[0] = len;
|
||||
data[1] = (len >> 8);
|
||||
data[2] = BLE_HCI_UART_H4_ACL;
|
||||
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[3]);
|
||||
} else {
|
||||
data[0] = BLE_HCI_UART_H4_ACL;
|
||||
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]);
|
||||
}
|
||||
#else /* Unicore */
|
||||
data[0] = BLE_HCI_UART_H4_ACL;
|
||||
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]);
|
||||
#endif
|
||||
|
||||
if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) {
|
||||
/* esp_ipc_call_blocking does not exist for solo */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
if (tx_using_nimble_core) {
|
||||
esp_ipc_call_blocking(CONFIG_BT_NIMBLE_PINNED_TO_CORE,
|
||||
ble_hci_trans_hs_acl_tx_on_core, data);
|
||||
} else {
|
||||
ble_hci_trans_hs_acl_tx_on_core_0(om);
|
||||
esp_vhci_host_send_packet(data, len);
|
||||
}
|
||||
#else /* Unicore */
|
||||
esp_vhci_host_send_packet(data, len);
|
||||
#endif
|
||||
} else {
|
||||
rc = BLE_HS_ETIMEOUT_HCI;
|
||||
}
|
||||
|
@ -367,6 +407,13 @@ static int host_rcv_pkt(uint8_t *data, uint16_t len)
|
|||
totlen = BLE_HCI_EVENT_HDR_LEN + data[2];
|
||||
assert(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN);
|
||||
|
||||
if (totlen > MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) {
|
||||
ESP_LOGE(TAG, "Received HCI data length at host (%d) exceeds maximum configured HCI event buffer size (%d).",
|
||||
totlen, MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE));
|
||||
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[1] == BLE_HCI_EVCODE_HW_ERROR) {
|
||||
assert(0);
|
||||
}
|
||||
|
@ -476,6 +523,9 @@ esp_err_t esp_nimble_hci_and_controller_init(void)
|
|||
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
/* Added to ensure BLE only mode */
|
||||
bt_cfg.mode = ESP_BT_MODE_BLE;
|
||||
/* Added to set max connections from nimconfig */
|
||||
bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS;
|
||||
|
||||
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
|
||||
|
@ -485,6 +535,7 @@ esp_err_t esp_nimble_hci_and_controller_init(void)
|
|||
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return esp_nimble_hci_init();
|
||||
}
|
||||
|
||||
|
|
|
@ -483,6 +483,10 @@
|
|||
#define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_L2CAP_COC_MPS
|
||||
#define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE - 8)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS
|
||||
#define MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS (1)
|
||||
#endif
|
||||
|
|
|
@ -76,7 +76,7 @@ ble_eddystone_set_adv_data_gen(struct ble_hs_adv_fields *adv_fields,
|
|||
if (adv_fields->num_uuids16 > BLE_EDDYSTONE_MAX_UUIDS16) {
|
||||
return BLE_HS_EINVAL;
|
||||
}
|
||||
if (svc_data_len > BLE_EDDYSTONE_MAX_SVC_DATA_LEN) {
|
||||
if (svc_data_len > (BLE_EDDYSTONE_MAX_SVC_DATA_LEN - BLE_EDDYSTONE_SVC_DATA_BASE_SZ)) {
|
||||
return BLE_HS_EINVAL;
|
||||
}
|
||||
if (adv_fields->num_uuids16 > 0 && !adv_fields->uuids16_is_complete) {
|
||||
|
|
|
@ -1017,7 +1017,7 @@ ble_gap_master_failed(int status)
|
|||
#endif
|
||||
|
||||
default:
|
||||
BLE_HS_DBG_ASSERT(0);
|
||||
//BLE_HS_DBG_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1458,8 +1458,8 @@ ble_gap_rx_periodic_adv_rpt(struct hci_le_subev_periodic_adv_rpt *evt)
|
|||
{
|
||||
struct ble_hs_periodic_sync *psync;
|
||||
struct ble_gap_event event;
|
||||
ble_gap_event_fn *cb;
|
||||
void *cb_arg;
|
||||
ble_gap_event_fn *cb = NULL;
|
||||
void *cb_arg = NULL;
|
||||
|
||||
ble_hs_lock();
|
||||
psync = ble_hs_periodic_sync_find_by_handle(evt->sync_handle);
|
||||
|
|
|
@ -470,29 +470,52 @@ ble_hs_conn_timer(void)
|
|||
int32_t time_diff;
|
||||
uint16_t conn_handle;
|
||||
|
||||
conn_handle = BLE_HS_CONN_HANDLE_NONE;
|
||||
next_exp_in = BLE_HS_FOREVER;
|
||||
now = ble_npl_time_get();
|
||||
for (;;) {
|
||||
conn_handle = BLE_HS_CONN_HANDLE_NONE;
|
||||
next_exp_in = BLE_HS_FOREVER;
|
||||
now = ble_npl_time_get();
|
||||
|
||||
ble_hs_lock();
|
||||
ble_hs_lock();
|
||||
|
||||
/* This loop performs one of two tasks:
|
||||
* 1. Determine if any connections need to be terminated due to timeout.
|
||||
* If so, break out of the loop and terminate the connection. This
|
||||
* function will need to be executed again.
|
||||
* 2. Otherwise, determine when the next timeout will occur.
|
||||
*/
|
||||
SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
|
||||
if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING)) {
|
||||
/* This loop performs one of two tasks:
|
||||
* 1. Determine if any connections need to be terminated due to timeout.
|
||||
* If so, break out of the loop and terminate the connection. This
|
||||
* function will need to be executed again.
|
||||
* 2. Otherwise, determine when the next timeout will occur.
|
||||
*/
|
||||
SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
|
||||
if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING)) {
|
||||
|
||||
#if MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) != 0
|
||||
/* Check each connection's rx fragment timer. If too much time
|
||||
* passes after a partial packet is received, the connection is
|
||||
* terminated.
|
||||
*/
|
||||
if (conn->bhc_rx_chan != NULL) {
|
||||
time_diff = conn->bhc_rx_timeout - now;
|
||||
/* Check each connection's rx fragment timer. If too much time
|
||||
* passes after a partial packet is received, the connection is
|
||||
* terminated.
|
||||
*/
|
||||
if (conn->bhc_rx_chan != NULL) {
|
||||
time_diff = conn->bhc_rx_timeout - now;
|
||||
|
||||
if (time_diff <= 0) {
|
||||
/* ACL reassembly has timed out. Remember the connection
|
||||
* handle so it can be terminated after the mutex is
|
||||
* unlocked.
|
||||
*/
|
||||
conn_handle = conn->bhc_handle;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Determine if this connection is the soonest to time out. */
|
||||
if (time_diff < next_exp_in) {
|
||||
next_exp_in = time_diff;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO
|
||||
/* Check each connection's rx queued write timer. If too much
|
||||
* time passes after a prep write is received, the queue is
|
||||
* cleared.
|
||||
*/
|
||||
time_diff = ble_att_svr_ticks_until_tmo(&conn->bhc_att_svr, now);
|
||||
if (time_diff <= 0) {
|
||||
/* ACL reassembly has timed out. Remember the connection
|
||||
* handle so it can be terminated after the mutex is
|
||||
|
@ -506,45 +529,22 @@ ble_hs_conn_timer(void)
|
|||
if (time_diff < next_exp_in) {
|
||||
next_exp_in = time_diff;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO
|
||||
/* Check each connection's rx queued write timer. If too much
|
||||
* time passes after a prep write is received, the queue is
|
||||
* cleared.
|
||||
*/
|
||||
time_diff = ble_att_svr_ticks_until_tmo(&conn->bhc_att_svr, now);
|
||||
if (time_diff <= 0) {
|
||||
/* ACL reassembly has timed out. Remember the connection
|
||||
* handle so it can be terminated after the mutex is
|
||||
* unlocked.
|
||||
*/
|
||||
conn_handle = conn->bhc_handle;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Determine if this connection is the soonest to time out. */
|
||||
if (time_diff < next_exp_in) {
|
||||
next_exp_in = time_diff;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ble_hs_unlock();
|
||||
|
||||
/* If a connection has timed out, terminate it. We need to repeatedly
|
||||
* call this function again to determine when the next timeout is.
|
||||
*/
|
||||
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
continue;
|
||||
}
|
||||
|
||||
return next_exp_in;
|
||||
}
|
||||
|
||||
ble_hs_unlock();
|
||||
|
||||
/* If a connection has timed out, terminate it. We need to recursively
|
||||
* call this function again to determine when the next timeout is. This
|
||||
* is a tail-recursive call, so it should be optimized to execute in the
|
||||
* same stack frame.
|
||||
*/
|
||||
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return ble_hs_conn_timer();
|
||||
}
|
||||
|
||||
return next_exp_in;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -180,7 +180,9 @@ static int
|
|||
get_nvs_db_attribute(int obj_type, bool empty, void *value, int num_value)
|
||||
{
|
||||
union ble_store_value cur = {0};
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
struct ble_hs_dev_records p_dev_rec = {0};
|
||||
#endif
|
||||
esp_err_t err;
|
||||
int i, count = 0, max_limit = 0;
|
||||
char key_string[NIMBLE_NVS_STR_NAME_MAX_LEN];
|
||||
|
@ -190,11 +192,15 @@ get_nvs_db_attribute(int obj_type, bool empty, void *value, int num_value)
|
|||
for (i = 1; i <= max_limit; i++) {
|
||||
get_nvs_key_string(obj_type, i, key_string);
|
||||
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
if (obj_type != BLE_STORE_OBJ_TYPE_PEER_DEV_REC) {
|
||||
#endif
|
||||
err = get_nvs_db_value(obj_type, key_string, &cur);
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
} else {
|
||||
err = get_nvs_peer_record(key_string, &p_dev_rec);
|
||||
}
|
||||
#endif
|
||||
/* Check if the user is searching for empty index to write to */
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
if (empty) {
|
||||
|
@ -206,10 +212,13 @@ get_nvs_db_attribute(int obj_type, bool empty, void *value, int num_value)
|
|||
/* If user has provided value, then the purpose is to find
|
||||
* non-matching entry from NVS */
|
||||
if (value) {
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
if (obj_type == BLE_STORE_OBJ_TYPE_PEER_DEV_REC) {
|
||||
err = get_nvs_matching_index(&p_dev_rec, value, num_value,
|
||||
sizeof(struct ble_hs_dev_records));
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (obj_type != BLE_STORE_OBJ_TYPE_CCCD) {
|
||||
err = get_nvs_matching_index(&cur.sec, value, num_value,
|
||||
sizeof(struct ble_store_value_sec));
|
||||
|
@ -376,7 +385,9 @@ populate_db_from_nvs(int obj_type, void *dst, int *db_num)
|
|||
{
|
||||
uint8_t *db_item = (uint8_t *)dst;
|
||||
union ble_store_value cur = {0};
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
struct ble_hs_dev_records p_dev_rec = {0};
|
||||
#endif
|
||||
|
||||
esp_err_t err;
|
||||
int i;
|
||||
|
@ -385,8 +396,9 @@ populate_db_from_nvs(int obj_type, void *dst, int *db_num)
|
|||
for (i = 1; i <= get_nvs_max_obj_value(obj_type); i++) {
|
||||
get_nvs_key_string(obj_type, i, key_string);
|
||||
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
if (obj_type != BLE_STORE_OBJ_TYPE_PEER_DEV_REC) {
|
||||
|
||||
#endif
|
||||
err = get_nvs_db_value(obj_type, key_string, &cur);
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
continue;
|
||||
|
@ -394,6 +406,7 @@ populate_db_from_nvs(int obj_type, void *dst, int *db_num)
|
|||
ESP_LOGE(TAG, "NVS read operation failed !!");
|
||||
return -1;
|
||||
}
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
} else {
|
||||
err = get_nvs_peer_record(key_string, &p_dev_rec);
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
|
@ -410,7 +423,9 @@ populate_db_from_nvs(int obj_type, void *dst, int *db_num)
|
|||
memcpy(db_item, &p_dev_rec, sizeof(struct ble_hs_dev_records));
|
||||
db_item += sizeof(struct ble_hs_dev_records);
|
||||
(*db_num)++;
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (obj_type == BLE_STORE_OBJ_TYPE_CCCD) {
|
||||
ESP_LOGD(TAG, "CCCD in RAM is filled up from NVS index = %d", i);
|
||||
memcpy(db_item, &cur.cccd, sizeof(struct ble_store_value_cccd));
|
||||
|
@ -492,6 +507,11 @@ int ble_store_config_persist_cccds(void)
|
|||
union ble_store_value val;
|
||||
|
||||
nvs_count = get_nvs_db_attribute(BLE_STORE_OBJ_TYPE_CCCD, 0, NULL, 0);
|
||||
if (nvs_count == -1) {
|
||||
ESP_LOGE(TAG, "NVS operation failed while persisting CCCD");
|
||||
return BLE_HS_ESTORE_FAIL;
|
||||
}
|
||||
|
||||
if (nvs_count < ble_store_config_num_cccds) {
|
||||
|
||||
/* NVS db count less than RAM count, write operation */
|
||||
|
@ -518,6 +538,11 @@ int ble_store_config_persist_peer_secs(void)
|
|||
union ble_store_value val;
|
||||
|
||||
nvs_count = get_nvs_db_attribute(BLE_STORE_OBJ_TYPE_PEER_SEC, 0, NULL, 0);
|
||||
if (nvs_count == -1) {
|
||||
ESP_LOGE(TAG, "NVS operation failed while persisting peer sec");
|
||||
return BLE_HS_ESTORE_FAIL;
|
||||
}
|
||||
|
||||
if (nvs_count < ble_store_config_num_peer_secs) {
|
||||
|
||||
/* NVS db count less than RAM count, write operation */
|
||||
|
@ -544,6 +569,11 @@ int ble_store_config_persist_our_secs(void)
|
|||
union ble_store_value val;
|
||||
|
||||
nvs_count = get_nvs_db_attribute(BLE_STORE_OBJ_TYPE_OUR_SEC, 0, NULL, 0);
|
||||
if (nvs_count == -1) {
|
||||
ESP_LOGE(TAG, "NVS operation failed while persisting our sec");
|
||||
return BLE_HS_ESTORE_FAIL;
|
||||
}
|
||||
|
||||
if (nvs_count < ble_store_config_num_our_secs) {
|
||||
|
||||
/* NVS db count less than RAM count, write operation */
|
||||
|
@ -573,7 +603,13 @@ int ble_store_persist_peer_records(void)
|
|||
struct ble_hs_dev_records *peer_dev_rec = ble_rpa_get_peer_dev_records();
|
||||
|
||||
nvs_count = get_nvs_db_attribute(BLE_STORE_OBJ_TYPE_PEER_DEV_REC, 0, NULL, 0);
|
||||
if (nvs_count == -1) {
|
||||
ESP_LOGE(TAG, "NVS operation failed while persisting peer_dev_rec");
|
||||
return BLE_HS_ESTORE_FAIL;
|
||||
}
|
||||
|
||||
if (nvs_count < ble_store_num_peer_dev_rec) {
|
||||
|
||||
/* NVS db count less than RAM count, write operation */
|
||||
ESP_LOGD(TAG, "Persisting peer dev record to NVS...");
|
||||
peer_rec = peer_dev_rec[ble_store_num_peer_dev_rec - 1];
|
||||
|
|
|
@ -15,8 +15,13 @@
|
|||
* This converts them to "CONFIG_BT_NIMBLE_" format used in the latest IDF.
|
||||
*/
|
||||
|
||||
/* Detect if using ESP-IDF or Arduino (Arduino won't have these defines in sdkconfig) */
|
||||
#if defined(CONFIG_BT_NIMBLE_TASK_STACK_SIZE) || defined(CONFIG_NIMBLE_TASK_STACK_SIZE)
|
||||
/* Detect if using ESP-IDF or Arduino (Arduino won't have these defines in sdkconfig)
|
||||
*
|
||||
* Note: We do not use #ifdef CONFIG_BT_NIMBLE_ENABLED since we cannot enable NimBLE when using
|
||||
* Arduino as a component and the esp-nimble-compnent, so we check if other config options are defined.
|
||||
* We also need to use a config parameter that must be present and not likely defined in the command line.
|
||||
*/
|
||||
#if defined(CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN) || defined(CONFIG_NIMBLE_GAP_DEVICE_NAME_MAX_LEN)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ENABLED) && !defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||
#define CONFIG_BT_NIMBLE_ENABLED
|
||||
|
@ -51,22 +56,30 @@
|
|||
/** @brief Comment out if not using NimBLE Client functions \n
|
||||
* Reduces flash size by approx. 7kB.
|
||||
*/
|
||||
#ifndef CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED
|
||||
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
|
||||
#endif
|
||||
|
||||
/** @brief Comment out if not using NimBLE Scan functions \n
|
||||
* Reduces flash size by approx. 26kB.
|
||||
*/
|
||||
#ifndef CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED
|
||||
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
||||
#endif
|
||||
|
||||
/** @brief Comment out if not using NimBLE Server functions \n
|
||||
* Reduces flash size by approx. 16kB.
|
||||
*/
|
||||
// #define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#ifndef CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED
|
||||
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#endif
|
||||
|
||||
/** @brief Comment out if not using NimBLE Advertising functions \n
|
||||
* Reduces flash size by approx. 5kB.
|
||||
*/
|
||||
// #define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#ifndef CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED
|
||||
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#endif
|
||||
|
||||
/* Uncomment to see debug log messages from the NimBLE host
|
||||
* Uses approx. 32kB of flash memory.
|
||||
|
@ -89,29 +102,46 @@
|
|||
// #define CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
|
||||
|
||||
/** @brief Sets the core NimBLE host runs on */
|
||||
#ifndef CONFIG_BT_NIMBLE_PINNED_TO_CORE
|
||||
#define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0
|
||||
#endif
|
||||
|
||||
/** @brief Sets the stack size for the NimBLE host task */
|
||||
#ifndef CONFIG_BT_NIMBLE_TASK_STACK_SIZE
|
||||
#define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Sets the memory pool where NimBLE will be loaded
|
||||
* @details By default NimBLE is loaded in internal ram.\n
|
||||
* To use external PSRAM you must change this to `#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1`
|
||||
*/
|
||||
#ifndef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
|
||||
#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
|
||||
#endif
|
||||
|
||||
/** @brief Sets the number of simultaneous connections (esp controller max is 9) */
|
||||
#ifndef CONFIG_BT_NIMBLE_MAX_CONNECTIONS
|
||||
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
||||
#endif
|
||||
|
||||
/** @brief Sets the number of devices allowed to store/bond with */
|
||||
#ifndef CONFIG_BT_NIMBLE_MAX_BONDS
|
||||
#define CONFIG_BT_NIMBLE_MAX_BONDS 3
|
||||
#endif
|
||||
|
||||
/** @brief Sets the maximum number of CCCD subscriptions to store */
|
||||
#ifndef CONFIG_BT_NIMBLE_MAX_CCCDS
|
||||
#define CONFIG_BT_NIMBLE_MAX_CCCDS 8
|
||||
#endif
|
||||
|
||||
/** @brief Default device name */
|
||||
#ifndef CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME
|
||||
#define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
|
||||
#endif
|
||||
|
||||
/** @brief Set if CCCD's and bond data should be stored in NVS */
|
||||
#define CONFIG_BT_NIMBLE_NVS_PERSIST 0
|
||||
#define CONFIG_BT_NIMBLE_NVS_PERSIST 1
|
||||
|
||||
/** @brief Allow legacy paring */
|
||||
#define CONFIG_BT_NIMBLE_SM_LEGACY 1
|
||||
|
@ -119,9 +149,6 @@
|
|||
/** @brief Allow BLE secure connections */
|
||||
#define CONFIG_BT_NIMBLE_SM_SC 1
|
||||
|
||||
/** @brief Default device name */
|
||||
#define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
|
||||
|
||||
/** @brief Max device name length (bytes) */
|
||||
#define CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN 31
|
||||
|
||||
|
@ -154,7 +181,6 @@
|
|||
*/
|
||||
#define CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT 12
|
||||
|
||||
|
||||
/** @brief Random address refresh time in seconds */
|
||||
#define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@ void CRtspSession::Init()
|
|||
|
||||
bool CRtspSession::ParseRtspRequest(char const * aRequest, unsigned aRequestSize)
|
||||
{
|
||||
char CmdName[RTSP_PARAM_STRING_MAX];
|
||||
static char CurRequest[RTSP_BUFFER_SIZE]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
// char CmdName[RTSP_PARAM_STRING_MAX];
|
||||
//char CurRequest[RTSP_BUFFER_SIZE]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
unsigned CurRequestSize;
|
||||
|
||||
Init();
|
||||
|
@ -45,7 +45,7 @@ bool CRtspSession::ParseRtspRequest(char const * aRequest, unsigned aRequestSize
|
|||
// check whether the request contains information about the RTP/RTCP UDP client ports (SETUP command)
|
||||
char * ClientPortPtr;
|
||||
char * TmpPtr;
|
||||
static char CP[1024];
|
||||
char CP[128]; //static char CP[1024];
|
||||
char * pCP;
|
||||
|
||||
ClientPortPtr = strstr(CurRequest,"client_port");
|
||||
|
@ -230,7 +230,7 @@ RTSP_CMD_TYPES CRtspSession::Handle_RtspRequest(char const * aRequest, unsigned
|
|||
|
||||
void CRtspSession::Handle_RtspOPTION()
|
||||
{
|
||||
static char Response[1024]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
//static char Response[1024]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
|
||||
snprintf(Response,sizeof(Response),
|
||||
"RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
|
||||
|
@ -241,9 +241,9 @@ void CRtspSession::Handle_RtspOPTION()
|
|||
|
||||
void CRtspSession::Handle_RtspDESCRIBE()
|
||||
{
|
||||
static char Response[1024]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
static char SDPBuf[1024];
|
||||
static char URLBuf[1024];
|
||||
//static char Response[1024]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
char SDPBuf[128]; //static char SDPBuf[1024];
|
||||
char URLBuf[128]; //static char URLBuf[1024];
|
||||
|
||||
// check whether we know a stream with the URL which is requested
|
||||
m_StreamID = -1; // invalid URL
|
||||
|
@ -261,7 +261,7 @@ void CRtspSession::Handle_RtspDESCRIBE()
|
|||
};
|
||||
|
||||
// simulate DESCRIBE server response
|
||||
static char OBuf[256];
|
||||
// static char OBuf[256];
|
||||
char * ColonPtr;
|
||||
strcpy(OBuf,m_URLHostPort);
|
||||
ColonPtr = strstr(OBuf,":");
|
||||
|
@ -305,8 +305,8 @@ void CRtspSession::Handle_RtspDESCRIBE()
|
|||
|
||||
void CRtspSession::Handle_RtspSETUP()
|
||||
{
|
||||
static char Response[1024];
|
||||
static char Transport[255];
|
||||
//static char Response[1024];
|
||||
//static char Transport[255];
|
||||
|
||||
// init RTP streamer transport type (UDP or TCP) and ports for UDP transport
|
||||
m_Streamer->InitTransport(m_ClientRTPPort,m_ClientRTCPPort,m_TcpTransport);
|
||||
|
@ -336,7 +336,7 @@ void CRtspSession::Handle_RtspSETUP()
|
|||
|
||||
void CRtspSession::Handle_RtspPLAY()
|
||||
{
|
||||
static char Response[1024];
|
||||
//static char Response[1024];
|
||||
|
||||
// simulate SETUP server response
|
||||
snprintf(Response,sizeof(Response),
|
||||
|
@ -354,10 +354,10 @@ void CRtspSession::Handle_RtspPLAY()
|
|||
|
||||
char const * CRtspSession::DateHeader()
|
||||
{
|
||||
static char buf[200];
|
||||
//static char buf[200];
|
||||
time_t tt = time(NULL);
|
||||
strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));
|
||||
return buf;
|
||||
strftime(session_buf, sizeof(session_buf), "Date: %a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));
|
||||
return session_buf;
|
||||
}
|
||||
|
||||
int CRtspSession::GetStreamID()
|
||||
|
@ -375,7 +375,7 @@ bool CRtspSession::handleRequests(uint32_t readTimeoutMs)
|
|||
if(m_stopped)
|
||||
return false; // Already closed down
|
||||
|
||||
static char RecvBuf[RTSP_BUFFER_SIZE]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
//char RecvBuf[RTSP_BUFFER_SIZE]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
|
||||
memset(RecvBuf,0x00,sizeof(RecvBuf));
|
||||
int res = socketread(m_RtspClient,RecvBuf,sizeof(RecvBuf), readTimeoutMs);
|
||||
|
|
|
@ -70,4 +70,11 @@ private:
|
|||
char m_CSeq[RTSP_PARAM_STRING_MAX]; // RTSP command sequence number
|
||||
char m_URLHostPort[MAX_HOSTNAME_LEN]; // host:port part of the URL
|
||||
unsigned m_ContentLength; // SDP string size
|
||||
char CurRequest[RTSP_BUFFER_SIZE];
|
||||
char RecvBuf[RTSP_BUFFER_SIZE];
|
||||
char session_buf[128];
|
||||
char CmdName[RTSP_PARAM_STRING_MAX];
|
||||
char Transport[255];
|
||||
char Response[1024];
|
||||
char OBuf[256];
|
||||
};
|
||||
|
|
|
@ -48,7 +48,7 @@ int CStreamer::SendRtpPacket(unsigned const char * jpeg, int jpegLen, int fragme
|
|||
bool includeQuantTbl = quant0tbl && quant1tbl && fragmentOffset == 0;
|
||||
uint8_t q = includeQuantTbl ? 128 : 0x5e;
|
||||
|
||||
static char RtpBuf[2048]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
//static char RtpBuf[2048]; // Note: we assume single threaded, this large buf we keep off of the tiny stack
|
||||
int RtpPacketSize = fragmentLen + KRtpHeaderSize + KJpegHeaderSize + (includeQuantTbl ? (4 + 64 * 2) : 0);
|
||||
|
||||
memset(RtpBuf,0x00,sizeof(RtpBuf));
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
|
||||
u_short m_width; // image data info
|
||||
u_short m_height;
|
||||
char RtpBuf[2048];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
Copyright 2018 S. Kevin Hester-Chow, kevinh@geeksville.com (MIT License)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,93 @@
|
|||
# Micro-RTSP
|
||||
|
||||
This is a small library which can be used to serve up RTSP streams from
|
||||
resource constrained MCUs. It lets you trivially make a $10 open source
|
||||
RTSP video stream camera.
|
||||
|
||||
# Usage
|
||||
|
||||
This library works for ESP32/arduino targets but also for most any posixish platform.
|
||||
|
||||
## Example arduino/ESP32 usage
|
||||
|
||||
This library will work standalone, but it is _super_ easy to use if your app is platform.io based.
|
||||
Just "pio lib install Micro-RTSP" to pull the latest version from their library server. If you want to use the OV2640
|
||||
camera support you'll need to be targeting the espressif32 platform in your project.
|
||||
|
||||
See the [example platform.io app](/examples). It should build and run on virtually any of the $10
|
||||
ESP32-CAM boards (such as M5CAM). The relevant bit of the code is included below. In short:
|
||||
1. Listen for a TCP connection on the RTSP port with accept()
|
||||
2. When a connection comes in, create a CRtspSession and OV2640Streamer camera streamer objects.
|
||||
3. While the connection remains, call session->handleRequests(0) to handle any incoming client requests.
|
||||
4. Every 100ms or so call session->broadcastCurrentFrame() to send new frames to any clients.
|
||||
|
||||
```
|
||||
void loop()
|
||||
{
|
||||
uint32_t msecPerFrame = 100;
|
||||
static uint32_t lastimage = millis();
|
||||
|
||||
// If we have an active client connection, just service that until gone
|
||||
// (FIXME - support multiple simultaneous clients)
|
||||
if(session) {
|
||||
session->handleRequests(0); // we don't use a timeout here,
|
||||
// instead we send only if we have new enough frames
|
||||
|
||||
uint32_t now = millis();
|
||||
if(now > lastimage + msecPerFrame || now < lastimage) { // handle clock rollover
|
||||
session->broadcastCurrentFrame(now);
|
||||
lastimage = now;
|
||||
|
||||
// check if we are overrunning our max frame rate
|
||||
now = millis();
|
||||
if(now > lastimage + msecPerFrame)
|
||||
printf("warning exceeding max frame rate of %d ms\n", now - lastimage);
|
||||
}
|
||||
|
||||
if(session->m_stopped) {
|
||||
delete session;
|
||||
delete streamer;
|
||||
session = NULL;
|
||||
streamer = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
client = rtspServer.accept();
|
||||
|
||||
if(client) {
|
||||
//streamer = new SimStreamer(&client, true); // our streamer for UDP/TCP based RTP transport
|
||||
streamer = new OV2640Streamer(&client, cam); // our streamer for UDP/TCP based RTP transport
|
||||
|
||||
session = new CRtspSession(&client, streamer); // our threads RTSP session and state
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
## Example posix/linux usage
|
||||
|
||||
There is a small standalone example [here](/test/RTSPTestServer.cpp). You can build it by following [these](/test/README.md) directions. The usage of the two key classes (CRtspSession and SimStreamer) are very similar to to the ESP32 usage.
|
||||
|
||||
## Supporting new camera devices
|
||||
|
||||
Supporting new camera devices is quite simple. See OV2640Streamer for an example and implement streamImage()
|
||||
by reading a frame from your camera.
|
||||
|
||||
# Structure and design notes
|
||||
|
||||
# Issues and sending pull requests
|
||||
|
||||
Please report issues and send pull requests. I'll happily reply. ;-)
|
||||
|
||||
# Credits
|
||||
|
||||
The server code was initially based on a great 2013 [tutorial](https://www.medialan.de/usecase0001.html) by Medialan.
|
||||
|
||||
# License
|
||||
|
||||
Copyright 2018 S. Kevin Hester-Chow, kevinh@geeksville.com (MIT License)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,9 @@
|
|||
name=Micro-RTSP
|
||||
version=0.1.6
|
||||
author=Kevin Hester
|
||||
maintainer=Kevin Hester <kevinh@geeksville.com>
|
||||
sentence=Mikro RTSP server for mikros
|
||||
paragraph=A small/efficient RTSP server for ESP32 and other micros
|
||||
category=Data Storage
|
||||
url=https://github.com/geeksville/Micro-RTSP.git
|
||||
architectures=*
|
|
@ -3,26 +3,32 @@ import os
|
|||
import shutil
|
||||
import gzip
|
||||
|
||||
OUTPUT_DIR = "build_output{}".format(os.path.sep)
|
||||
platform = env.PioPlatform()
|
||||
board = env.BoardConfig()
|
||||
mcu = board.get("build.mcu", "esp32")
|
||||
# gzip only for ESP8266
|
||||
if env["PIOPLATFORM"] != "espressif32":
|
||||
|
||||
def bin_gzip(source, target, env):
|
||||
variant = str(target[0]).split(os.path.sep)[2]
|
||||
|
||||
# create string with location and file names based on variant
|
||||
bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
gzip_file = "{}firmware{}{}.bin.gz".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
OUTPUT_DIR = "build_output{}".format(os.path.sep)
|
||||
|
||||
# check if new target files exist and remove if necessary
|
||||
if os.path.isfile(gzip_file): os.remove(gzip_file)
|
||||
def bin_gzip(source, target, env):
|
||||
variant = str(target[0]).split(os.path.sep)[2]
|
||||
|
||||
# write gzip firmware file
|
||||
with open(bin_file,"rb") as fp:
|
||||
with gzip.open(gzip_file, "wb", compresslevel = 9) as f:
|
||||
shutil.copyfileobj(fp, f)
|
||||
|
||||
ORG_FIRMWARE_SIZE = os.stat(bin_file).st_size
|
||||
GZ_FIRMWARE_SIZE = os.stat(gzip_file).st_size
|
||||
# create string with location and file names based on variant
|
||||
bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
gzip_file = "{}firmware{}{}.bin.gz".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
|
||||
print("Compression reduced firmware size by {:.0f}% (was {} bytes, now {} bytes)".format((GZ_FIRMWARE_SIZE / ORG_FIRMWARE_SIZE) * 100, ORG_FIRMWARE_SIZE, GZ_FIRMWARE_SIZE))
|
||||
# check if new target files exist and remove if necessary
|
||||
if os.path.isfile(gzip_file): os.remove(gzip_file)
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_gzip])
|
||||
# write gzip firmware file
|
||||
with open(bin_file,"rb") as fp:
|
||||
with gzip.open(gzip_file, "wb", compresslevel = 9) as f:
|
||||
shutil.copyfileobj(fp, f)
|
||||
|
||||
ORG_FIRMWARE_SIZE = os.stat(bin_file).st_size
|
||||
GZ_FIRMWARE_SIZE = os.stat(gzip_file).st_size
|
||||
|
||||
print("Compression reduced firmware size by {:.0f}% (was {} bytes, now {} bytes)".format((GZ_FIRMWARE_SIZE / ORG_FIRMWARE_SIZE) * 100, ORG_FIRMWARE_SIZE, GZ_FIRMWARE_SIZE))
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_gzip])
|
||||
|
|
|
@ -37,6 +37,7 @@ default_envs =
|
|||
; tasmota32-ircustom
|
||||
; tasmota32solo1
|
||||
; tasmota32-odroidgo
|
||||
; tasmota32-core2
|
||||
|
||||
|
||||
[common]
|
||||
|
@ -165,7 +166,7 @@ lib_extra_dirs =
|
|||
; *** EXPERIMENTAL Tasmota version for ESP32solo1 (used in some Xiaomi devices)
|
||||
[env:tasmota32solo1]
|
||||
extends = env:tasmota32
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/raw/framework-arduinoespressif32/framework-arduinoespressif32-release_v3.3-solo1-4b325f52e.tar.gz
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/raw/framework-arduinoespressif32/framework-arduinoespressif32-solo1-release_v3.3-7e63061fa.tar.gz
|
||||
platformio/tool-mklittlefs @ ~1.203.200522
|
||||
platformio/tool-esptoolpy @ ~1.30000.0
|
||||
build_unflags = ${esp32_defaults.build_unflags}
|
||||
|
|
|
@ -9,6 +9,7 @@ default_envs = ${build_envs.default_envs}
|
|||
; tasmota32
|
||||
; tasmota32-webcam
|
||||
; tasmota32-odroidgo
|
||||
; tasmota32-core2
|
||||
; tasmota32-minimal
|
||||
; tasmota32-lite
|
||||
; tasmota32-knx
|
||||
|
@ -86,11 +87,13 @@ build_flags = ${esp_defaults.build_flags}
|
|||
-Dsint16_t=int16_t
|
||||
-Dmemcpy_P=memcpy
|
||||
-Dmemcmp_P=memcmp
|
||||
;for TLS we can afford compiling for 4K RSA keys
|
||||
-DUSE_4K_RSA
|
||||
|
||||
|
||||
[core32]
|
||||
platform = espressif32 @ 2.1.0
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/1.0.5-rc4/esp32-1.0.5-rc4.zip
|
||||
platform = espressif32 @ 3.0.0
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/1.0.5-rc6/esp32-1.0.5-rc6.zip
|
||||
platformio/tool-mklittlefs @ ~1.203.200522
|
||||
build_unflags = ${esp32_defaults.build_unflags}
|
||||
build_flags = ${esp32_defaults.build_flags}
|
||||
|
|
|
@ -40,10 +40,24 @@ lib_extra_dirs = lib/libesp32, lib/lib_basic
|
|||
extends = env:tasmota32
|
||||
board = odroid_esp32
|
||||
board_build.f_cpu = 240000000L
|
||||
board_build.flash_mode = qio
|
||||
board_build.f_flash = 80000000L
|
||||
upload_speed = 2000000
|
||||
board_build.partitions = esp32_partition_app1984k_spiffs12M.csv
|
||||
build_flags = ${common32.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -DFIRMWARE_ODROID_GO
|
||||
lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display
|
||||
|
||||
[env:tasmota32-core2]
|
||||
extends = env:tasmota32
|
||||
board = odroid_esp32
|
||||
board_build.f_cpu = 240000000L
|
||||
board_build.flash_mode = qio
|
||||
board_build.f_flash = 80000000L
|
||||
upload_speed = 2000000
|
||||
board_build.partitions = esp32_partition_app1984k_spiffs12M.csv
|
||||
build_flags = ${common32.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -DFIRMWARE_M5STACK_CORE2
|
||||
lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display, lib/lib_audio
|
||||
|
||||
[env:tasmota32-minimal]
|
||||
extends = env:tasmota32
|
||||
build_flags = ${common32.build_flags} -DFIRMWARE_MINIMAL
|
||||
|
|
|
@ -804,6 +804,7 @@ extern "C" {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifndef USE_MQTT_TLS_DROP_OLD_FINGERPRINT
|
||||
// No match under new algorithm, do some basic checking on the key.
|
||||
//
|
||||
// RSA keys normally have an e value of 65537, which is three bytes long.
|
||||
|
@ -838,6 +839,9 @@ extern "C" {
|
|||
pubkeyfingerprint_pubkey_fingerprint(xc, false);
|
||||
|
||||
return 0;
|
||||
#else // USE_TLS_OLD_FINGERPRINT_COMPAT
|
||||
return 1; // no match, error
|
||||
#endif // USE_TLS_OLD_FINGERPRINT_COMPAT
|
||||
} else {
|
||||
// Default (no validation at all) or no errors in prior checks = success.
|
||||
return 0;
|
||||
|
|
|
@ -156,6 +156,7 @@
|
|||
#define D_JSON_SERIALRECEIVED "SerialReceived"
|
||||
#define D_JSON_SET "Set"
|
||||
#define D_JSON_SIGNAL "Signal"
|
||||
#define D_JSON_SIZE "Size"
|
||||
#define D_JSON_SPEED "Speed"
|
||||
#define D_JSON_SPEED_UNIT "SpeedUnit"
|
||||
#define D_JSON_SSID "SSId"
|
||||
|
@ -180,6 +181,7 @@
|
|||
#define D_JSON_TOTAL_START_TIME "TotalStartTime"
|
||||
#define D_JSON_TVOC "TVOC"
|
||||
#define D_JSON_TYPE "Type"
|
||||
#define D_JSON_UID "UID"
|
||||
#define D_JSON_UPTIME "Uptime"
|
||||
#define D_JSON_UTC_TIME "UTC"
|
||||
#define D_JSON_UV_INDEX "UvIndex"
|
||||
|
@ -347,7 +349,11 @@
|
|||
#define D_CMND_CPU_FREQUENCY "CpuFrequency"
|
||||
#endif // ESP32
|
||||
|
||||
// Commands xdrv_01_mqtt.ino
|
||||
// Commands xdrv_02_mqtt.ino
|
||||
#define D_SO_MQTTJSONONLY "MqttJSONOnly"
|
||||
#define D_SO_MQTTTLS "MqttTLS"
|
||||
#define D_SO_MQTTNORETAIN "MqttNoRetain"
|
||||
#define D_SO_MQTTDETACHRELAY "MqttDetachRelay"
|
||||
#define D_CMND_MQTTLOG "MqttLog"
|
||||
#define D_CMND_MQTTHOST "MqttHost"
|
||||
#define D_CMND_MQTTPORT "MqttPort"
|
||||
|
@ -373,7 +379,7 @@
|
|||
#define D_CMND_SENSORRETAIN "SensorRetain"
|
||||
#define D_CMND_PUBLISH "Publish"
|
||||
|
||||
// Commands xdrv_02_webserver.ino
|
||||
// Commands xdrv_01_webserver.ino
|
||||
#define D_CMND_WEBSERVER "Webserver"
|
||||
#define D_JSON_WEBSERVER_MODE "WebServerMode"
|
||||
#define D_JSON_ACTIVE_FOR "Active for"
|
||||
|
@ -418,6 +424,13 @@
|
|||
#define D_JSON_MAXENERGYREACHED "MaxEnergyReached"
|
||||
|
||||
// Commands xdrv_04_light.ino
|
||||
#define D_SO_CHANNELREMAP "ChannelRemap" // SO37
|
||||
#define D_SO_MULTIPWM "MultiPWM" // SO68
|
||||
#define D_SO_ALEXACTRANGE "AlexaCTRange" // SO82
|
||||
#define D_SO_POWERONFADE "PowerOnFade" // SO91
|
||||
#define D_SO_PWMCT "PWMCT" // SO92
|
||||
#define D_SO_WHITEBLEND "WhiteBlend" // SO105
|
||||
#define D_SO_VIRTUALCT "VirtualCT" // SO106
|
||||
#define D_CMND_CHANNEL "Channel"
|
||||
#define D_CMND_COLOR "Color"
|
||||
#define D_CMND_COLORTEMPERATURE "CT"
|
||||
|
@ -520,7 +533,16 @@
|
|||
|
||||
// Commands xdrv_23_zigbee.ino
|
||||
#define D_PRFX_ZB "Zb"
|
||||
#define D_ZIGBEE_NOT_STARTED "Zigbee not started"
|
||||
#define D_SO_ZIGBEE_NAMEKEY "NameKey"
|
||||
#define D_SO_ZIGBEE_DEVICETOPIC "DeviceTopic"
|
||||
#define D_SO_ZIGBEE_NOPREFIX "NoPrefix"
|
||||
#define D_SO_ZIGBEE_ENDPOINTSUFFIX "EndpointSuffix"
|
||||
#define D_SO_ZIGBEE_NOAUTOBIND "NoAutoBind"
|
||||
#define D_SO_ZIGBEE_NAMETOPIC "NameTopic"
|
||||
#define D_SO_ZIGBEE_ENDPOINTTOPIC "EndpointTopic"
|
||||
#define D_SO_ZIGBEE_NOAUTOQUERY "NoAutoQuery"
|
||||
#define D_SO_ZIGBEE_ZBRECEIVEDTOPIC "ReceivedTopic"
|
||||
#define D_SO_ZIGBEE_OMITDEVICE "OmitDevice"
|
||||
#define D_CMND_ZIGBEE_PERMITJOIN "PermitJoin"
|
||||
#define D_CMND_ZIGBEE_STATUS "Status"
|
||||
#define D_CMND_ZIGBEE_RESET "Reset"
|
||||
|
@ -727,7 +749,6 @@ const char S_JSON_COMMAND_INDEX_NVALUE[] PROGMEM = "{\"%s%d\":%d}";
|
|||
const char S_JSON_COMMAND_INDEX_LVALUE[] PROGMEM = "{\"%s%d\":%lu}";
|
||||
const char S_JSON_COMMAND_INDEX_SVALUE[] PROGMEM = "{\"%s%d\":\"%s\"}";
|
||||
const char S_JSON_COMMAND_INDEX_ASTERISK[] PROGMEM = "{\"%s%d\":\"" D_ASTERISK_PWD "\"}";
|
||||
const char S_JSON_COMMAND_INDEX_SVALUE_SVALUE[] PROGMEM = "{\"%s%d\":\"%s%s\"}";
|
||||
|
||||
const char S_JSON_SENSOR_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":%d}";
|
||||
const char S_JSON_SENSOR_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":\"%s\"}";
|
||||
|
@ -737,6 +758,7 @@ const char S_JSON_DRIVER_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_DRIVE
|
|||
|
||||
const char S_JSON_SVALUE_ACTION_SVALUE[] PROGMEM = "{\"%s\":{\"Action\":\"%s\"}}";
|
||||
|
||||
const char JSON_SNS_F_TEMP[] PROGMEM = ",\"%s\":{\"" D_JSON_TEMPERATURE "\":%*_f}";
|
||||
const char JSON_SNS_TEMP[] PROGMEM = ",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}";
|
||||
|
||||
const char JSON_SNS_ILLUMINANCE[] PROGMEM = ",\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d}";
|
||||
|
@ -769,7 +791,9 @@ const float kSpeedConversionFactor[] = {1, // none
|
|||
// xdrv_02_webserver.ino
|
||||
#ifdef USE_WEBSERVER
|
||||
// {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
||||
const char HTTP_SNS_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%s " D_UNIT_DEGREE "%c{e}";
|
||||
const char HTTP_SNS_F_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%*_f " D_UNIT_DEGREE "%c{e}";
|
||||
//const char HTTP_SNS_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%s " D_UNIT_DEGREE "%c{e}";
|
||||
|
||||
const char HTTP_SNS_HUM[] PROGMEM = "{s}%s " D_HUMIDITY "{m}%s " D_UNIT_PERCENT "{e}";
|
||||
const char HTTP_SNS_DEW[] PROGMEM = "{s}%s " D_DEWPOINT "{m}%s " D_UNIT_DEGREE "%c{e}";
|
||||
const char HTTP_SNS_PRESSURE[] PROGMEM = "{s}%s " D_PRESSURE "{m}%s " "%s{e}";
|
||||
|
@ -782,6 +806,7 @@ const char HTTP_SNS_GALLONS[] PROGMEM = "{s}%s " D_TOTAL_USAGE "{
|
|||
const char HTTP_SNS_GPM[] PROGMEM = "{s}%s " D_FLOW_RATE "{m}%s " D_UNIT_GALLONS_PER_MIN "{e}";
|
||||
const char HTTP_SNS_MOISTURE[] PROGMEM = "{s}%s " D_MOISTURE "{m}%d " D_UNIT_PERCENT "{e}";
|
||||
const char HTTP_SNS_RANGE[] PROGMEM = "{s}%s " D_RANGE "{m}%d" "{e}";
|
||||
const char HTTP_SNS_DISTANCE[] PROGMEM = "{s}%s " D_DISTANCE "{m}%d " D_UNIT_MILLIMETER "{e}";
|
||||
const char HTTP_SNS_VOLTAGE[] PROGMEM = "{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}";
|
||||
const char HTTP_SNS_CURRENT[] PROGMEM = "{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}";
|
||||
const char HTTP_SNS_POWER[] PROGMEM = "{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}";
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Wagwoord geverifieer" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Fout" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_AF_AF_H_
|
||||
|
|
|
@ -781,6 +781,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -952,4 +957,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_BG_BG_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_CS_CZ_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Übereinstimmung" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Fehler" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (Gelb)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (Blau)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (Grün)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (Hellblau)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (Rot)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (Lila)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (Orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manuell" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heizung"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Rückspülung"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "Langsam"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "Mittel"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "Schnell"
|
||||
#define D_NEOPOOL_TYPE "Typ" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlor"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Konduktivität"
|
||||
#define D_NEOPOOL_IONIZATION "Ionisierung"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolyse"
|
||||
#define D_NEOPOOL_RELAY "Relais"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Licht"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Säurepumpe"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Laugenpumpe"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox Pegel"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorpumpe"
|
||||
#define D_NEOPOOL_RELAY_CD "Salzwasserpumpe"
|
||||
#define D_NEOPOOL_TIME "Zeit"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrAus"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Abdeckung"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Niedrig"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "zu hoch" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "zu niedrig"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "Pumpzeit überschritten"
|
||||
|
||||
#endif // _LANGUAGE_DE_DE_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_EL_GR_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_EN_GB_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Clave Correcta" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_ES_ES_H_
|
||||
|
|
|
@ -778,6 +778,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "CarteSD CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -947,4 +952,56 @@
|
|||
#define D_FP_PASSVERIFY "Mot-de-passe vérifié" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Erreur" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_FR_FR_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_HE_HE_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_HU_HU_H_
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
it-IT.h - localization for Italian - Italy for Tasmota
|
||||
|
||||
Copyright (C) 2021 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 09.01.2021
|
||||
Copyright (C) 2021 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 22.01.2021
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -782,6 +782,10 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 - CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 - DC"
|
||||
#define D_SENSOR_SDCARD_CS "Scheda SD - CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand - D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand - D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +957,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verificata" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Errore" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (giallo)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blu)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (verde)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (azzurro)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (rosso)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (arancio)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generico"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manuale" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Automatico"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Riscaldamento"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Rapido"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligente"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Contro lavaggio"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "lento"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medio"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "veloce"
|
||||
#define D_NEOPOOL_TYPE "Tipo" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Cloro"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conduttività"
|
||||
#define D_NEOPOOL_IONIZATION "Ionizzazione"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Idrolisi"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtrazione"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Luce"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Pompa per acido"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Popa base"
|
||||
#define D_NEOPOOL_RELAY_RX "Livello Redox"
|
||||
#define D_NEOPOOL_RELAY_CL "Pompa cloro"
|
||||
#define D_NEOPOOL_RELAY_CD "Pompa salamoia"
|
||||
#define D_NEOPOOL_TIME "Orario"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtrazione"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "OK"
|
||||
#define D_NEOPOOL_COVER "Copertura"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "troppo alto" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "troppo basso"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "tempo pompa superato"
|
||||
|
||||
#endif // _LANGUAGE_IT_IT_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_KO_KO_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_NL_NL_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_PL_PL_D_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_PT_BR_H_
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
#define D_SENSOR_SSD1331_CS "SSD1331 CS"
|
||||
#define D_SENSOR_SSD1331_DC "SSD1331 DC"
|
||||
#define D_SENSOR_SDCARD_CS "SDCard CS"
|
||||
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
|
||||
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
|
||||
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
|
||||
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
|
||||
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
@ -953,4 +958,56 @@
|
|||
#define D_FP_PASSVERIFY "Password verified" // 0x21 Verify the fingerprint passed
|
||||
#define D_FP_UNKNOWNERROR "Error" // Any other error
|
||||
|
||||
// xsns_83_neopool.ino
|
||||
#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names
|
||||
#define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (yellow)"
|
||||
#define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blue)"
|
||||
#define D_NEOPOOL_MACH_OXILIFE "Oxilife (green)"
|
||||
#define D_NEOPOOL_MACH_BIONET "Bionet (light blue)"
|
||||
#define D_NEOPOOL_MACH_HIDRONISER "Hidroniser (red)"
|
||||
#define D_NEOPOOL_MACH_UVSCENIC "UVScenic (lilac)"
|
||||
#define D_NEOPOOL_MACH_STATION "Station (orange)"
|
||||
#define D_NEOPOOL_MACH_BRILIX "Brilix"
|
||||
#define D_NEOPOOL_MACH_GENERIC "Generic"
|
||||
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
|
||||
#define D_NEOPOOL_MACH_HAY "Hay"
|
||||
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
|
||||
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
|
||||
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
|
||||
#define D_NEOPOOL_FILTRATION_SMART "Smart"
|
||||
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
|
||||
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
|
||||
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
|
||||
#define D_NEOPOOL_FILTRATION_SLOW "slow"
|
||||
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
|
||||
#define D_NEOPOOL_FILTRATION_FAST "fast"
|
||||
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
|
||||
#define D_NEOPOOL_REDOX "Redox"
|
||||
#define D_NEOPOOL_CHLORINE "Chlorine"
|
||||
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
|
||||
#define D_NEOPOOL_IONIZATION "Ionization"
|
||||
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
|
||||
#define D_NEOPOOL_RELAY "Relay"
|
||||
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
|
||||
#define D_NEOPOOL_RELAY_LIGHT "Light"
|
||||
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
|
||||
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
|
||||
#define D_NEOPOOL_RELAY_RX "Redox level"
|
||||
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
|
||||
#define D_NEOPOOL_RELAY_CD "Brine pump"
|
||||
#define D_NEOPOOL_TIME "Time"
|
||||
#define D_NEOPOOL_FILT_MODE "Filtration"
|
||||
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
|
||||
#define D_NEOPOOL_PR_OFF "PrOff"
|
||||
#define D_NEOPOOL_SETPOINT_OK "Ok"
|
||||
#define D_NEOPOOL_COVER "Cover"
|
||||
#define D_NEOPOOL_SHOCK "Shock"
|
||||
#define D_NEOPOOL_ALARM "! "
|
||||
#define D_NEOPOOL_LOW "Low"
|
||||
#define D_NEOPOOL_FLOW1 "FL1"
|
||||
#define D_NEOPOOL_FLOW2 "FL2"
|
||||
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
|
||||
#define D_NEOPOOL_PH_LOW "too low"
|
||||
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
|
||||
|
||||
#endif // _LANGUAGE_PT_PT_H_
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue