diff --git a/BUILDS.md b/BUILDS.md
index 91bbd287e..700407907 100644
--- a/BUILDS.md
+++ b/BUILDS.md
@@ -77,6 +77,7 @@
| USE_MAX31855 | - | - | - | - | x | - | - |
| USE_MAX31865 | - | - | - | - | - | - | - |
| USE_THERMOSTAT | - | - | - | - | - | - | - |
+| USE_LMT01 | - | - | - | - | x | - | - |
| | | | | | | | |
| Feature or Sensor | minimal | lite | tasmota | knx | sensors | ir | display | Remarks
| USE_I2C | - | - | x | x | x | - | x |
@@ -181,3 +182,4 @@
|-----------------------|---------|-------|--------|-----|---------|----|---------|--------|--------
| USE_MI_ESP32 | - | - | - | - | - | - | - | - |
| USE_WEBCAM | - | - | - | - | - | - | - | x |
+| USE_ETHERNET | - | - | - | - | - | - | - | - |
diff --git a/I2CDEVICES.md b/I2CDEVICES.md
index 4f6718b90..b67cc9029 100644
--- a/I2CDEVICES.md
+++ b/I2CDEVICES.md
@@ -72,4 +72,5 @@ Index | Define | Driver | Device | Address(es) | Description
48 | USE_AS3935 | xsns_67 | AS3935 | 0x03 | Franklin Lightning Sensor
49 | USE_VEML6075 | xsns_70 | VEML6075 | 0x10 | UVA/UVB/UVINDEX Sensor
50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor
- 51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor
\ No newline at end of file
+ 51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor
+ 52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor
\ No newline at end of file
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index fa35311dd..410ecc1d1 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -52,19 +52,22 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
## Changelog
-### Version 8.3.1.2
+### Version 8.3.1.6
-- Created Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff
-- Added Library to be used for decoding Teleinfo (French Metering Smart Meter)
- Change IRremoteESP8266 library updated to v2.7.7
- Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519)
- Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]``
- Change Energy JSON ExportActive field from ``"ExportActive":[33.736,11.717,16.978]`` to ``"ExportActive":33.736,"ExportTariff":[11.717,16.978]``
+- Change ESP32 USER GPIO template representation decreasing template message size
+- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT
+- Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset``
- Fix escape of non-JSON received serial data (#8329)
- Add command ``Rule0`` to change global rule parameters
- Add command ``Time 4`` to display timestamp using milliseconds (#8537)
- Add command ``SetOption94 0/1`` to select MAX31855 or MAX6675 thermocouple support (#8616)
+- Add command ``Module2`` to configure fallback module on fast reboot (#8464)
- Add commands ``LedPwmOn 0..255``, ``LedPwmOff 0..255`` and ``LedPwmMode1 0/1`` to control led brightness by George (#8491)
+- Add ESP32 ethernet commands ``EthType 0/1``, ``EthAddress 0..31`` and ``EthClockMode 0..3``
- Add support for unique MQTTClient (and inherited fallback topic) by full Mac address using ``mqttclient DVES_%12X`` (#8300)
- Add more functionality to ``Switchmode`` 11 and 12 (#8450)
- Add wildcard pattern ``?`` for JSON matching in rules
@@ -78,3 +81,10 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
- Add support for up to two BH1750 sensors controlled by commands ``BH1750Resolution`` and ``BH1750MTime`` (#8139)
- Add support for up to eight MCP9808 temperature sensors by device111 (#8594)
- Add support for BL0940 energy monitor as used in Blitzwolf BW-SHP10 (#8175)
+- Add initial support for Telegram bot (#8619)
+- Add support for HP303B Temperature and Pressure sensor by Robert Jaakke (#8638)
+- Add rule trigger ``System#Init`` to allow early rule execution without wifi and mqtt initialized yet
+- Add support for Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff
+- Add Library to be used for decoding Teleinfo (French Metering Smart Meter)
+- Add basic support for ESP32 ethernet adding commands ``Wifi 0/1`` and ``Ethernet 0/1`` both default ON
+- Add support for single wire LMT01 temperature Sensor by justifiably (#8713)
diff --git a/lib/LOLIN_HP303B/README.md b/lib/LOLIN_HP303B/README.md
new file mode 100644
index 000000000..24d6c2d1b
--- /dev/null
+++ b/lib/LOLIN_HP303B/README.md
@@ -0,0 +1,4 @@
+# Arduino library for the HP303B
+### Installation
+- Clone this repository or download&unzip [zip file](https://github.com/wemos/LOLIN_HP303B_Library/archive/master.zip) into Arduino/libraries
+
diff --git a/lib/LOLIN_HP303B/examples/i2c_background/i2c_background.ino b/lib/LOLIN_HP303B/examples/i2c_background/i2c_background.ino
new file mode 100644
index 000000000..1b9ae6e68
--- /dev/null
+++ b/lib/LOLIN_HP303B/examples/i2c_background/i2c_background.ino
@@ -0,0 +1,98 @@
+#include
+
+// HP303B Opject
+LOLIN_HP303B HP303BPressureSensor = LOLIN_HP303B();
+
+void setup()
+{
+ Serial.begin(115200);
+ while (!Serial);
+
+ //Call begin to initialize HP303BPressureSensor
+ //The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given.
+ //HP303BPressureSensor.begin(Wire, 0x76);
+ //Use the commented line below instead to use the default I2C address.
+ HP303BPressureSensor.begin();
+
+ //temperature measure rate (value from 0 to 7)
+ //2^temp_mr temperature measurement results per second
+ int16_t temp_mr = 2;
+ //temperature oversampling rate (value from 0 to 7)
+ //2^temp_osr internal temperature measurements per result
+ //A higher value increases precision
+ int16_t temp_osr = 2;
+ //pressure measure rate (value from 0 to 7)
+ //2^prs_mr pressure measurement results per second
+ int16_t prs_mr = 2;
+ //pressure oversampling rate (value from 0 to 7)
+ //2^prs_osr internal pressure measurements per result
+ //A higher value increases precision
+ int16_t prs_osr = 2;
+ //startMeasureBothCont enables background mode
+ //temperature and pressure ar measured automatically
+ //High precision and hgh measure rates at the same time are not available.
+ //Consult Datasheet (or trial and error) for more information
+ int16_t ret = HP303BPressureSensor.startMeasureBothCont(temp_mr, temp_osr, prs_mr, prs_osr);
+ //Use one of the commented lines below instead to measure only temperature or pressure
+ //int16_t ret = HP303BPressureSensor.startMeasureTempCont(temp_mr, temp_osr);
+ //int16_t ret = HP303BPressureSensor.startMeasurePressureCont(prs_mr, prs_osr);
+
+
+ if (ret != 0)
+ {
+ Serial.print("Init FAILED! ret = ");
+ Serial.println(ret);
+ }
+ else
+ {
+ Serial.println("Init complete!");
+ }
+}
+
+
+
+void loop()
+{
+ unsigned char pressureCount = 20;
+ int32_t pressure[pressureCount];
+ unsigned char temperatureCount = 20;
+ int32_t temperature[temperatureCount];
+
+ //This function writes the results of continuous measurements to the arrays given as parameters
+ //The parameters temperatureCount and pressureCount should hold the sizes of the arrays temperature and pressure when the function is called
+ //After the end of the function, temperatureCount and pressureCount hold the numbers of values written to the arrays
+ //Note: The HP303B cannot save more than 32 results. When its result buffer is full, it won't save any new measurement results
+ int16_t ret = HP303BPressureSensor.getContResults(temperature, temperatureCount, pressure, pressureCount);
+
+ if (ret != 0)
+ {
+ Serial.println();
+ Serial.println();
+ Serial.print("FAIL! ret = ");
+ Serial.println(ret);
+ }
+ else
+ {
+ Serial.println();
+ Serial.println();
+ Serial.print(temperatureCount);
+ Serial.println(" temperature values found: ");
+ for (int16_t i = 0; i < temperatureCount; i++)
+ {
+ Serial.print(temperature[i]);
+ Serial.println(" degrees of Celsius");
+ }
+
+ Serial.println();
+ Serial.print(pressureCount);
+ Serial.println(" pressure values found: ");
+ for (int16_t i = 0; i < pressureCount; i++)
+ {
+ Serial.print(pressure[i]);
+ Serial.println(" Pascal");
+ }
+ }
+
+ //Wait some time, so that the HP303B can refill its buffer
+ delay(10000);
+}
diff --git a/lib/LOLIN_HP303B/examples/i2c_command/i2c_command.ino b/lib/LOLIN_HP303B/examples/i2c_command/i2c_command.ino
new file mode 100644
index 000000000..e629f7d5f
--- /dev/null
+++ b/lib/LOLIN_HP303B/examples/i2c_command/i2c_command.ino
@@ -0,0 +1,75 @@
+#include
+
+// HP303B Opject
+LOLIN_HP303B HP303BPressureSensor;
+
+
+void setup()
+{
+ Serial.begin(115200);
+ while (!Serial);
+
+
+ //Call begin to initialize HP303BPressureSensor
+ //The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given.
+ //HP303BPressureSensor.begin(Wire, 0x76);
+ //Use the commented line below instead of the one above to use the default I2C address.
+ //if you are using the Pressure 3 click Board, you need 0x76
+ HP303BPressureSensor.begin();
+
+ Serial.println("Init complete!");
+}
+
+
+
+void loop()
+{
+ int32_t temperature;
+ int32_t pressure;
+ int16_t oversampling = 7;
+ int16_t ret;
+ Serial.println();
+
+ //lets the HP303B perform a Single temperature measurement with the last (or standard) configuration
+ //The result will be written to the paramerter temperature
+ //ret = HP303BPressureSensor.measureTempOnce(temperature);
+ //the commented line below does exactly the same as the one above, but you can also config the precision
+ //oversampling can be a value from 0 to 7
+ //the HP303B will perform 2^oversampling internal temperature measurements and combine them to one result with higher precision
+ //measurements with higher precision take more time, consult datasheet for more information
+ ret = HP303BPressureSensor.measureTempOnce(temperature, oversampling);
+
+ if (ret != 0)
+ {
+ //Something went wrong.
+ //Look at the library code for more information about return codes
+ Serial.print("FAIL! ret = ");
+ Serial.println(ret);
+ }
+ else
+ {
+ Serial.print("Temperature: ");
+ Serial.print(temperature);
+ Serial.println(" degrees of Celsius");
+ }
+
+ //Pressure measurement behaves like temperature measurement
+ //ret = HP303BPressureSensor.measurePressureOnce(pressure);
+ ret = HP303BPressureSensor.measurePressureOnce(pressure, oversampling);
+ if (ret != 0)
+ {
+ //Something went wrong.
+ //Look at the library code for more information about return codes
+ Serial.print("FAIL! ret = ");
+ Serial.println(ret);
+ }
+ else
+ {
+ Serial.print("Pressure: ");
+ Serial.print(pressure);
+ Serial.println(" Pascal");
+ }
+
+ //Wait some time
+ delay(500);
+}
diff --git a/lib/LOLIN_HP303B/examples/i2c_interrupt/i2c_interrupt.ino b/lib/LOLIN_HP303B/examples/i2c_interrupt/i2c_interrupt.ino
new file mode 100644
index 000000000..d1221109b
--- /dev/null
+++ b/lib/LOLIN_HP303B/examples/i2c_interrupt/i2c_interrupt.ino
@@ -0,0 +1,112 @@
+#include
+
+// HP303B Opject
+LOLIN_HP303B HP303BPressureSensor = LOLIN_HP303B();
+
+void onFifoFull();
+
+const unsigned char pressureLength = 50;
+unsigned char pressureCount = 0;
+int32_t pressure[pressureLength];
+unsigned char temperatureCount = 0;
+const unsigned char temperatureLength = 50;
+int32_t temperature[temperatureLength];
+
+
+
+void setup()
+{
+ Serial.begin(115200);
+ while (!Serial);
+
+ //Call begin to initialize HP303BPressureSensor
+ //The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given.
+ //HP303BPressureSensor.begin(Wire, 0x76);
+ //Use the commented line below instead to use the default I2C address.
+ HP303BPressureSensor.begin();
+
+ int16_t ret = HP303BPressureSensor.setInterruptPolarity(1);
+ ret = HP303BPressureSensor.setInterruptSources(1, 0, 0);
+ //clear interrupt flag by reading
+ HP303BPressureSensor.getIntStatusFifoFull();
+
+ //initialization of Interrupt for Controller unit
+ //SDO pin of HP303B has to be connected with interrupt pin
+ int16_t interruptPin = 3;
+ pinMode(interruptPin, INPUT);
+ attachInterrupt(digitalPinToInterrupt(interruptPin), onFifoFull, RISING);
+
+ //start of a continuous measurement just like before
+ int16_t temp_mr = 3;
+ int16_t temp_osr = 2;
+ int16_t prs_mr = 1;
+ int16_t prs_osr = 3;
+ ret = HP303BPressureSensor.startMeasureBothCont(temp_mr, temp_osr, prs_mr, prs_osr);
+ if (ret != 0)
+ {
+ Serial.print("Init FAILED! ret = ");
+ Serial.println(ret);
+ }
+ else
+ {
+ Serial.println("Init complete!");
+ }
+}
+
+
+void loop()
+{
+ //do other stuff
+ Serial.println("loop running");
+ delay(500);
+
+
+ //if result arrays are full
+ //This could also be in the interrupt handler, but it would take too much time for a proper ISR
+ if (pressureCount == pressureLength && temperatureCount == temperatureLength)
+ {
+ //print results
+ Serial.println();
+ Serial.println();
+ Serial.print(temperatureCount);
+ Serial.println(" temperature values found: ");
+ for (int16_t i = 0; i < temperatureCount; i++)
+ {
+ Serial.print(temperature[i]);
+ Serial.println(" degrees of Celsius");
+ }
+ Serial.println();
+ Serial.print(pressureCount);
+ Serial.println(" pressure values found: ");
+ for (int16_t i = 0; i < pressureCount; i++)
+ {
+ Serial.print(pressure[i]);
+ Serial.println(" Pascal");
+ }
+ Serial.println();
+ Serial.println();
+ //reset result counters
+ pressureCount = 0;
+ temperatureCount = 0;
+ }
+}
+
+
+//interrupt handler
+void onFifoFull()
+{
+ //message for debugging
+ Serial.println("Interrupt handler called");
+
+ //clear interrupt flag by reading
+ HP303BPressureSensor.getIntStatusFifoFull();
+
+ //calculate the number of free indexes in the result arrays
+ unsigned char prs_freespace = pressureLength - pressureCount;
+ unsigned char temp_freespace = temperatureLength - temperatureCount;
+ //read the results from HP303B, new results will be added at the end of the arrays
+ HP303BPressureSensor.getContResults(&temperature[temperatureCount], temp_freespace, &pressure[pressureCount], prs_freespace);
+ //after reading the result counters are increased by the amount of new results
+ pressureCount += prs_freespace;
+ temperatureCount += temp_freespace;
+}
diff --git a/lib/LOLIN_HP303B/keywords.txt b/lib/LOLIN_HP303B/keywords.txt
new file mode 100644
index 000000000..b283317f5
--- /dev/null
+++ b/lib/LOLIN_HP303B/keywords.txt
@@ -0,0 +1,26 @@
+#######################################
+# Syntax Coloring Map For DHT12
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+DHT12 KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+get KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+
+cTemp LITERAL1
+fTemp LITERAL1
+humidity LITERAL1
+
+
+
diff --git a/lib/LOLIN_HP303B/library.properties b/lib/LOLIN_HP303B/library.properties
new file mode 100644
index 000000000..7f71ad2b2
--- /dev/null
+++ b/lib/LOLIN_HP303B/library.properties
@@ -0,0 +1,9 @@
+name=LOLIN_HP303B
+version=1.0.0
+author=WEMOS.CC
+maintainer=WEMOS.CC
+sentence=Library for the HP303B..
+paragraph=LOLIN HP303B
+category=Device Control
+url=https://github.com/wemos/LOLIN_HP303B_Library
+architectures=*
diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp
new file mode 100644
index 000000000..c6f8aeb1d
--- /dev/null
+++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp
@@ -0,0 +1,1685 @@
+#include "LOLIN_HP303B.h"
+
+
+
+const int32_t LOLIN_HP303B::scaling_facts[HP303B__NUM_OF_SCAL_FACTS]
+ = {524288, 1572864, 3670016, 7864320, 253952, 516096, 1040384, 2088960};
+
+
+
+//////// Constructor, Destructor, begin, end ////////
+
+
+/**
+ * Standard Constructor
+ */
+LOLIN_HP303B::LOLIN_HP303B(void)
+{
+ //assume that initialization has failed before it has been done
+ m_initFail = 1U;
+}
+
+/**
+ * Standard Destructor
+ */
+LOLIN_HP303B::~LOLIN_HP303B(void)
+{
+ end();
+}
+
+
+
+/**
+ * Standard I2C begin function
+ *
+ * &bus: I2CBus which connects MC to HP303B
+ * slaveAddress: Address of the HP303B (0x77 or 0x76)
+ */
+uint8_t LOLIN_HP303B::begin(TwoWire &bus, uint8_t slaveAddress)
+{
+ //this flag will show if the initialization was successful
+ m_initFail = 0U;
+
+ //Set I2C bus connection
+ m_SpiI2c = 1U;
+ m_i2cbus = &bus;
+ m_slaveAddress = slaveAddress;
+
+ // Init bus
+ m_i2cbus->begin();
+
+ delay(50); //startup time of HP303B
+
+ return init();
+}
+
+uint8_t LOLIN_HP303B::begin(uint8_t slaveAddress)
+{
+ return begin(Wire,slaveAddress);
+}
+
+/**
+ * SPI begin function for HP303B with 4-wire SPI
+ */
+uint8_t LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect)
+{
+ return begin(bus, chipSelect, 0U);
+}
+
+/**
+ * Standard SPI begin function
+ *
+ * &bus: SPI bus which connects MC to HP303B
+ * chipSelect: Number of the CS line for the HP303B
+ * threeWire: 1 if HP303B is connected with 3-wire SPI
+ * 0 if HP303B is connected with 4-wire SPI (standard)
+ */
+uint8_t LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire)
+{
+ //this flag will show if the initialization was successful
+ m_initFail = 0U;
+
+ //Set SPI bus connection
+ m_SpiI2c = 0U;
+ m_spibus = &bus;
+ m_chipSelect = chipSelect;
+
+ // Init bus
+ m_spibus->begin();
+ m_spibus->setDataMode(SPI_MODE3);
+
+ pinMode(m_chipSelect, OUTPUT);
+ digitalWrite(m_chipSelect, HIGH);
+
+ delay(50); //startup time of HP303B
+
+ //switch to 3-wire mode if necessary
+ //do not use writeByteBitfield or check option to set SPI mode!
+ //Reading is not possible until SPI-mode is valid
+ if(threeWire)
+ {
+ m_threeWire = 1U;
+ if(writeByte(HP303B__REG_ADR_SPI3W, HP303B__REG_CONTENT_SPI3W))
+ {
+ m_initFail = 1U;
+ return 0U;
+ }
+ }
+
+ return init();
+}
+
+/**
+ * End function for HP303B
+ * Sets the sensor to idle mode
+ */
+void LOLIN_HP303B::end(void)
+{
+ standby();
+}
+
+
+//////// Declaration of other public functions starts here ////////
+
+
+/**
+ * returns the Product ID of the connected HP303B sensor
+ */
+uint8_t LOLIN_HP303B::getProductId(void)
+{
+ return m_productID;
+}
+
+/**
+ * returns the Revision ID of the connected HP303B sensor
+ */
+uint8_t LOLIN_HP303B::getRevisionId(void)
+{
+ return m_revisionID;
+}
+
+/**
+ * Sets the HP303B to standby mode
+ *
+ * returns: 0 on success
+ * -2 if object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::standby(void)
+{
+ //set device to idling mode
+ int16_t ret = setOpMode(IDLE);
+ if(ret != HP303B__SUCCEEDED)
+ {
+ return ret;
+ }
+ //flush the FIFO
+ ret = writeByteBitfield(1U, HP303B__REG_INFO_FIFO_FL);
+ if(ret < 0)
+ {
+ return ret;
+ }
+ //disable the FIFO
+ ret = writeByteBitfield(0U, HP303B__REG_INFO_FIFO_EN);
+ return ret;
+}
+
+
+/**
+ * performs one temperature measurement and writes result to the given address
+ *
+ * &result: reference to a 32-Bit signed Integer value where the result will be written
+ * It will not be written if result==NULL
+ * returns: 0 on success
+ * -4 if the HP303B is could not finish its measurement in time
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::measureTempOnce(float &result)
+{
+ return measureTempOnce(result, m_slaveAddress, m_tempOsr);
+}
+
+/**
+ * performs one temperature measurement and writes result to the given address
+ *
+ * &result: reference to a 32-Bit signed Integer value where the result will be written
+ * It will not be written if result==NULL
+ * returns: 0 on success
+ * -4 if the HP303B is could not finish its measurement in time
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::measureTempOnce(float &result, uint8_t slaveAddress)
+{
+ return measureTempOnce(result, slaveAddress, m_tempOsr);
+}
+
+/**
+ * performs one temperature measurement and writes result to the given address
+ * the desired precision can be set with oversamplingRate
+ *
+ * &result: reference to a 32-Bit signed Integer where the result will be written
+ * It will not be written if result==NULL
+ * oversamplingRate: a value from 0 to 7 that decides about the precision
+ * of the measurement
+ * If this value equals n, the HP303B will perform
+ * 2^n measurements and combine the results
+ * returns: 0 on success
+ * -4 if the HP303B is could not finish its measurement in time
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::measureTempOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate)
+{
+ //Set I2C bus connection
+ m_slaveAddress = slaveAddress;
+
+ //Start measurement
+ int16_t ret = startMeasureTempOnce(oversamplingRate);
+ if(ret!=HP303B__SUCCEEDED)
+ {
+ return ret;
+ }
+
+ //wait until measurement is finished
+ delay(calcBusyTime(0U, m_tempOsr)/HP303B__BUSYTIME_SCALING);
+ delay(HP303B__BUSYTIME_FAILSAFE);
+
+ ret = getSingleResult(result);
+ if(ret!=HP303B__SUCCEEDED)
+ {
+ standby();
+ }
+ return ret;
+}
+
+/**
+ * starts a single temperature measurement
+ *
+ * returns: 0 on success
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::startMeasureTempOnce(void)
+{
+ return startMeasureTempOnce(m_tempOsr);
+}
+
+/**
+ * starts a single temperature measurement
+ * The desired precision can be set with oversamplingRate
+ *
+ * oversamplingRate: a value from 0 to 7 that decides about the precision
+ * of the measurement
+ * If this value equals n, the HP303B will perform
+ * 2^n measurements and combine the results
+ * returns: 0 on success
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::startMeasureTempOnce(uint8_t oversamplingRate)
+{
+ //abort if device is not in idling mode
+ if(m_opMode!=IDLE)
+ {
+ return HP303B__FAIL_TOOBUSY;
+ }
+
+ if(oversamplingRate!=m_tempOsr)
+ {
+ //configuration of oversampling rate
+ if(configTemp(0U, oversamplingRate) != HP303B__SUCCEEDED)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ }
+
+ //set device to temperature measuring mode
+ return setOpMode(0U, 1U, 0U);
+}
+
+/**
+ * performs one pressure measurement and writes result to the given address
+ *
+ * &result: reference to a 32-Bit signed Integer value where the result will be written
+ * It will not be written if result==NULL
+ * returns: 0 on success
+ * -4 if the HP303B is could not finish its measurement in time
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::measurePressureOnce(float &result)
+{
+ return measurePressureOnce(result, m_slaveAddress, m_prsOsr);
+}
+
+/**
+ * performs one pressure measurement and writes result to the given address
+ *
+ * &result: reference to a 32-Bit signed Integer value where the result will be written
+ * It will not be written if result==NULL
+ * returns: 0 on success
+ * -4 if the HP303B is could not finish its measurement in time
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::measurePressureOnce(float &result, uint8_t slaveAddress)
+{
+ return measurePressureOnce(result, slaveAddress, m_prsOsr);
+}
+
+/**
+ * performs one pressure measurement and writes result to the given address
+ * the desired precision can be set with oversamplingRate
+ *
+ * &result: reference to a 32-Bit signed Integer where the result will be written
+ * It will not be written if result==NULL
+ * oversamplingRate: a value from 0 to 7 that decides about the precision
+ * of the measurement
+ * If this value equals n, the HP303B will perform
+ * 2^n measurements and combine the results
+ * returns: 0 on success
+ * -4 if the HP303B is could not finish its measurement in time
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::measurePressureOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate)
+{
+ //Set I2C bus connection
+ m_slaveAddress = slaveAddress;
+
+ //start the measurement
+ int16_t ret = startMeasurePressureOnce(oversamplingRate);
+ if(ret != HP303B__SUCCEEDED)
+ {
+ return ret;
+ }
+
+ //wait until measurement is finished
+ delay(calcBusyTime(0U, m_prsOsr)/HP303B__BUSYTIME_SCALING);
+ delay(HP303B__BUSYTIME_FAILSAFE);
+
+ ret = getSingleResult(result);
+ if(ret!=HP303B__SUCCEEDED)
+ {
+ standby();
+ }
+ return ret;
+}
+
+/**
+ * starts a single pressure measurement
+ *
+ * returns: 0 on success
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::startMeasurePressureOnce(void)
+{
+ return startMeasurePressureOnce(m_prsOsr);
+}
+
+/**
+ * starts a single pressure measurement
+ * The desired precision can be set with oversamplingRate
+ *
+ * oversamplingRate: a value from 0 to 7 that decides about the precision
+ * of the measurement
+ * If this value equals n, the HP303B will perform
+ * 2^n measurements and combine the results
+ * returns: 0 on success
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::startMeasurePressureOnce(uint8_t oversamplingRate)
+{
+ //abort if device is not in idling mode
+ if(m_opMode != IDLE)
+ {
+ return HP303B__FAIL_TOOBUSY;
+ }
+ //configuration of oversampling rate, lowest measure rate to avoid conflicts
+ if(oversamplingRate != m_prsOsr)
+ {
+ if(configPressure(0U, oversamplingRate))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ }
+ //set device to pressure measuring mode
+ return setOpMode(0U, 0U, 1U);
+}
+
+/**
+ * gets the result a single temperature or pressure measurement in °C or Pa
+ *
+ * &result: reference to a 32-Bit signed Integer value where the result will be written
+ * returns: 0 on success
+ * -4 if the HP303B is still busy
+ * -3 if the HP303B is not in command mode
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::getSingleResult(float &result)
+{
+ //read finished bit for current opMode
+ int16_t rdy;
+ switch(m_opMode)
+ {
+ case CMD_TEMP: //temperature
+ rdy = readByteBitfield(HP303B__REG_INFO_TEMP_RDY);
+ break;
+ case CMD_PRS: //pressure
+ rdy = readByteBitfield(HP303B__REG_INFO_PRS_RDY);
+ break;
+ default: //HP303B not in command mode
+ return HP303B__FAIL_TOOBUSY;
+ }
+
+ //read new measurement result
+ switch(rdy)
+ {
+ case HP303B__FAIL_UNKNOWN: //could not read ready flag
+ return HP303B__FAIL_UNKNOWN;
+ case 0: //ready flag not set, measurement still in progress
+ return HP303B__FAIL_UNFINISHED;
+ case 1: //measurement ready, expected case
+ LOLIN_HP303B::Mode oldMode = m_opMode;
+ m_opMode = IDLE; //opcode was automatically reseted by HP303B
+ switch(oldMode)
+ {
+ case CMD_TEMP: //temperature
+ return getTemp(&result); //get and calculate the temperature value
+ case CMD_PRS: //pressure
+ return getPressure(&result); //get and calculate the pressure value
+ default:
+ return HP303B__FAIL_UNKNOWN; //should already be filtered above
+ }
+ }
+ return HP303B__FAIL_UNKNOWN;
+}
+
+/**
+ * starts a continuous temperature measurement
+ * The desired precision can be set with oversamplingRate
+ * The desired number of measurements per second can be set with measureRate
+ *
+ * measureRate: a value from 0 to 7 that decides about
+ * the number of measurements per second
+ * If this value equals n, the HP303B will perform
+ * 2^n measurements per second
+ * oversamplingRate: a value from 0 to 7 that decides about
+ * the precision of the measurements
+ * If this value equals m, the HP303B will perform
+ * 2^m internal measurements and combine the results
+ * to one more exact measurement
+ * returns: 0 on success
+ * -4 if measureRate or oversamplingRate is too high
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ * NOTE: If measure rate is n and oversampling rate is m,
+ * the HP303B performs 2^(n+m) internal measurements per second.
+ * The HP303B cannot operate with high precision and high speed
+ * at the same time.
+ * Consult the datasheet for more information.
+ */
+int16_t LOLIN_HP303B::startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate)
+{
+ //abort if initialization failed
+ if(m_initFail)
+ {
+ return HP303B__FAIL_INIT_FAILED;
+ }
+ //abort if device is not in idling mode
+ if(m_opMode != IDLE)
+ {
+ return HP303B__FAIL_TOOBUSY;
+ }
+ //abort if speed and precision are too high
+ if(calcBusyTime(measureRate, oversamplingRate) >= HP303B__MAX_BUSYTIME)
+ {
+ return HP303B__FAIL_UNFINISHED;
+ }
+ //update precision and measuring rate
+ if(configTemp(measureRate, oversamplingRate))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //enable result FIFO
+ if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //Start measuring in background mode
+ if(setOpMode(1U, 1U, 0U))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ return HP303B__SUCCEEDED;
+}
+
+
+/**
+ * starts a continuous temperature measurement
+ * The desired precision can be set with oversamplingRate
+ * The desired number of measurements per second can be set with measureRate
+ *
+ * measureRate: a value from 0 to 7 that decides about
+ * the number of measurements per second
+ * If this value equals n, the HP303B will perform
+ * 2^n measurements per second
+ * oversamplingRate: a value from 0 to 7 that decides about the precision
+ * of the measurements
+ * If this value equals m, the HP303B will perform
+ * 2^m internal measurements
+ * and combine the results to one more exact measurement
+ * returns: 0 on success
+ * -4 if measureRate or oversamplingRate is too high
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ * NOTE: If measure rate is n and oversampling rate is m,
+ * the HP303B performs 2^(n+m) internal measurements per second.
+ * The HP303B cannot operate with high precision and high speed
+ * at the same time.
+ * Consult the datasheet for more information.
+ */
+int16_t LOLIN_HP303B::startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate)
+{
+ //abort if initialization failed
+ if(m_initFail)
+ {
+ return HP303B__FAIL_INIT_FAILED;
+ }
+ //abort if device is not in idling mode
+ if(m_opMode != IDLE)
+ {
+ return HP303B__FAIL_TOOBUSY;
+ }
+ //abort if speed and precision are too high
+ if(calcBusyTime(measureRate, oversamplingRate) >= HP303B__MAX_BUSYTIME)
+ {
+ return HP303B__FAIL_UNFINISHED;
+ }
+ //update precision and measuring rate
+ if(configPressure(measureRate, oversamplingRate))
+ return HP303B__FAIL_UNKNOWN;
+ //enable result FIFO
+ if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //Start measuring in background mode
+ if(setOpMode(1U, 0U, 1U))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ return HP303B__SUCCEEDED;
+}
+
+/**
+ * starts a continuous temperature and pressure measurement
+ * The desired precision can be set with tempOsr and prsOsr
+ * The desired number of measurements per second can be set with tempMr and prsMr
+ *
+ * tempMr measure rate for temperature
+ * tempOsr oversampling rate for temperature
+ * prsMr measure rate for pressure
+ * prsOsr oversampling rate for pressure
+ * returns: 0 on success
+ * -4 if precision or speed is too high
+ * -3 if the HP303B is already busy
+ * -2 if the object initialization failed
+ * -1 on other fail
+ * NOTE: High precision and speed for both temperature and pressure
+ * can not be reached at the same time.
+ * Estimated time for temperature and pressure measurement
+ * is the sum of both values.
+ * This sum must not be more than 1 second.
+ * Consult the datasheet for more information.
+ */
+int16_t LOLIN_HP303B::startMeasureBothCont(uint8_t tempMr,
+ uint8_t tempOsr,
+ uint8_t prsMr,
+ uint8_t prsOsr)
+{
+ //abort if initialization failed
+ if(m_initFail)
+ {
+ return HP303B__FAIL_INIT_FAILED;
+ }
+ //abort if device is not in idling mode
+ if(m_opMode!=IDLE)
+ {
+ return HP303B__FAIL_TOOBUSY;
+ }
+ //abort if speed and precision are too high
+ if(calcBusyTime(tempMr, tempOsr) + calcBusyTime(prsMr, prsOsr)>=HP303B__MAX_BUSYTIME)
+ {
+ return HP303B__FAIL_UNFINISHED;
+ }
+ //update precision and measuring rate
+ if(configTemp(tempMr, tempOsr))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //update precision and measuring rate
+ if(configPressure(prsMr, prsOsr))
+ return HP303B__FAIL_UNKNOWN;
+ //enable result FIFO
+ if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //Start measuring in background mode
+ if(setOpMode(1U, 1U, 1U))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ return HP303B__SUCCEEDED;
+}
+
+/**
+ * Gets the results from continuous measurements and writes them to given arrays
+ *
+ * *tempBuffer: The start address of the buffer where the temperature results
+ * are written
+ * If this is NULL, no temperature results will be written out
+ * &tempCount: This has to be a reference to a number which contains
+ * the size of the buffer for temperature results.
+ * When the function ends, it will contain
+ * the number of bytes written to the buffer
+ * *prsBuffer: The start address of the buffer where the pressure results
+ * are written
+ * If this is NULL, no pressure results will be written out
+ * &prsCount: This has to be a reference to a number which contains
+ * the size of the buffer for pressure results.
+ * When the function ends, it will contain
+ * the number of bytes written to the buffer
+ * returns: 0 on success
+ * -3 if HP303B is not in background mode
+ * -2 if the object initialization failed
+ * -1 on other fail
+ */
+int16_t LOLIN_HP303B::getContResults(float *tempBuffer,
+ uint8_t &tempCount,
+ float *prsBuffer,
+ uint8_t &prsCount)
+{
+ if(m_initFail)
+ {
+ return HP303B__FAIL_INIT_FAILED;
+ }
+ //abort if device is not in background mode
+ if(!(m_opMode & INVAL_OP_CONT_NONE))
+ {
+ return HP303B__FAIL_TOOBUSY;
+ }
+
+ //prepare parameters for buffer length and count
+ uint8_t tempLen = tempCount;
+ uint8_t prsLen = prsCount;
+ tempCount = 0U;
+ prsCount = 0U;
+
+ //while FIFO is not empty
+ while(readByteBitfield(HP303B__REG_INFO_FIFO_EMPTY) == 0)
+ {
+ float result;
+ //read next result from FIFO
+ int16_t type = getFIFOvalue(&result);
+ switch(type)
+ {
+ case 0: //temperature
+ //calculate compensated pressure value
+ result = calcTemp(result);
+ //if buffer exists and is not full
+ //write result to buffer and increase temperature result counter
+ if(tempBuffer != NULL)
+ {
+ if(tempCount> HP303B__REG_SHIFT_INT_EN_FIFO;
+ tempReady &= HP303B__REG_MASK_INT_EN_TEMP >> HP303B__REG_SHIFT_INT_EN_TEMP;
+ prsReady &= HP303B__REG_MASK_INT_EN_PRS >> HP303B__REG_SHIFT_INT_EN_PRS;
+ //read old value from register
+ int16_t regData = readByte(HP303B__REG_ADR_INT_EN_FIFO);
+ if(regData <0)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ uint8_t toWrite = (uint8_t)regData;
+ //update FIFO enable bit
+ toWrite &= ~HP303B__REG_MASK_INT_EN_FIFO; //clear bit
+ toWrite |= fifoFull << HP303B__REG_SHIFT_INT_EN_FIFO; //set new bit
+ //update TempReady enable bit
+ toWrite &= ~HP303B__REG_MASK_INT_EN_TEMP;
+ toWrite |= tempReady << HP303B__REG_SHIFT_INT_EN_TEMP;
+ //update PrsReady enable bit
+ toWrite &= ~HP303B__REG_MASK_INT_EN_PRS;
+ toWrite |= prsReady << HP303B__REG_SHIFT_INT_EN_PRS;
+ //write updated value to register
+ return writeByte(HP303B__REG_ADR_INT_EN_FIFO, toWrite);
+}
+
+/**
+ * Gets the interrupt status flag of the FIFO
+ *
+ * Returns: 1 if the FIFO is full and caused an interrupt
+ * 0 if the FIFO is not full or FIFO interrupt is disabled
+ * -1 on fail
+ */
+int16_t LOLIN_HP303B::getIntStatusFifoFull(void)
+{
+ return readByteBitfield(HP303B__REG_INFO_INT_FLAG_FIFO);
+}
+
+/**
+ * Gets the interrupt status flag that indicates a finished temperature measurement
+ *
+ * Returns: 1 if a finished temperature measurement caused an interrupt
+ * 0 if there is no finished temperature measurement
+ * or interrupts are disabled
+ * -1 on fail
+ */
+int16_t LOLIN_HP303B::getIntStatusTempReady(void)
+{
+ return readByteBitfield(HP303B__REG_INFO_INT_FLAG_TEMP);
+}
+
+/**
+ * Gets the interrupt status flag that indicates a finished pressure measurement
+ *
+ * Returns: 1 if a finished pressure measurement caused an interrupt
+ * 0 if there is no finished pressure measurement
+ * or interrupts are disabled
+ * -1 on fail
+ */
+int16_t LOLIN_HP303B::getIntStatusPrsReady(void)
+{
+ return readByteBitfield(HP303B__REG_INFO_INT_FLAG_PRS);
+}
+
+/**
+ * Function to fix a hardware problem on some devices
+ * You have this problem if you measure a temperature which is too high (e.g. 60°C when temperature is around 20°C)
+ * Call correctTemp() directly after begin() to fix this issue
+ */
+int16_t LOLIN_HP303B::correctTemp(void)
+{
+ if(m_initFail)
+ {
+ return HP303B__FAIL_INIT_FAILED;
+ }
+ writeByte(0x0E, 0xA5);
+ writeByte(0x0F, 0x96);
+ writeByte(0x62, 0x02);
+ writeByte(0x0E, 0x00);
+ writeByte(0x0F, 0x00);
+
+ //perform a first temperature measurement (again)
+ //the most recent temperature will be saved internally
+ //and used for compensation when calculating pressure
+ float trash;
+ measureTempOnce(trash);
+
+ return HP303B__SUCCEEDED;
+}
+
+
+
+//////// Declaration of private functions starts here ////////
+
+
+/**
+ * Initializes the sensor.
+ * This function has to be called from begin()
+ * and requires a valid bus initialization.
+ */
+uint8_t LOLIN_HP303B::init(void)
+{
+ int16_t prodId = readByteBitfield(HP303B__REG_INFO_PROD_ID);
+ if(prodId != HP303B__PROD_ID)
+ {
+ //Connected device is not a HP303B
+ m_initFail = 1U;
+ return 0U;
+ }
+ m_productID = prodId;
+
+ int16_t revId = readByteBitfield(HP303B__REG_INFO_REV_ID);
+ if(revId < 0)
+ {
+ m_initFail = 1U;
+ return 0U;
+ }
+ m_revisionID = revId;
+
+ //find out which temperature sensor is calibrated with coefficients...
+ int16_t sensor = readByteBitfield(HP303B__REG_INFO_TEMP_SENSORREC);
+ if(sensor < 0)
+ {
+ m_initFail = 1U;
+ return 0U;
+ }
+
+ //...and use this sensor for temperature measurement
+ m_tempSensor = sensor;
+ if(writeByteBitfield((uint8_t)sensor, HP303B__REG_INFO_TEMP_SENSOR) < 0)
+ {
+ m_initFail = 1U;
+ return 0U;
+ }
+
+ //read coefficients
+ if(readcoeffs() < 0)
+ {
+ m_initFail = 1U;
+ return 0U;
+ }
+
+ //set to standby for further configuration
+ standby();
+
+ //set measurement precision and rate to standard values;
+ configTemp(HP303B__TEMP_STD_MR, HP303B__TEMP_STD_OSR);
+ configPressure(HP303B__PRS_STD_MR, HP303B__PRS_STD_OSR);
+
+ //perform a first temperature measurement
+ //the most recent temperature will be saved internally
+ //and used for compensation when calculating pressure
+ float trash;
+ measureTempOnce(trash);
+
+ //make sure the HP303B is in standby after initialization
+ standby();
+
+ // Fix IC with a fuse bit problem, which lead to a wrong temperature
+ // Should not affect ICs without this problem
+ correctTemp();
+
+ return 1U;
+}
+
+
+/**
+ * reads the compensation coefficients from the HP303B
+ * this is called once from init(), which is called from begin()
+ *
+ * returns: 0 on success, -1 on fail
+ */
+int16_t LOLIN_HP303B::readcoeffs(void)
+{
+ uint8_t buffer[HP303B__REG_LEN_COEF];
+ //read COEF registers to buffer
+ int16_t ret = readBlock(HP303B__REG_ADR_COEF,
+ HP303B__REG_LEN_COEF,
+ buffer);
+ //abort if less than REG_LEN_COEF bytes were read
+ if(ret < HP303B__REG_LEN_COEF)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+
+ //compose coefficients from buffer content
+ m_c0Half = ((uint32_t)buffer[0] << 4)
+ | (((uint32_t)buffer[1] >> 4) & 0x0F);
+ //this construction recognizes non-32-bit negative numbers
+ //and converts them to 32-bit negative numbers with 2's complement
+ if(m_c0Half & ((uint32_t)1 << 11))
+ {
+ m_c0Half -= (uint32_t)1 << 12;
+ }
+ //c0 is only used as c0*0.5, so c0_half is calculated immediately
+ m_c0Half = m_c0Half / 2U;
+
+ //now do the same thing for all other coefficients
+ m_c1 = (((uint32_t)buffer[1] & 0x0F) << 8) | (uint32_t)buffer[2];
+ if(m_c1 & ((uint32_t)1 << 11))
+ {
+ m_c1 -= (uint32_t)1 << 12;
+ }
+
+ m_c00 = ((uint32_t)buffer[3] << 12)
+ | ((uint32_t)buffer[4] << 4)
+ | (((uint32_t)buffer[5] >> 4) & 0x0F);
+ if(m_c00 & ((uint32_t)1 << 19))
+ {
+ m_c00 -= (uint32_t)1 << 20;
+ }
+
+ m_c10 = (((uint32_t)buffer[5] & 0x0F) << 16)
+ | ((uint32_t)buffer[6] << 8)
+ | (uint32_t)buffer[7];
+ if(m_c10 & ((uint32_t)1<<19))
+ {
+ m_c10 -= (uint32_t)1 << 20;
+ }
+
+ m_c01 = ((uint32_t)buffer[8] << 8)
+ | (uint32_t)buffer[9];
+ if(m_c01 & ((uint32_t)1 << 15))
+ {
+ m_c01 -= (uint32_t)1 << 16;
+ }
+
+ m_c11 = ((uint32_t)buffer[10] << 8)
+ | (uint32_t)buffer[11];
+ if(m_c11 & ((uint32_t)1 << 15))
+ {
+ m_c11 -= (uint32_t)1 << 16;
+ }
+
+ m_c20 = ((uint32_t)buffer[12] << 8)
+ | (uint32_t)buffer[13];
+ if(m_c20 & ((uint32_t)1 << 15))
+ {
+ m_c20 -= (uint32_t)1 << 16;
+ }
+
+ m_c21 = ((uint32_t)buffer[14] << 8)
+ | (uint32_t)buffer[15];
+ if(m_c21 & ((uint32_t)1 << 15))
+ {
+ m_c21 -= (uint32_t)1 << 16;
+ }
+
+ m_c30 = ((uint32_t)buffer[16] << 8)
+ | (uint32_t)buffer[17];
+ if(m_c30 & ((uint32_t)1 << 15))
+ {
+ m_c30 -= (uint32_t)1 << 16;
+ }
+
+ return HP303B__SUCCEEDED;
+}
+
+/**
+ * Sets the Operation Mode of the HP303B
+ *
+ * background: determines the general behavior of the HP303B
+ * 0 enables command mode (only measure on commands)
+ * 1 enables background mode (continuous work in background)
+ * temperature: set 1 to measure temperature
+ * pressure: set 1 to measure pressure
+ * return: 0 on success, -1 on fail
+ *
+ * NOTE!
+ * You cannot set background to 1 without setting temperature and pressure
+ * You cannot set both temperature and pressure when background mode is disabled
+ */
+int16_t LOLIN_HP303B::setOpMode(uint8_t background, uint8_t temperature, uint8_t pressure)
+{
+ uint8_t opMode = (background & HP303B__LSB) << 2U
+ | (temperature & HP303B__LSB) << 1U
+ | (pressure & HP303B__LSB);
+ return setOpMode(opMode);
+}
+
+
+/**
+ * Sets the Operation Mode of the HP303B
+ *
+ * opMode: the new OpMode that has to be set
+ * return: 0 on success, -1 on fail
+ *
+ * NOTE!
+ * You cannot set background to 1 without setting temperature and pressure
+ * You cannot set both temperature and pressure when background mode is disabled
+ */
+int16_t LOLIN_HP303B::setOpMode(uint8_t opMode)
+{
+ //Filter irrelevant bits
+ opMode &= HP303B__REG_MASK_OPMODE >> HP303B__REG_SHIFT_OPMODE;
+ //Filter invalid OpModes
+ if(opMode == INVAL_OP_CMD_BOTH || opMode == INVAL_OP_CONT_NONE)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //Set OpMode
+ if(writeByte(HP303B__REG_ADR_OPMODE, opMode))
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ m_opMode = (LOLIN_HP303B::Mode)opMode;
+ return HP303B__SUCCEEDED;
+}
+
+/**
+ * Configures temperature measurement
+ *
+ * tempMr: the new measure rate for temperature
+ * This can be a value from 0U to 7U.
+ * Actual measure rate will be 2^tempMr,
+ * so this will be a value from 1 to 128.
+ * tempOsr: the new oversampling rate for temperature
+ * This can be a value from 0U to 7U.
+ * Actual measure rate will be 2^tempOsr,
+ * so this will be a value from 1 to 128.
+ * returns: 0 normally or -1 on fail
+ */
+int16_t LOLIN_HP303B::configTemp(uint8_t tempMr, uint8_t tempOsr)
+{
+ //mask parameters
+ tempMr &= HP303B__REG_MASK_TEMP_MR >> HP303B__REG_SHIFT_TEMP_MR;
+ tempOsr &= HP303B__REG_MASK_TEMP_OSR >> HP303B__REG_SHIFT_TEMP_OSR;
+
+ //set config register according to parameters
+ uint8_t toWrite = tempMr << HP303B__REG_SHIFT_TEMP_MR;
+ toWrite |= tempOsr << HP303B__REG_SHIFT_TEMP_OSR;
+ //using recommended temperature sensor
+ toWrite |= HP303B__REG_MASK_TEMP_SENSOR
+ & (m_tempSensor << HP303B__REG_SHIFT_TEMP_SENSOR);
+ int16_t ret = writeByte(HP303B__REG_ADR_TEMP_MR, toWrite);
+ //abort immediately on fail
+ if(ret != HP303B__SUCCEEDED)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+
+ //set TEMP SHIFT ENABLE if oversampling rate higher than eight(2^3)
+ if(tempOsr > HP303B__OSR_SE)
+ {
+ ret=writeByteBitfield(1U, HP303B__REG_INFO_TEMP_SE);
+ }
+ else
+ {
+ ret=writeByteBitfield(0U, HP303B__REG_INFO_TEMP_SE);
+ }
+
+ if(ret == HP303B__SUCCEEDED)
+ { //save new settings
+ m_tempMr = tempMr;
+ m_tempOsr = tempOsr;
+ }
+ else
+ {
+ //try to rollback on fail avoiding endless recursion
+ //this is to make sure that shift enable and oversampling rate
+ //are always consistent
+ if(tempMr != m_tempMr || tempOsr != m_tempOsr)
+ {
+ configTemp(m_tempMr, m_tempOsr);
+ }
+ }
+ return ret;
+}
+
+/**
+ * Configures pressure measurement
+ *
+ * prsMr: the new measure rate for pressure
+ * This can be a value from 0U to 7U.
+ * Actual measure rate will be 2^prs_mr,
+ * so this will be a value from 1 to 128.
+ * prsOs: the new oversampling rate for temperature
+ * This can be a value from 0U to 7U.
+ * Actual measure rate will be 2^prsOsr,
+ * so this will be a value from 1 to 128.
+ * returns: 0 normally or -1 on fail
+ */
+int16_t LOLIN_HP303B::configPressure(uint8_t prsMr, uint8_t prsOsr)
+{
+ //mask parameters
+ prsMr &= HP303B__REG_MASK_PRS_MR >> HP303B__REG_SHIFT_PRS_MR;
+ prsOsr &= HP303B__REG_MASK_PRS_OSR >> HP303B__REG_SHIFT_PRS_OSR;
+
+ //set config register according to parameters
+ uint8_t toWrite = prsMr << HP303B__REG_SHIFT_PRS_MR;
+ toWrite |= prsOsr << HP303B__REG_SHIFT_PRS_OSR;
+ int16_t ret = writeByte(HP303B__REG_ADR_PRS_MR, toWrite);
+ //abort immediately on fail
+ if(ret != HP303B__SUCCEEDED)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+
+ //set PM SHIFT ENABLE if oversampling rate higher than eight(2^3)
+ if(prsOsr > HP303B__OSR_SE)
+ {
+ ret = writeByteBitfield(1U, HP303B__REG_INFO_PRS_SE);
+ }
+ else
+ {
+ ret = writeByteBitfield(0U, HP303B__REG_INFO_PRS_SE);
+ }
+
+ if(ret == HP303B__SUCCEEDED)
+ { //save new settings
+ m_prsMr = prsMr;
+ m_prsOsr = prsOsr;
+ }
+ else
+ { //try to rollback on fail avoiding endless recursion
+ //this is to make sure that shift enable and oversampling rate
+ //are always consistent
+ if(prsMr != m_prsMr || prsOsr != m_prsOsr)
+ {
+ configPressure(m_prsMr, m_prsOsr);
+ }
+ }
+ return ret;
+}
+
+/**
+ * calculates the time that the HP303B needs for 2^mr measurements
+ * with an oversampling rate of 2^osr
+ *
+ * mr: Measure rate for temperature or pressure
+ * osr: Oversampling rate for temperature or pressure
+ * returns: time that the HP303B needs for this measurement
+ * a value of 10000 equals 1 second
+ * NOTE! The measurement time for temperature and pressure
+ * in sum must not be more than 1 second!
+ * Timing behavior of pressure and temperature sensors
+ * can be considered as equal.
+ */
+uint16_t LOLIN_HP303B::calcBusyTime(uint16_t mr, uint16_t osr)
+{
+ //mask parameters first
+ mr &= HP303B__REG_MASK_TEMP_MR >> HP303B__REG_SHIFT_TEMP_MR;
+ osr &= HP303B__REG_MASK_TEMP_OSR >> HP303B__REG_SHIFT_TEMP_OSR;
+ //formula from datasheet (optimized)
+ return ((uint32_t)20U << mr) + ((uint32_t)16U << (osr + mr));
+}
+
+/**
+ * Gets the next temperature measurement result in degrees of Celsius
+ *
+ * result: address where the result will be written
+ * returns: 0 on success
+ * -1 on fail;
+ */
+int16_t LOLIN_HP303B::getTemp(float *result)
+{
+ unsigned char buffer[3] = {0};
+ //read raw pressure data to buffer
+
+ int16_t i = readBlock(HP303B__REG_ADR_TEMP,
+ HP303B__REG_LEN_TEMP,
+ buffer);
+ if(i != HP303B__REG_LEN_TEMP)
+ {
+ //something went wrong
+ return HP303B__FAIL_UNKNOWN;
+ }
+
+ //compose raw temperature value from buffer
+ float temp = buffer[0] << 16
+ | buffer[1] << 8
+ | buffer[2];
+ //recognize non-32-bit negative numbers
+ //and convert them to 32-bit negative numbers using 2's complement
+ if(temp > 0x7FFFFF)
+ {
+ temp = temp - 0x1000000;
+ }
+
+ //return temperature
+ *result = calcTemp(temp);
+ return HP303B__SUCCEEDED;
+}
+
+/**
+ * Gets the next pressure measurement result in Pa
+ *
+ * result: address where the result will be written
+ * returns: 0 on success
+ * -1 on fail;
+ */
+int16_t LOLIN_HP303B::getPressure(float *result)
+{
+ unsigned char buffer[3] = {0};
+ //read raw pressure data to buffer
+ int16_t i = readBlock(HP303B__REG_ADR_PRS,
+ HP303B__REG_LEN_PRS,
+ buffer);
+ if(i != HP303B__REG_LEN_PRS)
+ {
+ //something went wrong
+ //negative pressure is not allowed
+ return HP303B__FAIL_UNKNOWN;
+ }
+
+ //compose raw pressure value from buffer
+ float prs = buffer[0] << 16 | buffer[1] << 8 | buffer[2];
+ //recognize non-32-bit negative numbers
+ //and convert them to 32-bit negative numbers using 2's complement
+ if(prs > 0x7FFFFF)
+ {
+ prs = prs - 0x1000000;
+ }
+
+ *result = calcPressure(prs);
+ return HP303B__SUCCEEDED;
+}
+
+/**
+ * reads the next raw value from the HP303B FIFO
+ *
+ * value: address where the value will be written
+ * returns: -1 on fail
+ * 0 if result is a temperature raw value
+ * 1 if result is a pressure raw value
+ */
+int16_t LOLIN_HP303B::getFIFOvalue(float *value)
+{
+ //abort on invalid argument
+ if(value == NULL)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+
+ unsigned char buffer[HP303B__REG_LEN_PRS] = {0};
+ //always read from pressure raw value register
+ int16_t i = readBlock(HP303B__REG_ADR_PRS,
+ HP303B__REG_LEN_PRS,
+ buffer);
+ if(i != HP303B__REG_LEN_PRS)
+ {
+ //something went wrong
+ //return error code
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //compose raw pressure value from buffer
+ *value = buffer[0] << 16
+ | buffer[1] << 8
+ | buffer[2];
+ //recognize non-32-bit negative numbers
+ //and convert them to 32-bit negative numbers using 2's complement
+ if(*value > 0x7FFFFF)
+ {
+ *value = *value - 0x1000000;
+ }
+
+ //least significant bit shows measurement type
+ return buffer[2] & HP303B__LSB;
+}
+
+/**
+ * Calculates a scaled and compensated pressure value from raw data
+ * raw: raw temperature value read from HP303B
+ * returns: temperature value in °C
+ */
+float LOLIN_HP303B::calcTemp(float raw)
+{
+ double temp = raw;
+
+ //scale temperature according to scaling table and oversampling
+ temp /= scaling_facts[m_tempOsr];
+
+ //update last measured temperature
+ //it will be used for pressure compensation
+ m_lastTempScal = temp;
+
+ //Calculate compensated temperature
+ temp = m_c0Half + m_c1 * temp;
+
+ //return temperature
+ return (float)temp;
+}
+
+/**
+ * Calculates a scaled and compensated pressure value from raw data
+ * raw: raw pressure value read from HP303B
+ * returns: pressure value in Pa
+ */
+float LOLIN_HP303B::calcPressure(float raw)
+{
+ double prs = raw;
+
+ //scale pressure according to scaling table and oversampling
+ prs /= scaling_facts[m_prsOsr];
+
+ //Calculate compensated pressure
+ prs = m_c00
+ + prs * (m_c10 + prs * (m_c20 + prs * m_c30))
+ + m_lastTempScal * (m_c01 + prs * (m_c11 + prs * m_c21));
+
+ //return pressure
+ return (float)prs;
+}
+
+/**
+ * reads a byte from HP303B
+ *
+ * regAdress: Address that has to be read
+ * returns: register content or -1 on fail
+ */
+int16_t LOLIN_HP303B::readByte(uint8_t regAddress)
+{
+ //delegate to specialized function if HP303B is connected via SPI
+ if(m_SpiI2c==0)
+ {
+ return readByteSPI(regAddress);
+ }
+
+ m_i2cbus->beginTransmission(m_slaveAddress);
+ m_i2cbus->write(regAddress);
+ m_i2cbus->endTransmission(0);
+ //request 1 byte from slave
+ if(m_i2cbus->requestFrom(m_slaveAddress, 1U, 1U) > 0)
+ {
+ return m_i2cbus->read(); //return this byte on success
+ }
+ else
+ {
+ return HP303B__FAIL_UNKNOWN; //if 0 bytes were read successfully
+ }
+}
+
+/**
+ * reads a byte from HP303B via SPI
+ * this function is automatically called by readByte
+ * if HP303B is connected via SPI
+ *
+ * regAdress: Address that has to be read
+ * returns: register content or -1 on fail
+ */
+int16_t LOLIN_HP303B::readByteSPI(uint8_t regAddress)
+{
+ //this function is only made for communication via SPI
+ if(m_SpiI2c != 0)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //mask regAddress
+ regAddress &= ~HP303B__SPI_RW_MASK;
+ //reserve and initialize bus
+ m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ,
+ MSBFIRST,
+ SPI_MODE3));
+ //enable ChipSelect for HP303B
+ digitalWrite(m_chipSelect, LOW);
+ //send address with read command to HP303B
+ m_spibus->transfer(regAddress | HP303B__SPI_READ_CMD);
+ //receive register content from HP303B
+ uint8_t ret = m_spibus->transfer(0xFF); //send a dummy byte while receiving
+ //disable ChipSelect for HP303B
+ digitalWrite(m_chipSelect, HIGH);
+ //close current SPI transaction
+ m_spibus->endTransaction();
+ //return received data
+ return ret;
+}
+
+/**
+ * reads a block from HP303B
+ *
+ * regAdress: Address that has to be read
+ * length: Length of data block
+ * buffer: Buffer where data will be stored
+ * returns: number of bytes that have been read successfully
+ * NOTE! This is not always equal to length
+ * due to rx-Buffer overflow etc.
+ */
+int16_t LOLIN_HP303B::readBlock(uint8_t regAddress, uint8_t length, uint8_t *buffer)
+{
+ //delegate to specialized function if HP303B is connected via SPI
+ if(m_SpiI2c == 0)
+ {
+ return readBlockSPI(regAddress, length, buffer);
+ }
+ //do not read if there is no buffer
+ if(buffer == NULL)
+ {
+ return 0; //0 bytes read successfully
+ }
+
+ m_i2cbus->beginTransmission(m_slaveAddress);
+ m_i2cbus->write(regAddress);
+ m_i2cbus->endTransmission(0);
+ //request length bytes from slave
+ int16_t ret = m_i2cbus->requestFrom(m_slaveAddress, length, 1U);
+ //read all received bytes to buffer
+ for(int16_t count = 0; count < ret; count++)
+ {
+ buffer[count] = m_i2cbus->read();
+ }
+ return ret;
+}
+
+/**
+ * reads a block from HP303B via SPI
+ *
+ * regAdress: Address that has to be read
+ * length: Length of data block
+ * readbuffer: Buffer where data will be stored
+ * returns: number of bytes that have been read successfully
+ * NOTE! This is not always equal to length
+ * due to rx-Buffer overflow etc.
+ */
+int16_t LOLIN_HP303B::readBlockSPI(uint8_t regAddress, uint8_t length, uint8_t *buffer)
+{
+ //this function is only made for communication via SPI
+ if(m_SpiI2c != 0)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //do not read if there is no buffer
+ if(buffer == NULL)
+ {
+ return 0; //0 bytes were read successfully
+ }
+ //mask regAddress
+ regAddress &= ~HP303B__SPI_RW_MASK;
+ //reserve and initialize bus
+ m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ,
+ MSBFIRST,
+ SPI_MODE3));
+ //enable ChipSelect for HP303B
+ digitalWrite(m_chipSelect, LOW);
+ //send address with read command to HP303B
+ m_spibus->transfer(regAddress | HP303B__SPI_READ_CMD);
+
+ //receive register contents from HP303B
+ for(uint8_t count = 0; count < length; count++)
+ {
+ buffer[count] = m_spibus->transfer(0xFF);//send a dummy byte while receiving
+ }
+
+ //disable ChipSelect for HP303B
+ digitalWrite(m_chipSelect, HIGH);
+ //close current SPI transaction
+ m_spibus->endTransaction();
+ //return received data
+ return length;
+}
+
+/**
+ * writes a given byte to a given register of HP303B without checking
+ *
+ * regAdress: Address of the register that has to be updated
+ * data: Byte that will be written to the register
+ * return: 0 if byte was written successfully
+ * or -1 on fail
+ */
+int16_t LOLIN_HP303B::writeByte(uint8_t regAddress, uint8_t data)
+{
+ return writeByte(regAddress, data, 0U);
+}
+
+/**
+ * writes a given byte to a given register of HP303B
+ *
+ * regAdress: Address of the register that has to be updated
+ * data: Byte that will be written to the register
+ * check: If this is true, register content will be read after writing
+ * to check if update was successful
+ * return: 0 if byte was written successfully
+ * or -1 on fail
+ */
+int16_t LOLIN_HP303B::writeByte(uint8_t regAddress, uint8_t data, uint8_t check)
+{
+ //delegate to specialized function if HP303B is connected via SPI
+ if(m_SpiI2c==0)
+ {
+ return writeByteSpi(regAddress, data, check);
+ }
+ m_i2cbus->beginTransmission(m_slaveAddress);
+ m_i2cbus->write(regAddress); //Write Register number to buffer
+ m_i2cbus->write(data); //Write data to buffer
+ if(m_i2cbus->endTransmission() != 0) //Send buffer content to slave
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ else
+ {
+ if(check == 0) return 0; //no checking
+ if(readByte(regAddress) == data) //check if desired by calling function
+ {
+ return HP303B__SUCCEEDED;
+ }
+ else
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ }
+}
+
+/**
+ * writes a given byte to a given register of HP303B via SPI
+ *
+ * regAdress: Address of the register that has to be updated
+ * data: Byte that will be written to the register
+ * check: If this is true, register content will be read after writing
+ * to check if update was successful
+ * return: 0 if byte was written successfully
+ * or -1 on fail
+ */
+int16_t LOLIN_HP303B::writeByteSpi(uint8_t regAddress, uint8_t data, uint8_t check)
+{
+ //this function is only made for communication via SPI
+ if(m_SpiI2c != 0)
+ {
+ return HP303B__FAIL_UNKNOWN;
+ }
+ //mask regAddress
+ regAddress &= ~HP303B__SPI_RW_MASK;
+ //reserve and initialize bus
+ m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ,
+ MSBFIRST,
+ SPI_MODE3));
+ //enable ChipSelect for HP303B
+ digitalWrite(m_chipSelect, LOW);
+ //send address with read command to HP303B
+ m_spibus->transfer(regAddress | HP303B__SPI_WRITE_CMD);
+
+ //write register content from HP303B
+ m_spibus->transfer(data);
+
+ //disable ChipSelect for HP303B
+ digitalWrite(m_chipSelect, HIGH);
+ //close current SPI transaction
+ m_spibus->endTransaction();
+
+ //check if necessary
+ if(check == 0)
+ {
+ //no checking necessary
+ return HP303B__SUCCEEDED;
+ }
+ //checking necessary
+ if(readByte(regAddress) == data)
+ {
+ //check passed
+ return HP303B__SUCCEEDED;
+ }
+ else
+ {
+ //check failed
+ return HP303B__FAIL_UNKNOWN;
+ }
+}
+
+/**
+ * updates some given bits of a given register of HP303B without checking
+ *
+ * regAdress: Address of the register that has to be updated
+ * data: BitValues that will be written to the register
+ * shift: Amount of bits the data byte is shifted (left) before being masked
+ * mask: Masks the bits of the register that have to be updated
+ * Bits with value 1 are updated
+ * Bits with value 0 are not changed
+ * return: 0 if byte was written successfully
+ * or -1 on fail
+ */
+int16_t LOLIN_HP303B::writeByteBitfield(uint8_t data,
+ uint8_t regAddress,
+ uint8_t mask,
+ uint8_t shift)
+{
+ return writeByteBitfield(data, regAddress, mask, shift, 0U);
+}
+
+/**
+ * updates some given bits of a given register of HP303B
+ *
+ * regAdress: Address of the register that has to be updated
+ * data: BitValues that will be written to the register
+ * shift: Amount of bits the data byte is shifted (left) before being masked
+ * mask: Masks the bits of the register that have to be updated
+ * Bits with value 1 are updated
+ * Bits with value 0 are not changed
+ * check: enables/disables check after writing
+ * 0 disables check
+ * if check fails, -1 will be returned
+ * return: 0 if byte was written successfully
+ * or -1 on fail
+ */
+int16_t LOLIN_HP303B::writeByteBitfield(uint8_t data,
+ uint8_t regAddress,
+ uint8_t mask,
+ uint8_t shift,
+ uint8_t check)
+{
+ int16_t old = readByte(regAddress);
+ if(old < 0)
+ {
+ //fail while reading
+ return old;
+ }
+ return writeByte(regAddress, ((uint8_t)old & ~mask)|((data << shift) & mask), check);
+}
+
+/**
+ * reads some given bits of a given register of HP303B
+ *
+ * regAdress: Address of the register that has to be updated
+ * mask: Masks the bits of the register that have to be updated
+ * Bits masked with value 1 are read
+ * Bits masked with value 0 are set 0
+ * shift: Amount of bits the data byte is shifted (right) after being masked
+ * return: read and processed bits
+ * or -1 on fail
+ */
+int16_t LOLIN_HP303B::readByteBitfield(uint8_t regAddress, uint8_t mask, uint8_t shift)
+{
+ int16_t ret = readByte(regAddress);
+ if(ret<0)
+ {
+ return ret;
+ }
+ return (((uint8_t)ret) & mask) >> shift;
+}
diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.h b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h
new file mode 100644
index 000000000..4d04ff6da
--- /dev/null
+++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h
@@ -0,0 +1,146 @@
+#ifndef __LOLIN_HP303B_H
+#define __LOLIN_HP303B_H
+
+#if ARDUINO >= 100
+#include "Arduino.h"
+#else
+#include "WProgram.h"
+#endif
+
+#include
+#include
+#include "util/hp303b_consts.h"
+
+class LOLIN_HP303B
+{
+public:
+ //constructor
+ LOLIN_HP303B(void);
+ //destructor
+ ~LOLIN_HP303B(void);
+ //begin
+ uint8_t begin(TwoWire &bus, uint8_t slaveAddress);
+ uint8_t begin(uint8_t slaveAddress=HP303B__STD_SLAVE_ADDRESS);
+ uint8_t begin(SPIClass &bus, int32_t chipSelect);
+ uint8_t begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire);
+ //end
+ void end(void);
+
+ //general
+ uint8_t getProductId(void);
+ uint8_t getRevisionId(void);
+
+ //Idle Mode
+ int16_t standby(void);
+
+ //Command Mode
+ int16_t measureTempOnce(float &result);
+ int16_t measureTempOnce(float &result, uint8_t slaveAddress);
+ int16_t measureTempOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate);
+ int16_t startMeasureTempOnce(void);
+ int16_t startMeasureTempOnce(uint8_t oversamplingRate);
+ int16_t measurePressureOnce(float &result);
+ int16_t measurePressureOnce(float &result, uint8_t slaveAddress);
+ int16_t measurePressureOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate);
+ int16_t startMeasurePressureOnce(void);
+ int16_t startMeasurePressureOnce(uint8_t oversamplingRate);
+ int16_t getSingleResult(float &result);
+
+ //Background Mode
+ int16_t startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate);
+ int16_t startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate);
+ int16_t startMeasureBothCont(uint8_t tempMr, uint8_t tempOsr, uint8_t prsMr, uint8_t prsOsr);
+ int16_t getContResults(float *tempBuffer, uint8_t &tempCount, float *prsBuffer, uint8_t &prsCount);
+
+ //Interrupt Control
+ int16_t setInterruptPolarity(uint8_t polarity);
+ int16_t setInterruptSources(uint8_t fifoFull, uint8_t tempReady, uint8_t prsReady);
+ int16_t getIntStatusFifoFull(void);
+ int16_t getIntStatusTempReady(void);
+ int16_t getIntStatusPrsReady(void);
+
+ //function to fix a hardware problem on some devices
+ int16_t correctTemp(void);
+
+private:
+ //scaling factor table
+ static const int32_t scaling_facts[HP303B__NUM_OF_SCAL_FACTS];
+
+ //enum for operating mode
+ enum Mode
+ {
+ IDLE = 0x00,
+ CMD_PRS = 0x01,
+ CMD_TEMP = 0x02,
+ INVAL_OP_CMD_BOTH = 0x03, //invalid
+ INVAL_OP_CONT_NONE = 0x04, //invalid
+ CONT_PRS = 0x05,
+ CONT_TMP = 0x06,
+ CONT_BOTH = 0x07
+ };
+ Mode m_opMode;
+
+ //flags
+ uint8_t m_initFail;
+ uint8_t m_productID;
+ uint8_t m_revisionID;
+
+ //settings
+ uint8_t m_tempMr;
+ uint8_t m_tempOsr;
+ uint8_t m_prsMr;
+ uint8_t m_prsOsr;
+ uint8_t m_tempSensor;
+
+ //compensation coefficients
+ int32_t m_c0Half;
+ int32_t m_c1;
+ int32_t m_c00;
+ int32_t m_c10;
+ int32_t m_c01;
+ int32_t m_c11;
+ int32_t m_c20;
+ int32_t m_c21;
+ int32_t m_c30;
+ //last measured scaled temperature
+ //(necessary for pressure compensation)
+ double m_lastTempScal;
+
+ //bus specific
+ uint8_t m_SpiI2c; //0=SPI, 1=I2C
+ //used for I2C
+ TwoWire *m_i2cbus;
+ uint8_t m_slaveAddress;
+ //used for SPI
+ SPIClass *m_spibus;
+ int32_t m_chipSelect;
+ uint8_t m_threeWire;
+
+ //measurement
+ uint8_t init(void);
+ int16_t readcoeffs(void);
+ int16_t setOpMode(uint8_t background, uint8_t temperature, uint8_t pressure);
+ int16_t setOpMode(uint8_t opMode);
+ int16_t configTemp(uint8_t temp_mr, uint8_t temp_osr);
+ int16_t configPressure(uint8_t prs_mr, uint8_t prs_osr);
+ uint16_t calcBusyTime(uint16_t temp_rate, uint16_t temp_osr);
+ int16_t getTemp(float *result);
+ int16_t getPressure(float *result);
+ int16_t getFIFOvalue(float *value);
+ float calcTemp(float raw);
+ float calcPressure(float raw);
+
+ //bus specific
+ int16_t readByte(uint8_t regAddress);
+ int16_t readByteSPI(uint8_t regAddress);
+ int16_t readBlock(uint8_t regAddress, uint8_t length, uint8_t *buffer);
+ int16_t readBlockSPI(uint8_t regAddress, uint8_t length, uint8_t *readbuffer);
+ int16_t writeByte(uint8_t regAddress, uint8_t data);
+ int16_t writeByte(uint8_t regAddress, uint8_t data, uint8_t check);
+ int16_t writeByteSpi(uint8_t regAddress, uint8_t data, uint8_t check);
+ int16_t writeByteBitfield(uint8_t data, uint8_t regAddress, uint8_t mask, uint8_t shift);
+ int16_t writeByteBitfield(uint8_t data, uint8_t regAddress, uint8_t mask, uint8_t shift, uint8_t check);
+ int16_t readByteBitfield(uint8_t regAddress, uint8_t mask, uint8_t shift);
+};
+
+#endif
diff --git a/lib/LOLIN_HP303B/src/util/hp303b_consts.h b/lib/LOLIN_HP303B/src/util/hp303b_consts.h
new file mode 100644
index 000000000..f93629e93
--- /dev/null
+++ b/lib/LOLIN_HP303B/src/util/hp303b_consts.h
@@ -0,0 +1,258 @@
+/**
+ *
+ *
+ */
+
+#ifndef __HP303B_CONSTS_H_
+#define __HP303B_CONSTS_H_
+
+
+ //general Constants
+#define HP303B__PROD_ID 0U
+#define HP303B__STD_SLAVE_ADDRESS 0x77U
+#define HP303B__SPI_WRITE_CMD 0x00U
+#define HP303B__SPI_READ_CMD 0x80U
+#define HP303B__SPI_RW_MASK 0x80U
+#define HP303B__SPI_MAX_FREQ 100000U
+
+#define HP303B__LSB 0x01U
+
+#define HP303B__TEMP_STD_MR 2U
+#define HP303B__TEMP_STD_OSR 3U
+#define HP303B__PRS_STD_MR 2U
+#define HP303B__PRS_STD_OSR 3U
+#define HP303B__OSR_SE 3U
+//we use 0.1 mS units for time calculations, so 10 units are one millisecond
+#define HP303B__BUSYTIME_SCALING 10U
+// DPS310 has 10 milliseconds of spare time for each synchronous measurement / per second for asynchronous measurements
+// this is for error prevention on friday-afternoon-products :D
+// you can set it to 0 if you dare, but there is no warranty that it will still work
+#define HP303B__BUSYTIME_FAILSAFE 10U
+#define HP303B__MAX_BUSYTIME ((1000U-HP303B__BUSYTIME_FAILSAFE)*HP303B__BUSYTIME_SCALING)
+#define HP303B__NUM_OF_SCAL_FACTS 8
+
+#define HP303B__SUCCEEDED 0
+#define HP303B__FAIL_UNKNOWN -1
+#define HP303B__FAIL_INIT_FAILED -2
+#define HP303B__FAIL_TOOBUSY -3
+#define HP303B__FAIL_UNFINISHED -4
+
+
+ //Constants for register manipulation
+ //SPI mode (3 or 4 wire)
+#define HP303B__REG_ADR_SPI3W 0x09U
+#define HP303B__REG_CONTENT_SPI3W 0x01U
+
+
+ //product id
+#define HP303B__REG_INFO_PROD_ID HP303B__REG_ADR_PROD_ID, \
+ HP303B__REG_MASK_PROD_ID, \
+ HP303B__REG_SHIFT_PROD_ID
+#define HP303B__REG_ADR_PROD_ID 0x0DU
+#define HP303B__REG_MASK_PROD_ID 0x0FU
+#define HP303B__REG_SHIFT_PROD_ID 0U
+
+ //revision id
+#define HP303B__REG_INFO_REV_ID HP303B__REG_ADR_REV_ID, \
+ HP303B__REG_MASK_REV_ID, \
+ HP303B__REG_SHIFT_REV_ID
+#define HP303B__REG_ADR_REV_ID 0x0DU
+#define HP303B__REG_MASK_REV_ID 0xF0U
+#define HP303B__REG_SHIFT_REV_ID 4U
+
+ //operating mode
+#define HP303B__REG_INFO_OPMODE HP303B__REG_ADR_OPMODE, \
+ HP303B__REG_MASK_OPMODE, \
+ HP303B__REG_SHIFT_OPMODE
+#define HP303B__REG_ADR_OPMODE 0x08U
+#define HP303B__REG_MASK_OPMODE 0x07U
+#define HP303B__REG_SHIFT_OPMODE 0U
+
+
+ //temperature measure rate
+#define HP303B__REG_INFO_TEMP_MR HP303B__REG_ADR_TEMP_MR, \
+ HP303B__REG_MASK_TEMP_MR, \
+ HP303B__REG_SHIFT_TEMP_MR
+#define HP303B__REG_ADR_TEMP_MR 0x07U
+#define HP303B__REG_MASK_TEMP_MR 0x70U
+#define HP303B__REG_SHIFT_TEMP_MR 4U
+
+ //temperature oversampling rate
+#define HP303B__REG_INFO_TEMP_OSR HP303B__REG_ADR_TEMP_OSR, \
+ HP303B__REG_MASK_TEMP_OSR, \
+ HP303B__REG_SHIFT_TEMP_OSR
+#define HP303B__REG_ADR_TEMP_OSR 0x07U
+#define HP303B__REG_MASK_TEMP_OSR 0x07U
+#define HP303B__REG_SHIFT_TEMP_OSR 0U
+
+ //temperature sensor
+#define HP303B__REG_INFO_TEMP_SENSOR HP303B__REG_ADR_TEMP_SENSOR, \
+ HP303B__REG_MASK_TEMP_SENSOR, \
+ HP303B__REG_SHIFT_TEMP_SENSOR
+#define HP303B__REG_ADR_TEMP_SENSOR 0x07U
+#define HP303B__REG_MASK_TEMP_SENSOR 0x80U
+#define HP303B__REG_SHIFT_TEMP_SENSOR 7U
+
+ //temperature sensor recommendation
+#define HP303B__REG_INFO_TEMP_SENSORREC HP303B__REG_ADR_TEMP_SENSORREC, \
+ HP303B__REG_MASK_TEMP_SENSORREC, \
+ HP303B__REG_SHIFT_TEMP_SENSORREC
+#define HP303B__REG_ADR_TEMP_SENSORREC 0x28U
+#define HP303B__REG_MASK_TEMP_SENSORREC 0x80U
+#define HP303B__REG_SHIFT_TEMP_SENSORREC 7U
+
+ //temperature shift enable (if temp_osr>3)
+#define HP303B__REG_INFO_TEMP_SE HP303B__REG_ADR_TEMP_SE, \
+ HP303B__REG_MASK_TEMP_SE, \
+ HP303B__REG_SHIFT_TEMP_SE
+#define HP303B__REG_ADR_TEMP_SE 0x09U
+#define HP303B__REG_MASK_TEMP_SE 0x08U
+#define HP303B__REG_SHIFT_TEMP_SE 3U
+
+
+ //pressure measure rate
+#define HP303B__REG_INFO_PRS_MR HP303B__REG_ADR_PRS_MR, \
+ HP303B__REG_MASK_PRS_MR, \
+ HP303B__REG_SHIFT_PRS_MR
+#define HP303B__REG_ADR_PRS_MR 0x06U
+#define HP303B__REG_MASK_PRS_MR 0x70U
+#define HP303B__REG_SHIFT_PRS_MR 4U
+
+ //pressure oversampling rate
+#define HP303B__REG_INFO_PRS_OSR HP303B__REG_ADR_PRS_OSR, \
+ HP303B__REG_MASK_PRS_OSR, \
+ HP303B__REG_SHIFT_PRS_OSR
+#define HP303B__REG_ADR_PRS_OSR 0x06U
+#define HP303B__REG_MASK_PRS_OSR 0x07U
+#define HP303B__REG_SHIFT_PRS_OSR 0U
+
+ //pressure shift enable (if prs_osr>3)
+#define HP303B__REG_INFO_PRS_SE HP303B__REG_ADR_PRS_SE, \
+ HP303B__REG_MASK_PRS_SE, \
+ HP303B__REG_SHIFT_PRS_SE
+#define HP303B__REG_ADR_PRS_SE 0x09U
+#define HP303B__REG_MASK_PRS_SE 0x04U
+#define HP303B__REG_SHIFT_PRS_SE 2U
+
+
+ //temperature ready flag
+#define HP303B__REG_INFO_TEMP_RDY HP303B__REG_ADR_TEMP_RDY, \
+ HP303B__REG_MASK_TEMP_RDY, \
+ HP303B__REG_SHIFT_TEMP_RDY
+#define HP303B__REG_ADR_TEMP_RDY 0x08U
+#define HP303B__REG_MASK_TEMP_RDY 0x20U
+#define HP303B__REG_SHIFT_TEMP_RDY 5U
+
+ //pressure ready flag
+#define HP303B__REG_INFO_PRS_RDY HP303B__REG_ADR_PRS_RDY, \
+ HP303B__REG_MASK_PRS_RDY, \
+ HP303B__REG_SHIFT_PRS_RDY
+#define HP303B__REG_ADR_PRS_RDY 0x08U
+#define HP303B__REG_MASK_PRS_RDY 0x10U
+#define HP303B__REG_SHIFT_PRS_RDY 4U
+
+ //pressure value
+#define HP303B__REG_ADR_PRS 0x00U
+#define HP303B__REG_LEN_PRS 3U
+
+ //temperature value
+#define HP303B__REG_ADR_TEMP 0x03U
+#define HP303B__REG_LEN_TEMP 3U
+
+ //compensation coefficients
+#define HP303B__REG_ADR_COEF 0x10U
+#define HP303B__REG_LEN_COEF 18
+
+
+ //FIFO enable
+#define HP303B__REG_INFO_FIFO_EN HP303B__REG_ADR_FIFO_EN, \
+ HP303B__REG_MASK_FIFO_EN, \
+ HP303B__REG_SHIFT_FIFO_EN
+#define HP303B__REG_ADR_FIFO_EN 0x09U
+#define HP303B__REG_MASK_FIFO_EN 0x02U
+#define HP303B__REG_SHIFT_FIFO_EN 1U
+
+ //FIFO flush
+#define HP303B__REG_INFO_FIFO_FL HP303B__REG_ADR_FIFO_EN, \
+ HP303B__REG_MASK_FIFO_EN, \
+ HP303B__REG_SHIFT_FIFO_EN
+#define HP303B__REG_ADR_FIFO_FL 0x0CU
+#define HP303B__REG_MASK_FIFO_FL 0x80U
+#define HP303B__REG_SHIFT_FIFO_FL 7U
+
+ //FIFO empty
+#define HP303B__REG_INFO_FIFO_EMPTY HP303B__REG_ADR_FIFO_EMPTY, \
+ HP303B__REG_MASK_FIFO_EMPTY, \
+ HP303B__REG_SHIFT_FIFO_EMPTY
+#define HP303B__REG_ADR_FIFO_EMPTY 0x0BU
+#define HP303B__REG_MASK_FIFO_EMPTY 0x01U
+#define HP303B__REG_SHIFT_FIFO_EMPTY 0U
+
+ //FIFO full
+#define HP303B__REG_INFO_FIFO_FULL HP303B__REG_ADR_FIFO_FULL, \
+ HP303B__REG_MASK_FIFO_FULL, \
+ HP303B__REG_SHIFT_FIFO_FULL
+#define HP303B__REG_ADR_FIFO_FULL 0x0BU
+#define HP303B__REG_MASK_FIFO_FULL 0x02U
+#define HP303B__REG_SHIFT_FIFO_FULL 1U
+
+
+ //INT HL
+#define HP303B__REG_INFO_INT_HL HP303B__REG_ADR_INT_HL, \
+ HP303B__REG_MASK_INT_HL, \
+ HP303B__REG_SHIFT_INT_HL
+#define HP303B__REG_ADR_INT_HL 0x09U
+#define HP303B__REG_MASK_INT_HL 0x80U
+#define HP303B__REG_SHIFT_INT_HL 7U
+
+ //INT FIFO enable
+#define HP303B__REG_INFO_INT_EN_FIFO HP303B__REG_ADR_INT_EN_FIFO, \
+ HP303B__REG_MASK_INT_EN_FIFO, \
+ HP303B__REG_SHIFT_INT_EN_FIFO
+#define HP303B__REG_ADR_INT_EN_FIFO 0x09U
+#define HP303B__REG_MASK_INT_EN_FIFO 0x40U
+#define HP303B__REG_SHIFT_INT_EN_FIFO 6U
+
+ //INT TEMP enable
+#define HP303B__REG_INFO_INT_EN_TEMP HP303B__REG_ADR_INT_EN_TEMP, \
+ HP303B__REG_MASK_INT_EN_TEMP, \
+ HP303B__REG_SHIFT_INT_EN_TEMP
+#define HP303B__REG_ADR_INT_EN_TEMP 0x09U
+#define HP303B__REG_MASK_INT_EN_TEMP 0x20U
+#define HP303B__REG_SHIFT_INT_EN_TEMP 5U
+
+ //INT PRS enable
+#define HP303B__REG_INFO_INT_EN_PRS HP303B__REG_ADR_INT_EN_PRS, \
+ HP303B__REG_MASK_INT_EN_PRS, \
+ HP303B__REG_SHIFT_INT_EN_PRS
+#define HP303B__REG_ADR_INT_EN_PRS 0x09U
+#define HP303B__REG_MASK_INT_EN_PRS 0x10U
+#define HP303B__REG_SHIFT_INT_EN_PRS 4U
+
+ //INT FIFO flag
+#define HP303B__REG_INFO_INT_FLAG_FIFO HP303B__REG_ADR_INT_FLAG_FIFO, \
+ HP303B__REG_MASK_INT_FLAG_FIFO, \
+ HP303B__REG_SHIFT_INT_FLAG_FIFO
+#define HP303B__REG_ADR_INT_FLAG_FIFO 0x0AU
+#define HP303B__REG_MASK_INT_FLAG_FIFO 0x04U
+#define HP303B__REG_SHIFT_INT_FLAG_FIFO 2U
+
+ //INT TMP flag
+#define HP303B__REG_INFO_INT_FLAG_TEMP HP303B__REG_ADR_INT_FLAG_TEMP, \
+ HP303B__REG_MASK_INT_FLAG_TEMP, \
+ HP303B__REG_SHIFT_INT_FLAG_TEMP
+#define HP303B__REG_ADR_INT_FLAG_TEMP 0x0AU
+#define HP303B__REG_MASK_INT_FLAG_TEMP 0x02U
+#define HP303B__REG_SHIFT_INT_FLAG_TEMP 1U
+
+ //INT PRS flag
+#define HP303B__REG_INFO_INT_FLAG_PRS HP303B__REG_ADR_INT_FLAG_PRS, \
+ HP303B__REG_MASK_INT_FLAG_PRS, \
+ HP303B__REG_SHIFT_INT_FLAG_PRS
+#define HP303B__REG_ADR_INT_FLAG_PRS 0x0AU
+#define HP303B__REG_MASK_INT_FLAG_PRS 0x01U
+#define HP303B__REG_SHIFT_INT_FLAG_PRS 0U
+
+
+
+#endif /* DPS310_CONSTS_H_ */
diff --git a/lib/LibTeleinfo/library.json b/lib/LibTeleinfo/library.json
index 70f368653..a93105e61 100755
--- a/lib/LibTeleinfo/library.json
+++ b/lib/LibTeleinfo/library.json
@@ -1,6 +1,6 @@
{
"name": "LibTeleinfo",
- "version": "1.1.1",
+ "version": "1.1.2",
"keywords": "teleinfo, french, meter, power, erdf, linky, tic",
"description": "Decoder for Teleinfo (aka TIC) from French smart power meters",
"repository":
diff --git a/lib/LibTeleinfo/library.properties b/lib/LibTeleinfo/library.properties
index fdcee4a25..7cfc9a635 100755
--- a/lib/LibTeleinfo/library.properties
+++ b/lib/LibTeleinfo/library.properties
@@ -1,5 +1,5 @@
name=LibTeleinfo
-version=1.1.1
+version=1.1.2
author=Charles-Henri Hallard
maintainer=Charles-Henri Hallard
sentence=Decoder for Teleinfo (aka TIC) from French smart power meters
diff --git a/lib/LibTeleinfo/src/LibTeleinfo.cpp b/lib/LibTeleinfo/src/LibTeleinfo.cpp
index 8d34e89d1..588555831 100644
--- a/lib/LibTeleinfo/src/LibTeleinfo.cpp
+++ b/lib/LibTeleinfo/src/LibTeleinfo.cpp
@@ -426,7 +426,45 @@ char * TInfo::valueGet(char * name, char * value)
if (me->value) {
// copy to dest buffer
uint8_t lgvalue = strlen(me->value);
- strlcpy(value, me->value , lgvalue );
+ strlcpy(value, me->value , lgvalue + 1 );
+ return ( value );
+ }
+ }
+ }
+ }
+ // not found
+ return ( NULL);
+}
+
+/* ======================================================================
+Function: valueGet_P
+Purpose : get value of one element
+Input : Pointer to the label name
+ pointer to the value where we fill data
+Output : pointer to the value where we filled data NULL is not found
+====================================================================== */
+char * TInfo::valueGet_P(const char * name, char * value)
+{
+ // Get our linked list
+ ValueList * me = &_valueslist;
+ uint8_t lgname = strlen_P(name);
+
+ // Got one and all seems good ?
+ if (me && lgname) {
+
+ // Loop thru the node
+ while (me->next) {
+
+ // go to next node
+ me = me->next;
+
+ // Check if we match this LABEL
+ if (lgname==strlen(me->name) && strncmp_P(me->name, name, lgname)==0) {
+ // this one has a value ?
+ if (me->value) {
+ // copy to dest buffer
+ uint8_t lgvalue = strlen(me->value);
+ strlcpy(value, me->value , lgvalue + 1 );
return ( value );
}
}
@@ -661,7 +699,7 @@ ValueList * TInfo::checkLine(char * pline)
return NULL;
// Get our own working copy
- strlcpy( buff, _recv_buff, len+1);
+ strlcpy( buff, pline, len+1);
p = &buff[0];
ptok = p; // for sure we start with token name
diff --git a/lib/LibTeleinfo/src/LibTeleinfo.h b/lib/LibTeleinfo/src/LibTeleinfo.h
index a9725b26a..5b43523c7 100755
--- a/lib/LibTeleinfo/src/LibTeleinfo.h
+++ b/lib/LibTeleinfo/src/LibTeleinfo.h
@@ -117,6 +117,7 @@ class TInfo
ValueList * getList(void);
uint8_t valuesDump(void);
char * valueGet(char * name, char * value);
+ char * valueGet_P(const char * name, char * value);
boolean listDelete();
unsigned char calcChecksum(char *etiquette, char *valeur) ;
diff --git a/lib/esp-knx-ip-0.5.2/esp-knx-ip.h b/lib/esp-knx-ip-0.5.2/esp-knx-ip.h
index ea711825f..7150706bb 100644
--- a/lib/esp-knx-ip-0.5.2/esp-knx-ip.h
+++ b/lib/esp-knx-ip-0.5.2/esp-knx-ip.h
@@ -398,7 +398,7 @@ typedef struct __callback_assignment
} callback_assignment_t;
// FastPrecisePowf from tasmota/support_float.ino
-extern float FastPrecisePowf(const float x, const float y);
+//extern float FastPrecisePowf(const float x, const float y);
class ESPKNXIP {
public:
@@ -567,7 +567,7 @@ class ESPKNXIP {
callback_assignment_id_t __callback_register_assignment(address_t address, callback_id_t id);
void __callback_delete_assignment(callback_assignment_id_t id);
- static inline float pow(float a, float b) { return FastPrecisePowf(a, b); }
+ //static inline float pow(float a, float b) { return FastPrecisePowf(a, b); }
ESP8266WebServer *server;
address_t physaddr;
diff --git a/lib/mbedtls/README.md b/lib/mbedtls/README.md
new file mode 100644
index 000000000..f5df7f0c8
--- /dev/null
+++ b/lib/mbedtls/README.md
@@ -0,0 +1 @@
+Stripped down library for aes-ccm-decryption in the MI_NRF24.ino.
\ No newline at end of file
diff --git a/lib/mbedtls/include/mbedtls/aes.h b/lib/mbedtls/include/mbedtls/aes.h
new file mode 100644
index 000000000..a36e825a2
--- /dev/null
+++ b/lib/mbedtls/include/mbedtls/aes.h
@@ -0,0 +1,297 @@
+/**
+ * \file aes.h
+ *
+ * \brief AES block cipher
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_AES_H
+#define MBEDTLS_AES_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include
+#include
+
+/* padlock.c and aesni.c rely on these values! */
+#define MBEDTLS_AES_ENCRYPT 1
+#define MBEDTLS_AES_DECRYPT 0
+
+#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
+#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
+
+#if !defined(MBEDTLS_AES_ALT)
+// Regular implementation
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief AES context structure
+ *
+ * \note buf is able to hold 32 extra bytes, which can be used:
+ * - for alignment purposes if VIA padlock is used, and/or
+ * - to simplify key expansion in the 256-bit case by
+ * generating an extra round key
+ */
+typedef struct
+{
+ int nr; /*!< number of rounds */
+ uint32_t *rk; /*!< AES round keys */
+ uint32_t buf[68]; /*!< unaligned data */
+}
+mbedtls_aes_context;
+
+/**
+ * \brief Initialize AES context
+ *
+ * \param ctx AES context to be initialized
+ */
+void mbedtls_aes_init( mbedtls_aes_context *ctx );
+
+/**
+ * \brief Clear AES context
+ *
+ * \param ctx AES context to be cleared
+ */
+void mbedtls_aes_free( mbedtls_aes_context *ctx );
+
+/**
+ * \brief AES key schedule (encryption)
+ *
+ * \param ctx AES context to be initialized
+ * \param key encryption key
+ * \param keybits must be 128, 192 or 256
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH
+ */
+int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits );
+
+/**
+ * \brief AES key schedule (decryption)
+ *
+ * \param ctx AES context to be initialized
+ * \param key decryption key
+ * \param keybits must be 128, 192 or 256
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH
+ */
+int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits );
+
+/**
+ * \brief AES-ECB block encryption/decryption
+ *
+ * \param ctx AES context
+ * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
+ * \param input 16-byte input block
+ * \param output 16-byte output block
+ *
+ * \return 0 if successful
+ */
+int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx,
+ int mode,
+ const unsigned char input[16],
+ unsigned char output[16] );
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/**
+ * \brief AES-CBC buffer encryption/decryption
+ * Length should be a multiple of the block
+ * size (16 bytes)
+ *
+ * \note Upon exit, the content of the IV is updated so that you can
+ * call the function same function again on the following
+ * block(s) of data and get the same result as if it was
+ * encrypted in one call. This allows a "streaming" usage.
+ * If on the other hand you need to retain the contents of the
+ * IV, you should either save it manually or use the cipher
+ * module instead.
+ *
+ * \param ctx AES context
+ * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
+ * \param length length of the input data
+ * \param iv initialization vector (updated after use)
+ * \param input buffer holding the input data
+ * \param output buffer holding the output data
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH
+ */
+int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output );
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+/**
+ * \brief AES-CFB128 buffer encryption/decryption.
+ *
+ * Note: Due to the nature of CFB you should use the same key schedule for
+ * both encryption and decryption. So a context initialized with
+ * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
+ *
+ * \note Upon exit, the content of the IV is updated so that you can
+ * call the function same function again on the following
+ * block(s) of data and get the same result as if it was
+ * encrypted in one call. This allows a "streaming" usage.
+ * If on the other hand you need to retain the contents of the
+ * IV, you should either save it manually or use the cipher
+ * module instead.
+ *
+ * \param ctx AES context
+ * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
+ * \param length length of the input data
+ * \param iv_off offset in IV (updated after use)
+ * \param iv initialization vector (updated after use)
+ * \param input buffer holding the input data
+ * \param output buffer holding the output data
+ *
+ * \return 0 if successful
+ */
+int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ size_t *iv_off,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output );
+
+/**
+ * \brief AES-CFB8 buffer encryption/decryption.
+ *
+ * Note: Due to the nature of CFB you should use the same key schedule for
+ * both encryption and decryption. So a context initialized with
+ * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
+ *
+ * \note Upon exit, the content of the IV is updated so that you can
+ * call the function same function again on the following
+ * block(s) of data and get the same result as if it was
+ * encrypted in one call. This allows a "streaming" usage.
+ * If on the other hand you need to retain the contents of the
+ * IV, you should either save it manually or use the cipher
+ * module instead.
+ *
+ * \param ctx AES context
+ * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
+ * \param length length of the input data
+ * \param iv initialization vector (updated after use)
+ * \param input buffer holding the input data
+ * \param output buffer holding the output data
+ *
+ * \return 0 if successful
+ */
+int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output );
+#endif /*MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+/**
+ * \brief AES-CTR buffer encryption/decryption
+ *
+ * Warning: You have to keep the maximum use of your counter in mind!
+ *
+ * Note: Due to the nature of CTR you should use the same key schedule for
+ * both encryption and decryption. So a context initialized with
+ * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
+ *
+ * \param ctx AES context
+ * \param length The length of the data
+ * \param nc_off The offset in the current stream_block (for resuming
+ * within current cipher stream). The offset pointer to
+ * should be 0 at the start of a stream.
+ * \param nonce_counter The 128-bit nonce and counter.
+ * \param stream_block The saved stream-block for resuming. Is overwritten
+ * by the function.
+ * \param input The input data stream
+ * \param output The output data stream
+ *
+ * \return 0 if successful
+ */
+int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx,
+ size_t length,
+ size_t *nc_off,
+ unsigned char nonce_counter[16],
+ unsigned char stream_block[16],
+ const unsigned char *input,
+ unsigned char *output );
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+/**
+ * \brief Internal AES block encryption function
+ * (Only exposed to allow overriding it,
+ * see MBEDTLS_AES_ENCRYPT_ALT)
+ *
+ * \param ctx AES context
+ * \param input Plaintext block
+ * \param output Output (ciphertext) block
+ */
+void mbedtls_aes_encrypt( mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16] );
+
+/**
+ * \brief Internal AES block decryption function
+ * (Only exposed to allow overriding it,
+ * see MBEDTLS_AES_DECRYPT_ALT)
+ *
+ * \param ctx AES context
+ * \param input Ciphertext block
+ * \param output Output (plaintext) block
+ */
+void mbedtls_aes_decrypt( mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16] );
+
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MBEDTLS_AES_ALT */
+#include "aes_alt.h"
+#endif /* MBEDTLS_AES_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ */
+int mbedtls_aes_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* aes.h */
diff --git a/lib/mbedtls/include/mbedtls/ccm.h b/lib/mbedtls/include/mbedtls/ccm.h
new file mode 100644
index 000000000..ef75839ba
--- /dev/null
+++ b/lib/mbedtls/include/mbedtls/ccm.h
@@ -0,0 +1,141 @@
+/**
+ * \file ccm.h
+ *
+ * \brief Counter with CBC-MAC (CCM) for 128-bit block ciphers
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_CCM_H
+#define MBEDTLS_CCM_H
+
+#include "cipher.h"
+
+#define MBEDTLS_ERR_CCM_BAD_INPUT -0x000D /**< Bad input parameters to function. */
+#define MBEDTLS_ERR_CCM_AUTH_FAILED -0x000F /**< Authenticated decryption failed. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief CCM context structure
+ */
+typedef struct {
+ mbedtls_cipher_context_t cipher_ctx; /*!< cipher context used */
+}
+mbedtls_ccm_context;
+
+/**
+ * \brief Initialize CCM context (just makes references valid)
+ * Makes the context ready for mbedtls_ccm_setkey() or
+ * mbedtls_ccm_free().
+ *
+ * \param ctx CCM context to initialize
+ */
+void mbedtls_ccm_init( mbedtls_ccm_context *ctx );
+
+/**
+ * \brief CCM initialization (encryption and decryption)
+ *
+ * \param ctx CCM context to be initialized
+ * \param cipher cipher to use (a 128-bit block cipher)
+ * \param key encryption key
+ * \param keybits key size in bits (must be acceptable by the cipher)
+ *
+ * \return 0 if successful, or a cipher specific error code
+ */
+int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
+ mbedtls_cipher_id_t cipher,
+ const unsigned char *key,
+ unsigned int keybits );
+
+/**
+ * \brief Free a CCM context and underlying cipher sub-context
+ *
+ * \param ctx CCM context to free
+ */
+void mbedtls_ccm_free( mbedtls_ccm_context *ctx );
+
+/**
+ * \brief CCM buffer encryption
+ *
+ * \param ctx CCM context
+ * \param length length of the input data in bytes
+ * \param iv nonce (initialization vector)
+ * \param iv_len length of IV in bytes
+ * must be 2, 3, 4, 5, 6, 7 or 8
+ * \param add additional data
+ * \param add_len length of additional data in bytes
+ * must be less than 2^16 - 2^8
+ * \param input buffer holding the input data
+ * \param output buffer for holding the output data
+ * must be at least 'length' bytes wide
+ * \param tag buffer for holding the tag
+ * \param tag_len length of the tag to generate in bytes
+ * must be 4, 6, 8, 10, 14 or 16
+ *
+ * \note The tag is written to a separate buffer. To get the tag
+ * concatenated with the output as in the CCM spec, use
+ * tag = output + length and make sure the output buffer is
+ * at least length + tag_len wide.
+ *
+ * \return 0 if successful
+ */
+int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, unsigned char *output,
+ unsigned char *tag, size_t tag_len );
+
+/**
+ * \brief CCM buffer authenticated decryption
+ *
+ * \param ctx CCM context
+ * \param length length of the input data
+ * \param iv initialization vector
+ * \param iv_len length of IV
+ * \param add additional data
+ * \param add_len length of additional data
+ * \param input buffer holding the input data
+ * \param output buffer for holding the output data
+ * \param tag buffer holding the tag
+ * \param tag_len length of the tag
+ *
+ * \return 0 if successful and authenticated,
+ * MBEDTLS_ERR_CCM_AUTH_FAILED if tag does not match
+ */
+int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, unsigned char *output,
+ const unsigned char *tag, size_t tag_len );
+
+#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ */
+int mbedtls_ccm_self_test( int verbose );
+#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBEDTLS_CCM_H */
diff --git a/lib/mbedtls/include/mbedtls/check_config.h b/lib/mbedtls/include/mbedtls/check_config.h
new file mode 100644
index 000000000..fe86c1e8d
--- /dev/null
+++ b/lib/mbedtls/include/mbedtls/check_config.h
@@ -0,0 +1,628 @@
+/**
+ * \file check_config.h
+ *
+ * \brief Consistency checks for configuration options
+ *
+ * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+/*
+ * It is recommended to include this file from your config.h
+ * in order to catch dependency issues early.
+ */
+
+#ifndef MBEDTLS_CHECK_CONFIG_H
+#define MBEDTLS_CHECK_CONFIG_H
+
+/*
+ * We assume CHAR_BIT is 8 in many places. In practice, this is true on our
+ * target platforms, so not an issue, but let's just be extra sure.
+ */
+#include
+#if CHAR_BIT != 8
+#error "mbed TLS requires a platform with 8-bit chars"
+#endif
+
+#if defined(_WIN32)
+#if !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_C is required on Windows"
+#endif
+
+/* Fix the config here. Not convenient to put an #ifdef _WIN32 in config.h as
+ * it would confuse config.pl. */
+#if !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && \
+ !defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
+#define MBEDTLS_PLATFORM_SNPRINTF_ALT
+#endif
+#endif /* _WIN32 */
+
+#if defined(TARGET_LIKE_MBED) && \
+ ( defined(MBEDTLS_NET_C) || defined(MBEDTLS_TIMING_C) )
+#error "The NET and TIMING modules are not available for mbed OS - please use the network and timing functions provided by mbed OS"
+#endif
+
+#if defined(MBEDTLS_DEPRECATED_WARNING) && \
+ !defined(__GNUC__) && !defined(__clang__)
+#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang"
+#endif
+
+#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_HAVE_TIME)
+#error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense"
+#endif
+
+#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM)
+#error "MBEDTLS_AESNI_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C)
+#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_DHM_C) && !defined(MBEDTLS_BIGNUM_C)
+#error "MBEDTLS_DHM_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_CMAC_C) && \
+ !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_DES_C)
+#error "MBEDTLS_CMAC_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C)
+#error "MBEDTLS_ECDH_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECDSA_C) && \
+ ( !defined(MBEDTLS_ECP_C) || \
+ !defined(MBEDTLS_ASN1_PARSE_C) || \
+ !defined(MBEDTLS_ASN1_WRITE_C) )
+#error "MBEDTLS_ECDSA_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECJPAKE_C) && \
+ ( !defined(MBEDTLS_ECP_C) || !defined(MBEDTLS_MD_C) )
+#error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C)
+#error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \
+ !defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) && \
+ !defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) )
+#error "MBEDTLS_ECP_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) && \
+ !defined(MBEDTLS_SHA256_C))
+#error "MBEDTLS_ENTROPY_C defined, but not all prerequisites"
+#endif
+#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_SHA512_C) && \
+ defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 64)
+#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
+#endif
+#if defined(MBEDTLS_ENTROPY_C) && \
+ ( !defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_ENTROPY_FORCE_SHA256) ) \
+ && defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 32)
+#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
+#endif
+#if defined(MBEDTLS_ENTROPY_C) && \
+ defined(MBEDTLS_ENTROPY_FORCE_SHA256) && !defined(MBEDTLS_SHA256_C)
+#error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \
+ ( !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) )
+#error "MBEDTLS_TEST_NULL_ENTROPY defined, but not all prerequisites"
+#endif
+#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \
+ ( defined(MBEDTLS_ENTROPY_NV_SEED) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT) || \
+ defined(MBEDTLS_HAVEGE_C) )
+#error "MBEDTLS_TEST_NULL_ENTROPY defined, but entropy sources too"
+#endif
+
+#if defined(MBEDTLS_GCM_C) && ( \
+ !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) )
+#error "MBEDTLS_GCM_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_HAVEGE_C) && !defined(MBEDTLS_TIMING_C)
+#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C)
+#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) && \
+ ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
+#error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \
+ ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
+#error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(MBEDTLS_DHM_C)
+#error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \
+ !defined(MBEDTLS_ECDH_C)
+#error "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \
+ ( !defined(MBEDTLS_DHM_C) || !defined(MBEDTLS_RSA_C) || \
+ !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
+ ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_RSA_C) || \
+ !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \
+ ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDSA_C) || \
+ !defined(MBEDTLS_X509_CRT_PARSE_C) )
+#error "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \
+ ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
+ !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \
+ ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
+ !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+ ( !defined(MBEDTLS_ECJPAKE_C) || !defined(MBEDTLS_SHA256_C) || \
+ !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) )
+#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \
+ ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
+#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM)
+#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C)
+#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C)
+#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PK_C) && \
+ ( !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_C) )
+#error "MBEDTLS_PK_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C)
+#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C)
+#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PKCS11_C) && !defined(MBEDTLS_PK_C)
+#error "MBEDTLS_PKCS11_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\
+ defined(MBEDTLS_PLATFORM_EXIT_ALT) )
+#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\
+ ( !defined(MBEDTLS_PLATFORM_C) ||\
+ !defined(MBEDTLS_HAVE_TIME) )
+#error "MBEDTLS_PLATFORM_TIME_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
+ ( !defined(MBEDTLS_PLATFORM_C) ||\
+ !defined(MBEDTLS_HAVE_TIME) )
+#error "MBEDTLS_PLATFORM_TIME_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
+ ( !defined(MBEDTLS_PLATFORM_C) ||\
+ !defined(MBEDTLS_HAVE_TIME) )
+#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
+ defined(MBEDTLS_PLATFORM_TIME_ALT) )
+#error "MBEDTLS_PLATFORM_TIME_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
+ defined(MBEDTLS_PLATFORM_TIME_ALT) )
+#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\
+ defined(MBEDTLS_PLATFORM_FPRINTF_ALT) )
+#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
+ ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
+#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
+ defined(MBEDTLS_PLATFORM_STD_FREE)
+#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
+#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
+ ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
+#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
+ defined(MBEDTLS_PLATFORM_STD_CALLOC)
+#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO)
+#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\
+ defined(MBEDTLS_PLATFORM_PRINTF_ALT) )
+#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\
+ defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) )
+#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\
+ !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
+#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
+#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
+#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY)
+#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\
+ !defined(MBEDTLS_PLATFORM_EXIT_ALT)
+#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_TIME) &&\
+ ( !defined(MBEDTLS_PLATFORM_TIME_ALT) ||\
+ !defined(MBEDTLS_HAVE_TIME) )
+#error "MBEDTLS_PLATFORM_STD_TIME defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\
+ !defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
+#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\
+ !defined(MBEDTLS_PLATFORM_PRINTF_ALT)
+#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\
+ !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
+#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\
+ ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_ENTROPY_C) )
+#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\
+ !defined(MBEDTLS_ENTROPY_NV_SEED)
+#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\
+ !defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\
+ !defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\
+ defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
+#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\
+ defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
+#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
+ !defined(MBEDTLS_OID_C) )
+#error "MBEDTLS_RSA_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_PKCS1_V21) && \
+ !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_RSA_C defined, but none of the PKCS1 versions enabled"
+#endif
+
+#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) && \
+ ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_PKCS1_V21) )
+#error "MBEDTLS_X509_RSASSA_PSS_SUPPORT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_SSL3) && ( !defined(MBEDTLS_MD5_C) || \
+ !defined(MBEDTLS_SHA1_C) )
+#error "MBEDTLS_SSL_PROTO_SSL3 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1) && ( !defined(MBEDTLS_MD5_C) || \
+ !defined(MBEDTLS_SHA1_C) )
+#error "MBEDTLS_SSL_PROTO_TLS1 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_1) && ( !defined(MBEDTLS_MD5_C) || \
+ !defined(MBEDTLS_SHA1_C) )
+#error "MBEDTLS_SSL_PROTO_TLS1_1 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && ( !defined(MBEDTLS_SHA1_C) && \
+ !defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) )
+#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1_2)
+#error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_CLI_C) && !defined(MBEDTLS_SSL_TLS_C)
+#error "MBEDTLS_SSL_CLI_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && ( !defined(MBEDTLS_CIPHER_C) || \
+ !defined(MBEDTLS_MD_C) )
+#error "MBEDTLS_SSL_TLS_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_TLS_C)
+#error "MBEDTLS_SSL_SRV_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1_2))
+#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
+ defined(MBEDTLS_SSL_PROTO_TLS1_1) && !defined(MBEDTLS_SSL_PROTO_TLS1))
+#error "Illegal protocol selection"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_TLS1) && \
+ defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_1))
+#error "Illegal protocol selection"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
+ defined(MBEDTLS_SSL_PROTO_TLS1_2) && (!defined(MBEDTLS_SSL_PROTO_TLS1) || \
+ !defined(MBEDTLS_SSL_PROTO_TLS1_1)))
+#error "Illegal protocol selection"
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_PROTO_DTLS)
+#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \
+ !defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
+#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \
+ ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
+#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) && \
+ ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
+#error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1_2)
+#error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequsites"
+#endif
+
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
+ !defined(MBEDTLS_SSL_PROTO_TLS1_2)
+#error "MBEDTLS_SSL_EXTENDED_MASTER_SECRET defined, but not all prerequsites"
+#endif
+
+#if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C)
+#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \
+ !defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1)
+#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \
+ !defined(MBEDTLS_X509_CRT_PARSE_C)
+#error "MBEDTLS_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
+#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites"
+#endif
+#define MBEDTLS_THREADING_IMPL
+#endif
+
+#if defined(MBEDTLS_THREADING_ALT)
+#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
+#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites"
+#endif
+#define MBEDTLS_THREADING_IMPL
+#endif
+
+#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL)
+#error "MBEDTLS_THREADING_C defined, single threading implementation required"
+#endif
+#undef MBEDTLS_THREADING_IMPL
+
+#if defined(MBEDTLS_VERSION_FEATURES) && !defined(MBEDTLS_VERSION_C)
+#error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
+ !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) || \
+ !defined(MBEDTLS_PK_PARSE_C) )
+#error "MBEDTLS_X509_USE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
+ !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) || \
+ !defined(MBEDTLS_PK_WRITE_C) )
+#error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
+#error "MBEDTLS_X509_CRT_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CRL_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
+#error "MBEDTLS_X509_CRL_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CSR_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
+#error "MBEDTLS_X509_CSR_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CRT_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
+#error "MBEDTLS_X509_CRT_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CSR_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
+#error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites"
+#endif
+
+/*
+ * Avoid warning from -pedantic. This is a convenient place for this
+ * workaround since this is included by every single file before the
+ * #if defined(MBEDTLS_xxx_C) that results in emtpy translation units.
+ */
+typedef int mbedtls_iso_c_forbids_empty_translation_units;
+
+#endif /* MBEDTLS_CHECK_CONFIG_H */
diff --git a/lib/mbedtls/include/mbedtls/cipher.h b/lib/mbedtls/include/mbedtls/cipher.h
new file mode 100644
index 000000000..b12e38843
--- /dev/null
+++ b/lib/mbedtls/include/mbedtls/cipher.h
@@ -0,0 +1,709 @@
+/**
+ * \file cipher.h
+ *
+ * \brief Generic cipher wrapper.
+ *
+ * \author Adriaan de Jong
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#ifndef MBEDTLS_CIPHER_H
+#define MBEDTLS_CIPHER_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include
+
+#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C)
+#define MBEDTLS_CIPHER_MODE_AEAD
+#endif
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+#define MBEDTLS_CIPHER_MODE_WITH_PADDING
+#endif
+
+#if defined(MBEDTLS_ARC4_C)
+#define MBEDTLS_CIPHER_MODE_STREAM
+#endif
+
+#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
+ !defined(inline) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
+#define MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE -0x6080 /**< The selected feature is not available. */
+#define MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA -0x6100 /**< Bad input parameters to function. */
+#define MBEDTLS_ERR_CIPHER_ALLOC_FAILED -0x6180 /**< Failed to allocate memory. */
+#define MBEDTLS_ERR_CIPHER_INVALID_PADDING -0x6200 /**< Input data contains invalid padding and is rejected. */
+#define MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 /**< Decryption of block requires a full block. */
+#define MBEDTLS_ERR_CIPHER_AUTH_FAILED -0x6300 /**< Authentication failed (for AEAD modes). */
+#define MBEDTLS_ERR_CIPHER_INVALID_CONTEXT -0x6380 /**< The context is invalid, eg because it was free()ed. */
+
+#define MBEDTLS_CIPHER_VARIABLE_IV_LEN 0x01 /**< Cipher accepts IVs of variable length */
+#define MBEDTLS_CIPHER_VARIABLE_KEY_LEN 0x02 /**< Cipher accepts keys of variable length */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ MBEDTLS_CIPHER_ID_NONE = 0,
+ MBEDTLS_CIPHER_ID_NULL,
+ MBEDTLS_CIPHER_ID_AES,
+ MBEDTLS_CIPHER_ID_DES,
+ MBEDTLS_CIPHER_ID_3DES,
+ MBEDTLS_CIPHER_ID_CAMELLIA,
+ MBEDTLS_CIPHER_ID_BLOWFISH,
+ MBEDTLS_CIPHER_ID_ARC4,
+} mbedtls_cipher_id_t;
+
+typedef enum {
+ MBEDTLS_CIPHER_NONE = 0,
+ MBEDTLS_CIPHER_NULL,
+ MBEDTLS_CIPHER_AES_128_ECB,
+ MBEDTLS_CIPHER_AES_192_ECB,
+ MBEDTLS_CIPHER_AES_256_ECB,
+ MBEDTLS_CIPHER_AES_128_CBC,
+ MBEDTLS_CIPHER_AES_192_CBC,
+ MBEDTLS_CIPHER_AES_256_CBC,
+ MBEDTLS_CIPHER_AES_128_CFB128,
+ MBEDTLS_CIPHER_AES_192_CFB128,
+ MBEDTLS_CIPHER_AES_256_CFB128,
+ MBEDTLS_CIPHER_AES_128_CTR,
+ MBEDTLS_CIPHER_AES_192_CTR,
+ MBEDTLS_CIPHER_AES_256_CTR,
+ MBEDTLS_CIPHER_AES_128_GCM,
+ MBEDTLS_CIPHER_AES_192_GCM,
+ MBEDTLS_CIPHER_AES_256_GCM,
+ MBEDTLS_CIPHER_CAMELLIA_128_ECB,
+ MBEDTLS_CIPHER_CAMELLIA_192_ECB,
+ MBEDTLS_CIPHER_CAMELLIA_256_ECB,
+ MBEDTLS_CIPHER_CAMELLIA_128_CBC,
+ MBEDTLS_CIPHER_CAMELLIA_192_CBC,
+ MBEDTLS_CIPHER_CAMELLIA_256_CBC,
+ MBEDTLS_CIPHER_CAMELLIA_128_CFB128,
+ MBEDTLS_CIPHER_CAMELLIA_192_CFB128,
+ MBEDTLS_CIPHER_CAMELLIA_256_CFB128,
+ MBEDTLS_CIPHER_CAMELLIA_128_CTR,
+ MBEDTLS_CIPHER_CAMELLIA_192_CTR,
+ MBEDTLS_CIPHER_CAMELLIA_256_CTR,
+ MBEDTLS_CIPHER_CAMELLIA_128_GCM,
+ MBEDTLS_CIPHER_CAMELLIA_192_GCM,
+ MBEDTLS_CIPHER_CAMELLIA_256_GCM,
+ MBEDTLS_CIPHER_DES_ECB,
+ MBEDTLS_CIPHER_DES_CBC,
+ MBEDTLS_CIPHER_DES_EDE_ECB,
+ MBEDTLS_CIPHER_DES_EDE_CBC,
+ MBEDTLS_CIPHER_DES_EDE3_ECB,
+ MBEDTLS_CIPHER_DES_EDE3_CBC,
+ MBEDTLS_CIPHER_BLOWFISH_ECB,
+ MBEDTLS_CIPHER_BLOWFISH_CBC,
+ MBEDTLS_CIPHER_BLOWFISH_CFB64,
+ MBEDTLS_CIPHER_BLOWFISH_CTR,
+ MBEDTLS_CIPHER_ARC4_128,
+ MBEDTLS_CIPHER_AES_128_CCM,
+ MBEDTLS_CIPHER_AES_192_CCM,
+ MBEDTLS_CIPHER_AES_256_CCM,
+ MBEDTLS_CIPHER_CAMELLIA_128_CCM,
+ MBEDTLS_CIPHER_CAMELLIA_192_CCM,
+ MBEDTLS_CIPHER_CAMELLIA_256_CCM,
+} mbedtls_cipher_type_t;
+
+typedef enum {
+ MBEDTLS_MODE_NONE = 0,
+ MBEDTLS_MODE_ECB,
+ MBEDTLS_MODE_CBC,
+ MBEDTLS_MODE_CFB,
+ MBEDTLS_MODE_OFB, /* Unused! */
+ MBEDTLS_MODE_CTR,
+ MBEDTLS_MODE_GCM,
+ MBEDTLS_MODE_STREAM,
+ MBEDTLS_MODE_CCM,
+} mbedtls_cipher_mode_t;
+
+typedef enum {
+ MBEDTLS_PADDING_PKCS7 = 0, /**< PKCS7 padding (default) */
+ MBEDTLS_PADDING_ONE_AND_ZEROS, /**< ISO/IEC 7816-4 padding */
+ MBEDTLS_PADDING_ZEROS_AND_LEN, /**< ANSI X.923 padding */
+ MBEDTLS_PADDING_ZEROS, /**< zero padding (not reversible!) */
+ MBEDTLS_PADDING_NONE, /**< never pad (full blocks only) */
+} mbedtls_cipher_padding_t;
+
+typedef enum {
+ MBEDTLS_OPERATION_NONE = -1,
+ MBEDTLS_DECRYPT = 0,
+ MBEDTLS_ENCRYPT,
+} mbedtls_operation_t;
+
+enum {
+ /** Undefined key length */
+ MBEDTLS_KEY_LENGTH_NONE = 0,
+ /** Key length, in bits (including parity), for DES keys */
+ MBEDTLS_KEY_LENGTH_DES = 64,
+ /** Key length, in bits (including parity), for DES in two key EDE */
+ MBEDTLS_KEY_LENGTH_DES_EDE = 128,
+ /** Key length, in bits (including parity), for DES in three-key EDE */
+ MBEDTLS_KEY_LENGTH_DES_EDE3 = 192,
+};
+
+/** Maximum length of any IV, in bytes */
+#define MBEDTLS_MAX_IV_LENGTH 16
+/** Maximum block size of any cipher, in bytes */
+#define MBEDTLS_MAX_BLOCK_LENGTH 16
+
+/**
+ * Base cipher information (opaque struct).
+ */
+typedef struct mbedtls_cipher_base_t mbedtls_cipher_base_t;
+
+/**
+ * CMAC context (opaque struct).
+ */
+typedef struct mbedtls_cmac_context_t mbedtls_cmac_context_t;
+
+/**
+ * Cipher information. Allows cipher functions to be called in a generic way.
+ */
+typedef struct {
+ /** Full cipher identifier (e.g. MBEDTLS_CIPHER_AES_256_CBC) */
+ mbedtls_cipher_type_t type;
+
+ /** Cipher mode (e.g. MBEDTLS_MODE_CBC) */
+ mbedtls_cipher_mode_t mode;
+
+ /** Cipher key length, in bits (default length for variable sized ciphers)
+ * (Includes parity bits for ciphers like DES) */
+ unsigned int key_bitlen;
+
+ /** Name of the cipher */
+ const char * name;
+
+ /** IV/NONCE size, in bytes.
+ * For cipher that accept many sizes: recommended size */
+ unsigned int iv_size;
+
+ /** Flags for variable IV size, variable key size, etc. */
+ int flags;
+
+ /** block size, in bytes */
+ unsigned int block_size;
+
+ /** Base cipher information and functions */
+ const mbedtls_cipher_base_t *base;
+
+} mbedtls_cipher_info_t;
+
+/**
+ * Generic cipher context.
+ */
+typedef struct {
+ /** Information about the associated cipher */
+ const mbedtls_cipher_info_t *cipher_info;
+
+ /** Key length to use */
+ int key_bitlen;
+
+ /** Operation that the context's key has been initialised for */
+ mbedtls_operation_t operation;
+
+#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
+ /** Padding functions to use, if relevant for cipher mode */
+ void (*add_padding)( unsigned char *output, size_t olen, size_t data_len );
+ int (*get_padding)( unsigned char *input, size_t ilen, size_t *data_len );
+#endif
+
+ /** Buffer for data that hasn't been encrypted yet */
+ unsigned char unprocessed_data[MBEDTLS_MAX_BLOCK_LENGTH];
+
+ /** Number of bytes that still need processing */
+ size_t unprocessed_len;
+
+ /** Current IV or NONCE_COUNTER for CTR-mode */
+ unsigned char iv[MBEDTLS_MAX_IV_LENGTH];
+
+ /** IV size in bytes (for ciphers with variable-length IVs) */
+ size_t iv_size;
+
+ /** Cipher-specific context */
+ void *cipher_ctx;
+
+#if defined(MBEDTLS_CMAC_C)
+ /** CMAC Specific context */
+ mbedtls_cmac_context_t *cmac_ctx;
+#endif
+} mbedtls_cipher_context_t;
+
+/**
+ * \brief Returns the list of ciphers supported by the generic cipher module.
+ *
+ * \return a statically allocated array of ciphers, the last entry
+ * is 0.
+ */
+const int *mbedtls_cipher_list( void );
+
+/**
+ * \brief Returns the cipher information structure associated
+ * with the given cipher name.
+ *
+ * \param cipher_name Name of the cipher to search for.
+ *
+ * \return the cipher information structure associated with the
+ * given cipher_name, or NULL if not found.
+ */
+const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name );
+
+/**
+ * \brief Returns the cipher information structure associated
+ * with the given cipher type.
+ *
+ * \param cipher_type Type of the cipher to search for.
+ *
+ * \return the cipher information structure associated with the
+ * given cipher_type, or NULL if not found.
+ */
+const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type );
+
+/**
+ * \brief Returns the cipher information structure associated
+ * with the given cipher id, key size and mode.
+ *
+ * \param cipher_id Id of the cipher to search for
+ * (e.g. MBEDTLS_CIPHER_ID_AES)
+ * \param key_bitlen Length of the key in bits
+ * \param mode Cipher mode (e.g. MBEDTLS_MODE_CBC)
+ *
+ * \return the cipher information structure associated with the
+ * given cipher_type, or NULL if not found.
+ */
+const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id,
+ int key_bitlen,
+ const mbedtls_cipher_mode_t mode );
+
+/**
+ * \brief Initialize a cipher_context (as NONE)
+ */
+void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx );
+
+/**
+ * \brief Free and clear the cipher-specific context of ctx.
+ * Freeing ctx itself remains the responsibility of the
+ * caller.
+ */
+void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx );
+
+/**
+ * \brief Initialises and fills the cipher context structure with
+ * the appropriate values.
+ *
+ * \note Currently also clears structure. In future versions you
+ * will be required to call mbedtls_cipher_init() on the structure
+ * first.
+ *
+ * \param ctx context to initialise. May not be NULL.
+ * \param cipher_info cipher to use.
+ *
+ * \return 0 on success,
+ * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter failure,
+ * MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the
+ * cipher-specific context failed.
+ */
+int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info );
+
+/**
+ * \brief Returns the block size of the given cipher.
+ *
+ * \param ctx cipher's context. Must have been initialised.
+ *
+ * \return size of the cipher's blocks, or 0 if ctx has not been
+ * initialised.
+ */
+static inline unsigned int mbedtls_cipher_get_block_size( const mbedtls_cipher_context_t *ctx )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return 0;
+
+ return ctx->cipher_info->block_size;
+}
+
+/**
+ * \brief Returns the mode of operation for the cipher.
+ * (e.g. MBEDTLS_MODE_CBC)
+ *
+ * \param ctx cipher's context. Must have been initialised.
+ *
+ * \return mode of operation, or MBEDTLS_MODE_NONE if ctx
+ * has not been initialised.
+ */
+static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( const mbedtls_cipher_context_t *ctx )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return MBEDTLS_MODE_NONE;
+
+ return ctx->cipher_info->mode;
+}
+
+/**
+ * \brief Returns the size of the cipher's IV/NONCE in bytes.
+ *
+ * \param ctx cipher's context. Must have been initialised.
+ *
+ * \return If IV has not been set yet: (recommended) IV size
+ * (0 for ciphers not using IV/NONCE).
+ * If IV has already been set: actual size.
+ */
+static inline int mbedtls_cipher_get_iv_size( const mbedtls_cipher_context_t *ctx )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return 0;
+
+ if( ctx->iv_size != 0 )
+ return (int) ctx->iv_size;
+
+ return (int) ctx->cipher_info->iv_size;
+}
+
+/**
+ * \brief Returns the type of the given cipher.
+ *
+ * \param ctx cipher's context. Must have been initialised.
+ *
+ * \return type of the cipher, or MBEDTLS_CIPHER_NONE if ctx has
+ * not been initialised.
+ */
+static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( const mbedtls_cipher_context_t *ctx )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return MBEDTLS_CIPHER_NONE;
+
+ return ctx->cipher_info->type;
+}
+
+/**
+ * \brief Returns the name of the given cipher, as a string.
+ *
+ * \param ctx cipher's context. Must have been initialised.
+ *
+ * \return name of the cipher, or NULL if ctx was not initialised.
+ */
+static inline const char *mbedtls_cipher_get_name( const mbedtls_cipher_context_t *ctx )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return 0;
+
+ return ctx->cipher_info->name;
+}
+
+/**
+ * \brief Returns the key length of the cipher.
+ *
+ * \param ctx cipher's context. Must have been initialised.
+ *
+ * \return cipher's key length, in bits, or
+ * MBEDTLS_KEY_LENGTH_NONE if ctx has not been
+ * initialised.
+ */
+static inline int mbedtls_cipher_get_key_bitlen( const mbedtls_cipher_context_t *ctx )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return MBEDTLS_KEY_LENGTH_NONE;
+
+ return (int) ctx->cipher_info->key_bitlen;
+}
+
+/**
+ * \brief Returns the operation of the given cipher.
+ *
+ * \param ctx cipher's context. Must have been initialised.
+ *
+ * \return operation (MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT),
+ * or MBEDTLS_OPERATION_NONE if ctx has not been
+ * initialised.
+ */
+static inline mbedtls_operation_t mbedtls_cipher_get_operation( const mbedtls_cipher_context_t *ctx )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return MBEDTLS_OPERATION_NONE;
+
+ return ctx->operation;
+}
+
+/**
+ * \brief Set the key to use with the given context.
+ *
+ * \param ctx generic cipher context. May not be NULL. Must have been
+ * initialised using cipher_context_from_type or
+ * cipher_context_from_string.
+ * \param key The key to use.
+ * \param key_bitlen key length to use, in bits.
+ * \param operation Operation that the key will be used for, either
+ * MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT.
+ *
+ * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if
+ * parameter verification fails or a cipher specific
+ * error code.
+ */
+int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key,
+ int key_bitlen, const mbedtls_operation_t operation );
+
+#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
+/**
+ * \brief Set padding mode, for cipher modes that use padding.
+ * (Default: PKCS7 padding.)
+ *
+ * \param ctx generic cipher context
+ * \param mode padding mode
+ *
+ * \returns 0 on success, MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE
+ * if selected padding mode is not supported, or
+ * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if the cipher mode
+ * does not support padding.
+ */
+int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode );
+#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
+
+/**
+ * \brief Set the initialization vector (IV) or nonce
+ *
+ * \param ctx generic cipher context
+ * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers)
+ * \param iv_len IV length for ciphers with variable-size IV;
+ * discarded by ciphers with fixed-size IV.
+ *
+ * \returns 0 on success, or MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+ *
+ * \note Some ciphers don't use IVs nor NONCE. For these
+ * ciphers, this function has no effect.
+ */
+int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
+ const unsigned char *iv, size_t iv_len );
+
+/**
+ * \brief Finish preparation of the given context
+ *
+ * \param ctx generic cipher context
+ *
+ * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+ * if parameter verification fails.
+ */
+int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx );
+
+#if defined(MBEDTLS_GCM_C)
+/**
+ * \brief Add additional data (for AEAD ciphers).
+ * Currently only supported with GCM.
+ * Must be called exactly once, after mbedtls_cipher_reset().
+ *
+ * \param ctx generic cipher context
+ * \param ad Additional data to use.
+ * \param ad_len Length of ad.
+ *
+ * \return 0 on success, or a specific error code.
+ */
+int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
+ const unsigned char *ad, size_t ad_len );
+#endif /* MBEDTLS_GCM_C */
+
+/**
+ * \brief Generic cipher update function. Encrypts/decrypts
+ * using the given cipher context. Writes as many block
+ * size'd blocks of data as possible to output. Any data
+ * that cannot be written immediately will either be added
+ * to the next block, or flushed when cipher_final is
+ * called.
+ * Exception: for MBEDTLS_MODE_ECB, expects single block
+ * in size (e.g. 16 bytes for AES)
+ *
+ * \param ctx generic cipher context
+ * \param input buffer holding the input data
+ * \param ilen length of the input data
+ * \param output buffer for the output data. Should be able to hold at
+ * least ilen + block_size. Cannot be the same buffer as
+ * input!
+ * \param olen length of the output data, will be filled with the
+ * actual number of bytes written.
+ *
+ * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if
+ * parameter verification fails,
+ * MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an
+ * unsupported mode for a cipher or a cipher specific
+ * error code.
+ *
+ * \note If the underlying cipher is GCM, all calls to this
+ * function, except the last one before mbedtls_cipher_finish(),
+ * must have ilen a multiple of the block size.
+ */
+int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input,
+ size_t ilen, unsigned char *output, size_t *olen );
+
+/**
+ * \brief Generic cipher finalisation function. If data still
+ * needs to be flushed from an incomplete block, data
+ * contained within it will be padded with the size of
+ * the last block, and written to the output buffer.
+ *
+ * \param ctx Generic cipher context
+ * \param output buffer to write data to. Needs block_size available.
+ * \param olen length of the data written to the output buffer.
+ *
+ * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if
+ * parameter verification fails,
+ * MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption
+ * expected a full block but was not provided one,
+ * MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding
+ * while decrypting or a cipher specific error code.
+ */
+int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx,
+ unsigned char *output, size_t *olen );
+
+#if defined(MBEDTLS_GCM_C)
+/**
+ * \brief Write tag for AEAD ciphers.
+ * Currently only supported with GCM.
+ * Must be called after mbedtls_cipher_finish().
+ *
+ * \param ctx Generic cipher context
+ * \param tag buffer to write the tag
+ * \param tag_len Length of the tag to write
+ *
+ * \return 0 on success, or a specific error code.
+ */
+int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
+ unsigned char *tag, size_t tag_len );
+
+/**
+ * \brief Check tag for AEAD ciphers.
+ * Currently only supported with GCM.
+ * Must be called after mbedtls_cipher_finish().
+ *
+ * \param ctx Generic cipher context
+ * \param tag Buffer holding the tag
+ * \param tag_len Length of the tag to check
+ *
+ * \return 0 on success, or a specific error code.
+ */
+int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
+ const unsigned char *tag, size_t tag_len );
+#endif /* MBEDTLS_GCM_C */
+
+/**
+ * \brief Generic all-in-one encryption/decryption
+ * (for all ciphers except AEAD constructs).
+ *
+ * \param ctx generic cipher context
+ * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers)
+ * \param iv_len IV length for ciphers with variable-size IV;
+ * discarded by ciphers with fixed-size IV.
+ * \param input buffer holding the input data
+ * \param ilen length of the input data
+ * \param output buffer for the output data. Should be able to hold at
+ * least ilen + block_size. Cannot be the same buffer as
+ * input!
+ * \param olen length of the output data, will be filled with the
+ * actual number of bytes written.
+ *
+ * \note Some ciphers don't use IVs nor NONCE. For these
+ * ciphers, use iv = NULL and iv_len = 0.
+ *
+ * \returns 0 on success, or
+ * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or
+ * MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption
+ * expected a full block but was not provided one, or
+ * MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding
+ * while decrypting, or
+ * a cipher specific error code.
+ */
+int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen );
+
+#if defined(MBEDTLS_CIPHER_MODE_AEAD)
+/**
+ * \brief Generic autenticated encryption (AEAD ciphers).
+ *
+ * \param ctx generic cipher context
+ * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers)
+ * \param iv_len IV length for ciphers with variable-size IV;
+ * discarded by ciphers with fixed-size IV.
+ * \param ad Additional data to authenticate.
+ * \param ad_len Length of ad.
+ * \param input buffer holding the input data
+ * \param ilen length of the input data
+ * \param output buffer for the output data.
+ * Should be able to hold at least ilen.
+ * \param olen length of the output data, will be filled with the
+ * actual number of bytes written.
+ * \param tag buffer for the authentication tag
+ * \param tag_len desired tag length
+ *
+ * \returns 0 on success, or
+ * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or
+ * a cipher specific error code.
+ */
+int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *ad, size_t ad_len,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen,
+ unsigned char *tag, size_t tag_len );
+
+/**
+ * \brief Generic autenticated decryption (AEAD ciphers).
+ *
+ * \param ctx generic cipher context
+ * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers)
+ * \param iv_len IV length for ciphers with variable-size IV;
+ * discarded by ciphers with fixed-size IV.
+ * \param ad Additional data to be authenticated.
+ * \param ad_len Length of ad.
+ * \param input buffer holding the input data
+ * \param ilen length of the input data
+ * \param output buffer for the output data.
+ * Should be able to hold at least ilen.
+ * \param olen length of the output data, will be filled with the
+ * actual number of bytes written.
+ * \param tag buffer holding the authentication tag
+ * \param tag_len length of the authentication tag
+ *
+ * \returns 0 on success, or
+ * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or
+ * MBEDTLS_ERR_CIPHER_AUTH_FAILED if data isn't authentic,
+ * or a cipher specific error code.
+ *
+ * \note If the data is not authentic, then the output buffer
+ * is zeroed out to prevent the unauthentic plaintext to
+ * be used by mistake, making this interface safer.
+ */
+int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *ad, size_t ad_len,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen,
+ const unsigned char *tag, size_t tag_len );
+#endif /* MBEDTLS_CIPHER_MODE_AEAD */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBEDTLS_CIPHER_H */
diff --git a/lib/mbedtls/include/mbedtls/cipher_internal.h b/lib/mbedtls/include/mbedtls/cipher_internal.h
new file mode 100644
index 000000000..6c58bcc52
--- /dev/null
+++ b/lib/mbedtls/include/mbedtls/cipher_internal.h
@@ -0,0 +1,109 @@
+/**
+ * \file cipher_internal.h
+ *
+ * \brief Cipher wrappers.
+ *
+ * \author Adriaan de Jong
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_CIPHER_WRAP_H
+#define MBEDTLS_CIPHER_WRAP_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "cipher.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Base cipher information. The non-mode specific functions and values.
+ */
+struct mbedtls_cipher_base_t
+{
+ /** Base Cipher type (e.g. MBEDTLS_CIPHER_ID_AES) */
+ mbedtls_cipher_id_t cipher;
+
+ /** Encrypt using ECB */
+ int (*ecb_func)( void *ctx, mbedtls_operation_t mode,
+ const unsigned char *input, unsigned char *output );
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ /** Encrypt using CBC */
+ int (*cbc_func)( void *ctx, mbedtls_operation_t mode, size_t length,
+ unsigned char *iv, const unsigned char *input,
+ unsigned char *output );
+#endif
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ /** Encrypt using CFB (Full length) */
+ int (*cfb_func)( void *ctx, mbedtls_operation_t mode, size_t length, size_t *iv_off,
+ unsigned char *iv, const unsigned char *input,
+ unsigned char *output );
+#endif
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ /** Encrypt using CTR */
+ int (*ctr_func)( void *ctx, size_t length, size_t *nc_off,
+ unsigned char *nonce_counter, unsigned char *stream_block,
+ const unsigned char *input, unsigned char *output );
+#endif
+
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ /** Encrypt using STREAM */
+ int (*stream_func)( void *ctx, size_t length,
+ const unsigned char *input, unsigned char *output );
+#endif
+
+ /** Set key for encryption purposes */
+ int (*setkey_enc_func)( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen );
+
+ /** Set key for decryption purposes */
+ int (*setkey_dec_func)( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen);
+
+ /** Allocate a new context */
+ void * (*ctx_alloc_func)( void );
+
+ /** Free the given context */
+ void (*ctx_free_func)( void *ctx );
+
+};
+
+typedef struct
+{
+ mbedtls_cipher_type_t type;
+ const mbedtls_cipher_info_t *info;
+} mbedtls_cipher_definition_t;
+
+extern const mbedtls_cipher_definition_t mbedtls_cipher_definitions[];
+
+extern int mbedtls_cipher_supported[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBEDTLS_CIPHER_WRAP_H */
diff --git a/lib/mbedtls/include/mbedtls/config.h b/lib/mbedtls/include/mbedtls/config.h
new file mode 100644
index 000000000..0a3e1bb44
--- /dev/null
+++ b/lib/mbedtls/include/mbedtls/config.h
@@ -0,0 +1,2600 @@
+/**
+ * \file config.h
+ *
+ * \brief Configuration options (set of defines)
+ *
+ * This set of compile-time options may be used to enable
+ * or disable features selectively, and reduce the global
+ * memory footprint.
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#ifndef MBEDTLS_CONFIG_H
+#define MBEDTLS_CONFIG_H
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+/**
+ * \name SECTION: System support
+ *
+ * This section sets system specific settings.
+ * \{
+ */
+
+/**
+ * \def MBEDTLS_HAVE_ASM
+ *
+ * The compiler has support for asm().
+ *
+ * Requires support for asm() in compiler.
+ *
+ * Used in:
+ * library/timing.c
+ * library/padlock.c
+ * include/mbedtls/bn_mul.h
+ *
+ * Comment to disable the use of assembly code.
+ */
+#define MBEDTLS_HAVE_ASM
+
+/**
+ * \def MBEDTLS_HAVE_SSE2
+ *
+ * CPU supports SSE2 instruction set.
+ *
+ * Uncomment if the CPU supports SSE2 (IA-32 specific).
+ */
+//#define MBEDTLS_HAVE_SSE2
+
+/**
+ * \def MBEDTLS_HAVE_TIME
+ *
+ * System has time.h and time().
+ * The time does not need to be correct, only time differences are used,
+ * by contrast with MBEDTLS_HAVE_TIME_DATE
+ *
+ * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT,
+ * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and
+ * MBEDTLS_PLATFORM_STD_TIME.
+ *
+ * Comment if your system does not support time functions
+ */
+// #define MBEDTLS_HAVE_TIME
+
+/**
+ * \def MBEDTLS_HAVE_TIME_DATE
+ *
+ * System has time.h and time(), gmtime() and the clock is correct.
+ * The time needs to be correct (not necesarily very accurate, but at least
+ * the date should be correct). This is used to verify the validity period of
+ * X.509 certificates.
+ *
+ * Comment if your system does not have a correct clock.
+ */
+// #define MBEDTLS_HAVE_TIME_DATE
+
+/**
+ * \def MBEDTLS_PLATFORM_MEMORY
+ *
+ * Enable the memory allocation layer.
+ *
+ * By default mbed TLS uses the system-provided calloc() and free().
+ * This allows different allocators (self-implemented or provided) to be
+ * provided to the platform abstraction layer.
+ *
+ * Enabling MBEDTLS_PLATFORM_MEMORY without the
+ * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide
+ * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and
+ * free() function pointer at runtime.
+ *
+ * Enabling MBEDTLS_PLATFORM_MEMORY and specifying
+ * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the
+ * alternate function at compile time.
+ *
+ * Requires: MBEDTLS_PLATFORM_C
+ *
+ * Enable this layer to allow use of alternative memory allocators.
+ */
+//#define MBEDTLS_PLATFORM_MEMORY
+
+/**
+ * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+ *
+ * Do not assign standard functions in the platform layer (e.g. calloc() to
+ * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF)
+ *
+ * This makes sure there are no linking errors on platforms that do not support
+ * these functions. You will HAVE to provide alternatives, either at runtime
+ * via the platform_set_xxx() functions or at compile time by setting
+ * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a
+ * MBEDTLS_PLATFORM_XXX_MACRO.
+ *
+ * Requires: MBEDTLS_PLATFORM_C
+ *
+ * Uncomment to prevent default assignment of standard functions in the
+ * platform layer.
+ */
+//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+
+/**
+ * \def MBEDTLS_PLATFORM_EXIT_ALT
+ *
+ * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the
+ * function in the platform abstraction layer.
+ *
+ * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will
+ * provide a function "mbedtls_platform_set_printf()" that allows you to set an
+ * alternative printf function pointer.
+ *
+ * All these define require MBEDTLS_PLATFORM_C to be defined!
+ *
+ * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows;
+ * it will be enabled automatically by check_config.h
+ *
+ * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as
+ * MBEDTLS_PLATFORM_XXX_MACRO!
+ *
+ * Requires: MBEDTLS_PLATFORM_TIME_ALT requires MBEDTLS_HAVE_TIME
+ *
+ * Uncomment a macro to enable alternate implementation of specific base
+ * platform function
+ */
+//#define MBEDTLS_PLATFORM_EXIT_ALT
+//#define MBEDTLS_PLATFORM_TIME_ALT
+//#define MBEDTLS_PLATFORM_FPRINTF_ALT
+//#define MBEDTLS_PLATFORM_PRINTF_ALT
+//#define MBEDTLS_PLATFORM_SNPRINTF_ALT
+//#define MBEDTLS_PLATFORM_NV_SEED_ALT
+
+/**
+ * \def MBEDTLS_DEPRECATED_WARNING
+ *
+ * Mark deprecated functions so that they generate a warning if used.
+ * Functions deprecated in one version will usually be removed in the next
+ * version. You can enable this to help you prepare the transition to a new
+ * major version by making sure your code is not using these functions.
+ *
+ * This only works with GCC and Clang. With other compilers, you may want to
+ * use MBEDTLS_DEPRECATED_REMOVED
+ *
+ * Uncomment to get warnings on using deprecated functions.
+ */
+//#define MBEDTLS_DEPRECATED_WARNING
+
+/**
+ * \def MBEDTLS_DEPRECATED_REMOVED
+ *
+ * Remove deprecated functions so that they generate an error if used.
+ * Functions deprecated in one version will usually be removed in the next
+ * version. You can enable this to help you prepare the transition to a new
+ * major version by making sure your code is not using these functions.
+ *
+ * Uncomment to get errors on using deprecated functions.
+ */
+//#define MBEDTLS_DEPRECATED_REMOVED
+
+/* \} name SECTION: System support */
+
+/**
+ * \name SECTION: mbed TLS feature support
+ *
+ * This section sets support for features that are or are not needed
+ * within the modules that are enabled.
+ * \{
+ */
+
+/**
+ * \def MBEDTLS_TIMING_ALT
+ *
+ * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(),
+ * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay()
+ *
+ * Only works if you have MBEDTLS_TIMING_C enabled.
+ *
+ * You will need to provide a header "timing_alt.h" and an implementation at
+ * compile time.
+ */
+//#define MBEDTLS_TIMING_ALT
+
+/**
+ * \def MBEDTLS_AES_ALT
+ *
+ * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your
+ * alternate core implementation of a symmetric crypto or hash module (e.g.
+ * platform specific assembly optimized implementations). Keep in mind that
+ * the function prototypes should remain the same.
+ *
+ * This replaces the whole module. If you only want to replace one of the
+ * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags.
+ *
+ * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer
+ * provide the "struct mbedtls_aes_context" definition and omit the base function
+ * declarations and implementations. "aes_alt.h" will be included from
+ * "aes.h" to include the new function definitions.
+ *
+ * Uncomment a macro to enable alternate implementation of the corresponding
+ * module.
+ */
+//#define MBEDTLS_AES_ALT
+//#define MBEDTLS_ARC4_ALT
+//#define MBEDTLS_BLOWFISH_ALT
+//#define MBEDTLS_CAMELLIA_ALT
+//#define MBEDTLS_DES_ALT
+//#define MBEDTLS_XTEA_ALT
+//#define MBEDTLS_MD2_ALT
+//#define MBEDTLS_MD4_ALT
+//#define MBEDTLS_MD5_ALT
+//#define MBEDTLS_RIPEMD160_ALT
+//#define MBEDTLS_SHA1_ALT
+//#define MBEDTLS_SHA256_ALT
+//#define MBEDTLS_SHA512_ALT
+
+/**
+ * \def MBEDTLS_MD2_PROCESS_ALT
+ *
+ * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you
+ * alternate core implementation of symmetric crypto or hash function. Keep in
+ * mind that function prototypes should remain the same.
+ *
+ * This replaces only one function. The header file from mbed TLS is still
+ * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags.
+ *
+ * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will
+ * no longer provide the mbedtls_sha1_process() function, but it will still provide
+ * the other function (using your mbedtls_sha1_process() function) and the definition
+ * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible
+ * with this definition.
+ *
+ * Note: if you use the AES_xxx_ALT macros, then is is recommended to also set
+ * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES
+ * tables.
+ *
+ * Uncomment a macro to enable alternate implementation of the corresponding
+ * function.
+ */
+//#define MBEDTLS_MD2_PROCESS_ALT
+//#define MBEDTLS_MD4_PROCESS_ALT
+//#define MBEDTLS_MD5_PROCESS_ALT
+//#define MBEDTLS_RIPEMD160_PROCESS_ALT
+//#define MBEDTLS_SHA1_PROCESS_ALT
+//#define MBEDTLS_SHA256_PROCESS_ALT
+//#define MBEDTLS_SHA512_PROCESS_ALT
+//#define MBEDTLS_DES_SETKEY_ALT
+//#define MBEDTLS_DES_CRYPT_ECB_ALT
+//#define MBEDTLS_DES3_CRYPT_ECB_ALT
+//#define MBEDTLS_AES_SETKEY_ENC_ALT
+//#define MBEDTLS_AES_SETKEY_DEC_ALT
+//#define MBEDTLS_AES_ENCRYPT_ALT
+//#define MBEDTLS_AES_DECRYPT_ALT
+
+/**
+ * \def MBEDTLS_TEST_NULL_ENTROPY
+ *
+ * Enables testing and use of mbed TLS without any configured entropy sources.
+ * This permits use of the library on platforms before an entropy source has
+ * been integrated (see for example the MBEDTLS_ENTROPY_HARDWARE_ALT or the
+ * MBEDTLS_ENTROPY_NV_SEED switches).
+ *
+ * WARNING! This switch MUST be disabled in production builds, and is suitable
+ * only for development.
+ * Enabling the switch negates any security provided by the library.
+ *
+ * Requires MBEDTLS_ENTROPY_C, MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+ *
+ */
+//#define MBEDTLS_TEST_NULL_ENTROPY
+
+/**
+ * \def MBEDTLS_ENTROPY_HARDWARE_ALT
+ *
+ * Uncomment this macro to let mbed TLS use your own implementation of a
+ * hardware entropy collector.
+ *
+ * Your function must be called \c mbedtls_hardware_poll(), have the same
+ * prototype as declared in entropy_poll.h, and accept NULL as first argument.
+ *
+ * Uncomment to use your own hardware entropy collector.
+ */
+//#define MBEDTLS_ENTROPY_HARDWARE_ALT
+
+/**
+ * \def MBEDTLS_AES_ROM_TABLES
+ *
+ * Store the AES tables in ROM.
+ *
+ * Uncomment this macro to store the AES tables in ROM.
+ */
+//#define MBEDTLS_AES_ROM_TABLES
+
+/**
+ * \def MBEDTLS_CAMELLIA_SMALL_MEMORY
+ *
+ * Use less ROM for the Camellia implementation (saves about 768 bytes).
+ *
+ * Uncomment this macro to use less memory for Camellia.
+ */
+//#define MBEDTLS_CAMELLIA_SMALL_MEMORY
+
+/**
+ * \def MBEDTLS_CIPHER_MODE_CBC
+ *
+ * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers.
+ */
+// #define MBEDTLS_CIPHER_MODE_CBC
+
+/**
+ * \def MBEDTLS_CIPHER_MODE_CFB
+ *
+ * Enable Cipher Feedback mode (CFB) for symmetric ciphers.
+ */
+// #define MBEDTLS_CIPHER_MODE_CFB
+
+/**
+ * \def MBEDTLS_CIPHER_MODE_CTR
+ *
+ * Enable Counter Block Cipher mode (CTR) for symmetric ciphers.
+ */
+#define MBEDTLS_CIPHER_MODE_CTR
+
+/**
+ * \def MBEDTLS_CIPHER_NULL_CIPHER
+ *
+ * Enable NULL cipher.
+ * Warning: Only do so when you know what you are doing. This allows for
+ * encryption or channels without any security!
+ *
+ * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable
+ * the following ciphersuites:
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA
+ * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384
+ * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256
+ * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA
+ * MBEDTLS_TLS_RSA_WITH_NULL_SHA256
+ * MBEDTLS_TLS_RSA_WITH_NULL_SHA
+ * MBEDTLS_TLS_RSA_WITH_NULL_MD5
+ * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384
+ * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256
+ * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA
+ * MBEDTLS_TLS_PSK_WITH_NULL_SHA384
+ * MBEDTLS_TLS_PSK_WITH_NULL_SHA256
+ * MBEDTLS_TLS_PSK_WITH_NULL_SHA
+ *
+ * Uncomment this macro to enable the NULL cipher and ciphersuites
+ */
+//#define MBEDTLS_CIPHER_NULL_CIPHER
+
+/**
+ * \def MBEDTLS_CIPHER_PADDING_PKCS7
+ *
+ * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for
+ * specific padding modes in the cipher layer with cipher modes that support
+ * padding (e.g. CBC)
+ *
+ * If you disable all padding modes, only full blocks can be used with CBC.
+ *
+ * Enable padding modes in the cipher layer.
+ */
+#define MBEDTLS_CIPHER_PADDING_PKCS7
+#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS
+#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN
+#define MBEDTLS_CIPHER_PADDING_ZEROS
+
+/**
+ * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES
+ *
+ * Enable weak ciphersuites in SSL / TLS.
+ * Warning: Only do so when you know what you are doing. This allows for
+ * channels with virtually no security at all!
+ *
+ * This enables the following ciphersuites:
+ * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA
+ * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA
+ *
+ * Uncomment this macro to enable weak ciphersuites
+ */
+//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES
+
+/**
+ * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+ *
+ * Remove RC4 ciphersuites by default in SSL / TLS.
+ * This flag removes the ciphersuites based on RC4 from the default list as
+ * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to
+ * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them
+ * explicitly.
+ *
+ * Uncomment this macro to remove RC4 ciphersuites by default.
+ */
+#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+
+/**
+ * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ *
+ * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve
+ * module. By default all supported curves are enabled.
+ *
+ * Comment macros to disable the curve and functions for it
+ */
+// #define MBEDTLS_ECP_DP_SECP192R1_ENABLED
+// #define MBEDTLS_ECP_DP_SECP224R1_ENABLED
+// #define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+// #define MBEDTLS_ECP_DP_SECP384R1_ENABLED
+// #define MBEDTLS_ECP_DP_SECP521R1_ENABLED
+// #define MBEDTLS_ECP_DP_SECP192K1_ENABLED
+// #define MBEDTLS_ECP_DP_SECP224K1_ENABLED
+// #define MBEDTLS_ECP_DP_SECP256K1_ENABLED
+// #define MBEDTLS_ECP_DP_BP256R1_ENABLED
+// #define MBEDTLS_ECP_DP_BP384R1_ENABLED
+// #define MBEDTLS_ECP_DP_BP512R1_ENABLED
+// #define MBEDTLS_ECP_DP_CURVE25519_ENABLED
+
+/**
+ * \def MBEDTLS_ECP_NIST_OPTIM
+ *
+ * Enable specific 'modulo p' routines for each NIST prime.
+ * Depending on the prime and architecture, makes operations 4 to 8 times
+ * faster on the corresponding curve.
+ *
+ * Comment this macro to disable NIST curves optimisation.
+ */
+// #define MBEDTLS_ECP_NIST_OPTIM
+
+/**
+ * \def MBEDTLS_ECDSA_DETERMINISTIC
+ *
+ * Enable deterministic ECDSA (RFC 6979).
+ * Standard ECDSA is "fragile" in the sense that lack of entropy when signing
+ * may result in a compromise of the long-term signing key. This is avoided by
+ * the deterministic variant.
+ *
+ * Requires: MBEDTLS_HMAC_DRBG_C
+ *
+ * Comment this macro to disable deterministic ECDSA.
+ */
+// #define MBEDTLS_ECDSA_DETERMINISTIC
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
+ *
+ * Enable the PSK based ciphersuite modes in SSL / TLS.
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA
+ */
+// #define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
+ *
+ * Enable the DHE-PSK based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_DHM_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA
+ */
+// #define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+ *
+ * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA
+ */
+// #define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
+ *
+ * Enable the RSA-PSK based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15,
+ * MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA
+ */
+// #define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+ *
+ * Enable the RSA-only based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15,
+ * MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256
+ * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+ * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+ * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5
+ */
+// #define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
+ *
+ * Enable the DHE-RSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15,
+ * MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
+ */
+// #define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
+ *
+ * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15,
+ * MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+ */
+// #define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+ *
+ * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C,
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+ */
+// #define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
+ *
+ * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ */
+// #define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
+ *
+ * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ */
+// #define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+ *
+ * Enable the ECJPAKE based ciphersuite modes in SSL / TLS.
+ *
+ * \warning This is currently experimental. EC J-PAKE support is based on the
+ * Thread v1.0.0 specification; incompatible changes to the specification
+ * might still happen. For this reason, this is disabled by default.
+ *
+ * Requires: MBEDTLS_ECJPAKE_C
+ * MBEDTLS_SHA256_C
+ * MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
+ */
+//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+
+/**
+ * \def MBEDTLS_PK_PARSE_EC_EXTENDED
+ *
+ * Enhance support for reading EC keys using variants of SEC1 not allowed by
+ * RFC 5915 and RFC 5480.
+ *
+ * Currently this means parsing the SpecifiedECDomain choice of EC
+ * parameters (only known groups are supported, not arbitrary domains, to
+ * avoid validation issues).
+ *
+ * Disable if you only need to support RFC 5915 + 5480 key formats.
+ */
+// #define MBEDTLS_PK_PARSE_EC_EXTENDED
+
+/**
+ * \def MBEDTLS_ERROR_STRERROR_DUMMY
+ *
+ * Enable a dummy error function to make use of mbedtls_strerror() in
+ * third party libraries easier when MBEDTLS_ERROR_C is disabled
+ * (no effect when MBEDTLS_ERROR_C is enabled).
+ *
+ * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're
+ * not using mbedtls_strerror() or error_strerror() in your application.
+ *
+ * Disable if you run into name conflicts and want to really remove the
+ * mbedtls_strerror()
+ */
+// #define MBEDTLS_ERROR_STRERROR_DUMMY
+
+/**
+ * \def MBEDTLS_GENPRIME
+ *
+ * Enable the prime-number generation code.
+ *
+ * Requires: MBEDTLS_BIGNUM_C
+ */
+// #define MBEDTLS_GENPRIME
+
+/**
+ * \def MBEDTLS_FS_IO
+ *
+ * Enable functions that use the filesystem.
+ */
+//#define MBEDTLS_FS_IO
+
+/**
+ * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+ *
+ * Do not add default entropy sources. These are the platform specific,
+ * mbedtls_timing_hardclock and HAVEGE based poll functions.
+ *
+ * This is useful to have more control over the added entropy sources in an
+ * application.
+ *
+ * Uncomment this macro to prevent loading of default entropy functions.
+ */
+//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+
+/**
+ * \def MBEDTLS_NO_PLATFORM_ENTROPY
+ *
+ * Do not use built-in platform entropy functions.
+ * This is useful if your platform does not support
+ * standards like the /dev/urandom or Windows CryptoAPI.
+ *
+ * Uncomment this macro to disable the built-in platform entropy functions.
+ */
+// #define MBEDTLS_NO_PLATFORM_ENTROPY
+
+/**
+ * \def MBEDTLS_ENTROPY_FORCE_SHA256
+ *
+ * Force the entropy accumulator to use a SHA-256 accumulator instead of the
+ * default SHA-512 based one (if both are available).
+ *
+ * Requires: MBEDTLS_SHA256_C
+ *
+ * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option
+ * if you have performance concerns.
+ *
+ * This option is only useful if both MBEDTLS_SHA256_C and
+ * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used.
+ */
+//#define MBEDTLS_ENTROPY_FORCE_SHA256
+
+/**
+ * \def MBEDTLS_ENTROPY_NV_SEED
+ *
+ * Enable the non-volatile (NV) seed file-based entropy source.
+ * (Also enables the NV seed read/write functions in the platform layer)
+ *
+ * This is crucial (if not required) on systems that do not have a
+ * cryptographic entropy source (in hardware or kernel) available.
+ *
+ * Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C
+ *
+ * \note The read/write functions that are used by the entropy source are
+ * determined in the platform layer, and can be modified at runtime and/or
+ * compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used.
+ *
+ * \note If you use the default implementation functions that read a seedfile
+ * with regular fopen(), please make sure you make a seedfile with the
+ * proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at
+ * least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from
+ * and written to or you will get an entropy source error! The default
+ * implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE
+ * bytes from the file.
+ *
+ * \note The entropy collector will write to the seed file before entropy is
+ * given to an external source, to update it.
+ */
+//#define MBEDTLS_ENTROPY_NV_SEED
+
+/**
+ * \def MBEDTLS_MEMORY_DEBUG
+ *
+ * Enable debugging of buffer allocator memory issues. Automatically prints
+ * (to stderr) all (fatal) messages on memory allocation issues. Enables
+ * function for 'debug output' of allocated memory.
+ *
+ * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C
+ *
+ * Uncomment this macro to let the buffer allocator print out error messages.
+ */
+//#define MBEDTLS_MEMORY_DEBUG
+
+/**
+ * \def MBEDTLS_MEMORY_BACKTRACE
+ *
+ * Include backtrace information with each allocated block.
+ *
+ * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C
+ * GLIBC-compatible backtrace() an backtrace_symbols() support
+ *
+ * Uncomment this macro to include backtrace information
+ */
+//#define MBEDTLS_MEMORY_BACKTRACE
+
+/**
+ * \def MBEDTLS_PK_RSA_ALT_SUPPORT
+ *
+ * Support external private RSA keys (eg from a HSM) in the PK layer.
+ *
+ * Comment this macro to disable support for external private RSA keys.
+ */
+// #define MBEDTLS_PK_RSA_ALT_SUPPORT
+
+/**
+ * \def MBEDTLS_PKCS1_V15
+ *
+ * Enable support for PKCS#1 v1.5 encoding.
+ *
+ * Requires: MBEDTLS_RSA_C
+ *
+ * This enables support for PKCS#1 v1.5 operations.
+ */
+// #define MBEDTLS_PKCS1_V15
+
+/**
+ * \def MBEDTLS_PKCS1_V21
+ *
+ * Enable support for PKCS#1 v2.1 encoding.
+ *
+ * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C
+ *
+ * This enables support for RSAES-OAEP and RSASSA-PSS operations.
+ */
+// #define MBEDTLS_PKCS1_V21
+
+/**
+ * \def MBEDTLS_RSA_NO_CRT
+ *
+ * Do not use the Chinese Remainder Theorem for the RSA private operation.
+ *
+ * Uncomment this macro to disable the use of CRT in RSA.
+ *
+ */
+//#define MBEDTLS_RSA_NO_CRT
+
+/**
+ * \def MBEDTLS_SELF_TEST
+ *
+ * Enable the checkup functions (*_self_test).
+ */
+// #define MBEDTLS_SELF_TEST
+
+/**
+ * \def MBEDTLS_SHA256_SMALLER
+ *
+ * Enable an implementation of SHA-256 that has lower ROM footprint but also
+ * lower performance.
+ *
+ * The default implementation is meant to be a reasonnable compromise between
+ * performance and size. This version optimizes more aggressively for size at
+ * the expense of performance. Eg on Cortex-M4 it reduces the size of
+ * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about
+ * 30%.
+ *
+ * Uncomment to enable the smaller implementation of SHA256.
+ */
+//#define MBEDTLS_SHA256_SMALLER
+
+/**
+ * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES
+ *
+ * Enable sending of alert messages in case of encountered errors as per RFC.
+ * If you choose not to send the alert messages, mbed TLS can still communicate
+ * with other servers, only debugging of failures is harder.
+ *
+ * The advantage of not sending alert messages, is that no information is given
+ * about reasons for failures thus preventing adversaries of gaining intel.
+ *
+ * Enable sending of all alert messages
+ */
+// #define MBEDTLS_SSL_ALL_ALERT_MESSAGES
+
+/**
+ * \def MBEDTLS_SSL_DEBUG_ALL
+ *
+ * Enable the debug messages in SSL module for all issues.
+ * Debug messages have been disabled in some places to prevent timing
+ * attacks due to (unbalanced) debugging function calls.
+ *
+ * If you need all error reporting you should enable this during debugging,
+ * but remove this for production servers that should log as well.
+ *
+ * Uncomment this macro to report all debug messages on errors introducing
+ * a timing side-channel.
+ *
+ */
+//#define MBEDTLS_SSL_DEBUG_ALL
+
+/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC
+ *
+ * Enable support for Encrypt-then-MAC, RFC 7366.
+ *
+ * This allows peers that both support it to use a more robust protection for
+ * ciphersuites using CBC, providing deep resistance against timing attacks
+ * on the padding or underlying cipher.
+ *
+ * This only affects CBC ciphersuites, and is useless if none is defined.
+ *
+ * Requires: MBEDTLS_SSL_PROTO_TLS1 or
+ * MBEDTLS_SSL_PROTO_TLS1_1 or
+ * MBEDTLS_SSL_PROTO_TLS1_2
+ *
+ * Comment this macro to disable support for Encrypt-then-MAC
+ */
+// #define MBEDTLS_SSL_ENCRYPT_THEN_MAC
+
+/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET
+ *
+ * Enable support for Extended Master Secret, aka Session Hash
+ * (draft-ietf-tls-session-hash-02).
+ *
+ * This was introduced as "the proper fix" to the Triple Handshake familiy of
+ * attacks, but it is recommended to always use it (even if you disable
+ * renegotiation), since it actually fixes a more fundamental issue in the
+ * original SSL/TLS design, and has implications beyond Triple Handshake.
+ *
+ * Requires: MBEDTLS_SSL_PROTO_TLS1 or
+ * MBEDTLS_SSL_PROTO_TLS1_1 or
+ * MBEDTLS_SSL_PROTO_TLS1_2
+ *
+ * Comment this macro to disable support for Extended Master Secret.
+ */
+// #define MBEDTLS_SSL_EXTENDED_MASTER_SECRET
+
+/**
+ * \def MBEDTLS_SSL_FALLBACK_SCSV
+ *
+ * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00).
+ *
+ * For servers, it is recommended to always enable this, unless you support
+ * only one version of TLS, or know for sure that none of your clients
+ * implements a fallback strategy.
+ *
+ * For clients, you only need this if you're using a fallback strategy, which
+ * is not recommended in the first place, unless you absolutely need it to
+ * interoperate with buggy (version-intolerant) servers.
+ *
+ * Comment this macro to disable support for FALLBACK_SCSV
+ */
+// #define MBEDTLS_SSL_FALLBACK_SCSV
+
+/**
+ * \def MBEDTLS_SSL_HW_RECORD_ACCEL
+ *
+ * Enable hooking functions in SSL module for hardware acceleration of
+ * individual records.
+ *
+ * Uncomment this macro to enable hooking functions.
+ */
+//#define MBEDTLS_SSL_HW_RECORD_ACCEL
+
+/**
+ * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING
+ *
+ * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0.
+ *
+ * This is a countermeasure to the BEAST attack, which also minimizes the risk
+ * of interoperability issues compared to sending 0-length records.
+ *
+ * Comment this macro to disable 1/n-1 record splitting.
+ */
+// #define MBEDTLS_SSL_CBC_RECORD_SPLITTING
+
+/**
+ * \def MBEDTLS_SSL_RENEGOTIATION
+ *
+ * Disable support for TLS renegotiation.
+ *
+ * The two main uses of renegotiation are (1) refresh keys on long-lived
+ * connections and (2) client authentication after the initial handshake.
+ * If you don't need renegotiation, it's probably better to disable it, since
+ * it has been associated with security issues in the past and is easy to
+ * misuse/misunderstand.
+ *
+ * Comment this to disable support for renegotiation.
+ */
+// #define MBEDTLS_SSL_RENEGOTIATION
+
+/**
+ * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
+ *
+ * Enable support for receiving and parsing SSLv2 Client Hello messages for the
+ * SSL Server module (MBEDTLS_SSL_SRV_C).
+ *
+ * Uncomment this macro to enable support for SSLv2 Client Hello messages.
+ */
+//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
+
+/**
+ * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE
+ *
+ * Pick the ciphersuite according to the client's preferences rather than ours
+ * in the SSL Server module (MBEDTLS_SSL_SRV_C).
+ *
+ * Uncomment this macro to respect client's ciphersuite order
+ */
+//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE
+
+/**
+ * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+ *
+ * Enable support for RFC 6066 max_fragment_length extension in SSL.
+ *
+ * Comment this macro to disable support for the max_fragment_length extension
+ */
+// #define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+
+/**
+ * \def MBEDTLS_SSL_PROTO_SSL3
+ *
+ * Enable support for SSL 3.0.
+ *
+ * Requires: MBEDTLS_MD5_C
+ * MBEDTLS_SHA1_C
+ *
+ * Comment this macro to disable support for SSL 3.0
+ */
+//#define MBEDTLS_SSL_PROTO_SSL3
+
+/**
+ * \def MBEDTLS_SSL_PROTO_TLS1
+ *
+ * Enable support for TLS 1.0.
+ *
+ * Requires: MBEDTLS_MD5_C
+ * MBEDTLS_SHA1_C
+ *
+ * Comment this macro to disable support for TLS 1.0
+ */
+// #define MBEDTLS_SSL_PROTO_TLS1
+
+/**
+ * \def MBEDTLS_SSL_PROTO_TLS1_1
+ *
+ * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled).
+ *
+ * Requires: MBEDTLS_MD5_C
+ * MBEDTLS_SHA1_C
+ *
+ * Comment this macro to disable support for TLS 1.1 / DTLS 1.0
+ */
+// #define MBEDTLS_SSL_PROTO_TLS1_1
+
+/**
+ * \def MBEDTLS_SSL_PROTO_TLS1_2
+ *
+ * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled).
+ *
+ * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C
+ * (Depends on ciphersuites)
+ *
+ * Comment this macro to disable support for TLS 1.2 / DTLS 1.2
+ */
+// #define MBEDTLS_SSL_PROTO_TLS1_2
+
+/**
+ * \def MBEDTLS_SSL_PROTO_DTLS
+ *
+ * Enable support for DTLS (all available versions).
+ *
+ * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0,
+ * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2.
+ *
+ * Requires: MBEDTLS_SSL_PROTO_TLS1_1
+ * or MBEDTLS_SSL_PROTO_TLS1_2
+ *
+ * Comment this macro to disable support for DTLS
+ */
+// #define MBEDTLS_SSL_PROTO_DTLS
+
+/**
+ * \def MBEDTLS_SSL_ALPN
+ *
+ * Enable support for RFC 7301 Application Layer Protocol Negotiation.
+ *
+ * Comment this macro to disable support for ALPN.
+ */
+// #define MBEDTLS_SSL_ALPN
+
+/**
+ * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY
+ *
+ * Enable support for the anti-replay mechanism in DTLS.
+ *
+ * Requires: MBEDTLS_SSL_TLS_C
+ * MBEDTLS_SSL_PROTO_DTLS
+ *
+ * \warning Disabling this is often a security risk!
+ * See mbedtls_ssl_conf_dtls_anti_replay() for details.
+ *
+ * Comment this to disable anti-replay in DTLS.
+ */
+// #define MBEDTLS_SSL_DTLS_ANTI_REPLAY
+
+/**
+ * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY
+ *
+ * Enable support for HelloVerifyRequest on DTLS servers.
+ *
+ * This feature is highly recommended to prevent DTLS servers being used as
+ * amplifiers in DoS attacks against other hosts. It should always be enabled
+ * unless you know for sure amplification cannot be a problem in the
+ * environment in which your server operates.
+ *
+ * \warning Disabling this can ba a security risk! (see above)
+ *
+ * Requires: MBEDTLS_SSL_PROTO_DTLS
+ *
+ * Comment this to disable support for HelloVerifyRequest.
+ */
+// #define MBEDTLS_SSL_DTLS_HELLO_VERIFY
+
+/**
+ * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
+ *
+ * Enable server-side support for clients that reconnect from the same port.
+ *
+ * Some clients unexpectedly close the connection and try to reconnect using the
+ * same source port. This needs special support from the server to handle the
+ * new connection securely, as described in section 4.2.8 of RFC 6347. This
+ * flag enables that support.
+ *
+ * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY
+ *
+ * Comment this to disable support for clients reusing the source port.
+ */
+// #define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
+
+/**
+ * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT
+ *
+ * Enable support for a limit of records with bad MAC.
+ *
+ * See mbedtls_ssl_conf_dtls_badmac_limit().
+ *
+ * Requires: MBEDTLS_SSL_PROTO_DTLS
+ */
+// #define MBEDTLS_SSL_DTLS_BADMAC_LIMIT
+
+/**
+ * \def MBEDTLS_SSL_SESSION_TICKETS
+ *
+ * Enable support for RFC 5077 session tickets in SSL.
+ * Client-side, provides full support for session tickets (maintainance of a
+ * session store remains the responsibility of the application, though).
+ * Server-side, you also need to provide callbacks for writing and parsing
+ * tickets, including authenticated encryption and key management. Example
+ * callbacks are provided by MBEDTLS_SSL_TICKET_C.
+ *
+ * Comment this macro to disable support for SSL session tickets
+ */
+// #define MBEDTLS_SSL_SESSION_TICKETS
+
+/**
+ * \def MBEDTLS_SSL_EXPORT_KEYS
+ *
+ * Enable support for exporting key block and master secret.
+ * This is required for certain users of TLS, e.g. EAP-TLS.
+ *
+ * Comment this macro to disable support for key export
+ */
+// #define MBEDTLS_SSL_EXPORT_KEYS
+
+/**
+ * \def MBEDTLS_SSL_SERVER_NAME_INDICATION
+ *
+ * Enable support for RFC 6066 server name indication (SNI) in SSL.
+ *
+ * Requires: MBEDTLS_X509_CRT_PARSE_C
+ *
+ * Comment this macro to disable support for server name indication in SSL
+ */
+// #define MBEDTLS_SSL_SERVER_NAME_INDICATION
+
+/**
+ * \def MBEDTLS_SSL_TRUNCATED_HMAC
+ *
+ * Enable support for RFC 6066 truncated HMAC in SSL.
+ *
+ * Comment this macro to disable support for truncated HMAC in SSL
+ */
+// #define MBEDTLS_SSL_TRUNCATED_HMAC
+
+/**
+ * \def MBEDTLS_THREADING_ALT
+ *
+ * Provide your own alternate threading implementation.
+ *
+ * Requires: MBEDTLS_THREADING_C
+ *
+ * Uncomment this to allow your own alternate threading implementation.
+ */
+//#define MBEDTLS_THREADING_ALT
+
+/**
+ * \def MBEDTLS_THREADING_PTHREAD
+ *
+ * Enable the pthread wrapper layer for the threading layer.
+ *
+ * Requires: MBEDTLS_THREADING_C
+ *
+ * Uncomment this to enable pthread mutexes.
+ */
+//#define MBEDTLS_THREADING_PTHREAD
+
+/**
+ * \def MBEDTLS_VERSION_FEATURES
+ *
+ * Allow run-time checking of compile-time enabled features. Thus allowing users
+ * to check at run-time if the library is for instance compiled with threading
+ * support via mbedtls_version_check_feature().
+ *
+ * Requires: MBEDTLS_VERSION_C
+ *
+ * Comment this to disable run-time checking and save ROM space
+ */
+// #define MBEDTLS_VERSION_FEATURES
+
+/**
+ * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
+ *
+ * If set, the X509 parser will not break-off when parsing an X509 certificate
+ * and encountering an extension in a v1 or v2 certificate.
+ *
+ * Uncomment to prevent an error.
+ */
+//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
+
+/**
+ * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
+ *
+ * If set, the X509 parser will not break-off when parsing an X509 certificate
+ * and encountering an unknown critical extension.
+ *
+ * \warning Depending on your PKI use, enabling this can be a security risk!
+ *
+ * Uncomment to prevent an error.
+ */
+//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
+
+/**
+ * \def MBEDTLS_X509_CHECK_KEY_USAGE
+ *
+ * Enable verification of the keyUsage extension (CA and leaf certificates).
+ *
+ * Disabling this avoids problems with mis-issued and/or misused
+ * (intermediate) CA and leaf certificates.
+ *
+ * \warning Depending on your PKI use, disabling this can be a security risk!
+ *
+ * Comment to skip keyUsage checking for both CA and leaf certificates.
+ */
+// #define MBEDTLS_X509_CHECK_KEY_USAGE
+
+/**
+ * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
+ *
+ * Enable verification of the extendedKeyUsage extension (leaf certificates).
+ *
+ * Disabling this avoids problems with mis-issued and/or misused certificates.
+ *
+ * \warning Depending on your PKI use, disabling this can be a security risk!
+ *
+ * Comment to skip extendedKeyUsage checking for certificates.
+ */
+// #define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
+
+/**
+ * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT
+ *
+ * Enable parsing and verification of X.509 certificates, CRLs and CSRS
+ * signed with RSASSA-PSS (aka PKCS#1 v2.1).
+ *
+ * Comment this macro to disallow using RSASSA-PSS in certificates.
+ */
+// #define MBEDTLS_X509_RSASSA_PSS_SUPPORT
+
+/**
+ * \def MBEDTLS_ZLIB_SUPPORT
+ *
+ * If set, the SSL/TLS module uses ZLIB to support compression and
+ * decompression of packet data.
+ *
+ * \warning TLS-level compression MAY REDUCE SECURITY! See for example the
+ * CRIME attack. Before enabling this option, you should examine with care if
+ * CRIME or similar exploits may be a applicable to your use case.
+ *
+ * \note Currently compression can't be used with DTLS.
+ *
+ * Used in: library/ssl_tls.c
+ * library/ssl_cli.c
+ * library/ssl_srv.c
+ *
+ * This feature requires zlib library and headers to be present.
+ *
+ * Uncomment to enable use of ZLIB
+ */
+//#define MBEDTLS_ZLIB_SUPPORT
+/* \} name SECTION: mbed TLS feature support */
+
+/**
+ * \name SECTION: mbed TLS modules
+ *
+ * This section enables or disables entire modules in mbed TLS
+ * \{
+ */
+
+/**
+ * \def MBEDTLS_AESNI_C
+ *
+ * Enable AES-NI support on x86-64.
+ *
+ * Module: library/aesni.c
+ * Caller: library/aes.c
+ *
+ * Requires: MBEDTLS_HAVE_ASM
+ *
+ * This modules adds support for the AES-NI instructions on x86-64
+ */
+// #define MBEDTLS_AESNI_C
+
+/**
+ * \def MBEDTLS_AES_C
+ *
+ * Enable the AES block cipher.
+ *
+ * Module: library/aes.c
+ * Caller: library/ssl_tls.c
+ * library/pem.c
+ * library/ctr_drbg.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256
+ * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA
+ * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384
+ * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384
+ * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA
+ * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256
+ * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256
+ * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA
+ *
+ * PEM_PARSE uses AES for decrypting encrypted keys.
+ */
+#define MBEDTLS_AES_C
+
+/**
+ * \def MBEDTLS_ARC4_C
+ *
+ * Enable the ARCFOUR stream cipher.
+ *
+ * Module: library/arc4.c
+ * Caller: library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5
+ * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA
+ * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA
+ */
+// #define MBEDTLS_ARC4_C
+
+/**
+ * \def MBEDTLS_ASN1_PARSE_C
+ *
+ * Enable the generic ASN1 parser.
+ *
+ * Module: library/asn1.c
+ * Caller: library/x509.c
+ * library/dhm.c
+ * library/pkcs12.c
+ * library/pkcs5.c
+ * library/pkparse.c
+ */
+// #define MBEDTLS_ASN1_PARSE_C
+
+/**
+ * \def MBEDTLS_ASN1_WRITE_C
+ *
+ * Enable the generic ASN1 writer.
+ *
+ * Module: library/asn1write.c
+ * Caller: library/ecdsa.c
+ * library/pkwrite.c
+ * library/x509_create.c
+ * library/x509write_crt.c
+ * library/x509write_csr.c
+ */
+// #define MBEDTLS_ASN1_WRITE_C
+
+/**
+ * \def MBEDTLS_BASE64_C
+ *
+ * Enable the Base64 module.
+ *
+ * Module: library/base64.c
+ * Caller: library/pem.c
+ *
+ * This module is required for PEM support (required by X.509).
+ */
+// #define MBEDTLS_BASE64_C
+
+/**
+ * \def MBEDTLS_BIGNUM_C
+ *
+ * Enable the multi-precision integer library.
+ *
+ * Module: library/bignum.c
+ * Caller: library/dhm.c
+ * library/ecp.c
+ * library/ecdsa.c
+ * library/rsa.c
+ * library/ssl_tls.c
+ *
+ * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support.
+ */
+// #define MBEDTLS_BIGNUM_C
+
+/**
+ * \def MBEDTLS_BLOWFISH_C
+ *
+ * Enable the Blowfish block cipher.
+ *
+ * Module: library/blowfish.c
+ */
+// #define MBEDTLS_BLOWFISH_C
+
+/**
+ * \def MBEDTLS_CAMELLIA_C
+ *
+ * Enable the Camellia block cipher.
+ *
+ * Module: library/camellia.c
+ * Caller: library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+ * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ */
+// #define MBEDTLS_CAMELLIA_C
+
+/**
+ * \def MBEDTLS_CCM_C
+ *
+ * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher.
+ *
+ * Module: library/ccm.c
+ *
+ * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C
+ *
+ * This module enables the AES-CCM ciphersuites, if other requisites are
+ * enabled as well.
+ */
+#define MBEDTLS_CCM_C
+
+/**
+ * \def MBEDTLS_CERTS_C
+ *
+ * Enable the test certificates.
+ *
+ * Module: library/certs.c
+ * Caller:
+ *
+ * This module is used for testing (ssl_client/server).
+ */
+// #define MBEDTLS_CERTS_C
+
+/**
+ * \def MBEDTLS_CIPHER_C
+ *
+ * Enable the generic cipher layer.
+ *
+ * Module: library/cipher.c
+ * Caller: library/ssl_tls.c
+ *
+ * Uncomment to enable generic cipher wrappers.
+ */
+#define MBEDTLS_CIPHER_C
+
+/**
+ * \def MBEDTLS_CMAC_C
+ *
+ * Enable the CMAC (Cipher-based Message Authentication Code) mode for block
+ * ciphers.
+ *
+ * Module: library/cmac.c
+ *
+ * Requires: MBEDTLS_AES_C or MBEDTLS_DES_C
+ *
+ */
+//#define MBEDTLS_CMAC_C
+
+/**
+ * \def MBEDTLS_CTR_DRBG_C
+ *
+ * Enable the CTR_DRBG AES-256-based random generator.
+ *
+ * Module: library/ctr_drbg.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_AES_C
+ *
+ * This module provides the CTR_DRBG AES-256 random number generator.
+ */
+// #define MBEDTLS_CTR_DRBG_C
+
+/**
+ * \def MBEDTLS_DEBUG_C
+ *
+ * Enable the debug functions.
+ *
+ * Module: library/debug.c
+ * Caller: library/ssl_cli.c
+ * library/ssl_srv.c
+ * library/ssl_tls.c
+ *
+ * This module provides debugging functions.
+ */
+// #define MBEDTLS_DEBUG_C
+
+/**
+ * \def MBEDTLS_DES_C
+ *
+ * Enable the DES block cipher.
+ *
+ * Module: library/des.c
+ * Caller: library/pem.c
+ * library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA
+ * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA
+ *
+ * PEM_PARSE uses DES/3DES for decrypting encrypted keys.
+ */
+// #define MBEDTLS_DES_C
+
+/**
+ * \def MBEDTLS_DHM_C
+ *
+ * Enable the Diffie-Hellman-Merkle module.
+ *
+ * Module: library/dhm.c
+ * Caller: library/ssl_cli.c
+ * library/ssl_srv.c
+ *
+ * This module is used by the following key exchanges:
+ * DHE-RSA, DHE-PSK
+ */
+// #define MBEDTLS_DHM_C
+
+/**
+ * \def MBEDTLS_ECDH_C
+ *
+ * Enable the elliptic curve Diffie-Hellman library.
+ *
+ * Module: library/ecdh.c
+ * Caller: library/ssl_cli.c
+ * library/ssl_srv.c
+ *
+ * This module is used by the following key exchanges:
+ * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK
+ *
+ * Requires: MBEDTLS_ECP_C
+ */
+// #define MBEDTLS_ECDH_C
+
+/**
+ * \def MBEDTLS_ECDSA_C
+ *
+ * Enable the elliptic curve DSA library.
+ *
+ * Module: library/ecdsa.c
+ * Caller:
+ *
+ * This module is used by the following key exchanges:
+ * ECDHE-ECDSA
+ *
+ * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C
+ */
+// #define MBEDTLS_ECDSA_C
+
+/**
+ * \def MBEDTLS_ECJPAKE_C
+ *
+ * Enable the elliptic curve J-PAKE library.
+ *
+ * \warning This is currently experimental. EC J-PAKE support is based on the
+ * Thread v1.0.0 specification; incompatible changes to the specification
+ * might still happen. For this reason, this is disabled by default.
+ *
+ * Module: library/ecjpake.c
+ * Caller:
+ *
+ * This module is used by the following key exchanges:
+ * ECJPAKE
+ *
+ * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C
+ */
+//#define MBEDTLS_ECJPAKE_C
+
+/**
+ * \def MBEDTLS_ECP_C
+ *
+ * Enable the elliptic curve over GF(p) library.
+ *
+ * Module: library/ecp.c
+ * Caller: library/ecdh.c
+ * library/ecdsa.c
+ * library/ecjpake.c
+ *
+ * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED
+ */
+// #define MBEDTLS_ECP_C
+
+/**
+ * \def MBEDTLS_ENTROPY_C
+ *
+ * Enable the platform-specific entropy code.
+ *
+ * Module: library/entropy.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C
+ *
+ * This module provides a generic entropy pool
+ */
+// #define MBEDTLS_ENTROPY_C
+
+/**
+ * \def MBEDTLS_ERROR_C
+ *
+ * Enable error code to error string conversion.
+ *
+ * Module: library/error.c
+ * Caller:
+ *
+ * This module enables mbedtls_strerror().
+ */
+// #define MBEDTLS_ERROR_C
+
+/**
+ * \def MBEDTLS_GCM_C
+ *
+ * Enable the Galois/Counter Mode (GCM) for AES.
+ *
+ * Module: library/gcm.c
+ *
+ * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C
+ *
+ * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other
+ * requisites are enabled as well.
+ */
+// #define MBEDTLS_GCM_C
+
+/**
+ * \def MBEDTLS_HAVEGE_C
+ *
+ * Enable the HAVEGE random generator.
+ *
+ * Warning: the HAVEGE random generator is not suitable for virtualized
+ * environments
+ *
+ * Warning: the HAVEGE random generator is dependent on timing and specific
+ * processor traits. It is therefore not advised to use HAVEGE as
+ * your applications primary random generator or primary entropy pool
+ * input. As a secondary input to your entropy pool, it IS able add
+ * the (limited) extra entropy it provides.
+ *
+ * Module: library/havege.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_TIMING_C
+ *
+ * Uncomment to enable the HAVEGE random generator.
+ */
+//#define MBEDTLS_HAVEGE_C
+
+/**
+ * \def MBEDTLS_HMAC_DRBG_C
+ *
+ * Enable the HMAC_DRBG random generator.
+ *
+ * Module: library/hmac_drbg.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_MD_C
+ *
+ * Uncomment to enable the HMAC_DRBG random number geerator.
+ */
+// #define MBEDTLS_HMAC_DRBG_C
+
+/**
+ * \def MBEDTLS_MD_C
+ *
+ * Enable the generic message digest layer.
+ *
+ * Module: library/md.c
+ * Caller:
+ *
+ * Uncomment to enable generic message digest wrappers.
+ */
+// #define MBEDTLS_MD_C
+
+/**
+ * \def MBEDTLS_MD2_C
+ *
+ * Enable the MD2 hash algorithm.
+ *
+ * Module: library/md2.c
+ * Caller:
+ *
+ * Uncomment to enable support for (rare) MD2-signed X.509 certs.
+ */
+//#define MBEDTLS_MD2_C
+
+/**
+ * \def MBEDTLS_MD4_C
+ *
+ * Enable the MD4 hash algorithm.
+ *
+ * Module: library/md4.c
+ * Caller:
+ *
+ * Uncomment to enable support for (rare) MD4-signed X.509 certs.
+ */
+//#define MBEDTLS_MD4_C
+
+/**
+ * \def MBEDTLS_MD5_C
+ *
+ * Enable the MD5 hash algorithm.
+ *
+ * Module: library/md5.c
+ * Caller: library/md.c
+ * library/pem.c
+ * library/ssl_tls.c
+ *
+ * This module is required for SSL/TLS and X.509.
+ * PEM_PARSE uses MD5 for decrypting encrypted keys.
+ */
+// #define MBEDTLS_MD5_C
+
+/**
+ * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C
+ *
+ * Enable the buffer allocator implementation that makes use of a (stack)
+ * based buffer to 'allocate' dynamic memory. (replaces calloc() and free()
+ * calls)
+ *
+ * Module: library/memory_buffer_alloc.c
+ *
+ * Requires: MBEDTLS_PLATFORM_C
+ * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS)
+ *
+ * Enable this module to enable the buffer memory allocator.
+ */
+//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
+
+/**
+ * \def MBEDTLS_NET_C
+ *
+ * Enable the TCP and UDP over IPv6/IPv4 networking routines.
+ *
+ * \note This module only works on POSIX/Unix (including Linux, BSD and OS X)
+ * and Windows. For other platforms, you'll want to disable it, and write your
+ * own networking callbacks to be passed to \c mbedtls_ssl_set_bio().
+ *
+ * \note See also our Knowledge Base article about porting to a new
+ * environment:
+ * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
+ *
+ * Module: library/net_sockets.c
+ *
+ * This module provides networking routines.
+ */
+//#define MBEDTLS_NET_C
+
+/**
+ * \def MBEDTLS_OID_C
+ *
+ * Enable the OID database.
+ *
+ * Module: library/oid.c
+ * Caller: library/asn1write.c
+ * library/pkcs5.c
+ * library/pkparse.c
+ * library/pkwrite.c
+ * library/rsa.c
+ * library/x509.c
+ * library/x509_create.c
+ * library/x509_crl.c
+ * library/x509_crt.c
+ * library/x509_csr.c
+ * library/x509write_crt.c
+ * library/x509write_csr.c
+ *
+ * This modules translates between OIDs and internal values.
+ */
+#define MBEDTLS_OID_C
+
+/**
+ * \def MBEDTLS_PADLOCK_C
+ *
+ * Enable VIA Padlock support on x86.
+ *
+ * Module: library/padlock.c
+ * Caller: library/aes.c
+ *
+ * Requires: MBEDTLS_HAVE_ASM
+ *
+ * This modules adds support for the VIA PadLock on x86.
+ */
+// #define MBEDTLS_PADLOCK_C
+
+/**
+ * \def MBEDTLS_PEM_PARSE_C
+ *
+ * Enable PEM decoding / parsing.
+ *
+ * Module: library/pem.c
+ * Caller: library/dhm.c
+ * library/pkparse.c
+ * library/x509_crl.c
+ * library/x509_crt.c
+ * library/x509_csr.c
+ *
+ * Requires: MBEDTLS_BASE64_C
+ *
+ * This modules adds support for decoding / parsing PEM files.
+ */
+// #define MBEDTLS_PEM_PARSE_C
+
+/**
+ * \def MBEDTLS_PEM_WRITE_C
+ *
+ * Enable PEM encoding / writing.
+ *
+ * Module: library/pem.c
+ * Caller: library/pkwrite.c
+ * library/x509write_crt.c
+ * library/x509write_csr.c
+ *
+ * Requires: MBEDTLS_BASE64_C
+ *
+ * This modules adds support for encoding / writing PEM files.
+ */
+// // #define MBEDTLS_PEM_WRITE_C
+
+/**
+ * \def MBEDTLS_PK_C
+ *
+ * Enable the generic public (asymetric) key layer.
+ *
+ * Module: library/pk.c
+ * Caller: library/ssl_tls.c
+ * library/ssl_cli.c
+ * library/ssl_srv.c
+ *
+ * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C
+ *
+ * Uncomment to enable generic public key wrappers.
+ */
+// #define MBEDTLS_PK_C
+
+/**
+ * \def MBEDTLS_PK_PARSE_C
+ *
+ * Enable the generic public (asymetric) key parser.
+ *
+ * Module: library/pkparse.c
+ * Caller: library/x509_crt.c
+ * library/x509_csr.c
+ *
+ * Requires: MBEDTLS_PK_C
+ *
+ * Uncomment to enable generic public key parse functions.
+ */
+// #define MBEDTLS_PK_PARSE_C
+
+/**
+ * \def MBEDTLS_PK_WRITE_C
+ *
+ * Enable the generic public (asymetric) key writer.
+ *
+ * Module: library/pkwrite.c
+ * Caller: library/x509write.c
+ *
+ * Requires: MBEDTLS_PK_C
+ *
+ * Uncomment to enable generic public key write functions.
+ */
+// #define MBEDTLS_PK_WRITE_C
+
+/**
+ * \def MBEDTLS_PKCS5_C
+ *
+ * Enable PKCS#5 functions.
+ *
+ * Module: library/pkcs5.c
+ *
+ * Requires: MBEDTLS_MD_C
+ *
+ * This module adds support for the PKCS#5 functions.
+ */
+// #define MBEDTLS_PKCS5_C
+
+/**
+ * \def MBEDTLS_PKCS11_C
+ *
+ * Enable wrapper for PKCS#11 smartcard support.
+ *
+ * Module: library/pkcs11.c
+ * Caller: library/pk.c
+ *
+ * Requires: MBEDTLS_PK_C
+ *
+ * This module enables SSL/TLS PKCS #11 smartcard support.
+ * Requires the presence of the PKCS#11 helper library (libpkcs11-helper)
+ */
+//#define MBEDTLS_PKCS11_C
+
+/**
+ * \def MBEDTLS_PKCS12_C
+ *
+ * Enable PKCS#12 PBE functions.
+ * Adds algorithms for parsing PKCS#8 encrypted private keys
+ *
+ * Module: library/pkcs12.c
+ * Caller: library/pkparse.c
+ *
+ * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C
+ * Can use: MBEDTLS_ARC4_C
+ *
+ * This module enables PKCS#12 functions.
+ */
+// #define MBEDTLS_PKCS12_C
+
+/**
+ * \def MBEDTLS_PLATFORM_C
+ *
+ * Enable the platform abstraction layer that allows you to re-assign
+ * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit().
+ *
+ * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT
+ * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned
+ * above to be specified at runtime or compile time respectively.
+ *
+ * \note This abstraction layer must be enabled on Windows (including MSYS2)
+ * as other module rely on it for a fixed snprintf implementation.
+ *
+ * Module: library/platform.c
+ * Caller: Most other .c files
+ *
+ * This module enables abstraction of common (libc) functions.
+ */
+// #define MBEDTLS_PLATFORM_C
+
+/**
+ * \def MBEDTLS_RIPEMD160_C
+ *
+ * Enable the RIPEMD-160 hash algorithm.
+ *
+ * Module: library/ripemd160.c
+ * Caller: library/md.c
+ *
+ */
+// #define MBEDTLS_RIPEMD160_C
+
+/**
+ * \def MBEDTLS_RSA_C
+ *
+ * Enable the RSA public-key cryptosystem.
+ *
+ * Module: library/rsa.c
+ * Caller: library/ssl_cli.c
+ * library/ssl_srv.c
+ * library/ssl_tls.c
+ * library/x509.c
+ *
+ * This module is used by the following key exchanges:
+ * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK
+ *
+ * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C
+ */
+// #define MBEDTLS_RSA_C
+
+/**
+ * \def MBEDTLS_SHA1_C
+ *
+ * Enable the SHA1 cryptographic hash algorithm.
+ *
+ * Module: library/sha1.c
+ * Caller: library/md.c
+ * library/ssl_cli.c
+ * library/ssl_srv.c
+ * library/ssl_tls.c
+ * library/x509write_crt.c
+ *
+ * This module is required for SSL/TLS and SHA1-signed certificates.
+ */
+// #define MBEDTLS_SHA1_C
+
+/**
+ * \def MBEDTLS_SHA256_C
+ *
+ * Enable the SHA-224 and SHA-256 cryptographic hash algorithms.
+ *
+ * Module: library/sha256.c
+ * Caller: library/entropy.c
+ * library/md.c
+ * library/ssl_cli.c
+ * library/ssl_srv.c
+ * library/ssl_tls.c
+ *
+ * This module adds support for SHA-224 and SHA-256.
+ * This module is required for the SSL/TLS 1.2 PRF function.
+ */
+// #define MBEDTLS_SHA256_C
+
+/**
+ * \def MBEDTLS_SHA512_C
+ *
+ * Enable the SHA-384 and SHA-512 cryptographic hash algorithms.
+ *
+ * Module: library/sha512.c
+ * Caller: library/entropy.c
+ * library/md.c
+ * library/ssl_cli.c
+ * library/ssl_srv.c
+ *
+ * This module adds support for SHA-384 and SHA-512.
+ */
+// #define MBEDTLS_SHA512_C
+
+/**
+ * \def MBEDTLS_SSL_CACHE_C
+ *
+ * Enable simple SSL cache implementation.
+ *
+ * Module: library/ssl_cache.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_SSL_CACHE_C
+ */
+// #define MBEDTLS_SSL_CACHE_C
+
+/**
+ * \def MBEDTLS_SSL_COOKIE_C
+ *
+ * Enable basic implementation of DTLS cookies for hello verification.
+ *
+ * Module: library/ssl_cookie.c
+ * Caller:
+ */
+// #define MBEDTLS_SSL_COOKIE_C
+
+/**
+ * \def MBEDTLS_SSL_TICKET_C
+ *
+ * Enable an implementation of TLS server-side callbacks for session tickets.
+ *
+ * Module: library/ssl_ticket.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_CIPHER_C
+ */
+// #define MBEDTLS_SSL_TICKET_C
+
+/**
+ * \def MBEDTLS_SSL_CLI_C
+ *
+ * Enable the SSL/TLS client code.
+ *
+ * Module: library/ssl_cli.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_SSL_TLS_C
+ *
+ * This module is required for SSL/TLS client support.
+ */
+// #define MBEDTLS_SSL_CLI_C
+
+/**
+ * \def MBEDTLS_SSL_SRV_C
+ *
+ * Enable the SSL/TLS server code.
+ *
+ * Module: library/ssl_srv.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_SSL_TLS_C
+ *
+ * This module is required for SSL/TLS server support.
+ */
+// #define MBEDTLS_SSL_SRV_C
+
+/**
+ * \def MBEDTLS_SSL_TLS_C
+ *
+ * Enable the generic SSL/TLS code.
+ *
+ * Module: library/ssl_tls.c
+ * Caller: library/ssl_cli.c
+ * library/ssl_srv.c
+ *
+ * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C
+ * and at least one of the MBEDTLS_SSL_PROTO_XXX defines
+ *
+ * This module is required for SSL/TLS.
+ */
+// #define MBEDTLS_SSL_TLS_C
+
+/**
+ * \def MBEDTLS_THREADING_C
+ *
+ * Enable the threading abstraction layer.
+ * By default mbed TLS assumes it is used in a non-threaded environment or that
+ * contexts are not shared between threads. If you do intend to use contexts
+ * between threads, you will need to enable this layer to prevent race
+ * conditions. See also our Knowledge Base article about threading:
+ * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading
+ *
+ * Module: library/threading.c
+ *
+ * This allows different threading implementations (self-implemented or
+ * provided).
+ *
+ * You will have to enable either MBEDTLS_THREADING_ALT or
+ * MBEDTLS_THREADING_PTHREAD.
+ *
+ * Enable this layer to allow use of mutexes within mbed TLS
+ */
+//#define MBEDTLS_THREADING_C
+
+/**
+ * \def MBEDTLS_TIMING_C
+ *
+ * Enable the semi-portable timing interface.
+ *
+ * \note The provided implementation only works on POSIX/Unix (including Linux,
+ * BSD and OS X) and Windows. On other platforms, you can either disable that
+ * module and provide your own implementations of the callbacks needed by
+ * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide
+ * your own implementation of the whole module by setting
+ * \c MBEDTLS_TIMING_ALT in the current file.
+ *
+ * \note See also our Knowledge Base article about porting to a new
+ * environment:
+ * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
+ *
+ * Module: library/timing.c
+ * Caller: library/havege.c
+ *
+ * This module is used by the HAVEGE random number generator.
+ */
+//#define MBEDTLS_TIMING_C
+
+/**
+ * \def MBEDTLS_VERSION_C
+ *
+ * Enable run-time version information.
+ *
+ * Module: library/version.c
+ *
+ * This module provides run-time version information.
+ */
+// #define MBEDTLS_VERSION_C
+
+/**
+ * \def MBEDTLS_X509_USE_C
+ *
+ * Enable X.509 core for using certificates.
+ *
+ * Module: library/x509.c
+ * Caller: library/x509_crl.c
+ * library/x509_crt.c
+ * library/x509_csr.c
+ *
+ * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C,
+ * MBEDTLS_PK_PARSE_C
+ *
+ * This module is required for the X.509 parsing modules.
+ */
+// #define MBEDTLS_X509_USE_C
+
+/**
+ * \def MBEDTLS_X509_CRT_PARSE_C
+ *
+ * Enable X.509 certificate parsing.
+ *
+ * Module: library/x509_crt.c
+ * Caller: library/ssl_cli.c
+ * library/ssl_srv.c
+ * library/ssl_tls.c
+ *
+ * Requires: MBEDTLS_X509_USE_C
+ *
+ * This module is required for X.509 certificate parsing.
+ */
+// #define MBEDTLS_X509_CRT_PARSE_C
+
+/**
+ * \def MBEDTLS_X509_CRL_PARSE_C
+ *
+ * Enable X.509 CRL parsing.
+ *
+ * Module: library/x509_crl.c
+ * Caller: library/x509_crt.c
+ *
+ * Requires: MBEDTLS_X509_USE_C
+ *
+ * This module is required for X.509 CRL parsing.
+ */
+// #define MBEDTLS_X509_CRL_PARSE_C
+
+/**
+ * \def MBEDTLS_X509_CSR_PARSE_C
+ *
+ * Enable X.509 Certificate Signing Request (CSR) parsing.
+ *
+ * Module: library/x509_csr.c
+ * Caller: library/x509_crt_write.c
+ *
+ * Requires: MBEDTLS_X509_USE_C
+ *
+ * This module is used for reading X.509 certificate request.
+ */
+// #define MBEDTLS_X509_CSR_PARSE_C
+
+/**
+ * \def MBEDTLS_X509_CREATE_C
+ *
+ * Enable X.509 core for creating certificates.
+ *
+ * Module: library/x509_create.c
+ *
+ * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C
+ *
+ * This module is the basis for creating X.509 certificates and CSRs.
+ */
+// #define MBEDTLS_X509_CREATE_C
+
+/**
+ * \def MBEDTLS_X509_CRT_WRITE_C
+ *
+ * Enable creating X.509 certificates.
+ *
+ * Module: library/x509_crt_write.c
+ *
+ * Requires: MBEDTLS_X509_CREATE_C
+ *
+ * This module is required for X.509 certificate creation.
+ */
+// #define MBEDTLS_X509_CRT_WRITE_C
+
+/**
+ * \def MBEDTLS_X509_CSR_WRITE_C
+ *
+ * Enable creating X.509 Certificate Signing Requests (CSR).
+ *
+ * Module: library/x509_csr_write.c
+ *
+ * Requires: MBEDTLS_X509_CREATE_C
+ *
+ * This module is required for X.509 certificate request writing.
+ */
+// #define MBEDTLS_X509_CSR_WRITE_C
+
+/**
+ * \def MBEDTLS_XTEA_C
+ *
+ * Enable the XTEA block cipher.
+ *
+ * Module: library/xtea.c
+ * Caller:
+ */
+// #define MBEDTLS_XTEA_C
+
+/* \} name SECTION: mbed TLS modules */
+
+/**
+ * \name SECTION: Module configuration options
+ *
+ * This section allows for the setting of module specific sizes and
+ * configuration options. The default values are already present in the
+ * relevant header files and should suffice for the regular use cases.
+ *
+ * Our advice is to enable options and change their values here
+ * only if you have a good reason and know the consequences.
+ *
+ * Please check the respective header file for documentation on these
+ * parameters (to prevent duplicate documentation).
+ * \{
+ */
+
+/* MPI / BIGNUM options */
+//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */
+//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */
+
+/* CTR_DRBG options */
+//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */
+//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */
+//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */
+//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */
+//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */
+
+/* HMAC_DRBG options */
+//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */
+//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */
+//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */
+//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */
+
+/* ECP options */
+//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */
+//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */
+//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */
+
+/* Entropy options */
+//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */
+//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */
+//#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */
+
+/* Memory buffer allocator options */
+//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */
+
+/* Platform options */
+//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */
+//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
+//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */
+/* Note: your snprintf must correclty zero-terminate the buffer! */
+//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" /**< Seed file to read/write with default implementation */
+
+/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */
+/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */
+//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
+//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
+//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */
+/* Note: your snprintf must correclty zero-terminate the buffer! */
+//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */
+//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
+
+/* SSL Cache options */
+//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */
+//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */
+
+/* SSL options */
+//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
+//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */
+//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
+//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */
+
+/**
+ * Complete list of ciphersuites to use, in order of preference.
+ *
+ * \warning No dependency checking is done on that field! This option can only
+ * be used to restrict the set of available ciphersuites. It is your
+ * responsibility to make sure the needed modules are active.
+ *
+ * Use this to save a few hundred bytes of ROM (default ordering of all
+ * available ciphersuites) and a few to a few hundred bytes of RAM.
+ *
+ * The value below is only an example, not the default.
+ */
+//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+
+/* X509 options */
+//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */
+//#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */
+
+/* \} name SECTION: Customisation configuration options */
+
+/* Target and application specific configurations */
+//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "mbedtls/target_config.h"
+
+#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE)
+#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE
+#endif
+
+/*
+ * Allow user to override any previous default.
+ *
+ * Use two macro names for that, as:
+ * - with yotta the prefix YOTTA_CFG_ is forced
+ * - without yotta is looks weird to have a YOTTA prefix.
+ */
+#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE)
+#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE
+#elif defined(MBEDTLS_USER_CONFIG_FILE)
+#include MBEDTLS_USER_CONFIG_FILE
+#endif
+
+#include "check_config.h"
+
+#endif /* MBEDTLS_CONFIG_H */
diff --git a/lib/mbedtls/include/mbedtls/platform.h b/lib/mbedtls/include/mbedtls/platform.h
new file mode 100644
index 000000000..b1b019e55
--- /dev/null
+++ b/lib/mbedtls/include/mbedtls/platform.h
@@ -0,0 +1,295 @@
+/**
+ * \file platform.h
+ *
+ * \brief mbed TLS Platform abstraction layer
+ *
+ * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_PLATFORM_H
+#define MBEDTLS_PLATFORM_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_HAVE_TIME)
+#include "mbedtls/platform_time.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \name SECTION: Module settings
+ *
+ * The configuration options you can set for this module are in this section.
+ * Either change them in config.h or define them on the compiler command line.
+ * \{
+ */
+
+#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
+#include
+#include
+#include
+#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
+#if defined(_WIN32)
+#define MBEDTLS_PLATFORM_STD_SNPRINTF mbedtls_platform_win32_snprintf /**< Default snprintf to use */
+#else
+#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use */
+#endif
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
+#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF)
+#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_CALLOC)
+#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_FREE)
+#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_EXIT)
+#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_TIME)
+#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS)
+#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS /**< Default exit value to use */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
+#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE /**< Default exit value to use */
+#endif
+#if defined(MBEDTLS_FS_IO)
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ)
+#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE)
+#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_FILE)
+#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile"
+#endif
+#endif /* MBEDTLS_FS_IO */
+#else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
+#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR)
+#include MBEDTLS_PLATFORM_STD_MEM_HDR
+#endif
+#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
+
+
+/* \} name SECTION: Module settings */
+
+/*
+ * The function pointers for calloc and free
+ */
+#if defined(MBEDTLS_PLATFORM_MEMORY)
+#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \
+ defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
+#define mbedtls_free MBEDTLS_PLATFORM_FREE_MACRO
+#define mbedtls_calloc MBEDTLS_PLATFORM_CALLOC_MACRO
+#else
+/* For size_t */
+#include
+extern void * (*mbedtls_calloc)( size_t n, size_t size );
+extern void (*mbedtls_free)( void *ptr );
+
+/**
+ * \brief Set your own memory implementation function pointers
+ *
+ * \param calloc_func the calloc function implementation
+ * \param free_func the free function implementation
+ *
+ * \return 0 if successful
+ */
+int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ),
+ void (*free_func)( void * ) );
+#endif /* MBEDTLS_PLATFORM_FREE_MACRO && MBEDTLS_PLATFORM_CALLOC_MACRO */
+#else /* !MBEDTLS_PLATFORM_MEMORY */
+#define mbedtls_free free
+#define mbedtls_calloc calloc
+#endif /* MBEDTLS_PLATFORM_MEMORY && !MBEDTLS_PLATFORM_{FREE,CALLOC}_MACRO */
+
+/*
+ * The function pointers for fprintf
+ */
+#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
+/* We need FILE * */
+#include
+extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... );
+
+/**
+ * \brief Set your own fprintf function pointer
+ *
+ * \param fprintf_func the fprintf function implementation
+ *
+ * \return 0
+ */
+int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char *,
+ ... ) );
+#else
+#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO)
+#define mbedtls_fprintf MBEDTLS_PLATFORM_FPRINTF_MACRO
+#else
+#define mbedtls_fprintf fprintf
+#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */
+#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */
+
+/*
+ * The function pointers for printf
+ */
+#if defined(MBEDTLS_PLATFORM_PRINTF_ALT)
+extern int (*mbedtls_printf)( const char *format, ... );
+
+/**
+ * \brief Set your own printf function pointer
+ *
+ * \param printf_func the printf function implementation
+ *
+ * \return 0
+ */
+int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) );
+#else /* !MBEDTLS_PLATFORM_PRINTF_ALT */
+#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO)
+#define mbedtls_printf MBEDTLS_PLATFORM_PRINTF_MACRO
+#else
+#define mbedtls_printf printf
+#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */
+#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */
+
+/*
+ * The function pointers for snprintf
+ *
+ * The snprintf implementation should conform to C99:
+ * - it *must* always correctly zero-terminate the buffer
+ * (except when n == 0, then it must leave the buffer untouched)
+ * - however it is acceptable to return -1 instead of the required length when
+ * the destination buffer is too short.
+ */
+#if defined(_WIN32)
+/* For Windows (inc. MSYS2), we provide our own fixed implementation */
+int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... );
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
+extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... );
+
+/**
+ * \brief Set your own snprintf function pointer
+ *
+ * \param snprintf_func the snprintf function implementation
+ *
+ * \return 0
+ */
+int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n,
+ const char * format, ... ) );
+#else /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
+#define mbedtls_snprintf MBEDTLS_PLATFORM_SNPRINTF_MACRO
+#else
+#define mbedtls_snprintf snprintf
+#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */
+#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
+
+/*
+ * The function pointers for exit
+ */
+#if defined(MBEDTLS_PLATFORM_EXIT_ALT)
+extern void (*mbedtls_exit)( int status );
+
+/**
+ * \brief Set your own exit function pointer
+ *
+ * \param exit_func the exit function implementation
+ *
+ * \return 0
+ */
+int mbedtls_platform_set_exit( void (*exit_func)( int status ) );
+#else
+#if defined(MBEDTLS_PLATFORM_EXIT_MACRO)
+#define mbedtls_exit MBEDTLS_PLATFORM_EXIT_MACRO
+#else
+#define mbedtls_exit exit
+#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */
+#endif /* MBEDTLS_PLATFORM_EXIT_ALT */
+
+/*
+ * The default exit values
+ */
+#if defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS)
+#define MBEDTLS_EXIT_SUCCESS MBEDTLS_PLATFORM_STD_EXIT_SUCCESS
+#else
+#define MBEDTLS_EXIT_SUCCESS 0
+#endif
+#if defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
+#define MBEDTLS_EXIT_FAILURE MBEDTLS_PLATFORM_STD_EXIT_FAILURE
+#else
+#define MBEDTLS_EXIT_FAILURE 1
+#endif
+
+/*
+ * The function pointers for reading from and writing a seed file to
+ * Non-Volatile storage (NV) in a platform-independent way
+ *
+ * Only enabled when the NV seed entropy source is enabled
+ */
+#if defined(MBEDTLS_ENTROPY_NV_SEED)
+#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO)
+/* Internal standard platform definitions */
+int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len );
+int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len );
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+extern int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len );
+extern int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len );
+
+/**
+ * \brief Set your own seed file writing/reading functions
+ *
+ * \param nv_seed_read_func the seed reading function implementation
+ * \param nv_seed_write_func the seed writing function implementation
+ *
+ * \return 0
+ */
+int mbedtls_platform_set_nv_seed(
+ int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ),
+ int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len )
+ );
+#else
+#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) && \
+ defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO)
+#define mbedtls_nv_seed_read MBEDTLS_PLATFORM_NV_SEED_READ_MACRO
+#define mbedtls_nv_seed_write MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO
+#else
+#define mbedtls_nv_seed_read mbedtls_platform_std_nv_seed_read
+#define mbedtls_nv_seed_write mbedtls_platform_std_nv_seed_write
+#endif
+#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
+#endif /* MBEDTLS_ENTROPY_NV_SEED */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* platform.h */
diff --git a/lib/mbedtls/include/mbedtls/platform_time.h b/lib/mbedtls/include/mbedtls/platform_time.h
new file mode 100644
index 000000000..abb343142
--- /dev/null
+++ b/lib/mbedtls/include/mbedtls/platform_time.h
@@ -0,0 +1,81 @@
+/**
+ * \file platform_time.h
+ *
+ * \brief mbed TLS Platform time abstraction
+ *
+ * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_PLATFORM_TIME_H
+#define MBEDTLS_PLATFORM_TIME_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \name SECTION: Module settings
+ *
+ * The configuration options you can set for this module are in this section.
+ * Either change them in config.h or define them on the compiler command line.
+ * \{
+ */
+
+/*
+ * The time_t datatype
+ */
+#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO)
+typedef MBEDTLS_PLATFORM_TIME_TYPE_MACRO mbedtls_time_t;
+#else
+/* For time_t */
+#include
+typedef time_t mbedtls_time_t;
+#endif /* MBEDTLS_PLATFORM_TIME_TYPE_MACRO */
+
+/*
+ * The function pointers for time
+ */
+#if defined(MBEDTLS_PLATFORM_TIME_ALT)
+extern mbedtls_time_t (*mbedtls_time)( mbedtls_time_t* time );
+
+/**
+ * \brief Set your own time function pointer
+ *
+ * \param time_func the time function implementation
+ *
+ * \return 0
+ */
+int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* time ) );
+#else
+#if defined(MBEDTLS_PLATFORM_TIME_MACRO)
+#define mbedtls_time MBEDTLS_PLATFORM_TIME_MACRO
+#else
+#define mbedtls_time time
+#endif /* MBEDTLS_PLATFORM_TIME_MACRO */
+#endif /* MBEDTLS_PLATFORM_TIME_ALT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* platform_time.h */
diff --git a/lib/mbedtls/src/aes.c b/lib/mbedtls/src/aes.c
new file mode 100644
index 000000000..a186dee98
--- /dev/null
+++ b/lib/mbedtls/src/aes.c
@@ -0,0 +1,1492 @@
+/*
+ * FIPS-197 compliant AES implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+/*
+ * The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
+ *
+ * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
+ * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_AES_C)
+
+#include
+
+#include "mbedtls/aes.h"
+#if defined(MBEDTLS_PADLOCK_C)
+#include "mbedtls/padlock.h"
+#endif
+#if defined(MBEDTLS_AESNI_C)
+#include "mbedtls/aesni.h"
+#endif
+
+#if defined(MBEDTLS_SELF_TEST)
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include
+#define mbedtls_printf printf
+#endif /* MBEDTLS_PLATFORM_C */
+#endif /* MBEDTLS_SELF_TEST */
+
+#if !defined(MBEDTLS_AES_ALT)
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize( void *v, size_t n ) {
+ volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef GET_UINT32_LE
+#define GET_UINT32_LE(n,b,i) \
+{ \
+ (n) = ( (uint32_t) (b)[(i) ] ) \
+ | ( (uint32_t) (b)[(i) + 1] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 3] << 24 ); \
+}
+#endif
+
+#ifndef PUT_UINT32_LE
+#define PUT_UINT32_LE(n,b,i) \
+{ \
+ (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
+ (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
+ (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
+ (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
+}
+#endif
+
+#if defined(MBEDTLS_PADLOCK_C) && \
+ ( defined(MBEDTLS_HAVE_X86) || defined(MBEDTLS_PADLOCK_ALIGN16) )
+static int aes_padlock_ace = -1;
+#endif
+
+#if defined(MBEDTLS_AES_ROM_TABLES)
+/*
+ * Forward S-box
+ */
+static const unsigned char FSb[256] =
+{
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
+ 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
+ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
+ 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
+ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
+ 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
+ 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
+ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
+ 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
+ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
+ 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
+ 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
+ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
+ 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
+ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
+ 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
+ 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
+ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
+ 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
+ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
+ 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
+ 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
+ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
+ 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
+ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
+ 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
+ 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
+};
+
+/*
+ * Forward tables
+ */
+#define FT \
+\
+ V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \
+ V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \
+ V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \
+ V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \
+ V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \
+ V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \
+ V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \
+ V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \
+ V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \
+ V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \
+ V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \
+ V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \
+ V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \
+ V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \
+ V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \
+ V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \
+ V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \
+ V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \
+ V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \
+ V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \
+ V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \
+ V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \
+ V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \
+ V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \
+ V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \
+ V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \
+ V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \
+ V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \
+ V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \
+ V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \
+ V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \
+ V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \
+ V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \
+ V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \
+ V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \
+ V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \
+ V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \
+ V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \
+ V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \
+ V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \
+ V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \
+ V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \
+ V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \
+ V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \
+ V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \
+ V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \
+ V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \
+ V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \
+ V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \
+ V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \
+ V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \
+ V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \
+ V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \
+ V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \
+ V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \
+ V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \
+ V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \
+ V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \
+ V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \
+ V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \
+ V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \
+ V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \
+ V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \
+ V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
+
+#define V(a,b,c,d) 0x##a##b##c##d
+static const uint32_t FT0[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##b##c##d##a
+static const uint32_t FT1[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##c##d##a##b
+static const uint32_t FT2[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##d##a##b##c
+static const uint32_t FT3[256] = { FT };
+#undef V
+
+#undef FT
+
+/*
+ * Reverse S-box
+ */
+static const unsigned char RSb[256] =
+{
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
+ 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
+ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
+ 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
+ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
+ 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
+ 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
+ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
+ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
+ 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
+ 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
+ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
+ 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
+ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
+ 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
+ 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
+ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
+ 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
+ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
+ 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
+ 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
+ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
+ 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
+ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
+ 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
+ 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
+};
+
+/*
+ * Reverse tables
+ */
+#define RT \
+\
+ V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \
+ V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \
+ V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \
+ V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \
+ V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \
+ V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \
+ V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \
+ V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \
+ V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \
+ V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \
+ V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \
+ V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \
+ V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \
+ V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \
+ V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \
+ V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \
+ V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \
+ V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \
+ V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \
+ V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \
+ V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \
+ V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \
+ V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \
+ V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \
+ V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \
+ V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \
+ V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \
+ V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \
+ V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \
+ V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \
+ V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \
+ V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \
+ V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \
+ V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \
+ V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \
+ V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \
+ V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \
+ V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \
+ V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \
+ V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \
+ V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \
+ V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \
+ V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \
+ V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \
+ V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \
+ V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \
+ V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \
+ V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \
+ V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \
+ V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \
+ V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \
+ V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \
+ V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \
+ V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \
+ V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \
+ V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \
+ V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \
+ V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \
+ V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \
+ V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \
+ V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \
+ V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \
+ V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \
+ V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0)
+
+#define V(a,b,c,d) 0x##a##b##c##d
+static const uint32_t RT0[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##b##c##d##a
+static const uint32_t RT1[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##c##d##a##b
+static const uint32_t RT2[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##d##a##b##c
+static const uint32_t RT3[256] = { RT };
+#undef V
+
+#undef RT
+
+/*
+ * Round constants
+ */
+static const uint32_t RCON[10] =
+{
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x0000001B, 0x00000036
+};
+
+#else /* MBEDTLS_AES_ROM_TABLES */
+
+/*
+ * Forward S-box & tables
+ */
+static unsigned char FSb[256];
+static uint32_t FT0[256];
+static uint32_t FT1[256];
+static uint32_t FT2[256];
+static uint32_t FT3[256];
+
+/*
+ * Reverse S-box & tables
+ */
+static unsigned char RSb[256];
+static uint32_t RT0[256];
+static uint32_t RT1[256];
+static uint32_t RT2[256];
+static uint32_t RT3[256];
+
+/*
+ * Round constants
+ */
+static uint32_t RCON[10];
+
+/*
+ * Tables generation code
+ */
+#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 )
+#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) )
+#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 )
+
+static int aes_init_done = 0;
+
+static void aes_gen_tables( void )
+{
+ int i, x, y, z;
+ int pow[256];
+ int log[256];
+
+ /*
+ * compute pow and log tables over GF(2^8)
+ */
+ for( i = 0, x = 1; i < 256; i++ )
+ {
+ pow[i] = x;
+ log[x] = i;
+ x = ( x ^ XTIME( x ) ) & 0xFF;
+ }
+
+ /*
+ * calculate the round constants
+ */
+ for( i = 0, x = 1; i < 10; i++ )
+ {
+ RCON[i] = (uint32_t) x;
+ x = XTIME( x ) & 0xFF;
+ }
+
+ /*
+ * generate the forward and reverse S-boxes
+ */
+ FSb[0x00] = 0x63;
+ RSb[0x63] = 0x00;
+
+ for( i = 1; i < 256; i++ )
+ {
+ x = pow[255 - log[i]];
+
+ y = x; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
+ x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
+ x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
+ x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
+ x ^= y ^ 0x63;
+
+ FSb[i] = (unsigned char) x;
+ RSb[x] = (unsigned char) i;
+ }
+
+ /*
+ * generate the forward and reverse tables
+ */
+ for( i = 0; i < 256; i++ )
+ {
+ x = FSb[i];
+ y = XTIME( x ) & 0xFF;
+ z = ( y ^ x ) & 0xFF;
+
+ FT0[i] = ( (uint32_t) y ) ^
+ ( (uint32_t) x << 8 ) ^
+ ( (uint32_t) x << 16 ) ^
+ ( (uint32_t) z << 24 );
+
+ FT1[i] = ROTL8( FT0[i] );
+ FT2[i] = ROTL8( FT1[i] );
+ FT3[i] = ROTL8( FT2[i] );
+
+ x = RSb[i];
+
+ RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^
+ ( (uint32_t) MUL( 0x09, x ) << 8 ) ^
+ ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^
+ ( (uint32_t) MUL( 0x0B, x ) << 24 );
+
+ RT1[i] = ROTL8( RT0[i] );
+ RT2[i] = ROTL8( RT1[i] );
+ RT3[i] = ROTL8( RT2[i] );
+ }
+}
+
+#endif /* MBEDTLS_AES_ROM_TABLES */
+
+void mbedtls_aes_init( mbedtls_aes_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedtls_aes_context ) );
+}
+
+void mbedtls_aes_free( mbedtls_aes_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) );
+}
+
+/*
+ * AES key schedule (encryption)
+ */
+#if !defined(MBEDTLS_AES_SETKEY_ENC_ALT)
+int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits )
+{
+ unsigned int i;
+ uint32_t *RK;
+
+#if !defined(MBEDTLS_AES_ROM_TABLES)
+ if( aes_init_done == 0 )
+ {
+ aes_gen_tables();
+ aes_init_done = 1;
+
+ }
+#endif
+
+ switch( keybits )
+ {
+ case 128: ctx->nr = 10; break;
+ case 192: ctx->nr = 12; break;
+ case 256: ctx->nr = 14; break;
+ default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH );
+ }
+
+#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16)
+ if( aes_padlock_ace == -1 )
+ aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE );
+
+ if( aes_padlock_ace )
+ ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf );
+ else
+#endif
+ ctx->rk = RK = ctx->buf;
+
+#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+ if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) )
+ return( mbedtls_aesni_setkey_enc( (unsigned char *) ctx->rk, key, keybits ) );
+#endif
+
+ for( i = 0; i < ( keybits >> 5 ); i++ )
+ {
+ GET_UINT32_LE( RK[i], key, i << 2 );
+ }
+
+ switch( ctx->nr )
+ {
+ case 10:
+
+ for( i = 0; i < 10; i++, RK += 4 )
+ {
+ RK[4] = RK[0] ^ RCON[i] ^
+ ( (uint32_t) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( RK[3] ) & 0xFF ] << 24 );
+
+ RK[5] = RK[1] ^ RK[4];
+ RK[6] = RK[2] ^ RK[5];
+ RK[7] = RK[3] ^ RK[6];
+ }
+ break;
+
+ case 12:
+
+ for( i = 0; i < 8; i++, RK += 6 )
+ {
+ RK[6] = RK[0] ^ RCON[i] ^
+ ( (uint32_t) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( RK[5] ) & 0xFF ] << 24 );
+
+ RK[7] = RK[1] ^ RK[6];
+ RK[8] = RK[2] ^ RK[7];
+ RK[9] = RK[3] ^ RK[8];
+ RK[10] = RK[4] ^ RK[9];
+ RK[11] = RK[5] ^ RK[10];
+ }
+ break;
+
+ case 14:
+
+ for( i = 0; i < 7; i++, RK += 8 )
+ {
+ RK[8] = RK[0] ^ RCON[i] ^
+ ( (uint32_t) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( RK[7] ) & 0xFF ] << 24 );
+
+ RK[9] = RK[1] ^ RK[8];
+ RK[10] = RK[2] ^ RK[9];
+ RK[11] = RK[3] ^ RK[10];
+
+ RK[12] = RK[4] ^
+ ( (uint32_t) FSb[ ( RK[11] ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 );
+
+ RK[13] = RK[5] ^ RK[12];
+ RK[14] = RK[6] ^ RK[13];
+ RK[15] = RK[7] ^ RK[14];
+ }
+ break;
+ }
+
+ return( 0 );
+}
+#endif /* !MBEDTLS_AES_SETKEY_ENC_ALT */
+
+/*
+ * AES key schedule (decryption)
+ */
+#if !defined(MBEDTLS_AES_SETKEY_DEC_ALT)
+int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits )
+{
+ int i, j, ret;
+ mbedtls_aes_context cty;
+ uint32_t *RK;
+ uint32_t *SK;
+
+ mbedtls_aes_init( &cty );
+
+#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16)
+ if( aes_padlock_ace == -1 )
+ aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE );
+
+ if( aes_padlock_ace )
+ ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf );
+ else
+#endif
+ ctx->rk = RK = ctx->buf;
+
+ /* Also checks keybits */
+ if( ( ret = mbedtls_aes_setkey_enc( &cty, key, keybits ) ) != 0 )
+ goto exit;
+
+ ctx->nr = cty.nr;
+
+#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+ if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) )
+ {
+ mbedtls_aesni_inverse_key( (unsigned char *) ctx->rk,
+ (const unsigned char *) cty.rk, ctx->nr );
+ goto exit;
+ }
+#endif
+
+ SK = cty.rk + cty.nr * 4;
+
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+
+ for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 )
+ {
+ for( j = 0; j < 4; j++, SK++ )
+ {
+ *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^
+ RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^
+ RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^
+ RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ];
+ }
+ }
+
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+
+exit:
+ mbedtls_aes_free( &cty );
+
+ return( ret );
+}
+#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */
+
+#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
+{ \
+ X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \
+ FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \
+ FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \
+ FT3[ ( Y3 >> 24 ) & 0xFF ]; \
+ \
+ X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \
+ FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \
+ FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \
+ FT3[ ( Y0 >> 24 ) & 0xFF ]; \
+ \
+ X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \
+ FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \
+ FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
+ FT3[ ( Y1 >> 24 ) & 0xFF ]; \
+ \
+ X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \
+ FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \
+ FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
+ FT3[ ( Y2 >> 24 ) & 0xFF ]; \
+}
+
+#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
+{ \
+ X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \
+ RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \
+ RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \
+ RT3[ ( Y1 >> 24 ) & 0xFF ]; \
+ \
+ X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \
+ RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \
+ RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \
+ RT3[ ( Y2 >> 24 ) & 0xFF ]; \
+ \
+ X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \
+ RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \
+ RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
+ RT3[ ( Y3 >> 24 ) & 0xFF ]; \
+ \
+ X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \
+ RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \
+ RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
+ RT3[ ( Y0 >> 24 ) & 0xFF ]; \
+}
+
+/*
+ * AES-ECB block encryption
+ */
+#if !defined(MBEDTLS_AES_ENCRYPT_ALT)
+void mbedtls_aes_encrypt( mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16] )
+{
+ int i;
+ uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
+
+ RK = ctx->rk;
+
+ GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++;
+ GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++;
+ GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++;
+ GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++;
+
+ for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- )
+ {
+ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
+ }
+
+ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+
+ X0 = *RK++ ^ \
+ ( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
+
+ X1 = *RK++ ^ \
+ ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
+
+ X2 = *RK++ ^ \
+ ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
+
+ X3 = *RK++ ^ \
+ ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
+
+ PUT_UINT32_LE( X0, output, 0 );
+ PUT_UINT32_LE( X1, output, 4 );
+ PUT_UINT32_LE( X2, output, 8 );
+ PUT_UINT32_LE( X3, output, 12 );
+}
+#endif /* !MBEDTLS_AES_ENCRYPT_ALT */
+
+/*
+ * AES-ECB block decryption
+ */
+#if !defined(MBEDTLS_AES_DECRYPT_ALT)
+void mbedtls_aes_decrypt( mbedtls_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16] )
+{
+ int i;
+ uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
+
+ RK = ctx->rk;
+
+ GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++;
+ GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++;
+ GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++;
+ GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++;
+
+ for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- )
+ {
+ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
+ }
+
+ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+
+ X0 = *RK++ ^ \
+ ( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
+
+ X1 = *RK++ ^ \
+ ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
+
+ X2 = *RK++ ^ \
+ ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
+
+ X3 = *RK++ ^ \
+ ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
+
+ PUT_UINT32_LE( X0, output, 0 );
+ PUT_UINT32_LE( X1, output, 4 );
+ PUT_UINT32_LE( X2, output, 8 );
+ PUT_UINT32_LE( X3, output, 12 );
+}
+#endif /* !MBEDTLS_AES_DECRYPT_ALT */
+
+/*
+ * AES-ECB block encryption/decryption
+ */
+int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx,
+ int mode,
+ const unsigned char input[16],
+ unsigned char output[16] )
+{
+#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+ if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) )
+ return( mbedtls_aesni_crypt_ecb( ctx, mode, input, output ) );
+#endif
+
+#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
+ if( aes_padlock_ace )
+ {
+ if( mbedtls_padlock_xcryptecb( ctx, mode, input, output ) == 0 )
+ return( 0 );
+
+ // If padlock data misaligned, we just fall back to
+ // unaccelerated mode
+ //
+ }
+#endif
+
+ if( mode == MBEDTLS_AES_ENCRYPT )
+ mbedtls_aes_encrypt( ctx, input, output );
+ else
+ mbedtls_aes_decrypt( ctx, input, output );
+
+ return( 0 );
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/*
+ * AES-CBC buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int i;
+ unsigned char temp[16];
+
+ if( length % 16 )
+ return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH );
+
+#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
+ if( aes_padlock_ace )
+ {
+ if( mbedtls_padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 )
+ return( 0 );
+
+ // If padlock data misaligned, we just fall back to
+ // unaccelerated mode
+ //
+ }
+#endif
+
+ if( mode == MBEDTLS_AES_DECRYPT )
+ {
+ while( length > 0 )
+ {
+ memcpy( temp, input, 16 );
+ mbedtls_aes_crypt_ecb( ctx, mode, input, output );
+
+ for( i = 0; i < 16; i++ )
+ output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+ memcpy( iv, temp, 16 );
+
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+ }
+ else
+ {
+ while( length > 0 )
+ {
+ for( i = 0; i < 16; i++ )
+ output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+ mbedtls_aes_crypt_ecb( ctx, mode, output, output );
+ memcpy( iv, output, 16 );
+
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+ }
+
+ return( 0 );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+/*
+ * AES-CFB128 buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ size_t *iv_off,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int c;
+ size_t n = *iv_off;
+
+ if( mode == MBEDTLS_AES_DECRYPT )
+ {
+ while( length-- )
+ {
+ if( n == 0 )
+ mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv );
+
+ c = *input++;
+ *output++ = (unsigned char)( c ^ iv[n] );
+ iv[n] = (unsigned char) c;
+
+ n = ( n + 1 ) & 0x0F;
+ }
+ }
+ else
+ {
+ while( length-- )
+ {
+ if( n == 0 )
+ mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv );
+
+ iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
+
+ n = ( n + 1 ) & 0x0F;
+ }
+ }
+
+ *iv_off = n;
+
+ return( 0 );
+}
+
+/*
+ * AES-CFB8 buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[16],
+ const unsigned char *input,
+ unsigned char *output )
+{
+ unsigned char c;
+ unsigned char ov[17];
+
+ while( length-- )
+ {
+ memcpy( ov, iv, 16 );
+ mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv );
+
+ if( mode == MBEDTLS_AES_DECRYPT )
+ ov[16] = *input;
+
+ c = *output++ = (unsigned char)( iv[0] ^ *input++ );
+
+ if( mode == MBEDTLS_AES_ENCRYPT )
+ ov[16] = c;
+
+ memcpy( iv, ov + 1, 16 );
+ }
+
+ return( 0 );
+}
+#endif /*MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+/*
+ * AES-CTR buffer encryption/decryption
+ */
+int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx,
+ size_t length,
+ size_t *nc_off,
+ unsigned char nonce_counter[16],
+ unsigned char stream_block[16],
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int c, i;
+ size_t n = *nc_off;
+
+ while( length-- )
+ {
+ if( n == 0 ) {
+ mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block );
+
+ for( i = 16; i > 0; i-- )
+ if( ++nonce_counter[i - 1] != 0 )
+ break;
+ }
+ c = *input++;
+ *output++ = (unsigned char)( c ^ stream_block[n] );
+
+ n = ( n + 1 ) & 0x0F;
+ }
+
+ *nc_off = n;
+
+ return( 0 );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+#endif /* !MBEDTLS_AES_ALT */
+
+#if defined(MBEDTLS_SELF_TEST)
+/*
+ * AES test vectors from:
+ *
+ * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip
+ */
+static const unsigned char aes_test_ecb_dec[3][16] =
+{
+ { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58,
+ 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 },
+ { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2,
+ 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 },
+ { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D,
+ 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE }
+};
+
+static const unsigned char aes_test_ecb_enc[3][16] =
+{
+ { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73,
+ 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F },
+ { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11,
+ 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 },
+ { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D,
+ 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 }
+};
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static const unsigned char aes_test_cbc_dec[3][16] =
+{
+ { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73,
+ 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 },
+ { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75,
+ 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B },
+ { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75,
+ 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 }
+};
+
+static const unsigned char aes_test_cbc_enc[3][16] =
+{
+ { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84,
+ 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D },
+ { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB,
+ 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 },
+ { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5,
+ 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 }
+};
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+/*
+ * AES-CFB128 test vectors from:
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
+ */
+static const unsigned char aes_test_cfb128_key[3][32] =
+{
+ { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
+ 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C },
+ { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52,
+ 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5,
+ 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B },
+ { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE,
+ 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81,
+ 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7,
+ 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 }
+};
+
+static const unsigned char aes_test_cfb128_iv[16] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+};
+
+static const unsigned char aes_test_cfb128_pt[64] =
+{
+ 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96,
+ 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A,
+ 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C,
+ 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51,
+ 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11,
+ 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF,
+ 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17,
+ 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10
+};
+
+static const unsigned char aes_test_cfb128_ct[3][64] =
+{
+ { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20,
+ 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A,
+ 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F,
+ 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B,
+ 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40,
+ 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF,
+ 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E,
+ 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 },
+ { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB,
+ 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74,
+ 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21,
+ 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A,
+ 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1,
+ 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9,
+ 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0,
+ 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF },
+ { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B,
+ 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60,
+ 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8,
+ 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B,
+ 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92,
+ 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9,
+ 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8,
+ 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 }
+};
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+/*
+ * AES-CTR test vectors from:
+ *
+ * http://www.faqs.org/rfcs/rfc3686.html
+ */
+
+static const unsigned char aes_test_ctr_key[3][16] =
+{
+ { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC,
+ 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E },
+ { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7,
+ 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 },
+ { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8,
+ 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC }
+};
+
+static const unsigned char aes_test_ctr_nonce_counter[3][16] =
+{
+ { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+ { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59,
+ 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 },
+ { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F,
+ 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 }
+};
+
+static const unsigned char aes_test_ctr_pt[3][48] =
+{
+ { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62,
+ 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 },
+
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F },
+
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23 }
+};
+
+static const unsigned char aes_test_ctr_ct[3][48] =
+{
+ { 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79,
+ 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 },
+ { 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9,
+ 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88,
+ 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8,
+ 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 },
+ { 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9,
+ 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7,
+ 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36,
+ 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53,
+ 0x25, 0xB2, 0x07, 0x2F }
+};
+
+static const int aes_test_ctr_len[3] =
+ { 16, 32, 36 };
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+/*
+ * Checkup routine
+ */
+int mbedtls_aes_self_test( int verbose )
+{
+ int ret = 0, i, j, u, v;
+ unsigned char key[32];
+ unsigned char buf[64];
+#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB)
+ unsigned char iv[16];
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ unsigned char prv[16];
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB)
+ size_t offset;
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ int len;
+ unsigned char nonce_counter[16];
+ unsigned char stream_block[16];
+#endif
+ mbedtls_aes_context ctx;
+
+ memset( key, 0, 32 );
+ mbedtls_aes_init( &ctx );
+
+ /*
+ * ECB mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ v = i & 1;
+
+ if( verbose != 0 )
+ mbedtls_printf( " AES-ECB-%3d (%s): ", 128 + u * 64,
+ ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
+
+ memset( buf, 0, 16 );
+
+ if( v == MBEDTLS_AES_DECRYPT )
+ {
+ mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 );
+
+ for( j = 0; j < 10000; j++ )
+ mbedtls_aes_crypt_ecb( &ctx, v, buf, buf );
+
+ if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+ }
+ else
+ {
+ mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 );
+
+ for( j = 0; j < 10000; j++ )
+ mbedtls_aes_crypt_ecb( &ctx, v, buf, buf );
+
+ if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "\n" );
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ /*
+ * CBC mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ v = i & 1;
+
+ if( verbose != 0 )
+ mbedtls_printf( " AES-CBC-%3d (%s): ", 128 + u * 64,
+ ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
+
+ memset( iv , 0, 16 );
+ memset( prv, 0, 16 );
+ memset( buf, 0, 16 );
+
+ if( v == MBEDTLS_AES_DECRYPT )
+ {
+ mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 );
+
+ for( j = 0; j < 10000; j++ )
+ mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf );
+
+ if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+ }
+ else
+ {
+ mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 );
+
+ for( j = 0; j < 10000; j++ )
+ {
+ unsigned char tmp[16];
+
+ mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf );
+
+ memcpy( tmp, prv, 16 );
+ memcpy( prv, buf, 16 );
+ memcpy( buf, tmp, 16 );
+ }
+
+ if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "\n" );
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ /*
+ * CFB128 mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ v = i & 1;
+
+ if( verbose != 0 )
+ mbedtls_printf( " AES-CFB128-%3d (%s): ", 128 + u * 64,
+ ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
+
+ memcpy( iv, aes_test_cfb128_iv, 16 );
+ memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 );
+
+ offset = 0;
+ mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 );
+
+ if( v == MBEDTLS_AES_DECRYPT )
+ {
+ memcpy( buf, aes_test_cfb128_ct[u], 64 );
+ mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf );
+
+ if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+ }
+ else
+ {
+ memcpy( buf, aes_test_cfb128_pt, 64 );
+ mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf );
+
+ if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "\n" );
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ /*
+ * CTR mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ v = i & 1;
+
+ if( verbose != 0 )
+ mbedtls_printf( " AES-CTR-128 (%s): ",
+ ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
+
+ memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 );
+ memcpy( key, aes_test_ctr_key[u], 16 );
+
+ offset = 0;
+ mbedtls_aes_setkey_enc( &ctx, key, 128 );
+
+ if( v == MBEDTLS_AES_DECRYPT )
+ {
+ len = aes_test_ctr_len[u];
+ memcpy( buf, aes_test_ctr_ct[u], len );
+
+ mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block,
+ buf, buf );
+
+ if( memcmp( buf, aes_test_ctr_pt[u], len ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+ }
+ else
+ {
+ len = aes_test_ctr_len[u];
+ memcpy( buf, aes_test_ctr_pt[u], len );
+
+ mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block,
+ buf, buf );
+
+ if( memcmp( buf, aes_test_ctr_ct[u], len ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "\n" );
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+ ret = 0;
+
+exit:
+ mbedtls_aes_free( &ctx );
+
+ return( ret );
+}
+
+#endif /* MBEDTLS_SELF_TEST */
+
+#endif /* MBEDTLS_AES_C */
diff --git a/lib/mbedtls/src/ccm.c b/lib/mbedtls/src/ccm.c
new file mode 100644
index 000000000..13a8fd1a2
--- /dev/null
+++ b/lib/mbedtls/src/ccm.c
@@ -0,0 +1,464 @@
+/*
+ * NIST SP800-38C compliant CCM implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+/*
+ * Definition of CCM:
+ * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
+ * RFC 3610 "Counter with CBC-MAC (CCM)"
+ *
+ * Related:
+ * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_CCM_C)
+
+#include "mbedtls/ccm.h"
+
+#include
+
+#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include
+#define mbedtls_printf printf
+#endif /* MBEDTLS_PLATFORM_C */
+#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize( void *v, size_t n ) {
+ volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
+}
+
+#define CCM_ENCRYPT 0
+#define CCM_DECRYPT 1
+
+/*
+ * Initialize context
+ */
+void mbedtls_ccm_init( mbedtls_ccm_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedtls_ccm_context ) );
+}
+
+int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
+ mbedtls_cipher_id_t cipher,
+ const unsigned char *key,
+ unsigned int keybits )
+{
+ int ret;
+ const mbedtls_cipher_info_t *cipher_info;
+
+ cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB );
+ if( cipher_info == NULL )
+ return( MBEDTLS_ERR_CCM_BAD_INPUT );
+
+ if( cipher_info->block_size != 16 )
+ return( MBEDTLS_ERR_CCM_BAD_INPUT );
+
+ mbedtls_cipher_free( &ctx->cipher_ctx );
+
+ if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
+ MBEDTLS_ENCRYPT ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Free context
+ */
+void mbedtls_ccm_free( mbedtls_ccm_context *ctx )
+{
+ mbedtls_cipher_free( &ctx->cipher_ctx );
+ mbedtls_zeroize( ctx, sizeof( mbedtls_ccm_context ) );
+}
+
+/*
+ * Macros for common operations.
+ * Results in smaller compiled code than static inline functions.
+ */
+
+/*
+ * Update the CBC-MAC state in y using a block in b
+ * (Always using b as the source helps the compiler optimise a bit better.)
+ */
+#define UPDATE_CBC_MAC \
+ for( i = 0; i < 16; i++ ) \
+ y[i] ^= b[i]; \
+ \
+ if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
+ return( ret );
+
+/*
+ * Encrypt or decrypt a partial block with CTR
+ * Warning: using b for temporary storage! src and dst must not be b!
+ * This avoids allocating one more 16 bytes buffer while allowing src == dst.
+ */
+#define CTR_CRYPT( dst, src, len ) \
+ if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \
+ return( ret ); \
+ \
+ for( i = 0; i < len; i++ ) \
+ dst[i] = src[i] ^ b[i];
+
+/*
+ * Authenticated encryption or decryption
+ */
+static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, unsigned char *output,
+ unsigned char *tag, size_t tag_len )
+{
+ int ret;
+ unsigned char i;
+ unsigned char q;
+ size_t len_left, olen;
+ unsigned char b[16];
+ unsigned char y[16];
+ unsigned char ctr[16];
+ const unsigned char *src;
+ unsigned char *dst;
+
+ /*
+ * Check length requirements: SP800-38C A.1
+ * Additional requirement: a < 2^16 - 2^8 to simplify the code.
+ * 'length' checked later (when writing it to the first block)
+ */
+ if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 )
+ return( MBEDTLS_ERR_CCM_BAD_INPUT );
+
+ /* Also implies q is within bounds */
+ if( iv_len < 7 || iv_len > 13 )
+ return( MBEDTLS_ERR_CCM_BAD_INPUT );
+
+ if( add_len > 0xFF00 )
+ return( MBEDTLS_ERR_CCM_BAD_INPUT );
+
+ q = 16 - 1 - (unsigned char) iv_len;
+
+ /*
+ * First block B_0:
+ * 0 .. 0 flags
+ * 1 .. iv_len nonce (aka iv)
+ * iv_len+1 .. 15 length
+ *
+ * With flags as (bits):
+ * 7 0
+ * 6 add present?
+ * 5 .. 3 (t - 2) / 2
+ * 2 .. 0 q - 1
+ */
+ b[0] = 0;
+ b[0] |= ( add_len > 0 ) << 6;
+ b[0] |= ( ( tag_len - 2 ) / 2 ) << 3;
+ b[0] |= q - 1;
+
+ memcpy( b + 1, iv, iv_len );
+
+ for( i = 0, len_left = length; i < q; i++, len_left >>= 8 )
+ b[15-i] = (unsigned char)( len_left & 0xFF );
+
+ if( len_left > 0 )
+ return( MBEDTLS_ERR_CCM_BAD_INPUT );
+
+
+ /* Start CBC-MAC with first block */
+ memset( y, 0, 16 );
+ UPDATE_CBC_MAC;
+
+ /*
+ * If there is additional data, update CBC-MAC with
+ * add_len, add, 0 (padding to a block boundary)
+ */
+ if( add_len > 0 )
+ {
+ size_t use_len;
+ len_left = add_len;
+ src = add;
+
+ memset( b, 0, 16 );
+ b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF );
+ b[1] = (unsigned char)( ( add_len ) & 0xFF );
+
+ use_len = len_left < 16 - 2 ? len_left : 16 - 2;
+ memcpy( b + 2, src, use_len );
+ len_left -= use_len;
+ src += use_len;
+
+ UPDATE_CBC_MAC;
+
+ while( len_left > 0 )
+ {
+ use_len = len_left > 16 ? 16 : len_left;
+
+ memset( b, 0, 16 );
+ memcpy( b, src, use_len );
+ UPDATE_CBC_MAC;
+
+ len_left -= use_len;
+ src += use_len;
+ }
+ }
+
+ /*
+ * Prepare counter block for encryption:
+ * 0 .. 0 flags
+ * 1 .. iv_len nonce (aka iv)
+ * iv_len+1 .. 15 counter (initially 1)
+ *
+ * With flags as (bits):
+ * 7 .. 3 0
+ * 2 .. 0 q - 1
+ */
+ ctr[0] = q - 1;
+ memcpy( ctr + 1, iv, iv_len );
+ memset( ctr + 1 + iv_len, 0, q );
+ ctr[15] = 1;
+
+ /*
+ * Authenticate and {en,de}crypt the message.
+ *
+ * The only difference between encryption and decryption is
+ * the respective order of authentication and {en,de}cryption.
+ */
+ len_left = length;
+ src = input;
+ dst = output;
+
+ while( len_left > 0 )
+ {
+ size_t use_len = len_left > 16 ? 16 : len_left;
+
+ if( mode == CCM_ENCRYPT )
+ {
+ memset( b, 0, 16 );
+ memcpy( b, src, use_len );
+ UPDATE_CBC_MAC;
+ }
+
+ CTR_CRYPT( dst, src, use_len );
+
+ if( mode == CCM_DECRYPT )
+ {
+ memset( b, 0, 16 );
+ memcpy( b, dst, use_len );
+ UPDATE_CBC_MAC;
+ }
+
+ dst += use_len;
+ src += use_len;
+ len_left -= use_len;
+
+ /*
+ * Increment counter.
+ * No need to check for overflow thanks to the length check above.
+ */
+ for( i = 0; i < q; i++ )
+ if( ++ctr[15-i] != 0 )
+ break;
+ }
+
+ /*
+ * Authentication: reset counter and crypt/mask internal tag
+ */
+ for( i = 0; i < q; i++ )
+ ctr[15-i] = 0;
+
+ CTR_CRYPT( y, y, 16 );
+ memcpy( tag, y, tag_len );
+
+ return( 0 );
+}
+
+/*
+ * Authenticated encryption
+ */
+int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, unsigned char *output,
+ unsigned char *tag, size_t tag_len )
+{
+ return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len,
+ add, add_len, input, output, tag, tag_len ) );
+}
+
+/*
+ * Authenticated decryption
+ */
+int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *add, size_t add_len,
+ const unsigned char *input, unsigned char *output,
+ const unsigned char *tag, size_t tag_len )
+{
+ int ret;
+ unsigned char check_tag[16];
+ unsigned char i;
+ int diff;
+
+ if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length,
+ iv, iv_len, add, add_len,
+ input, output, check_tag, tag_len ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ /* Check tag in "constant-time" */
+ for( diff = 0, i = 0; i < tag_len; i++ )
+ diff |= tag[i] ^ check_tag[i];
+
+ if( diff != 0 )
+ {
+ mbedtls_zeroize( output, length );
+ return( MBEDTLS_ERR_CCM_AUTH_FAILED );
+ }
+
+ return( 0 );
+}
+
+
+#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
+/*
+ * Examples 1 to 3 from SP800-38C Appendix C
+ */
+
+#define NB_TESTS 3
+
+/*
+ * The data is the same for all tests, only the used length changes
+ */
+static const unsigned char key[] = {
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+};
+
+static const unsigned char iv[] = {
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b
+};
+
+static const unsigned char ad[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13
+};
+
+static const unsigned char msg[] = {
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+};
+
+static const size_t iv_len [NB_TESTS] = { 7, 8, 12 };
+static const size_t add_len[NB_TESTS] = { 8, 16, 20 };
+static const size_t msg_len[NB_TESTS] = { 4, 16, 24 };
+static const size_t tag_len[NB_TESTS] = { 4, 6, 8 };
+
+static const unsigned char res[NB_TESTS][32] = {
+ { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
+ { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
+ 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
+ 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
+ { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
+ 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
+ 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
+ 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
+};
+
+int mbedtls_ccm_self_test( int verbose )
+{
+ mbedtls_ccm_context ctx;
+ unsigned char out[32];
+ size_t i;
+ int ret;
+
+ mbedtls_ccm_init( &ctx );
+
+ if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( " CCM: setup failed" );
+
+ return( 1 );
+ }
+
+ for( i = 0; i < NB_TESTS; i++ )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 );
+
+ ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i],
+ iv, iv_len[i], ad, add_len[i],
+ msg, out,
+ out + msg_len[i], tag_len[i] );
+
+ if( ret != 0 ||
+ memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i],
+ iv, iv_len[i], ad, add_len[i],
+ res[i], out,
+ res[i] + msg_len[i], tag_len[i] );
+
+ if( ret != 0 ||
+ memcmp( out, msg, msg_len[i] ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+ }
+
+ mbedtls_ccm_free( &ctx );
+
+ if( verbose != 0 )
+ mbedtls_printf( "\n" );
+
+ return( 0 );
+}
+
+#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
+
+#endif /* MBEDTLS_CCM_C */
diff --git a/lib/mbedtls/src/cipher.c b/lib/mbedtls/src/cipher.c
new file mode 100644
index 000000000..a88343869
--- /dev/null
+++ b/lib/mbedtls/src/cipher.c
@@ -0,0 +1,917 @@
+/**
+ * \file cipher.c
+ *
+ * \brief Generic cipher wrapper for mbed TLS
+ *
+ * \author Adriaan de Jong
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_CIPHER_C)
+
+#include "mbedtls/cipher.h"
+#include "mbedtls/cipher_internal.h"
+
+#include
+#include
+
+#if defined(MBEDTLS_GCM_C)
+#include "mbedtls/gcm.h"
+#endif
+
+#if defined(MBEDTLS_CCM_C)
+#include "mbedtls/ccm.h"
+#endif
+
+#if defined(MBEDTLS_CMAC_C)
+#include "mbedtls/cmac.h"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif
+
+#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER)
+#define MBEDTLS_CIPHER_MODE_STREAM
+#endif
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize( void *v, size_t n ) {
+ volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
+}
+
+static int supported_init = 0;
+
+const int *mbedtls_cipher_list( void )
+{
+ const mbedtls_cipher_definition_t *def;
+ int *type;
+
+ if( ! supported_init )
+ {
+ def = mbedtls_cipher_definitions;
+ type = mbedtls_cipher_supported;
+
+ while( def->type != 0 )
+ *type++ = (*def++).type;
+
+ *type = 0;
+
+ supported_init = 1;
+ }
+
+ return( mbedtls_cipher_supported );
+}
+
+const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type )
+{
+ const mbedtls_cipher_definition_t *def;
+
+ for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
+ if( def->type == cipher_type )
+ return( def->info );
+
+ return( NULL );
+}
+
+const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name )
+{
+ const mbedtls_cipher_definition_t *def;
+
+ if( NULL == cipher_name )
+ return( NULL );
+
+ for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
+ if( ! strcmp( def->info->name, cipher_name ) )
+ return( def->info );
+
+ return( NULL );
+}
+
+const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id,
+ int key_bitlen,
+ const mbedtls_cipher_mode_t mode )
+{
+ const mbedtls_cipher_definition_t *def;
+
+ for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
+ if( def->info->base->cipher == cipher_id &&
+ def->info->key_bitlen == (unsigned) key_bitlen &&
+ def->info->mode == mode )
+ return( def->info );
+
+ return( NULL );
+}
+
+void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx )
+{
+ memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
+}
+
+void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+#if defined(MBEDTLS_CMAC_C)
+ if( ctx->cmac_ctx )
+ {
+ mbedtls_zeroize( ctx->cmac_ctx, sizeof( mbedtls_cmac_context_t ) );
+ mbedtls_free( ctx->cmac_ctx );
+ }
+#endif
+
+ if( ctx->cipher_ctx )
+ ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx );
+
+ mbedtls_zeroize( ctx, sizeof(mbedtls_cipher_context_t) );
+}
+
+int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info )
+{
+ if( NULL == cipher_info || NULL == ctx )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
+
+ if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) )
+ return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED );
+
+ ctx->cipher_info = cipher_info;
+
+#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
+ /*
+ * Ignore possible errors caused by a cipher mode that doesn't use padding
+ */
+#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
+ (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 );
+#else
+ (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE );
+#endif
+#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
+
+ return( 0 );
+}
+
+int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key,
+ int key_bitlen, const mbedtls_operation_t operation )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 &&
+ (int) ctx->cipher_info->key_bitlen != key_bitlen )
+ {
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ ctx->key_bitlen = key_bitlen;
+ ctx->operation = operation;
+
+ /*
+ * For CFB and CTR mode always use the encryption key schedule
+ */
+ if( MBEDTLS_ENCRYPT == operation ||
+ MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
+ MBEDTLS_MODE_CTR == ctx->cipher_info->mode )
+ {
+ return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key,
+ ctx->key_bitlen );
+ }
+
+ if( MBEDTLS_DECRYPT == operation )
+ return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key,
+ ctx->key_bitlen );
+
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+}
+
+int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
+ const unsigned char *iv, size_t iv_len )
+{
+ size_t actual_iv_size;
+
+ if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ /* avoid buffer overflow in ctx->iv */
+ if( iv_len > MBEDTLS_MAX_IV_LENGTH )
+ return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+
+ if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 )
+ actual_iv_size = iv_len;
+ else
+ {
+ actual_iv_size = ctx->cipher_info->iv_size;
+
+ /* avoid reading past the end of input buffer */
+ if( actual_iv_size > iv_len )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ memcpy( ctx->iv, iv, actual_iv_size );
+ ctx->iv_size = actual_iv_size;
+
+ return( 0 );
+}
+
+int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ ctx->unprocessed_len = 0;
+
+ return( 0 );
+}
+
+#if defined(MBEDTLS_GCM_C)
+int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
+ const unsigned char *ad, size_t ad_len )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
+ {
+ return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation,
+ ctx->iv, ctx->iv_size, ad, ad_len );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDTLS_GCM_C */
+
+int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input,
+ size_t ilen, unsigned char *output, size_t *olen )
+{
+ int ret;
+ size_t block_size = 0;
+
+ if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
+ {
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ *olen = 0;
+ block_size = mbedtls_cipher_get_block_size( ctx );
+
+ if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB )
+ {
+ if( ilen != block_size )
+ return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
+
+ *olen = ilen;
+
+ if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx,
+ ctx->operation, input, output ) ) )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+ }
+
+#if defined(MBEDTLS_GCM_C)
+ if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM )
+ {
+ *olen = ilen;
+ return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input,
+ output );
+ }
+#endif
+
+ if ( 0 == block_size )
+ {
+ return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT;
+ }
+
+ if( input == output &&
+ ( ctx->unprocessed_len != 0 || ilen % block_size ) )
+ {
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC )
+ {
+ size_t copy_len = 0;
+
+ /*
+ * If there is not enough data for a full block, cache it.
+ */
+ if( ( ctx->operation == MBEDTLS_DECRYPT &&
+ ilen + ctx->unprocessed_len <= block_size ) ||
+ ( ctx->operation == MBEDTLS_ENCRYPT &&
+ ilen + ctx->unprocessed_len < block_size ) )
+ {
+ memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
+ ilen );
+
+ ctx->unprocessed_len += ilen;
+ return( 0 );
+ }
+
+ /*
+ * Process cached data first
+ */
+ if( 0 != ctx->unprocessed_len )
+ {
+ copy_len = block_size - ctx->unprocessed_len;
+
+ memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
+ copy_len );
+
+ if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
+ ctx->operation, block_size, ctx->iv,
+ ctx->unprocessed_data, output ) ) )
+ {
+ return( ret );
+ }
+
+ *olen += block_size;
+ output += block_size;
+ ctx->unprocessed_len = 0;
+
+ input += copy_len;
+ ilen -= copy_len;
+ }
+
+ /*
+ * Cache final, incomplete block
+ */
+ if( 0 != ilen )
+ {
+ if( 0 == block_size )
+ {
+ return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT;
+ }
+
+ copy_len = ilen % block_size;
+ if( copy_len == 0 && ctx->operation == MBEDTLS_DECRYPT )
+ copy_len = block_size;
+
+ memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ),
+ copy_len );
+
+ ctx->unprocessed_len += copy_len;
+ ilen -= copy_len;
+ }
+
+ /*
+ * Process remaining full blocks
+ */
+ if( ilen )
+ {
+ if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
+ ctx->operation, ilen, ctx->iv, input, output ) ) )
+ {
+ return( ret );
+ }
+
+ *olen += ilen;
+ }
+
+ return( 0 );
+ }
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB )
+ {
+ if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx,
+ ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv,
+ input, output ) ) )
+ {
+ return( ret );
+ }
+
+ *olen = ilen;
+
+ return( 0 );
+ }
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR )
+ {
+ if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx,
+ ilen, &ctx->unprocessed_len, ctx->iv,
+ ctx->unprocessed_data, input, output ) ) )
+ {
+ return( ret );
+ }
+
+ *olen = ilen;
+
+ return( 0 );
+ }
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM )
+ {
+ if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx,
+ ilen, input, output ) ) )
+ {
+ return( ret );
+ }
+
+ *olen = ilen;
+
+ return( 0 );
+ }
+#endif /* MBEDTLS_CIPHER_MODE_STREAM */
+
+ return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
+#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
+/*
+ * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len
+ */
+static void add_pkcs_padding( unsigned char *output, size_t output_len,
+ size_t data_len )
+{
+ size_t padding_len = output_len - data_len;
+ unsigned char i;
+
+ for( i = 0; i < padding_len; i++ )
+ output[data_len + i] = (unsigned char) padding_len;
+}
+
+static int get_pkcs_padding( unsigned char *input, size_t input_len,
+ size_t *data_len )
+{
+ size_t i, pad_idx;
+ unsigned char padding_len, bad = 0;
+
+ if( NULL == input || NULL == data_len )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ padding_len = input[input_len - 1];
+ *data_len = input_len - padding_len;
+
+ /* Avoid logical || since it results in a branch */
+ bad |= padding_len > input_len;
+ bad |= padding_len == 0;
+
+ /* The number of bytes checked must be independent of padding_len,
+ * so pick input_len, which is usually 8 or 16 (one block) */
+ pad_idx = input_len - padding_len;
+ for( i = 0; i < input_len; i++ )
+ bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx );
+
+ return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
+}
+#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
+
+#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
+/*
+ * One and zeros padding: fill with 80 00 ... 00
+ */
+static void add_one_and_zeros_padding( unsigned char *output,
+ size_t output_len, size_t data_len )
+{
+ size_t padding_len = output_len - data_len;
+ unsigned char i = 0;
+
+ output[data_len] = 0x80;
+ for( i = 1; i < padding_len; i++ )
+ output[data_len + i] = 0x00;
+}
+
+static int get_one_and_zeros_padding( unsigned char *input, size_t input_len,
+ size_t *data_len )
+{
+ size_t i;
+ unsigned char done = 0, prev_done, bad;
+
+ if( NULL == input || NULL == data_len )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ bad = 0xFF;
+ *data_len = 0;
+ for( i = input_len; i > 0; i-- )
+ {
+ prev_done = done;
+ done |= ( input[i-1] != 0 );
+ *data_len |= ( i - 1 ) * ( done != prev_done );
+ bad &= ( input[i-1] ^ 0x80 ) | ( done == prev_done );
+ }
+
+ return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
+
+}
+#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
+
+#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
+/*
+ * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length
+ */
+static void add_zeros_and_len_padding( unsigned char *output,
+ size_t output_len, size_t data_len )
+{
+ size_t padding_len = output_len - data_len;
+ unsigned char i = 0;
+
+ for( i = 1; i < padding_len; i++ )
+ output[data_len + i - 1] = 0x00;
+ output[output_len - 1] = (unsigned char) padding_len;
+}
+
+static int get_zeros_and_len_padding( unsigned char *input, size_t input_len,
+ size_t *data_len )
+{
+ size_t i, pad_idx;
+ unsigned char padding_len, bad = 0;
+
+ if( NULL == input || NULL == data_len )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ padding_len = input[input_len - 1];
+ *data_len = input_len - padding_len;
+
+ /* Avoid logical || since it results in a branch */
+ bad |= padding_len > input_len;
+ bad |= padding_len == 0;
+
+ /* The number of bytes checked must be independent of padding_len */
+ pad_idx = input_len - padding_len;
+ for( i = 0; i < input_len - 1; i++ )
+ bad |= input[i] * ( i >= pad_idx );
+
+ return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
+}
+#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
+
+#if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
+/*
+ * Zero padding: fill with 00 ... 00
+ */
+static void add_zeros_padding( unsigned char *output,
+ size_t output_len, size_t data_len )
+{
+ size_t i;
+
+ for( i = data_len; i < output_len; i++ )
+ output[i] = 0x00;
+}
+
+static int get_zeros_padding( unsigned char *input, size_t input_len,
+ size_t *data_len )
+{
+ size_t i;
+ unsigned char done = 0, prev_done;
+
+ if( NULL == input || NULL == data_len )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ *data_len = 0;
+ for( i = input_len; i > 0; i-- )
+ {
+ prev_done = done;
+ done |= ( input[i-1] != 0 );
+ *data_len |= i * ( done != prev_done );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
+
+/*
+ * No padding: don't pad :)
+ *
+ * There is no add_padding function (check for NULL in mbedtls_cipher_finish)
+ * but a trivial get_padding function
+ */
+static int get_no_padding( unsigned char *input, size_t input_len,
+ size_t *data_len )
+{
+ if( NULL == input || NULL == data_len )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ *data_len = input_len;
+
+ return( 0 );
+}
+#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
+
+int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx,
+ unsigned char *output, size_t *olen )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ *olen = 0;
+
+ if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
+ MBEDTLS_MODE_CTR == ctx->cipher_info->mode ||
+ MBEDTLS_MODE_GCM == ctx->cipher_info->mode ||
+ MBEDTLS_MODE_STREAM == ctx->cipher_info->mode )
+ {
+ return( 0 );
+ }
+
+ if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode )
+ {
+ if( ctx->unprocessed_len != 0 )
+ return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
+
+ return( 0 );
+ }
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode )
+ {
+ int ret = 0;
+
+ if( MBEDTLS_ENCRYPT == ctx->operation )
+ {
+ /* check for 'no padding' mode */
+ if( NULL == ctx->add_padding )
+ {
+ if( 0 != ctx->unprocessed_len )
+ return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
+
+ return( 0 );
+ }
+
+ ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ),
+ ctx->unprocessed_len );
+ }
+ else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len )
+ {
+ /*
+ * For decrypt operations, expect a full block,
+ * or an empty block if no padding
+ */
+ if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len )
+ return( 0 );
+
+ return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
+ }
+
+ /* cipher block */
+ if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
+ ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv,
+ ctx->unprocessed_data, output ) ) )
+ {
+ return( ret );
+ }
+
+ /* Set output size for decryption */
+ if( MBEDTLS_DECRYPT == ctx->operation )
+ return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ),
+ olen );
+
+ /* Set output size for encryption */
+ *olen = mbedtls_cipher_get_block_size( ctx );
+ return( 0 );
+ }
+#else
+ ((void) output);
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+ return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
+int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode )
+{
+ if( NULL == ctx ||
+ MBEDTLS_MODE_CBC != ctx->cipher_info->mode )
+ {
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ switch( mode )
+ {
+#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
+ case MBEDTLS_PADDING_PKCS7:
+ ctx->add_padding = add_pkcs_padding;
+ ctx->get_padding = get_pkcs_padding;
+ break;
+#endif
+#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
+ case MBEDTLS_PADDING_ONE_AND_ZEROS:
+ ctx->add_padding = add_one_and_zeros_padding;
+ ctx->get_padding = get_one_and_zeros_padding;
+ break;
+#endif
+#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
+ case MBEDTLS_PADDING_ZEROS_AND_LEN:
+ ctx->add_padding = add_zeros_and_len_padding;
+ ctx->get_padding = get_zeros_and_len_padding;
+ break;
+#endif
+#if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
+ case MBEDTLS_PADDING_ZEROS:
+ ctx->add_padding = add_zeros_padding;
+ ctx->get_padding = get_zeros_padding;
+ break;
+#endif
+ case MBEDTLS_PADDING_NONE:
+ ctx->add_padding = NULL;
+ ctx->get_padding = get_no_padding;
+ break;
+
+ default:
+ return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
+
+#if defined(MBEDTLS_GCM_C)
+int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
+ unsigned char *tag, size_t tag_len )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( MBEDTLS_ENCRYPT != ctx->operation )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
+ return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len );
+
+ return( 0 );
+}
+
+int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
+ const unsigned char *tag, size_t tag_len )
+{
+ int ret;
+
+ if( NULL == ctx || NULL == ctx->cipher_info ||
+ MBEDTLS_DECRYPT != ctx->operation )
+ {
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
+ {
+ unsigned char check_tag[16];
+ size_t i;
+ int diff;
+
+ if( tag_len > sizeof( check_tag ) )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
+ check_tag, tag_len ) ) )
+ {
+ return( ret );
+ }
+
+ /* Check the tag in "constant-time" */
+ for( diff = 0, i = 0; i < tag_len; i++ )
+ diff |= tag[i] ^ check_tag[i];
+
+ if( diff != 0 )
+ return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
+
+ return( 0 );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDTLS_GCM_C */
+
+/*
+ * Packet-oriented wrapper for non-AEAD modes
+ */
+int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen )
+{
+ int ret;
+ size_t finish_olen;
+
+ if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 )
+ return( ret );
+
+ *olen += finish_olen;
+
+ return( 0 );
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_AEAD)
+/*
+ * Packet-oriented encryption for AEAD modes
+ */
+int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *ad, size_t ad_len,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen,
+ unsigned char *tag, size_t tag_len )
+{
+#if defined(MBEDTLS_GCM_C)
+ if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
+ {
+ *olen = ilen;
+ return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen,
+ iv, iv_len, ad, ad_len, input, output,
+ tag_len, tag ) );
+ }
+#endif /* MBEDTLS_GCM_C */
+#if defined(MBEDTLS_CCM_C)
+ if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
+ {
+ *olen = ilen;
+ return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen,
+ iv, iv_len, ad, ad_len, input, output,
+ tag, tag_len ) );
+ }
+#endif /* MBEDTLS_CCM_C */
+
+ return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+}
+
+/*
+ * Packet-oriented decryption for AEAD modes
+ */
+int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
+ const unsigned char *iv, size_t iv_len,
+ const unsigned char *ad, size_t ad_len,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen,
+ const unsigned char *tag, size_t tag_len )
+{
+#if defined(MBEDTLS_GCM_C)
+ if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
+ {
+ int ret;
+
+ *olen = ilen;
+ ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen,
+ iv, iv_len, ad, ad_len,
+ tag, tag_len, input, output );
+
+ if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED )
+ ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
+
+ return( ret );
+ }
+#endif /* MBEDTLS_GCM_C */
+#if defined(MBEDTLS_CCM_C)
+ if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
+ {
+ int ret;
+
+ *olen = ilen;
+ ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen,
+ iv, iv_len, ad, ad_len,
+ input, output, tag, tag_len );
+
+ if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
+ ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
+
+ return( ret );
+ }
+#endif /* MBEDTLS_CCM_C */
+
+ return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+}
+#endif /* MBEDTLS_CIPHER_MODE_AEAD */
+
+#endif /* MBEDTLS_CIPHER_C */
diff --git a/lib/mbedtls/src/cipher_wrap.c b/lib/mbedtls/src/cipher_wrap.c
new file mode 100644
index 000000000..dc76af8ff
--- /dev/null
+++ b/lib/mbedtls/src/cipher_wrap.c
@@ -0,0 +1,1451 @@
+/**
+ * \file cipher_wrap.c
+ *
+ * \brief Generic cipher wrapper for mbed TLS
+ *
+ * \author Adriaan de Jong
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_CIPHER_C)
+
+#include "mbedtls/cipher_internal.h"
+
+#if defined(MBEDTLS_AES_C)
+#include "mbedtls/aes.h"
+#endif
+
+#if defined(MBEDTLS_ARC4_C)
+#include "mbedtls/arc4.h"
+#endif
+
+#if defined(MBEDTLS_CAMELLIA_C)
+#include "mbedtls/camellia.h"
+#endif
+
+#if defined(MBEDTLS_DES_C)
+#include "mbedtls/des.h"
+#endif
+
+#if defined(MBEDTLS_BLOWFISH_C)
+#include "mbedtls/blowfish.h"
+#endif
+
+#if defined(MBEDTLS_GCM_C)
+#include "mbedtls/gcm.h"
+#endif
+
+#if defined(MBEDTLS_CCM_C)
+#include "mbedtls/ccm.h"
+#endif
+
+#if defined(MBEDTLS_CIPHER_NULL_CIPHER)
+#include
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif
+
+#if defined(MBEDTLS_GCM_C)
+/* shared by all GCM ciphers */
+static void *gcm_ctx_alloc( void )
+{
+ void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_gcm_context ) );
+
+ if( ctx != NULL )
+ mbedtls_gcm_init( (mbedtls_gcm_context *) ctx );
+
+ return( ctx );
+}
+
+static void gcm_ctx_free( void *ctx )
+{
+ mbedtls_gcm_free( ctx );
+ mbedtls_free( ctx );
+}
+#endif /* MBEDTLS_GCM_C */
+
+#if defined(MBEDTLS_CCM_C)
+/* shared by all CCM ciphers */
+static void *ccm_ctx_alloc( void )
+{
+ void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ccm_context ) );
+
+ if( ctx != NULL )
+ mbedtls_ccm_init( (mbedtls_ccm_context *) ctx );
+
+ return( ctx );
+}
+
+static void ccm_ctx_free( void *ctx )
+{
+ mbedtls_ccm_free( ctx );
+ mbedtls_free( ctx );
+}
+#endif /* MBEDTLS_CCM_C */
+
+#if defined(MBEDTLS_AES_C)
+
+static int aes_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_aes_crypt_ecb( (mbedtls_aes_context *) ctx, operation, input, output );
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static int aes_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length,
+ unsigned char *iv, const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_aes_crypt_cbc( (mbedtls_aes_context *) ctx, operation, length, iv, input,
+ output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+static int aes_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation,
+ size_t length, size_t *iv_off, unsigned char *iv,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_aes_crypt_cfb128( (mbedtls_aes_context *) ctx, operation, length, iv_off, iv,
+ input, output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+static int aes_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off,
+ unsigned char *nonce_counter, unsigned char *stream_block,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_aes_crypt_ctr( (mbedtls_aes_context *) ctx, length, nc_off, nonce_counter,
+ stream_block, input, output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+static int aes_setkey_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedtls_aes_setkey_dec( (mbedtls_aes_context *) ctx, key, key_bitlen );
+}
+
+static int aes_setkey_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedtls_aes_setkey_enc( (mbedtls_aes_context *) ctx, key, key_bitlen );
+}
+
+static void * aes_ctx_alloc( void )
+{
+ mbedtls_aes_context *aes = mbedtls_calloc( 1, sizeof( mbedtls_aes_context ) );
+
+ if( aes == NULL )
+ return( NULL );
+
+ mbedtls_aes_init( aes );
+
+ return( aes );
+}
+
+static void aes_ctx_free( void *ctx )
+{
+ mbedtls_aes_free( (mbedtls_aes_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static const mbedtls_cipher_base_t aes_info = {
+ MBEDTLS_CIPHER_ID_AES,
+ aes_crypt_ecb_wrap,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ aes_crypt_cbc_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ aes_crypt_cfb128_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ aes_crypt_ctr_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ aes_setkey_enc_wrap,
+ aes_setkey_dec_wrap,
+ aes_ctx_alloc,
+ aes_ctx_free
+};
+
+static const mbedtls_cipher_info_t aes_128_ecb_info = {
+ MBEDTLS_CIPHER_AES_128_ECB,
+ MBEDTLS_MODE_ECB,
+ 128,
+ "AES-128-ECB",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_ecb_info = {
+ MBEDTLS_CIPHER_AES_192_ECB,
+ MBEDTLS_MODE_ECB,
+ 192,
+ "AES-192-ECB",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_ecb_info = {
+ MBEDTLS_CIPHER_AES_256_ECB,
+ MBEDTLS_MODE_ECB,
+ 256,
+ "AES-256-ECB",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static const mbedtls_cipher_info_t aes_128_cbc_info = {
+ MBEDTLS_CIPHER_AES_128_CBC,
+ MBEDTLS_MODE_CBC,
+ 128,
+ "AES-128-CBC",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_cbc_info = {
+ MBEDTLS_CIPHER_AES_192_CBC,
+ MBEDTLS_MODE_CBC,
+ 192,
+ "AES-192-CBC",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_cbc_info = {
+ MBEDTLS_CIPHER_AES_256_CBC,
+ MBEDTLS_MODE_CBC,
+ 256,
+ "AES-256-CBC",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+static const mbedtls_cipher_info_t aes_128_cfb128_info = {
+ MBEDTLS_CIPHER_AES_128_CFB128,
+ MBEDTLS_MODE_CFB,
+ 128,
+ "AES-128-CFB128",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_cfb128_info = {
+ MBEDTLS_CIPHER_AES_192_CFB128,
+ MBEDTLS_MODE_CFB,
+ 192,
+ "AES-192-CFB128",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_cfb128_info = {
+ MBEDTLS_CIPHER_AES_256_CFB128,
+ MBEDTLS_MODE_CFB,
+ 256,
+ "AES-256-CFB128",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+static const mbedtls_cipher_info_t aes_128_ctr_info = {
+ MBEDTLS_CIPHER_AES_128_CTR,
+ MBEDTLS_MODE_CTR,
+ 128,
+ "AES-128-CTR",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_ctr_info = {
+ MBEDTLS_CIPHER_AES_192_CTR,
+ MBEDTLS_MODE_CTR,
+ 192,
+ "AES-192-CTR",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_ctr_info = {
+ MBEDTLS_CIPHER_AES_256_CTR,
+ MBEDTLS_MODE_CTR,
+ 256,
+ "AES-256-CTR",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+#if defined(MBEDTLS_GCM_C)
+static int gcm_aes_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_AES,
+ key, key_bitlen );
+}
+
+static const mbedtls_cipher_base_t gcm_aes_info = {
+ MBEDTLS_CIPHER_ID_AES,
+ NULL,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ gcm_aes_setkey_wrap,
+ gcm_aes_setkey_wrap,
+ gcm_ctx_alloc,
+ gcm_ctx_free,
+};
+
+static const mbedtls_cipher_info_t aes_128_gcm_info = {
+ MBEDTLS_CIPHER_AES_128_GCM,
+ MBEDTLS_MODE_GCM,
+ 128,
+ "AES-128-GCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_gcm_info = {
+ MBEDTLS_CIPHER_AES_192_GCM,
+ MBEDTLS_MODE_GCM,
+ 192,
+ "AES-192-GCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_gcm_info = {
+ MBEDTLS_CIPHER_AES_256_GCM,
+ MBEDTLS_MODE_GCM,
+ 256,
+ "AES-256-GCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_aes_info
+};
+#endif /* MBEDTLS_GCM_C */
+
+#if defined(MBEDTLS_CCM_C)
+static int ccm_aes_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_AES,
+ key, key_bitlen );
+}
+
+static const mbedtls_cipher_base_t ccm_aes_info = {
+ MBEDTLS_CIPHER_ID_AES,
+ NULL,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ ccm_aes_setkey_wrap,
+ ccm_aes_setkey_wrap,
+ ccm_ctx_alloc,
+ ccm_ctx_free,
+};
+
+static const mbedtls_cipher_info_t aes_128_ccm_info = {
+ MBEDTLS_CIPHER_AES_128_CCM,
+ MBEDTLS_MODE_CCM,
+ 128,
+ "AES-128-CCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_ccm_info = {
+ MBEDTLS_CIPHER_AES_192_CCM,
+ MBEDTLS_MODE_CCM,
+ 192,
+ "AES-192-CCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_ccm_info = {
+ MBEDTLS_CIPHER_AES_256_CCM,
+ MBEDTLS_MODE_CCM,
+ 256,
+ "AES-256-CCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_aes_info
+};
+#endif /* MBEDTLS_CCM_C */
+
+#endif /* MBEDTLS_AES_C */
+
+#if defined(MBEDTLS_CAMELLIA_C)
+
+static int camellia_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_camellia_crypt_ecb( (mbedtls_camellia_context *) ctx, operation, input,
+ output );
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static int camellia_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation,
+ size_t length, unsigned char *iv,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_camellia_crypt_cbc( (mbedtls_camellia_context *) ctx, operation, length, iv,
+ input, output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+static int camellia_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation,
+ size_t length, size_t *iv_off, unsigned char *iv,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_camellia_crypt_cfb128( (mbedtls_camellia_context *) ctx, operation, length,
+ iv_off, iv, input, output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+static int camellia_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off,
+ unsigned char *nonce_counter, unsigned char *stream_block,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_camellia_crypt_ctr( (mbedtls_camellia_context *) ctx, length, nc_off,
+ nonce_counter, stream_block, input, output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+static int camellia_setkey_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedtls_camellia_setkey_dec( (mbedtls_camellia_context *) ctx, key, key_bitlen );
+}
+
+static int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedtls_camellia_setkey_enc( (mbedtls_camellia_context *) ctx, key, key_bitlen );
+}
+
+static void * camellia_ctx_alloc( void )
+{
+ mbedtls_camellia_context *ctx;
+ ctx = mbedtls_calloc( 1, sizeof( mbedtls_camellia_context ) );
+
+ if( ctx == NULL )
+ return( NULL );
+
+ mbedtls_camellia_init( ctx );
+
+ return( ctx );
+}
+
+static void camellia_ctx_free( void *ctx )
+{
+ mbedtls_camellia_free( (mbedtls_camellia_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static const mbedtls_cipher_base_t camellia_info = {
+ MBEDTLS_CIPHER_ID_CAMELLIA,
+ camellia_crypt_ecb_wrap,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ camellia_crypt_cbc_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ camellia_crypt_cfb128_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ camellia_crypt_ctr_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ camellia_setkey_enc_wrap,
+ camellia_setkey_dec_wrap,
+ camellia_ctx_alloc,
+ camellia_ctx_free
+};
+
+static const mbedtls_cipher_info_t camellia_128_ecb_info = {
+ MBEDTLS_CIPHER_CAMELLIA_128_ECB,
+ MBEDTLS_MODE_ECB,
+ 128,
+ "CAMELLIA-128-ECB",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_192_ecb_info = {
+ MBEDTLS_CIPHER_CAMELLIA_192_ECB,
+ MBEDTLS_MODE_ECB,
+ 192,
+ "CAMELLIA-192-ECB",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_256_ecb_info = {
+ MBEDTLS_CIPHER_CAMELLIA_256_ECB,
+ MBEDTLS_MODE_ECB,
+ 256,
+ "CAMELLIA-256-ECB",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static const mbedtls_cipher_info_t camellia_128_cbc_info = {
+ MBEDTLS_CIPHER_CAMELLIA_128_CBC,
+ MBEDTLS_MODE_CBC,
+ 128,
+ "CAMELLIA-128-CBC",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_192_cbc_info = {
+ MBEDTLS_CIPHER_CAMELLIA_192_CBC,
+ MBEDTLS_MODE_CBC,
+ 192,
+ "CAMELLIA-192-CBC",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_256_cbc_info = {
+ MBEDTLS_CIPHER_CAMELLIA_256_CBC,
+ MBEDTLS_MODE_CBC,
+ 256,
+ "CAMELLIA-256-CBC",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+static const mbedtls_cipher_info_t camellia_128_cfb128_info = {
+ MBEDTLS_CIPHER_CAMELLIA_128_CFB128,
+ MBEDTLS_MODE_CFB,
+ 128,
+ "CAMELLIA-128-CFB128",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_192_cfb128_info = {
+ MBEDTLS_CIPHER_CAMELLIA_192_CFB128,
+ MBEDTLS_MODE_CFB,
+ 192,
+ "CAMELLIA-192-CFB128",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_256_cfb128_info = {
+ MBEDTLS_CIPHER_CAMELLIA_256_CFB128,
+ MBEDTLS_MODE_CFB,
+ 256,
+ "CAMELLIA-256-CFB128",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+static const mbedtls_cipher_info_t camellia_128_ctr_info = {
+ MBEDTLS_CIPHER_CAMELLIA_128_CTR,
+ MBEDTLS_MODE_CTR,
+ 128,
+ "CAMELLIA-128-CTR",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_192_ctr_info = {
+ MBEDTLS_CIPHER_CAMELLIA_192_CTR,
+ MBEDTLS_MODE_CTR,
+ 192,
+ "CAMELLIA-192-CTR",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_256_ctr_info = {
+ MBEDTLS_CIPHER_CAMELLIA_256_CTR,
+ MBEDTLS_MODE_CTR,
+ 256,
+ "CAMELLIA-256-CTR",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+#if defined(MBEDTLS_GCM_C)
+static int gcm_camellia_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA,
+ key, key_bitlen );
+}
+
+static const mbedtls_cipher_base_t gcm_camellia_info = {
+ MBEDTLS_CIPHER_ID_CAMELLIA,
+ NULL,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ gcm_camellia_setkey_wrap,
+ gcm_camellia_setkey_wrap,
+ gcm_ctx_alloc,
+ gcm_ctx_free,
+};
+
+static const mbedtls_cipher_info_t camellia_128_gcm_info = {
+ MBEDTLS_CIPHER_CAMELLIA_128_GCM,
+ MBEDTLS_MODE_GCM,
+ 128,
+ "CAMELLIA-128-GCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_192_gcm_info = {
+ MBEDTLS_CIPHER_CAMELLIA_192_GCM,
+ MBEDTLS_MODE_GCM,
+ 192,
+ "CAMELLIA-192-GCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_256_gcm_info = {
+ MBEDTLS_CIPHER_CAMELLIA_256_GCM,
+ MBEDTLS_MODE_GCM,
+ 256,
+ "CAMELLIA-256-GCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_camellia_info
+};
+#endif /* MBEDTLS_GCM_C */
+
+#if defined(MBEDTLS_CCM_C)
+static int ccm_camellia_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA,
+ key, key_bitlen );
+}
+
+static const mbedtls_cipher_base_t ccm_camellia_info = {
+ MBEDTLS_CIPHER_ID_CAMELLIA,
+ NULL,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ ccm_camellia_setkey_wrap,
+ ccm_camellia_setkey_wrap,
+ ccm_ctx_alloc,
+ ccm_ctx_free,
+};
+
+static const mbedtls_cipher_info_t camellia_128_ccm_info = {
+ MBEDTLS_CIPHER_CAMELLIA_128_CCM,
+ MBEDTLS_MODE_CCM,
+ 128,
+ "CAMELLIA-128-CCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_192_ccm_info = {
+ MBEDTLS_CIPHER_CAMELLIA_192_CCM,
+ MBEDTLS_MODE_CCM,
+ 192,
+ "CAMELLIA-192-CCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_camellia_info
+};
+
+static const mbedtls_cipher_info_t camellia_256_ccm_info = {
+ MBEDTLS_CIPHER_CAMELLIA_256_CCM,
+ MBEDTLS_MODE_CCM,
+ 256,
+ "CAMELLIA-256-CCM",
+ 12,
+ MBEDTLS_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_camellia_info
+};
+#endif /* MBEDTLS_CCM_C */
+
+#endif /* MBEDTLS_CAMELLIA_C */
+
+#if defined(MBEDTLS_DES_C)
+
+static int des_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ ((void) operation);
+ return mbedtls_des_crypt_ecb( (mbedtls_des_context *) ctx, input, output );
+}
+
+static int des3_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ ((void) operation);
+ return mbedtls_des3_crypt_ecb( (mbedtls_des3_context *) ctx, input, output );
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static int des_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length,
+ unsigned char *iv, const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_des_crypt_cbc( (mbedtls_des_context *) ctx, operation, length, iv, input,
+ output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static int des3_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length,
+ unsigned char *iv, const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_des3_crypt_cbc( (mbedtls_des3_context *) ctx, operation, length, iv, input,
+ output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+static int des_setkey_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedtls_des_setkey_dec( (mbedtls_des_context *) ctx, key );
+}
+
+static int des_setkey_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedtls_des_setkey_enc( (mbedtls_des_context *) ctx, key );
+}
+
+static int des3_set2key_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedtls_des3_set2key_dec( (mbedtls_des3_context *) ctx, key );
+}
+
+static int des3_set2key_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedtls_des3_set2key_enc( (mbedtls_des3_context *) ctx, key );
+}
+
+static int des3_set3key_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedtls_des3_set3key_dec( (mbedtls_des3_context *) ctx, key );
+}
+
+static int des3_set3key_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedtls_des3_set3key_enc( (mbedtls_des3_context *) ctx, key );
+}
+
+static void * des_ctx_alloc( void )
+{
+ mbedtls_des_context *des = mbedtls_calloc( 1, sizeof( mbedtls_des_context ) );
+
+ if( des == NULL )
+ return( NULL );
+
+ mbedtls_des_init( des );
+
+ return( des );
+}
+
+static void des_ctx_free( void *ctx )
+{
+ mbedtls_des_free( (mbedtls_des_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static void * des3_ctx_alloc( void )
+{
+ mbedtls_des3_context *des3;
+ des3 = mbedtls_calloc( 1, sizeof( mbedtls_des3_context ) );
+
+ if( des3 == NULL )
+ return( NULL );
+
+ mbedtls_des3_init( des3 );
+
+ return( des3 );
+}
+
+static void des3_ctx_free( void *ctx )
+{
+ mbedtls_des3_free( (mbedtls_des3_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static const mbedtls_cipher_base_t des_info = {
+ MBEDTLS_CIPHER_ID_DES,
+ des_crypt_ecb_wrap,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ des_crypt_cbc_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ des_setkey_enc_wrap,
+ des_setkey_dec_wrap,
+ des_ctx_alloc,
+ des_ctx_free
+};
+
+static const mbedtls_cipher_info_t des_ecb_info = {
+ MBEDTLS_CIPHER_DES_ECB,
+ MBEDTLS_MODE_ECB,
+ MBEDTLS_KEY_LENGTH_DES,
+ "DES-ECB",
+ 8,
+ 0,
+ 8,
+ &des_info
+};
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static const mbedtls_cipher_info_t des_cbc_info = {
+ MBEDTLS_CIPHER_DES_CBC,
+ MBEDTLS_MODE_CBC,
+ MBEDTLS_KEY_LENGTH_DES,
+ "DES-CBC",
+ 8,
+ 0,
+ 8,
+ &des_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+static const mbedtls_cipher_base_t des_ede_info = {
+ MBEDTLS_CIPHER_ID_DES,
+ des3_crypt_ecb_wrap,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ des3_crypt_cbc_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ des3_set2key_enc_wrap,
+ des3_set2key_dec_wrap,
+ des3_ctx_alloc,
+ des3_ctx_free
+};
+
+static const mbedtls_cipher_info_t des_ede_ecb_info = {
+ MBEDTLS_CIPHER_DES_EDE_ECB,
+ MBEDTLS_MODE_ECB,
+ MBEDTLS_KEY_LENGTH_DES_EDE,
+ "DES-EDE-ECB",
+ 8,
+ 0,
+ 8,
+ &des_ede_info
+};
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static const mbedtls_cipher_info_t des_ede_cbc_info = {
+ MBEDTLS_CIPHER_DES_EDE_CBC,
+ MBEDTLS_MODE_CBC,
+ MBEDTLS_KEY_LENGTH_DES_EDE,
+ "DES-EDE-CBC",
+ 8,
+ 0,
+ 8,
+ &des_ede_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+static const mbedtls_cipher_base_t des_ede3_info = {
+ MBEDTLS_CIPHER_ID_3DES,
+ des3_crypt_ecb_wrap,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ des3_crypt_cbc_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ des3_set3key_enc_wrap,
+ des3_set3key_dec_wrap,
+ des3_ctx_alloc,
+ des3_ctx_free
+};
+
+static const mbedtls_cipher_info_t des_ede3_ecb_info = {
+ MBEDTLS_CIPHER_DES_EDE3_ECB,
+ MBEDTLS_MODE_ECB,
+ MBEDTLS_KEY_LENGTH_DES_EDE3,
+ "DES-EDE3-ECB",
+ 8,
+ 0,
+ 8,
+ &des_ede3_info
+};
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static const mbedtls_cipher_info_t des_ede3_cbc_info = {
+ MBEDTLS_CIPHER_DES_EDE3_CBC,
+ MBEDTLS_MODE_CBC,
+ MBEDTLS_KEY_LENGTH_DES_EDE3,
+ "DES-EDE3-CBC",
+ 8,
+ 0,
+ 8,
+ &des_ede3_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+#endif /* MBEDTLS_DES_C */
+
+#if defined(MBEDTLS_BLOWFISH_C)
+
+static int blowfish_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_blowfish_crypt_ecb( (mbedtls_blowfish_context *) ctx, operation, input,
+ output );
+}
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static int blowfish_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation,
+ size_t length, unsigned char *iv, const unsigned char *input,
+ unsigned char *output )
+{
+ return mbedtls_blowfish_crypt_cbc( (mbedtls_blowfish_context *) ctx, operation, length, iv,
+ input, output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+static int blowfish_crypt_cfb64_wrap( void *ctx, mbedtls_operation_t operation,
+ size_t length, size_t *iv_off, unsigned char *iv,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_blowfish_crypt_cfb64( (mbedtls_blowfish_context *) ctx, operation, length,
+ iv_off, iv, input, output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+static int blowfish_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off,
+ unsigned char *nonce_counter, unsigned char *stream_block,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedtls_blowfish_crypt_ctr( (mbedtls_blowfish_context *) ctx, length, nc_off,
+ nonce_counter, stream_block, input, output );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+static int blowfish_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedtls_blowfish_setkey( (mbedtls_blowfish_context *) ctx, key, key_bitlen );
+}
+
+static void * blowfish_ctx_alloc( void )
+{
+ mbedtls_blowfish_context *ctx;
+ ctx = mbedtls_calloc( 1, sizeof( mbedtls_blowfish_context ) );
+
+ if( ctx == NULL )
+ return( NULL );
+
+ mbedtls_blowfish_init( ctx );
+
+ return( ctx );
+}
+
+static void blowfish_ctx_free( void *ctx )
+{
+ mbedtls_blowfish_free( (mbedtls_blowfish_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static const mbedtls_cipher_base_t blowfish_info = {
+ MBEDTLS_CIPHER_ID_BLOWFISH,
+ blowfish_crypt_ecb_wrap,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ blowfish_crypt_cbc_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ blowfish_crypt_cfb64_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ blowfish_crypt_ctr_wrap,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ blowfish_setkey_wrap,
+ blowfish_setkey_wrap,
+ blowfish_ctx_alloc,
+ blowfish_ctx_free
+};
+
+static const mbedtls_cipher_info_t blowfish_ecb_info = {
+ MBEDTLS_CIPHER_BLOWFISH_ECB,
+ MBEDTLS_MODE_ECB,
+ 128,
+ "BLOWFISH-ECB",
+ 8,
+ MBEDTLS_CIPHER_VARIABLE_KEY_LEN,
+ 8,
+ &blowfish_info
+};
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static const mbedtls_cipher_info_t blowfish_cbc_info = {
+ MBEDTLS_CIPHER_BLOWFISH_CBC,
+ MBEDTLS_MODE_CBC,
+ 128,
+ "BLOWFISH-CBC",
+ 8,
+ MBEDTLS_CIPHER_VARIABLE_KEY_LEN,
+ 8,
+ &blowfish_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+static const mbedtls_cipher_info_t blowfish_cfb64_info = {
+ MBEDTLS_CIPHER_BLOWFISH_CFB64,
+ MBEDTLS_MODE_CFB,
+ 128,
+ "BLOWFISH-CFB64",
+ 8,
+ MBEDTLS_CIPHER_VARIABLE_KEY_LEN,
+ 8,
+ &blowfish_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+static const mbedtls_cipher_info_t blowfish_ctr_info = {
+ MBEDTLS_CIPHER_BLOWFISH_CTR,
+ MBEDTLS_MODE_CTR,
+ 128,
+ "BLOWFISH-CTR",
+ 8,
+ MBEDTLS_CIPHER_VARIABLE_KEY_LEN,
+ 8,
+ &blowfish_info
+};
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+#endif /* MBEDTLS_BLOWFISH_C */
+
+#if defined(MBEDTLS_ARC4_C)
+static int arc4_crypt_stream_wrap( void *ctx, size_t length,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ return( mbedtls_arc4_crypt( (mbedtls_arc4_context *) ctx, length, input, output ) );
+}
+
+static int arc4_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ /* we get key_bitlen in bits, arc4 expects it in bytes */
+ if( key_bitlen % 8 != 0 )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ mbedtls_arc4_setup( (mbedtls_arc4_context *) ctx, key, key_bitlen / 8 );
+ return( 0 );
+}
+
+static void * arc4_ctx_alloc( void )
+{
+ mbedtls_arc4_context *ctx;
+ ctx = mbedtls_calloc( 1, sizeof( mbedtls_arc4_context ) );
+
+ if( ctx == NULL )
+ return( NULL );
+
+ mbedtls_arc4_init( ctx );
+
+ return( ctx );
+}
+
+static void arc4_ctx_free( void *ctx )
+{
+ mbedtls_arc4_free( (mbedtls_arc4_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static const mbedtls_cipher_base_t arc4_base_info = {
+ MBEDTLS_CIPHER_ID_ARC4,
+ NULL,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ arc4_crypt_stream_wrap,
+#endif
+ arc4_setkey_wrap,
+ arc4_setkey_wrap,
+ arc4_ctx_alloc,
+ arc4_ctx_free
+};
+
+static const mbedtls_cipher_info_t arc4_128_info = {
+ MBEDTLS_CIPHER_ARC4_128,
+ MBEDTLS_MODE_STREAM,
+ 128,
+ "ARC4-128",
+ 0,
+ 0,
+ 1,
+ &arc4_base_info
+};
+#endif /* MBEDTLS_ARC4_C */
+
+#if defined(MBEDTLS_CIPHER_NULL_CIPHER)
+static int null_crypt_stream( void *ctx, size_t length,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ ((void) ctx);
+ memmove( output, input, length );
+ return( 0 );
+}
+
+static int null_setkey( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) ctx);
+ ((void) key);
+ ((void) key_bitlen);
+
+ return( 0 );
+}
+
+static void * null_ctx_alloc( void )
+{
+ return( (void *) 1 );
+}
+
+static void null_ctx_free( void *ctx )
+{
+ ((void) ctx);
+}
+
+static const mbedtls_cipher_base_t null_base_info = {
+ MBEDTLS_CIPHER_ID_NULL,
+ NULL,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+ null_crypt_stream,
+#endif
+ null_setkey,
+ null_setkey,
+ null_ctx_alloc,
+ null_ctx_free
+};
+
+static const mbedtls_cipher_info_t null_cipher_info = {
+ MBEDTLS_CIPHER_NULL,
+ MBEDTLS_MODE_STREAM,
+ 0,
+ "NULL",
+ 0,
+ 0,
+ 1,
+ &null_base_info
+};
+#endif /* defined(MBEDTLS_CIPHER_NULL_CIPHER) */
+
+const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] =
+{
+#if defined(MBEDTLS_AES_C)
+ { MBEDTLS_CIPHER_AES_128_ECB, &aes_128_ecb_info },
+ { MBEDTLS_CIPHER_AES_192_ECB, &aes_192_ecb_info },
+ { MBEDTLS_CIPHER_AES_256_ECB, &aes_256_ecb_info },
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ { MBEDTLS_CIPHER_AES_128_CBC, &aes_128_cbc_info },
+ { MBEDTLS_CIPHER_AES_192_CBC, &aes_192_cbc_info },
+ { MBEDTLS_CIPHER_AES_256_CBC, &aes_256_cbc_info },
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ { MBEDTLS_CIPHER_AES_128_CFB128, &aes_128_cfb128_info },
+ { MBEDTLS_CIPHER_AES_192_CFB128, &aes_192_cfb128_info },
+ { MBEDTLS_CIPHER_AES_256_CFB128, &aes_256_cfb128_info },
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ { MBEDTLS_CIPHER_AES_128_CTR, &aes_128_ctr_info },
+ { MBEDTLS_CIPHER_AES_192_CTR, &aes_192_ctr_info },
+ { MBEDTLS_CIPHER_AES_256_CTR, &aes_256_ctr_info },
+#endif
+#if defined(MBEDTLS_GCM_C)
+ { MBEDTLS_CIPHER_AES_128_GCM, &aes_128_gcm_info },
+ { MBEDTLS_CIPHER_AES_192_GCM, &aes_192_gcm_info },
+ { MBEDTLS_CIPHER_AES_256_GCM, &aes_256_gcm_info },
+#endif
+#if defined(MBEDTLS_CCM_C)
+ { MBEDTLS_CIPHER_AES_128_CCM, &aes_128_ccm_info },
+ { MBEDTLS_CIPHER_AES_192_CCM, &aes_192_ccm_info },
+ { MBEDTLS_CIPHER_AES_256_CCM, &aes_256_ccm_info },
+#endif
+#endif /* MBEDTLS_AES_C */
+
+#if defined(MBEDTLS_ARC4_C)
+ { MBEDTLS_CIPHER_ARC4_128, &arc4_128_info },
+#endif
+
+#if defined(MBEDTLS_BLOWFISH_C)
+ { MBEDTLS_CIPHER_BLOWFISH_ECB, &blowfish_ecb_info },
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ { MBEDTLS_CIPHER_BLOWFISH_CBC, &blowfish_cbc_info },
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ { MBEDTLS_CIPHER_BLOWFISH_CFB64, &blowfish_cfb64_info },
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ { MBEDTLS_CIPHER_BLOWFISH_CTR, &blowfish_ctr_info },
+#endif
+#endif /* MBEDTLS_BLOWFISH_C */
+
+#if defined(MBEDTLS_CAMELLIA_C)
+ { MBEDTLS_CIPHER_CAMELLIA_128_ECB, &camellia_128_ecb_info },
+ { MBEDTLS_CIPHER_CAMELLIA_192_ECB, &camellia_192_ecb_info },
+ { MBEDTLS_CIPHER_CAMELLIA_256_ECB, &camellia_256_ecb_info },
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ { MBEDTLS_CIPHER_CAMELLIA_128_CBC, &camellia_128_cbc_info },
+ { MBEDTLS_CIPHER_CAMELLIA_192_CBC, &camellia_192_cbc_info },
+ { MBEDTLS_CIPHER_CAMELLIA_256_CBC, &camellia_256_cbc_info },
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+ { MBEDTLS_CIPHER_CAMELLIA_128_CFB128, &camellia_128_cfb128_info },
+ { MBEDTLS_CIPHER_CAMELLIA_192_CFB128, &camellia_192_cfb128_info },
+ { MBEDTLS_CIPHER_CAMELLIA_256_CFB128, &camellia_256_cfb128_info },
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+ { MBEDTLS_CIPHER_CAMELLIA_128_CTR, &camellia_128_ctr_info },
+ { MBEDTLS_CIPHER_CAMELLIA_192_CTR, &camellia_192_ctr_info },
+ { MBEDTLS_CIPHER_CAMELLIA_256_CTR, &camellia_256_ctr_info },
+#endif
+#if defined(MBEDTLS_GCM_C)
+ { MBEDTLS_CIPHER_CAMELLIA_128_GCM, &camellia_128_gcm_info },
+ { MBEDTLS_CIPHER_CAMELLIA_192_GCM, &camellia_192_gcm_info },
+ { MBEDTLS_CIPHER_CAMELLIA_256_GCM, &camellia_256_gcm_info },
+#endif
+#if defined(MBEDTLS_CCM_C)
+ { MBEDTLS_CIPHER_CAMELLIA_128_CCM, &camellia_128_ccm_info },
+ { MBEDTLS_CIPHER_CAMELLIA_192_CCM, &camellia_192_ccm_info },
+ { MBEDTLS_CIPHER_CAMELLIA_256_CCM, &camellia_256_ccm_info },
+#endif
+#endif /* MBEDTLS_CAMELLIA_C */
+
+#if defined(MBEDTLS_DES_C)
+ { MBEDTLS_CIPHER_DES_ECB, &des_ecb_info },
+ { MBEDTLS_CIPHER_DES_EDE_ECB, &des_ede_ecb_info },
+ { MBEDTLS_CIPHER_DES_EDE3_ECB, &des_ede3_ecb_info },
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+ { MBEDTLS_CIPHER_DES_CBC, &des_cbc_info },
+ { MBEDTLS_CIPHER_DES_EDE_CBC, &des_ede_cbc_info },
+ { MBEDTLS_CIPHER_DES_EDE3_CBC, &des_ede3_cbc_info },
+#endif
+#endif /* MBEDTLS_DES_C */
+
+#if defined(MBEDTLS_CIPHER_NULL_CIPHER)
+ { MBEDTLS_CIPHER_NULL, &null_cipher_info },
+#endif /* MBEDTLS_CIPHER_NULL_CIPHER */
+
+ { MBEDTLS_CIPHER_NONE, NULL }
+};
+
+#define NUM_CIPHERS sizeof mbedtls_cipher_definitions / sizeof mbedtls_cipher_definitions[0]
+int mbedtls_cipher_supported[NUM_CIPHERS];
+
+#endif /* MBEDTLS_CIPHER_C */
diff --git a/libesp32/ESP32-Ethernet/README.md b/libesp32/ESP32-Ethernet/README.md
new file mode 100644
index 000000000..ac4d80fa4
--- /dev/null
+++ b/libesp32/ESP32-Ethernet/README.md
@@ -0,0 +1,4 @@
+# Ethernet Arduino Library for ESP32
+
+See https://github.com/espressif/arduino-esp32/issues/3554#issuecomment-596902806
+
diff --git a/libesp32/ESP32-Ethernet/examples/EthernetLAN_IP101/EthernetLAN_IP101.ino b/libesp32/ESP32-Ethernet/examples/EthernetLAN_IP101/EthernetLAN_IP101.ino
new file mode 100644
index 000000000..3bbe837a1
--- /dev/null
+++ b/libesp32/ESP32-Ethernet/examples/EthernetLAN_IP101/EthernetLAN_IP101.ino
@@ -0,0 +1,82 @@
+#include
+
+#define ETH_ADDR 1
+#define ETH_POWER_PIN 5
+#define ETH_MDC_PIN 23
+#define ETH_MDIO_PIN 18
+#define ETH_TYPE ETH_PHY_IP101
+
+static bool eth_connected = false;
+
+void WiFiEvent(WiFiEvent_t event)
+{
+ switch (event) {
+ case SYSTEM_EVENT_ETH_START:
+ Serial.println("ETH Started");
+ //set eth hostname here
+ ETH.setHostname("esp32-ethernet");
+ break;
+ case SYSTEM_EVENT_ETH_CONNECTED:
+ Serial.println("ETH Connected");
+ break;
+ case SYSTEM_EVENT_ETH_GOT_IP:
+ Serial.print("ETH MAC: ");
+ Serial.print(ETH.macAddress());
+ Serial.print(", IPv4: ");
+ Serial.print(ETH.localIP());
+ if (ETH.fullDuplex()) {
+ Serial.print(", FULL_DUPLEX");
+ }
+ Serial.print(", ");
+ Serial.print(ETH.linkSpeed());
+ Serial.println("Mbps");
+ eth_connected = true;
+ break;
+ case SYSTEM_EVENT_ETH_DISCONNECTED:
+ Serial.println("ETH Disconnected");
+ eth_connected = false;
+ break;
+ case SYSTEM_EVENT_ETH_STOP:
+ Serial.println("ETH Stopped");
+ eth_connected = false;
+ break;
+ default:
+ break;
+ }
+}
+
+void testClient(const char * host, uint16_t port)
+{
+ Serial.print("\nconnecting to ");
+ Serial.println(host);
+
+ WiFiClient client;
+ if (!client.connect(host, port)) {
+ Serial.println("connection failed");
+ return;
+ }
+ client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
+ while (client.connected() && !client.available());
+ while (client.available()) {
+ Serial.write(client.read());
+ }
+
+ Serial.println("closing connection\n");
+ client.stop();
+}
+
+void setup()
+{
+ Serial.begin(115200);
+ WiFi.onEvent(WiFiEvent);
+ ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE);
+}
+
+
+void loop()
+{
+ if (eth_connected) {
+ testClient("google.com", 80);
+ }
+ delay(10000);
+}
\ No newline at end of file
diff --git a/libesp32/ESP32-Ethernet/library.properties b/libesp32/ESP32-Ethernet/library.properties
new file mode 100644
index 000000000..50c7b8ea1
--- /dev/null
+++ b/libesp32/ESP32-Ethernet/library.properties
@@ -0,0 +1,17 @@
+name=ESP32 Ethernet
+
+version=1.1.0
+
+author=Espressif
+
+maintainer=Espressif
+
+sentence=Ethernet Library for ESP32
+
+paragraph=This library allows ESP32 to use ethernet hardware
+
+category=Communication
+
+url=
+
+architectures=esp32
diff --git a/libesp32/ESP32-Ethernet/src/ETH.cpp b/libesp32/ESP32-Ethernet/src/ETH.cpp
new file mode 100644
index 000000000..2b3dd4390
--- /dev/null
+++ b/libesp32/ESP32-Ethernet/src/ETH.cpp
@@ -0,0 +1,299 @@
+/*
+ ETH.h - espre ETH PHY support.
+ Based on WiFi.h from Arduino WiFi shield library.
+ Copyright (c) 2011-2014 Arduino. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ETH.h"
+#include "eth_phy/phy.h"
+#include "eth_phy/phy_tlk110.h"
+#include "eth_phy/phy_lan8720.h"
+#include "eth_phy/phy_ip101.h"
+#include "lwip/err.h"
+#include "lwip/dns.h"
+
+extern void tcpipInit();
+
+static int _eth_phy_mdc_pin = -1;
+static int _eth_phy_mdio_pin = -1;
+static int _eth_phy_power_pin = -1;
+static eth_phy_power_enable_func _eth_phy_power_enable_orig = NULL;
+
+static void _eth_phy_config_gpio(void)
+{
+ if(_eth_phy_mdc_pin < 0 || _eth_phy_mdio_pin < 0){
+ log_e("MDC and MDIO pins are not configured!");
+ return;
+ }
+ phy_rmii_configure_data_interface_pins();
+ phy_rmii_smi_configure_pins(_eth_phy_mdc_pin, _eth_phy_mdio_pin);
+}
+
+static void _eth_phy_power_enable(bool enable)
+{
+ pinMode(_eth_phy_power_pin, OUTPUT);
+ digitalWrite(_eth_phy_power_pin, enable);
+ delay(1);
+}
+
+ETHClass::ETHClass():initialized(false),started(false),staticIP(false)
+{
+}
+
+ETHClass::~ETHClass()
+{}
+
+bool ETHClass::begin(uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_type_t type, eth_clock_mode_t clock_mode)
+{
+ esp_err_t err;
+ if(initialized){
+ err = esp_eth_enable();
+ if(err){
+ log_e("esp_eth_enable error: %d", err);
+ return false;
+ }
+ started = true;
+ return true;
+ }
+ _eth_phy_mdc_pin = mdc;
+ _eth_phy_mdio_pin = mdio;
+ _eth_phy_power_pin = power;
+
+ if(type == ETH_PHY_LAN8720)
+ {
+ eth_config_t config = phy_lan8720_default_ethernet_config;
+ memcpy(ð_config, &config, sizeof(eth_config_t));
+ }
+ else if(type == ETH_PHY_TLK110)
+ {
+ eth_config_t config = phy_tlk110_default_ethernet_config;
+ memcpy(ð_config, &config, sizeof(eth_config_t));
+ }
+ else if(type == ETH_PHY_IP101)
+ {
+ eth_config_t config = phy_ip101_default_ethernet_config;
+ memcpy(ð_config, &config, sizeof(eth_config_t));
+ }
+ else
+ {
+ log_e("Bad ETH_PHY type: %u", (uint8_t)type);
+ return false;
+ }
+
+ eth_config.phy_addr = (eth_phy_base_t)phy_addr;
+ eth_config.clock_mode = clock_mode;
+ eth_config.gpio_config = _eth_phy_config_gpio;
+ eth_config.tcpip_input = tcpip_adapter_eth_input;
+ if(_eth_phy_power_pin >= 0){
+ _eth_phy_power_enable_orig = eth_config.phy_power_enable;
+ eth_config.phy_power_enable = _eth_phy_power_enable;
+ }
+
+ tcpipInit();
+ err = esp_eth_init(ð_config);
+ if(!err){
+ initialized = true;
+ err = esp_eth_enable();
+ if(err){
+ log_e("esp_eth_enable error: %d", err);
+ } else {
+ started = true;
+ return true;
+ }
+ } else {
+ log_e("esp_eth_init error: %d", err);
+ }
+ return false;
+}
+
+bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2)
+{
+ esp_err_t err = ESP_OK;
+ tcpip_adapter_ip_info_t info;
+
+ if(local_ip != (uint32_t)0x00000000){
+ info.ip.addr = static_cast(local_ip);
+ info.gw.addr = static_cast(gateway);
+ info.netmask.addr = static_cast(subnet);
+ } else {
+ info.ip.addr = 0;
+ info.gw.addr = 0;
+ info.netmask.addr = 0;
+ }
+
+ err = tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_ETH);
+ if(err != ESP_OK && err != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED){
+ log_e("DHCP could not be stopped! Error: %d", err);
+ return false;
+ }
+
+ err = tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_ETH, &info);
+ if(err != ERR_OK){
+ log_e("STA IP could not be configured! Error: %d", err);
+ return false;
+}
+ if(info.ip.addr){
+ staticIP = true;
+ } else {
+ err = tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_ETH);
+ if(err != ESP_OK && err != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED){
+ log_w("DHCP could not be started! Error: %d", err);
+ return false;
+ }
+ staticIP = false;
+ }
+
+ ip_addr_t d;
+ d.type = IPADDR_TYPE_V4;
+
+ if(dns1 != (uint32_t)0x00000000) {
+ // Set DNS1-Server
+ d.u_addr.ip4.addr = static_cast(dns1);
+ dns_setserver(0, &d);
+ }
+
+ if(dns2 != (uint32_t)0x00000000) {
+ // Set DNS2-Server
+ d.u_addr.ip4.addr = static_cast(dns2);
+ dns_setserver(1, &d);
+ }
+
+ return true;
+}
+
+IPAddress ETHClass::localIP()
+{
+ tcpip_adapter_ip_info_t ip;
+ if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
+ return IPAddress();
+ }
+ return IPAddress(ip.ip.addr);
+}
+
+IPAddress ETHClass::subnetMask()
+{
+ tcpip_adapter_ip_info_t ip;
+ if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
+ return IPAddress();
+ }
+ return IPAddress(ip.netmask.addr);
+}
+
+IPAddress ETHClass::gatewayIP()
+{
+ tcpip_adapter_ip_info_t ip;
+ if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
+ return IPAddress();
+ }
+ return IPAddress(ip.gw.addr);
+}
+
+IPAddress ETHClass::dnsIP(uint8_t dns_no)
+{
+ ip_addr_t dns_ip = dns_getserver(dns_no);
+ return IPAddress(dns_ip.u_addr.ip4.addr);
+}
+
+IPAddress ETHClass::broadcastIP()
+{
+ tcpip_adapter_ip_info_t ip;
+ if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
+ return IPAddress();
+ }
+ return WiFiGenericClass::calculateBroadcast(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr));
+}
+
+IPAddress ETHClass::networkID()
+{
+ tcpip_adapter_ip_info_t ip;
+ if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
+ return IPAddress();
+ }
+ return WiFiGenericClass::calculateNetworkID(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr));
+}
+
+uint8_t ETHClass::subnetCIDR()
+{
+ tcpip_adapter_ip_info_t ip;
+ if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
+ return (uint8_t)0;
+ }
+ return WiFiGenericClass::calculateSubnetCIDR(IPAddress(ip.netmask.addr));
+}
+
+const char * ETHClass::getHostname()
+{
+ const char * hostname;
+ if(tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_ETH, &hostname)){
+ return NULL;
+ }
+ return hostname;
+}
+
+bool ETHClass::setHostname(const char * hostname)
+{
+ return tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_ETH, hostname) == 0;
+}
+
+bool ETHClass::fullDuplex()
+{
+ return eth_config.phy_get_duplex_mode();
+}
+
+bool ETHClass::linkUp()
+{
+ return eth_config.phy_check_link();
+}
+
+uint8_t ETHClass::linkSpeed()
+{
+ return eth_config.phy_get_speed_mode()?100:10;
+}
+
+bool ETHClass::enableIpV6()
+{
+ return tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_ETH) == 0;
+}
+
+IPv6Address ETHClass::localIPv6()
+{
+ static ip6_addr_t addr;
+ if(tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_ETH, &addr)){
+ return IPv6Address();
+ }
+ return IPv6Address(addr.addr);
+}
+
+uint8_t * macAddress(uint8_t* mac)
+{
+ if(!mac){
+ return NULL;
+ }
+ esp_eth_get_mac(mac);
+ return mac;
+}
+
+String ETHClass::macAddress(void)
+{
+ uint8_t mac[6];
+ char macStr[18] = { 0 };
+ esp_eth_get_mac(mac);
+ sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ return String(macStr);
+}
+
+ETHClass ETH;
diff --git a/libesp32/ESP32-Ethernet/src/ETH.h b/libesp32/ESP32-Ethernet/src/ETH.h
new file mode 100644
index 000000000..7f175e13f
--- /dev/null
+++ b/libesp32/ESP32-Ethernet/src/ETH.h
@@ -0,0 +1,95 @@
+/*
+ ETH.h - espre ETH PHY support.
+ Based on WiFi.h from Ardiono WiFi shield library.
+ Copyright (c) 2011-2014 Arduino. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ETH_H_
+#define _ETH_H_
+
+#include "WiFi.h"
+#include "esp_eth.h"
+
+#ifndef ETH_PHY_ADDR
+#define ETH_PHY_ADDR 0
+#endif
+
+#ifndef ETH_PHY_TYPE
+#define ETH_PHY_TYPE ETH_PHY_LAN8720
+#endif
+
+#ifndef ETH_PHY_POWER
+#define ETH_PHY_POWER -1
+#endif
+
+#ifndef ETH_PHY_MDC
+#define ETH_PHY_MDC 23
+#endif
+
+#ifndef ETH_PHY_MDIO
+#define ETH_PHY_MDIO 18
+#endif
+
+#ifndef ETH_CLK_MODE
+#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN
+#endif
+
+typedef enum { ETH_PHY_LAN8720, ETH_PHY_TLK110, ETH_PHY_IP101, ETH_PHY_MAX } eth_phy_type_t;
+
+class ETHClass {
+ private:
+ bool initialized;
+ bool started;
+ bool staticIP;
+ eth_config_t eth_config;
+ public:
+ ETHClass();
+ ~ETHClass();
+
+ bool begin(uint8_t phy_addr=ETH_PHY_ADDR, int power=ETH_PHY_POWER, int mdc=ETH_PHY_MDC, int mdio=ETH_PHY_MDIO, eth_phy_type_t type=ETH_PHY_TYPE, eth_clock_mode_t clk_mode=ETH_CLK_MODE);
+
+ bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000);
+
+ const char * getHostname();
+ bool setHostname(const char * hostname);
+
+ bool fullDuplex();
+ bool linkUp();
+ uint8_t linkSpeed();
+
+ bool enableIpV6();
+ IPv6Address localIPv6();
+
+ IPAddress localIP();
+ IPAddress subnetMask();
+ IPAddress gatewayIP();
+ IPAddress dnsIP(uint8_t dns_no = 0);
+
+ IPAddress broadcastIP();
+ IPAddress networkID();
+ uint8_t subnetCIDR();
+
+ uint8_t * macAddress(uint8_t* mac);
+ String macAddress();
+
+ friend class WiFiClient;
+ friend class WiFiServer;
+};
+
+extern ETHClass ETH;
+
+#endif /* _ETH_H_ */
diff --git a/platformio.ini b/platformio.ini
index 04835d6c0..abb9d364d 100755
--- a/platformio.ini
+++ b/platformio.ini
@@ -128,6 +128,6 @@ build_flags = ${tasmota_core.build_flags}
[tasmota_core]
; *** Esp8266 Arduino core 2.7.1
-platform = espressif8266@2.5.1
+platform = espressif8266@2.5.2
platform_packages =
build_flags = ${esp82xx_defaults.build_flags}
diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md
index 4f7d3132b..3ba3a1d38 100644
--- a/tasmota/CHANGELOG.md
+++ b/tasmota/CHANGELOG.md
@@ -1,5 +1,31 @@
## Unreleased (development)
+### 8.3.1.6 20200617
+
+- Add command ``Module2`` to configure fallback module on fast reboot (#8464)
+- Add support for Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff
+- Add library to be used for decoding Teleinfo (French Metering Smart Meter)
+- Add support for single wire LMT01 temperature Sensor by justifiably (#8713)
+- Change ESP32 USER GPIO template representation decreasing template message size
+- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT
+- Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset``
+
+### 8.3.1.5 20200616
+
+- Add ESP32 ethernet commands ``EthType 0/1``, ``EthAddress 0..31`` and ``EthClockMode 0..3``
+- Add Zigbee initial support for EmberZNet protocol (raw send/receive only)
+
+### 8.3.1.4 20200615
+
+- Add basic support for ESP32 ethernet adding commands ``Wifi 0/1`` and ``Ethernet 0/1`` both default ON
+
+### 8.3.1.3 20200611
+
+- Add initial support for Telegram bot (#8619)
+- Add support for HP303B Temperature and Pressure sensor by Robert Jaakke (#8638)
+- Add rule trigger ``System#Init`` to allow early rule execution without wifi and mqtt initialized yet
+- Add serial to TCP bridge, ``TCPStart`` and ``TCPBaudRate`` (needs #define USE_TCP_BRIDGE)
+
### 8.3.1.2 20200522
- Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]``
diff --git a/tasmota/StackThunk_light.cpp b/tasmota/StackThunk_light.cpp
index 5dcc20d62..c9f9bc78e 100644
--- a/tasmota/StackThunk_light.cpp
+++ b/tasmota/StackThunk_light.cpp
@@ -40,7 +40,7 @@ uint32_t *stack_thunk_light_save = NULL; /* Saved A1 while in BearSSL */
uint32_t stack_thunk_light_refcnt = 0;
//#define _stackSize (5600/4)
-#if defined(USE_MQTT_AWS_IOT) || defined(USE_MQTT_TLS_FORCE_EC_CIPHER)
+#ifdef USE_MQTT_TLS_FORCE_EC_CIPHER
#define _stackSize (5300/4) // using a light version of bearssl we can save 300 bytes
#else
#define _stackSize (3600/4) // using a light version of bearssl we can save 2k
diff --git a/tasmota/StackThunk_light.h b/tasmota/StackThunk_light.h
index 13a0cb7d3..164417000 100644
--- a/tasmota/StackThunk_light.h
+++ b/tasmota/StackThunk_light.h
@@ -52,7 +52,7 @@ extern uint32_t stack_thunk_light_refcnt;
// Thunking macro
#define make_stack_thunk_light(fcnToThunk) \
-__asm("\n\
+__asm__("\n\
.text\n\
.literal_position\n\
.literal .LC_STACK_VALUE"#fcnToThunk", 0xdeadbeef\n\
diff --git a/tasmota/WiFiClientSecureLightBearSSL.cpp b/tasmota/WiFiClientSecureLightBearSSL.cpp
old mode 100644
new mode 100755
index 434522b14..d0907788e
--- a/tasmota/WiFiClientSecureLightBearSSL.cpp
+++ b/tasmota/WiFiClientSecureLightBearSSL.cpp
@@ -1,912 +1,915 @@
-/*
- WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
- - Mostly compatible with Arduino WiFi shield library and standard
- WiFiClient/ServerSecure (except for certificate handling).
-
- Copyright (c) 2018 Earle F. Philhower, III
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
-#include "my_user_config.h"
-//#ifdef USE_MQTT_TLS
-#if defined ESP8266 && (defined(USE_MQTT_TLS) || defined (USE_SENDMAIL))
-
-//#define DEBUG_TLS
-
-#define LWIP_INTERNAL
-
-#include
-#include
-#include
-
-extern "C" {
-#include "osapi.h"
-#include "ets_sys.h"
-}
-#include "debug.h"
-#include "WiFiClientSecureLightBearSSL.h" // needs to be before "ESP8266WiFi.h" to avoid conflict with Arduino headers
-#include "ESP8266WiFi.h"
-#include "WiFiClient.h"
-#include "StackThunk_light.h"
-#include "lwip/opt.h"
-#include "lwip/ip.h"
-#include "lwip/tcp.h"
-#include "lwip/inet.h"
-#include "lwip/netif.h"
-#include
-#include "c_types.h"
-
-#include
-#ifndef ARDUINO_ESP8266_RELEASE_2_5_2
-#undef DEBUG_TLS
-#endif
-
-#ifdef DEBUG_TLS
-#include "coredecls.h"
-#define LOG_HEAP_SIZE(a) _Log_heap_size(a)
-void _Log_heap_size(const char *msg) {
- register uint32_t *sp asm("a1");
- int freestack = 4 * (sp - g_pcont->stack);
- Serial.printf("%s %d, Fragmentation=%d, Thunkstack=%d, Free stack=%d, FreeContStack=%d\n",
- msg, ESP.getFreeHeap(), ESP.getHeapFragmentation(), stack_thunk_light_get_max_usage(),
- freestack, ESP.getFreeContStack());
-}
-#else
-#define LOG_HEAP_SIZE(a)
-#endif
-
-// Stack thunked versions of calls
-// Initially in BearSSLHelpers.h
-extern "C" {
-extern unsigned char *thunk_light_br_ssl_engine_recvapp_buf( const br_ssl_engine_context *cc, size_t *len);
-extern void thunk_light_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len);
-extern unsigned char *thunk_light_br_ssl_engine_recvrec_buf( const br_ssl_engine_context *cc, size_t *len);
-extern void thunk_light_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len);
-extern unsigned char *thunk_light_br_ssl_engine_sendapp_buf( const br_ssl_engine_context *cc, size_t *len);
-extern void thunk_light_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len);
-extern unsigned char *thunk_light_br_ssl_engine_sendrec_buf( const br_ssl_engine_context *cc, size_t *len);
-extern void thunk_light_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len);
-};
-
-// Second stack thunked helpers
-make_stack_thunk_light(br_ssl_engine_recvapp_ack);
-make_stack_thunk_light(br_ssl_engine_recvapp_buf);
-make_stack_thunk_light(br_ssl_engine_recvrec_ack);
-make_stack_thunk_light(br_ssl_engine_recvrec_buf);
-make_stack_thunk_light(br_ssl_engine_sendapp_ack);
-make_stack_thunk_light(br_ssl_engine_sendapp_buf);
-make_stack_thunk_light(br_ssl_engine_sendrec_ack);
-make_stack_thunk_light(br_ssl_engine_sendrec_buf);
-
-// create new version of Thunk function to store on SYS stack
-// unless the Thunk was initialized. Thanks to AES128 GCM, we can keep
-// symetric processing on the stack
-void min_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len) {
- if (stack_thunk_light_get_refcnt()) {
- return thunk_light_br_ssl_engine_recvapp_ack(cc, len);
- } else {
- return br_ssl_engine_recvapp_ack(cc, len);
- }
-}
-unsigned char *min_br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len) {
- if (stack_thunk_light_get_refcnt()) {
- return thunk_light_br_ssl_engine_recvapp_buf(cc, len);
- } else {
- return br_ssl_engine_recvapp_buf(cc, len);
- }
-}
-void min_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len) {
- if (stack_thunk_light_get_refcnt()) {
- return thunk_light_br_ssl_engine_recvrec_ack(cc, len);
- } else {
- return br_ssl_engine_recvrec_ack(cc, len);
- }
-}
-unsigned char *min_br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len) {
- if (stack_thunk_light_get_refcnt()) {
- return thunk_light_br_ssl_engine_recvrec_buf(cc, len);
- } else {
- return br_ssl_engine_recvrec_buf(cc, len);
- }
-}
-void min_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len) {
- if (stack_thunk_light_get_refcnt()) {
- return thunk_light_br_ssl_engine_sendapp_ack(cc, len);
- } else {
- return br_ssl_engine_sendapp_ack(cc, len);
- }
-}
-unsigned char *min_br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len) {
- if (stack_thunk_light_get_refcnt()) {
- return thunk_light_br_ssl_engine_sendapp_buf(cc, len);
- } else {
- return br_ssl_engine_sendapp_buf(cc, len);
- }
-}
-void min_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len) {
- if (stack_thunk_light_get_refcnt()) {
- return thunk_light_br_ssl_engine_sendrec_ack(cc, len);
- } else {
- return br_ssl_engine_sendrec_ack(cc, len);
- }
-}
-unsigned char *min_br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len) {
- if (stack_thunk_light_get_refcnt()) {
- return thunk_light_br_ssl_engine_sendrec_buf(cc, len);
- } else {
- return br_ssl_engine_sendrec_buf(cc, len);
- }
-}
-
-// Use min_ instead of original thunk_
-#define br_ssl_engine_recvapp_ack min_br_ssl_engine_recvapp_ack
-#define br_ssl_engine_recvapp_buf min_br_ssl_engine_recvapp_buf
-#define br_ssl_engine_recvrec_ack min_br_ssl_engine_recvrec_ack
-#define br_ssl_engine_recvrec_buf min_br_ssl_engine_recvrec_buf
-#define br_ssl_engine_sendapp_ack min_br_ssl_engine_sendapp_ack
-#define br_ssl_engine_sendapp_buf min_br_ssl_engine_sendapp_buf
-#define br_ssl_engine_sendrec_ack min_br_ssl_engine_sendrec_ack
-#define br_ssl_engine_sendrec_buf min_br_ssl_engine_sendrec_buf
-
-//#define DEBUG_ESP_SSL
-#ifdef DEBUG_ESP_SSL
-#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__)
-//#define DEBUG_BSSL(fmt, ...) Serial.printf(fmt, ## __VA_ARGS__)
-#else
-#define DEBUG_BSSL(...)
-#endif
-
-namespace BearSSL {
-
-void WiFiClientSecure_light::_clear() {
- // TLS handshake may take more than the 5 second default timeout
- _timeout = 10000; // 10 seconds max, it should never go over 6 seconds
-
- _sc = nullptr;
- _ctx_present = false;
- _eng = nullptr;
- _iobuf_in = nullptr;
- _iobuf_out = nullptr;
- _now = 0; // You can override or ensure time() is correct w/configTime
- setBufferSizes(1024, 1024); // reasonable minimum
- _handshake_done = false;
- _last_error = 0;
- _recvapp_buf = nullptr;
- _recvapp_len = 0;
- _fingerprint_any = true; // by default accept all fingerprints
- _fingerprint1 = nullptr;
- _fingerprint2 = nullptr;
- _chain_P = nullptr;
- _sk_ec_P = nullptr;
- _ta_P = nullptr;
- _max_thunkstack_use = 0;
-}
-
-// Constructor
-WiFiClientSecure_light::WiFiClientSecure_light(int recv, int xmit) : WiFiClient() {
- _clear();
-LOG_HEAP_SIZE("StackThunk before");
- //stack_thunk_light_add_ref();
-LOG_HEAP_SIZE("StackThunk after");
- // now finish the setup
- setBufferSizes(recv, xmit); // reasonable minimum
- allocateBuffers();
-}
-
-WiFiClientSecure_light::~WiFiClientSecure_light() {
- if (_client) {
- _client->unref();
- _client = nullptr;
- }
- //_cipher_list = nullptr; // std::shared will free if last reference
- _freeSSL();
-}
-
-void WiFiClientSecure_light::allocateBuffers(void) {
- // We prefer to allocate all buffers at start, rather than lazy allocation and deallocation
- // in the long run it avoids heap fragmentation and improves stability
- LOG_HEAP_SIZE("allocateBuffers before");
- _sc = std::make_shared();
- LOG_HEAP_SIZE("allocateBuffers ClientContext");
- _iobuf_in = std::shared_ptr(new unsigned char[_iobuf_in_size], std::default_delete());
- _iobuf_out = std::shared_ptr(new unsigned char[_iobuf_out_size], std::default_delete());
- LOG_HEAP_SIZE("allocateBuffers after");
-}
-
-void WiFiClientSecure_light::setClientECCert(const br_x509_certificate *cert, const br_ec_private_key *sk,
- unsigned allowed_usages, unsigned cert_issuer_key_type) {
- _chain_P = cert;
- _sk_ec_P = sk;
- _allowed_usages = allowed_usages;
- _cert_issuer_key_type = cert_issuer_key_type;
-}
-
-void WiFiClientSecure_light::setTrustAnchor(const br_x509_trust_anchor *ta) {
- _ta_P = ta;
-}
-
-void WiFiClientSecure_light::setBufferSizes(int recv, int xmit) {
- // Following constants taken from bearssl/src/ssl/ssl_engine.c (not exported unfortunately)
- const int MAX_OUT_OVERHEAD = 85;
- const int MAX_IN_OVERHEAD = 325;
-
- // The data buffers must be between 512B and 16KB
- recv = std::max(512, std::min(16384, recv));
- xmit = std::max(512, std::min(16384, xmit));
-
- // Add in overhead for SSL protocol
- recv += MAX_IN_OVERHEAD;
- xmit += MAX_OUT_OVERHEAD;
- _iobuf_in_size = recv;
- _iobuf_out_size = xmit;
-}
-
-bool WiFiClientSecure_light::stop(unsigned int maxWaitMs) {
-#ifdef ARDUINO_ESP8266_RELEASE_2_4_2
- WiFiClient::stop(); // calls our virtual flush()
- _freeSSL();
- return true;
-#else
- bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush()
- _freeSSL();
- return ret;
-#endif
-}
-
-bool WiFiClientSecure_light::flush(unsigned int maxWaitMs) {
- (void) _run_until(BR_SSL_SENDAPP);
-#ifdef ARDUINO_ESP8266_RELEASE_2_4_2
- WiFiClient::flush();
-#else
- return WiFiClient::flush(maxWaitMs);
-#endif
-}
-
-int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
- clearLastError();
- if (!WiFiClient::connect(ip, port)) {
- setLastError(ERR_TCP_CONNECT);
- return 0;
- }
- return _connectSSL(nullptr);
-}
-
-int WiFiClientSecure_light::connect(const char* name, uint16_t port) {
- IPAddress remote_addr;
- clearLastError();
- if (!WiFi.hostByName(name, remote_addr)) {
- DEBUG_BSSL("connect: Name loopup failure\n");
- setLastError(ERR_CANT_RESOLVE_IP);
- return 0;
- }
- if (!WiFiClient::connect(remote_addr, port)) {
- DEBUG_BSSL("connect: Unable to connect TCP socket\n");
- _last_error = ERR_TCP_CONNECT;
- return 0;
- }
- LOG_HEAP_SIZE("Before calling _connectSSL");
- return _connectSSL(name);
-}
-
-void WiFiClientSecure_light::_freeSSL() {
- _ctx_present = false;
- _recvapp_buf = nullptr;
- _recvapp_len = 0;
- // This connection is toast
- _handshake_done = false;
-}
-
-bool WiFiClientSecure_light::_clientConnected() {
- return (_client && _client->state() == ESTABLISHED);
-}
-
-uint8_t WiFiClientSecure_light::connected() {
- if (available() || (_clientConnected() && _handshake_done)) {
- return true;
- }
- return false;
-}
-
-size_t WiFiClientSecure_light::_write(const uint8_t *buf, size_t size, bool pmem) {
- size_t sent_bytes = 0;
-
- if (!connected() || !size || !_handshake_done) {
- return 0;
- }
-
- do {
- // Ensure we yield if we need multiple fragments to avoid WDT
- if (sent_bytes) {
- optimistic_yield(1000);
- }
-
- // Get BearSSL to a state where we can send
- if (_run_until(BR_SSL_SENDAPP) < 0) {
- break;
- }
-
- if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) {
- size_t sendapp_len;
- unsigned char *sendapp_buf = br_ssl_engine_sendapp_buf(_eng, &sendapp_len);
- int to_send = size > sendapp_len ? sendapp_len : size;
- if (pmem) {
- memcpy_P(sendapp_buf, buf, to_send);
- } else {
- memcpy(sendapp_buf, buf, to_send);
- }
- br_ssl_engine_sendapp_ack(_eng, to_send);
- br_ssl_engine_flush(_eng, 0);
- flush();
- buf += to_send;
- sent_bytes += to_send;
- size -= to_send;
- } else {
- break;
- }
- } while (size);
-
- LOG_HEAP_SIZE("_write");
- return sent_bytes;
-}
-
-size_t WiFiClientSecure_light::write(const uint8_t *buf, size_t size) {
- return _write(buf, size, false);
-}
-
-size_t WiFiClientSecure_light::write_P(PGM_P buf, size_t size) {
- return _write((const uint8_t *)buf, size, true);
-}
-
-// We have to manually read and send individual chunks.
-size_t WiFiClientSecure_light::write(Stream& stream) {
- size_t totalSent = 0;
- size_t countRead;
- size_t countSent;
-
- if (!connected() || !_handshake_done) {
- DEBUG_BSSL("write: Connect/handshake not completed yet\n");
- return 0;
- }
-
- do {
- uint8_t temp[256]; // Temporary chunk size same as ClientContext
- countSent = 0;
- countRead = stream.readBytes(temp, sizeof(temp));
- if (countRead) {
- countSent = _write((const uint8_t*)temp, countRead, true);
- totalSent += countSent;
- }
- yield(); // Feed the WDT
- } while ((countSent == countRead) && (countSent > 0));
- return totalSent;
-}
-
-int WiFiClientSecure_light::read(uint8_t *buf, size_t size) {
- if (!ctx_present() || !_handshake_done) {
- return -1;
- }
-
- int avail = available();
- bool conn = connected();
- if (!avail && conn) {
- return 0; // We're still connected, but nothing to read
- }
- if (!avail && !conn) {
- DEBUG_BSSL("read: Not connected, none left available\n");
- return -1;
- }
-
- if (avail) {
- // Take data from the recvapp buffer
- int to_copy = _recvapp_len < size ? _recvapp_len : size;
- memcpy(buf, _recvapp_buf, to_copy);
- br_ssl_engine_recvapp_ack(_eng, to_copy);
- _recvapp_buf = nullptr;
- _recvapp_len = 0;
- return to_copy;
- }
-
- if (!conn) {
- DEBUG_BSSL("read: Not connected\n");
- return -1;
- }
- return 0; // If we're connected, no error but no read.
-}
-
-int WiFiClientSecure_light::read() {
- uint8_t c;
- if (1 == read(&c, 1)) {
- return c;
- }
- DEBUG_BSSL("read: failed\n");
- return -1;
-}
-
-int WiFiClientSecure_light::available() {
- if (_recvapp_buf) {
- return _recvapp_len; // Anything from last call?
- }
- _recvapp_buf = nullptr;
- _recvapp_len = 0;
- if (!ctx_present() || _run_until(BR_SSL_RECVAPP, false) < 0) {
- return 0;
- }
- int st = br_ssl_engine_current_state(_eng);
- if (st == BR_SSL_CLOSED) {
- return 0; // Nothing leftover, SSL is closed
- }
- if (st & BR_SSL_RECVAPP) {
- _recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len);
- return _recvapp_len;
- }
-
- return 0;
-}
-
-int WiFiClientSecure_light::peek() {
- if (!ctx_present() || !available()) {
- DEBUG_BSSL("peek: Not connected, none left available\n");
- return -1;
- }
- if (_recvapp_buf && _recvapp_len) {
- return _recvapp_buf[0];
- }
- DEBUG_BSSL("peek: No data left\n");
- return -1;
-}
-
-size_t WiFiClientSecure_light::peekBytes(uint8_t *buffer, size_t length) {
- size_t to_copy = 0;
- if (!ctx_present()) {
- DEBUG_BSSL("peekBytes: Not connected\n");
- return 0;
- }
-
- _startMillis = millis();
- while ((available() < (int) length) && ((millis() - _startMillis) < 5000)) {
- yield();
- }
-
- to_copy = _recvapp_len < length ? _recvapp_len : length;
- memcpy(buffer, _recvapp_buf, to_copy);
- return to_copy;
-}
-
-/* --- Copied almost verbatim from BEARSSL SSL_IO.C ---
- Run the engine, until the specified target state is achieved, or
- an error occurs. The target state is SENDAPP, RECVAPP, or the
- combination of both (the combination matches either). When a match is
- achieved, this function returns 0. On error, it returns -1.
-*/
-int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
-//LOG_HEAP_SIZE("_run_until 1");
- if (!ctx_present()) {
- DEBUG_BSSL("_run_until: Not connected\n");
- return -1;
- }
- for (int no_work = 0; blocking || no_work < 2;) {
- if (blocking) {
- // Only for blocking operations can we afford to yield()
- optimistic_yield(100);
- }
-
- int state;
- state = br_ssl_engine_current_state(_eng);
- if (state & BR_SSL_CLOSED) {
- return -1;
- }
-
- if (!(_client->state() == ESTABLISHED) && !WiFiClient::available()) {
- return (state & target) ? 0 : -1;
- }
-
- /*
- If there is some record data to send, do it. This takes
- precedence over everything else.
- */
- if (state & BR_SSL_SENDREC) {
- unsigned char *buf;
- size_t len;
- int wlen;
-
- buf = br_ssl_engine_sendrec_buf(_eng, &len);
- wlen = WiFiClient::write(buf, len);
- if (wlen <= 0) {
- /*
- If we received a close_notify and we
- still send something, then we have our
- own response close_notify to send, and
- the peer is allowed by RFC 5246 not to
- wait for it.
- */
- return -1;
- }
- if (wlen > 0) {
- br_ssl_engine_sendrec_ack(_eng, wlen);
- }
- no_work = 0;
- continue;
- }
-
- /*
- If we reached our target, then we are finished.
- */
- if (state & target) {
- return 0;
- }
- /*
- If some application data must be read, and we did not
- exit, then this means that we are trying to write data,
- and that's not possible until the application data is
- read. This may happen if using a shared in/out buffer,
- and the underlying protocol is not strictly half-duplex.
- This is unrecoverable here, so we report an error.
- */
- if (state & BR_SSL_RECVAPP) {
- DEBUG_BSSL("_run_until: Fatal protocol state\n");
- return -1;
- }
- /*
- If we reached that point, then either we are trying
- to read data and there is some, or the engine is stuck
- until a new record is obtained.
- */
- if (state & BR_SSL_RECVREC) {
- if (WiFiClient::available()) {
- unsigned char *buf;
- size_t len;
- int rlen;
-
- buf = br_ssl_engine_recvrec_buf(_eng, &len);
- rlen = WiFiClient::read(buf, len);
- if (rlen < 0) {
- return -1;
- }
- if (rlen > 0) {
- br_ssl_engine_recvrec_ack(_eng, rlen);
- }
- no_work = 0;
- continue;
- }
- }
- /*
- We can reach that point if the target RECVAPP, and
- the state contains SENDAPP only. This may happen with
- a shared in/out buffer. In that case, we must flush
- the buffered data to "make room" for a new incoming
- record.
- */
- br_ssl_engine_flush(_eng, 0);
-
- no_work++; // We didn't actually advance here
- }
- // We only get here if we ran through the loop without getting anything done
- return -1;
-}
-
-bool WiFiClientSecure_light::_wait_for_handshake() {
- _handshake_done = false;
- while (!_handshake_done && _clientConnected()) {
- int ret = _run_until(BR_SSL_SENDAPP);
- if (ret < 0) {
- DEBUG_BSSL("_wait_for_handshake: failed\n");
- break;
- }
- if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) {
- _handshake_done = true;
- }
- optimistic_yield(1000);
- }
- return _handshake_done;
-}
-
-static uint8_t htoi (unsigned char c)
-{
- if (c>='0' && c <='9') return c - '0';
- else if (c>='A' && c<='F') return 10 + c - 'A';
- else if (c>='a' && c<='f') return 10 + c - 'a';
- else return 255;
-}
-
-extern "C" {
-
- // see https://stackoverflow.com/questions/6357031/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-in-c
- void tohex(unsigned char * in, size_t insz, char * out, size_t outsz) {
- unsigned char * pin = in;
- static const char * hex = "0123456789ABCDEF";
- char * pout = out;
- for(; pin < in+insz; pout +=3, pin++){
- pout[0] = hex[(*pin>>4) & 0xF];
- pout[1] = hex[ *pin & 0xF];
- pout[2] = ':';
- if (pout + 3 - out > outsz){
- /* Better to truncate output string than overflow buffer */
- /* it would be still better to either return a status */
- /* or ensure the target buffer is large enough and it never happen */
- break;
- }
- }
- pout[-1] = 0;
- }
-
-
- // BearSSL doesn't define a true insecure decoder, so we make one ourselves
- // from the simple parser. It generates the issuer and subject hashes and
- // the SHA1 fingerprint, only one (or none!) of which will be used to
- // "verify" the certificate.
-
- // Private x509 decoder state
- struct br_x509_pubkeyfingerprint_context {
- const br_x509_class *vtable;
- bool done_cert; // did we parse the first cert already?
- bool fingerprint_all;
- uint8_t *pubkey_recv_fingerprint;
- const uint8_t *fingerprint1;
- const uint8_t *fingerprint2;
- unsigned usages; // pubkey usage
- br_x509_decoder_context ctx; // defined in BearSSL
- };
-
- // Callback on the first byte of any certificate
- static void pubkeyfingerprint_start_chain(const br_x509_class **ctx, const char *server_name) {
- br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
- // Don't process anything but the first certificate in the chain
- if (!xc->done_cert) {
- br_x509_decoder_init(&xc->ctx, nullptr, nullptr, nullptr, nullptr);
- }
- (void)server_name; // ignore server name
- }
-
- // Callback for each certificate present in the chain (but only operates
- // on the first one by design).
- static void pubkeyfingerprint_start_cert(const br_x509_class **ctx, uint32_t length) {
- (void) ctx; // do nothing
- (void) length;
- }
-
- // Callback for each byte stream in the chain. Only process first cert.
- static void pubkeyfingerprint_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) {
- br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
- // Don't process anything but the first certificate in the chain
- if (!xc->done_cert) {
- br_x509_decoder_push(&xc->ctx, (const void*)buf, len);
- }
- }
-
- // Callback on individual cert end.
- static void pubkeyfingerprint_end_cert(const br_x509_class **ctx) {
- br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
- xc->done_cert = true; // first cert already processed
- }
-
- static void pubkeyfingerprint_pubkey_fingerprint(br_sha1_context *shactx, br_rsa_public_key rsakey) {
- br_sha1_init(shactx);
- br_sha1_update(shactx, "ssh-rsa", 7); // tag
- br_sha1_update(shactx, rsakey.e, rsakey.elen); // exponent
- br_sha1_update(shactx, rsakey.n, rsakey.nlen); // modulus
- }
-
- // Callback when complete chain has been parsed.
- // Return 0 on validation success, !0 on validation error
- static unsigned pubkeyfingerprint_end_chain(const br_x509_class **ctx) {
- br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
-
- br_sha1_context sha1_context;
- pubkeyfingerprint_pubkey_fingerprint(&sha1_context, xc->ctx.pkey.key.rsa);
- br_sha1_out(&sha1_context, xc->pubkey_recv_fingerprint); // copy to fingerprint
-
- if (!xc->fingerprint_all) {
- if (0 == memcmp(xc->fingerprint1, xc->pubkey_recv_fingerprint, 20)) {
- return 0;
- }
- if (0 == memcmp(xc->fingerprint2, xc->pubkey_recv_fingerprint, 20)) {
- return 0;
- }
- return 1; // no match, error
- } else {
- // Default (no validation at all) or no errors in prior checks = success.
- return 0;
- }
- }
-
- // Return the public key from the validator (set by x509_minimal)
- static const br_x509_pkey *pubkeyfingerprint_get_pkey(const br_x509_class *const *ctx, unsigned *usages) {
- const br_x509_pubkeyfingerprint_context *xc = (const br_x509_pubkeyfingerprint_context *)ctx;
-
- if (usages != NULL) {
- *usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN; // I said we were insecure!
- }
- return &xc->ctx.pkey;
- }
-
- // Set up the x509 insecure data structures for BearSSL core to use.
- void br_x509_pubkeyfingerprint_init(br_x509_pubkeyfingerprint_context *ctx,
- const uint8_t *fingerprint1, const uint8_t *fingerprint2,
- uint8_t *recv_fingerprint,
- bool fingerprint_all) {
- static const br_x509_class br_x509_pubkeyfingerprint_vtable PROGMEM = {
- sizeof(br_x509_pubkeyfingerprint_context),
- pubkeyfingerprint_start_chain,
- pubkeyfingerprint_start_cert,
- pubkeyfingerprint_append,
- pubkeyfingerprint_end_cert,
- pubkeyfingerprint_end_chain,
- pubkeyfingerprint_get_pkey
- };
-
- memset(ctx, 0, sizeof * ctx);
- ctx->vtable = &br_x509_pubkeyfingerprint_vtable;
- ctx->done_cert = false;
- ctx->fingerprint1 = fingerprint1;
- ctx->fingerprint2 = fingerprint2;
- ctx->pubkey_recv_fingerprint = recv_fingerprint;
- ctx->fingerprint_all = fingerprint_all;
- }
-
- // We limit to a single cipher to reduce footprint
- // we reference it, don't put in PROGMEM
- static const uint16_t suites[] = {
-#if defined(USE_MQTT_AWS_IOT) || defined(USE_MQTT_TLS_FORCE_EC_CIPHER)
- BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-#else
- BR_TLS_RSA_WITH_AES_128_GCM_SHA256
-#endif
- };
-
- // Default initializion for our SSL clients
- static void br_ssl_client_base_init(br_ssl_client_context *cc) {
- br_ssl_client_zero(cc);
- // forbid SSL renegociation, as we free the Private Key after handshake
- br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION);
-
- br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
- br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0]));
- br_ssl_client_set_default_rsapub(cc);
- br_ssl_engine_set_default_rsavrfy(&cc->eng);
-
- // install hashes
- br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
- br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
-
- // AES CTR/GCM small version, not contstant time (we don't really care here as there is no TPM anyways)
- br_ssl_engine_set_gcm(&cc->eng, &br_sslrec_in_gcm_vtable, &br_sslrec_out_gcm_vtable);
- br_ssl_engine_set_aes_ctr(&cc->eng, &br_aes_small_ctr_vtable);
- br_ssl_engine_set_ghash(&cc->eng, &br_ghash_ctmul32);
-
-#if defined(USE_MQTT_AWS_IOT) || defined(USE_MQTT_TLS_FORCE_EC_CIPHER)
- // we support only P256 EC curve for AWS IoT, no EC curve for Letsencrypt unless forced
- br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15);
-#endif
- }
-}
-
-// Called by connect() to do the actual SSL setup and handshake.
-// Returns if the SSL handshake succeeded.
-bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
-#ifdef USE_MQTT_AWS_IOT
- if ((!_chain_P) || (!_sk_ec_P)) {
- setLastError(ERR_MISSING_EC_KEY);
- return false;
- }
-#endif
-
- // Validation context, either full CA validation or checking only fingerprints
-#ifdef USE_MQTT_TLS_CA_CERT
- br_x509_minimal_context *x509_minimal;
-#else
- br_x509_pubkeyfingerprint_context *x509_insecure;
-#endif
-
- LOG_HEAP_SIZE("_connectSSL.start");
-
- do { // used to exit on Out of Memory error and keep all cleanup code at the same place
- // ============================================================
- // allocate Thunk stack, move to alternate stack and initialize
- stack_thunk_light_add_ref();
- LOG_HEAP_SIZE("Thunk allocated");
- DEBUG_BSSL("_connectSSL: start connection\n");
- _freeSSL();
- clearLastError();
- if (!stack_thunk_light_get_stack_bot()) break;
-
- _ctx_present = true;
- _eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr
-
- br_ssl_client_base_init(_sc.get());
-
- // ============================================================
- // Allocatte and initialize Decoder Context
- LOG_HEAP_SIZE("_connectSSL before DecoderContext allocation");
- // Only failure possible in the installation is OOM
- #ifdef USE_MQTT_TLS_CA_CERT
- x509_minimal = (br_x509_minimal_context*) malloc(sizeof(br_x509_minimal_context));
- if (!x509_minimal) break;
- br_x509_minimal_init(x509_minimal, &br_sha256_vtable, _ta_P, 1);
- br_x509_minimal_set_rsa(x509_minimal, br_ssl_engine_get_rsavrfy(_eng));
- br_x509_minimal_set_hash(x509_minimal, br_sha256_ID, &br_sha256_vtable);
- br_ssl_engine_set_x509(_eng, &x509_minimal->vtable);
-
- #else
- x509_insecure = (br_x509_pubkeyfingerprint_context*) malloc(sizeof(br_x509_pubkeyfingerprint_context));
- //x509_insecure = std::unique_ptr(new br_x509_pubkeyfingerprint_context);
- if (!x509_insecure) break;
- br_x509_pubkeyfingerprint_init(x509_insecure, _fingerprint1, _fingerprint2, _recv_fingerprint, _fingerprint_any);
- br_ssl_engine_set_x509(_eng, &x509_insecure->vtable);
- #endif
- LOG_HEAP_SIZE("_connectSSL after DecoderContext allocation");
-
- // ============================================================
- // Set send/receive buffers
- br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size);
-
- // ============================================================
- // allocate Private key if needed, only if USE_MQTT_AWS_IOT
- LOG_HEAP_SIZE("_connectSSL before PrivKey allocation");
- #ifdef USE_MQTT_AWS_IOT
- // ============================================================
- // Set the EC Private Key, only USE_MQTT_AWS_IOT
- // limited to P256 curve
- br_ssl_client_set_single_ec(_sc.get(), _chain_P, 1,
- _sk_ec_P, _allowed_usages,
- _cert_issuer_key_type, &br_ec_p256_m15, br_ecdsa_sign_asn1_get_default());
- #endif // USE_MQTT_AWS_IOT
-
- // ============================================================
- // Start TLS connection, ALL
- if (!br_ssl_client_reset(_sc.get(), hostName, 0)) break;
-
- auto ret = _wait_for_handshake();
- #ifdef DEBUG_ESP_SSL
- if (!ret) {
- DEBUG_BSSL("Couldn't connect. Error = %d\n", getLastError());
- } else {
- DEBUG_BSSL("Connected! MFLNStatus = %d\n", getMFLNStatus());
- }
- #endif
- LOG_HEAP_SIZE("_connectSSL.end");
- _max_thunkstack_use = stack_thunk_light_get_max_usage();
- stack_thunk_light_del_ref();
- //stack_thunk_light_repaint();
- LOG_HEAP_SIZE("_connectSSL.end, freeing StackThunk");
-
- #ifdef USE_MQTT_TLS_CA_CERT
- free(x509_minimal);
- #else
- free(x509_insecure);
- #endif
- LOG_HEAP_SIZE("_connectSSL after release of Priv Key");
- return ret;
- } while (0);
-
- // ============================================================
- // if we arrived here, this means we had an OOM error, cleaning up
- setLastError(ERR_OOM);
- DEBUG_BSSL("_connectSSL: Out of memory\n");
- stack_thunk_light_del_ref();
-#ifdef USE_MQTT_TLS_CA_CERT
- free(x509_minimal);
-#else
- free(x509_insecure);
-#endif
- LOG_HEAP_SIZE("_connectSSL clean_on_error");
- return false;
-}
-
-};
-
-#include "t_bearssl_tasmota_config.h"
-
-#endif // USE_MQTT_TLS
+/*
+ WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
+ - Mostly compatible with Arduino WiFi shield library and standard
+ WiFiClient/ServerSecure (except for certificate handling).
+
+ Copyright (c) 2018 Earle F. Philhower, III
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "my_user_config.h"
+#if defined(ESP8266) && defined(USE_TLS)
+
+// #define DEBUG_TLS
+// #define DEBUG_ESP_SSL
+
+#define LWIP_INTERNAL
+
+#include
+#include
+#include
+
+extern "C" {
+#include "osapi.h"
+#include "ets_sys.h"
+}
+#include "debug.h"
+#include "WiFiClientSecureLightBearSSL.h" // needs to be before "ESP8266WiFi.h" to avoid conflict with Arduino headers
+#include "ESP8266WiFi.h"
+#include "WiFiClient.h"
+#include "StackThunk_light.h"
+#include "lwip/opt.h"
+#include "lwip/ip.h"
+#include "lwip/tcp.h"
+#include "lwip/inet.h"
+#include "lwip/netif.h"
+#include
+#include "c_types.h"
+
+#include
+#ifndef ARDUINO_ESP8266_RELEASE_2_5_2
+#undef DEBUG_TLS
+#endif
+
+#ifdef DEBUG_TLS
+#include "coredecls.h"
+#define LOG_HEAP_SIZE(a) _Log_heap_size(a)
+void _Log_heap_size(const char *msg) {
+ register uint32_t *sp asm("a1");
+ int freestack = 4 * (sp - g_pcont->stack);
+ Serial.printf("%s %d, Fragmentation=%d, Thunkstack=%d, Free stack=%d, FreeContStack=%d\n",
+ msg, ESP.getFreeHeap(), ESP.getHeapFragmentation(), stack_thunk_light_get_max_usage(),
+ freestack, ESP.getFreeContStack());
+}
+#else
+#define LOG_HEAP_SIZE(a)
+#endif
+
+// Stack thunked versions of calls
+// Initially in BearSSLHelpers.h
+extern "C" {
+extern unsigned char *thunk_light_br_ssl_engine_recvapp_buf( const br_ssl_engine_context *cc, size_t *len);
+extern void thunk_light_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len);
+extern unsigned char *thunk_light_br_ssl_engine_recvrec_buf( const br_ssl_engine_context *cc, size_t *len);
+extern void thunk_light_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len);
+extern unsigned char *thunk_light_br_ssl_engine_sendapp_buf( const br_ssl_engine_context *cc, size_t *len);
+extern void thunk_light_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len);
+extern unsigned char *thunk_light_br_ssl_engine_sendrec_buf( const br_ssl_engine_context *cc, size_t *len);
+extern void thunk_light_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len);
+};
+
+// Second stack thunked helpers
+make_stack_thunk_light(br_ssl_engine_recvapp_ack);
+make_stack_thunk_light(br_ssl_engine_recvapp_buf);
+make_stack_thunk_light(br_ssl_engine_recvrec_ack);
+make_stack_thunk_light(br_ssl_engine_recvrec_buf);
+make_stack_thunk_light(br_ssl_engine_sendapp_ack);
+make_stack_thunk_light(br_ssl_engine_sendapp_buf);
+make_stack_thunk_light(br_ssl_engine_sendrec_ack);
+make_stack_thunk_light(br_ssl_engine_sendrec_buf);
+
+// create new version of Thunk function to store on SYS stack
+// unless the Thunk was initialized. Thanks to AES128 GCM, we can keep
+// symetric processing on the stack
+void min_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len) {
+ if (stack_thunk_light_get_refcnt()) {
+ return thunk_light_br_ssl_engine_recvapp_ack(cc, len);
+ } else {
+ return br_ssl_engine_recvapp_ack(cc, len);
+ }
+}
+unsigned char *min_br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len) {
+ if (stack_thunk_light_get_refcnt()) {
+ return thunk_light_br_ssl_engine_recvapp_buf(cc, len);
+ } else {
+ return br_ssl_engine_recvapp_buf(cc, len);
+ }
+}
+void min_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len) {
+ if (stack_thunk_light_get_refcnt()) {
+ return thunk_light_br_ssl_engine_recvrec_ack(cc, len);
+ } else {
+ return br_ssl_engine_recvrec_ack(cc, len);
+ }
+}
+unsigned char *min_br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len) {
+ if (stack_thunk_light_get_refcnt()) {
+ return thunk_light_br_ssl_engine_recvrec_buf(cc, len);
+ } else {
+ return br_ssl_engine_recvrec_buf(cc, len);
+ }
+}
+void min_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len) {
+ if (stack_thunk_light_get_refcnt()) {
+ return thunk_light_br_ssl_engine_sendapp_ack(cc, len);
+ } else {
+ return br_ssl_engine_sendapp_ack(cc, len);
+ }
+}
+unsigned char *min_br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len) {
+ if (stack_thunk_light_get_refcnt()) {
+ return thunk_light_br_ssl_engine_sendapp_buf(cc, len);
+ } else {
+ return br_ssl_engine_sendapp_buf(cc, len);
+ }
+}
+void min_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len) {
+ if (stack_thunk_light_get_refcnt()) {
+ return thunk_light_br_ssl_engine_sendrec_ack(cc, len);
+ } else {
+ return br_ssl_engine_sendrec_ack(cc, len);
+ }
+}
+unsigned char *min_br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len) {
+ if (stack_thunk_light_get_refcnt()) {
+ return thunk_light_br_ssl_engine_sendrec_buf(cc, len);
+ } else {
+ return br_ssl_engine_sendrec_buf(cc, len);
+ }
+}
+
+// Use min_ instead of original thunk_
+#define br_ssl_engine_recvapp_ack min_br_ssl_engine_recvapp_ack
+#define br_ssl_engine_recvapp_buf min_br_ssl_engine_recvapp_buf
+#define br_ssl_engine_recvrec_ack min_br_ssl_engine_recvrec_ack
+#define br_ssl_engine_recvrec_buf min_br_ssl_engine_recvrec_buf
+#define br_ssl_engine_sendapp_ack min_br_ssl_engine_sendapp_ack
+#define br_ssl_engine_sendapp_buf min_br_ssl_engine_sendapp_buf
+#define br_ssl_engine_sendrec_ack min_br_ssl_engine_sendrec_ack
+#define br_ssl_engine_sendrec_buf min_br_ssl_engine_sendrec_buf
+
+//#define DEBUG_ESP_SSL
+#ifdef DEBUG_ESP_SSL
+//#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__)
+#define DEBUG_BSSL(fmt, ...) Serial.printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_BSSL(...)
+#endif
+
+namespace BearSSL {
+
+void WiFiClientSecure_light::_clear() {
+ // TLS handshake may take more than the 5 second default timeout
+ _timeout = 10000; // 10 seconds max, it should never go over 6 seconds
+
+ _sc = nullptr;
+ _ctx_present = false;
+ _eng = nullptr;
+ _iobuf_in = nullptr;
+ _iobuf_out = nullptr;
+ _now = 0; // You can override or ensure time() is correct w/configTime
+ setBufferSizes(1024, 1024); // reasonable minimum
+ _handshake_done = false;
+ _last_error = 0;
+ _recvapp_buf = nullptr;
+ _recvapp_len = 0;
+ _fingerprint_any = true; // by default accept all fingerprints
+ _fingerprint1 = nullptr;
+ _fingerprint2 = nullptr;
+ _chain_P = nullptr;
+ _sk_ec_P = nullptr;
+ _ta_P = nullptr;
+ _max_thunkstack_use = 0;
+}
+
+// Constructor
+WiFiClientSecure_light::WiFiClientSecure_light(int recv, int xmit) : WiFiClient() {
+ _clear();
+LOG_HEAP_SIZE("StackThunk before");
+ //stack_thunk_light_add_ref();
+LOG_HEAP_SIZE("StackThunk after");
+ // now finish the setup
+ setBufferSizes(recv, xmit); // reasonable minimum
+ allocateBuffers();
+}
+
+WiFiClientSecure_light::~WiFiClientSecure_light() {
+ if (_client) {
+ _client->unref();
+ _client = nullptr;
+ }
+ //_cipher_list = nullptr; // std::shared will free if last reference
+ _freeSSL();
+}
+
+void WiFiClientSecure_light::allocateBuffers(void) {
+ // We prefer to allocate all buffers at start, rather than lazy allocation and deallocation
+ // in the long run it avoids heap fragmentation and improves stability
+ LOG_HEAP_SIZE("allocateBuffers before");
+ _sc = std::make_shared();
+ LOG_HEAP_SIZE("allocateBuffers ClientContext");
+ _iobuf_in = std::shared_ptr(new unsigned char[_iobuf_in_size], std::default_delete());
+ _iobuf_out = std::shared_ptr(new unsigned char[_iobuf_out_size], std::default_delete());
+ LOG_HEAP_SIZE("allocateBuffers after");
+}
+
+void WiFiClientSecure_light::setClientECCert(const br_x509_certificate *cert, const br_ec_private_key *sk,
+ unsigned allowed_usages, unsigned cert_issuer_key_type) {
+ _chain_P = cert;
+ _sk_ec_P = sk;
+ _allowed_usages = allowed_usages;
+ _cert_issuer_key_type = cert_issuer_key_type;
+}
+
+void WiFiClientSecure_light::setTrustAnchor(const br_x509_trust_anchor *ta) {
+ _ta_P = ta;
+}
+
+void WiFiClientSecure_light::setBufferSizes(int recv, int xmit) {
+ // Following constants taken from bearssl/src/ssl/ssl_engine.c (not exported unfortunately)
+ const int MAX_OUT_OVERHEAD = 85;
+ const int MAX_IN_OVERHEAD = 325;
+
+ // The data buffers must be between 512B and 16KB
+ recv = std::max(512, std::min(16384, recv));
+ xmit = std::max(512, std::min(16384, xmit));
+
+ // Add in overhead for SSL protocol
+ recv += MAX_IN_OVERHEAD;
+ xmit += MAX_OUT_OVERHEAD;
+ _iobuf_in_size = recv;
+ _iobuf_out_size = xmit;
+}
+
+bool WiFiClientSecure_light::stop(unsigned int maxWaitMs) {
+#ifdef ARDUINO_ESP8266_RELEASE_2_4_2
+ WiFiClient::stop(); // calls our virtual flush()
+ _freeSSL();
+ return true;
+#else
+ bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush()
+ _freeSSL();
+ return ret;
+#endif
+}
+
+bool WiFiClientSecure_light::flush(unsigned int maxWaitMs) {
+ (void) _run_until(BR_SSL_SENDAPP);
+#ifdef ARDUINO_ESP8266_RELEASE_2_4_2
+ WiFiClient::flush();
+#else
+ return WiFiClient::flush(maxWaitMs);
+#endif
+}
+
+int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
+ DEBUG_BSSL("connect(%s,%d)", ip.toString().c_str(), port);
+ clearLastError();
+ if (!WiFiClient::connect(ip, port)) {
+ setLastError(ERR_TCP_CONNECT);
+ return 0;
+ }
+ return _connectSSL(nullptr);
+}
+
+int WiFiClientSecure_light::connect(const char* name, uint16_t port) {
+ DEBUG_BSSL("connect(%s,%d)\n", name, port);
+ IPAddress remote_addr;
+ clearLastError();
+ if (!WiFi.hostByName(name, remote_addr)) {
+ DEBUG_BSSL("connect: Name loopup failure\n");
+ setLastError(ERR_CANT_RESOLVE_IP);
+ return 0;
+ }
+ DEBUG_BSSL("connect(%s,%d)\n", remote_addr.toString().c_str(), port);
+ if (!WiFiClient::connect(remote_addr, port)) {
+ DEBUG_BSSL("connect: Unable to connect TCP socket\n");
+ _last_error = ERR_TCP_CONNECT;
+ return 0;
+ }
+ LOG_HEAP_SIZE("Before calling _connectSSL");
+ return _connectSSL(name);
+}
+
+void WiFiClientSecure_light::_freeSSL() {
+ _ctx_present = false;
+ _recvapp_buf = nullptr;
+ _recvapp_len = 0;
+ // This connection is toast
+ _handshake_done = false;
+}
+
+bool WiFiClientSecure_light::_clientConnected() {
+ return (_client && _client->state() == ESTABLISHED);
+}
+
+uint8_t WiFiClientSecure_light::connected() {
+ if (available() || (_clientConnected() && _handshake_done)) {
+ return true;
+ }
+ return false;
+}
+
+size_t WiFiClientSecure_light::_write(const uint8_t *buf, size_t size, bool pmem) {
+ size_t sent_bytes = 0;
+
+ if (!connected() || !size || !_handshake_done) {
+ return 0;
+ }
+
+ do {
+ // Ensure we yield if we need multiple fragments to avoid WDT
+ if (sent_bytes) {
+ optimistic_yield(1000);
+ }
+
+ // Get BearSSL to a state where we can send
+ if (_run_until(BR_SSL_SENDAPP) < 0) {
+ break;
+ }
+
+ if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) {
+ size_t sendapp_len;
+ unsigned char *sendapp_buf = br_ssl_engine_sendapp_buf(_eng, &sendapp_len);
+ int to_send = size > sendapp_len ? sendapp_len : size;
+ if (pmem) {
+ memcpy_P(sendapp_buf, buf, to_send);
+ } else {
+ memcpy(sendapp_buf, buf, to_send);
+ }
+ br_ssl_engine_sendapp_ack(_eng, to_send);
+ br_ssl_engine_flush(_eng, 0);
+ flush();
+ buf += to_send;
+ sent_bytes += to_send;
+ size -= to_send;
+ } else {
+ break;
+ }
+ } while (size);
+
+ LOG_HEAP_SIZE("_write");
+ return sent_bytes;
+}
+
+size_t WiFiClientSecure_light::write(const uint8_t *buf, size_t size) {
+ return _write(buf, size, false);
+}
+
+size_t WiFiClientSecure_light::write_P(PGM_P buf, size_t size) {
+ return _write((const uint8_t *)buf, size, true);
+}
+
+// We have to manually read and send individual chunks.
+size_t WiFiClientSecure_light::write(Stream& stream) {
+ size_t totalSent = 0;
+ size_t countRead;
+ size_t countSent;
+
+ if (!connected() || !_handshake_done) {
+ DEBUG_BSSL("write: Connect/handshake not completed yet\n");
+ return 0;
+ }
+
+ do {
+ uint8_t temp[256]; // Temporary chunk size same as ClientContext
+ countSent = 0;
+ countRead = stream.readBytes(temp, sizeof(temp));
+ if (countRead) {
+ countSent = _write((const uint8_t*)temp, countRead, true);
+ totalSent += countSent;
+ }
+ yield(); // Feed the WDT
+ } while ((countSent == countRead) && (countSent > 0));
+ return totalSent;
+}
+
+int WiFiClientSecure_light::read(uint8_t *buf, size_t size) {
+ if (!ctx_present() || !_handshake_done) {
+ return -1;
+ }
+
+ int avail = available();
+ bool conn = connected();
+ if (!avail && conn) {
+ return 0; // We're still connected, but nothing to read
+ }
+ if (!avail && !conn) {
+ DEBUG_BSSL("read: Not connected, none left available\n");
+ return -1;
+ }
+
+ if (avail) {
+ // Take data from the recvapp buffer
+ int to_copy = _recvapp_len < size ? _recvapp_len : size;
+ memcpy(buf, _recvapp_buf, to_copy);
+ br_ssl_engine_recvapp_ack(_eng, to_copy);
+ _recvapp_buf = nullptr;
+ _recvapp_len = 0;
+ return to_copy;
+ }
+
+ if (!conn) {
+ DEBUG_BSSL("read: Not connected\n");
+ return -1;
+ }
+ return 0; // If we're connected, no error but no read.
+}
+
+int WiFiClientSecure_light::read() {
+ uint8_t c;
+ if (1 == read(&c, 1)) {
+ return c;
+ }
+ DEBUG_BSSL("read: failed\n");
+ return -1;
+}
+
+int WiFiClientSecure_light::available() {
+ if (_recvapp_buf) {
+ return _recvapp_len; // Anything from last call?
+ }
+ _recvapp_buf = nullptr;
+ _recvapp_len = 0;
+ if (!ctx_present() || _run_until(BR_SSL_RECVAPP, false) < 0) {
+ return 0;
+ }
+ int st = br_ssl_engine_current_state(_eng);
+ if (st == BR_SSL_CLOSED) {
+ return 0; // Nothing leftover, SSL is closed
+ }
+ if (st & BR_SSL_RECVAPP) {
+ _recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len);
+ return _recvapp_len;
+ }
+
+ return 0;
+}
+
+int WiFiClientSecure_light::peek() {
+ if (!ctx_present() || !available()) {
+ DEBUG_BSSL("peek: Not connected, none left available\n");
+ return -1;
+ }
+ if (_recvapp_buf && _recvapp_len) {
+ return _recvapp_buf[0];
+ }
+ DEBUG_BSSL("peek: No data left\n");
+ return -1;
+}
+
+size_t WiFiClientSecure_light::peekBytes(uint8_t *buffer, size_t length) {
+ size_t to_copy = 0;
+ if (!ctx_present()) {
+ DEBUG_BSSL("peekBytes: Not connected\n");
+ return 0;
+ }
+
+ _startMillis = millis();
+ while ((available() < (int) length) && ((millis() - _startMillis) < 5000)) {
+ yield();
+ }
+
+ to_copy = _recvapp_len < length ? _recvapp_len : length;
+ memcpy(buffer, _recvapp_buf, to_copy);
+ return to_copy;
+}
+
+/* --- Copied almost verbatim from BEARSSL SSL_IO.C ---
+ Run the engine, until the specified target state is achieved, or
+ an error occurs. The target state is SENDAPP, RECVAPP, or the
+ combination of both (the combination matches either). When a match is
+ achieved, this function returns 0. On error, it returns -1.
+*/
+int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
+//LOG_HEAP_SIZE("_run_until 1");
+ if (!ctx_present()) {
+ DEBUG_BSSL("_run_until: Not connected\n");
+ return -1;
+ }
+ for (int no_work = 0; blocking || no_work < 2;) {
+ if (blocking) {
+ // Only for blocking operations can we afford to yield()
+ optimistic_yield(100);
+ }
+
+ int state;
+ state = br_ssl_engine_current_state(_eng);
+ if (state & BR_SSL_CLOSED) {
+ return -1;
+ }
+
+ if (!(_client->state() == ESTABLISHED) && !WiFiClient::available()) {
+ return (state & target) ? 0 : -1;
+ }
+
+ /*
+ If there is some record data to send, do it. This takes
+ precedence over everything else.
+ */
+ if (state & BR_SSL_SENDREC) {
+ unsigned char *buf;
+ size_t len;
+ int wlen;
+
+ buf = br_ssl_engine_sendrec_buf(_eng, &len);
+ wlen = WiFiClient::write(buf, len);
+ if (wlen <= 0) {
+ /*
+ If we received a close_notify and we
+ still send something, then we have our
+ own response close_notify to send, and
+ the peer is allowed by RFC 5246 not to
+ wait for it.
+ */
+ return -1;
+ }
+ if (wlen > 0) {
+ br_ssl_engine_sendrec_ack(_eng, wlen);
+ }
+ no_work = 0;
+ continue;
+ }
+
+ /*
+ If we reached our target, then we are finished.
+ */
+ if (state & target) {
+ return 0;
+ }
+ /*
+ If some application data must be read, and we did not
+ exit, then this means that we are trying to write data,
+ and that's not possible until the application data is
+ read. This may happen if using a shared in/out buffer,
+ and the underlying protocol is not strictly half-duplex.
+ This is unrecoverable here, so we report an error.
+ */
+ if (state & BR_SSL_RECVAPP) {
+ DEBUG_BSSL("_run_until: Fatal protocol state\n");
+ return -1;
+ }
+ /*
+ If we reached that point, then either we are trying
+ to read data and there is some, or the engine is stuck
+ until a new record is obtained.
+ */
+ if (state & BR_SSL_RECVREC) {
+ if (WiFiClient::available()) {
+ unsigned char *buf;
+ size_t len;
+ int rlen;
+
+ buf = br_ssl_engine_recvrec_buf(_eng, &len);
+ rlen = WiFiClient::read(buf, len);
+ if (rlen < 0) {
+ return -1;
+ }
+ if (rlen > 0) {
+ br_ssl_engine_recvrec_ack(_eng, rlen);
+ }
+ no_work = 0;
+ continue;
+ }
+ }
+ /*
+ We can reach that point if the target RECVAPP, and
+ the state contains SENDAPP only. This may happen with
+ a shared in/out buffer. In that case, we must flush
+ the buffered data to "make room" for a new incoming
+ record.
+ */
+ br_ssl_engine_flush(_eng, 0);
+
+ no_work++; // We didn't actually advance here
+ }
+ // We only get here if we ran through the loop without getting anything done
+ return -1;
+}
+
+bool WiFiClientSecure_light::_wait_for_handshake() {
+ _handshake_done = false;
+ while (!_handshake_done && _clientConnected()) {
+ int ret = _run_until(BR_SSL_SENDAPP);
+ if (ret < 0) {
+ DEBUG_BSSL("_wait_for_handshake: failed\n");
+ break;
+ }
+ if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) {
+ _handshake_done = true;
+ }
+ optimistic_yield(1000);
+ }
+ return _handshake_done;
+}
+
+static uint8_t htoi (unsigned char c)
+{
+ if (c>='0' && c <='9') return c - '0';
+ else if (c>='A' && c<='F') return 10 + c - 'A';
+ else if (c>='a' && c<='f') return 10 + c - 'a';
+ else return 255;
+}
+
+extern "C" {
+
+ // see https://stackoverflow.com/questions/6357031/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-in-c
+ void tohex(unsigned char * in, size_t insz, char * out, size_t outsz) {
+ unsigned char * pin = in;
+ static const char * hex = "0123456789ABCDEF";
+ char * pout = out;
+ for(; pin < in+insz; pout +=3, pin++){
+ pout[0] = hex[(*pin>>4) & 0xF];
+ pout[1] = hex[ *pin & 0xF];
+ pout[2] = ':';
+ if (pout + 3 - out > outsz){
+ /* Better to truncate output string than overflow buffer */
+ /* it would be still better to either return a status */
+ /* or ensure the target buffer is large enough and it never happen */
+ break;
+ }
+ }
+ pout[-1] = 0;
+ }
+
+
+ // BearSSL doesn't define a true insecure decoder, so we make one ourselves
+ // from the simple parser. It generates the issuer and subject hashes and
+ // the SHA1 fingerprint, only one (or none!) of which will be used to
+ // "verify" the certificate.
+
+ // Private x509 decoder state
+ struct br_x509_pubkeyfingerprint_context {
+ const br_x509_class *vtable;
+ bool done_cert; // did we parse the first cert already?
+ bool fingerprint_all;
+ uint8_t *pubkey_recv_fingerprint;
+ const uint8_t *fingerprint1;
+ const uint8_t *fingerprint2;
+ unsigned usages; // pubkey usage
+ br_x509_decoder_context ctx; // defined in BearSSL
+ };
+
+ // Callback on the first byte of any certificate
+ static void pubkeyfingerprint_start_chain(const br_x509_class **ctx, const char *server_name) {
+ br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
+ // Don't process anything but the first certificate in the chain
+ if (!xc->done_cert) {
+ br_x509_decoder_init(&xc->ctx, nullptr, nullptr, nullptr, nullptr);
+ }
+ (void)server_name; // ignore server name
+ }
+
+ // Callback for each certificate present in the chain (but only operates
+ // on the first one by design).
+ static void pubkeyfingerprint_start_cert(const br_x509_class **ctx, uint32_t length) {
+ (void) ctx; // do nothing
+ (void) length;
+ }
+
+ // Callback for each byte stream in the chain. Only process first cert.
+ static void pubkeyfingerprint_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) {
+ br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
+ // Don't process anything but the first certificate in the chain
+ if (!xc->done_cert) {
+ br_x509_decoder_push(&xc->ctx, (const void*)buf, len);
+ }
+ }
+
+ // Callback on individual cert end.
+ static void pubkeyfingerprint_end_cert(const br_x509_class **ctx) {
+ br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
+ xc->done_cert = true; // first cert already processed
+ }
+
+ static void pubkeyfingerprint_pubkey_fingerprint(br_sha1_context *shactx, br_rsa_public_key rsakey) {
+ br_sha1_init(shactx);
+ br_sha1_update(shactx, "ssh-rsa", 7); // tag
+ br_sha1_update(shactx, rsakey.e, rsakey.elen); // exponent
+ br_sha1_update(shactx, rsakey.n, rsakey.nlen); // modulus
+ }
+
+ // Callback when complete chain has been parsed.
+ // Return 0 on validation success, !0 on validation error
+ static unsigned pubkeyfingerprint_end_chain(const br_x509_class **ctx) {
+ br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
+
+ br_sha1_context sha1_context;
+ pubkeyfingerprint_pubkey_fingerprint(&sha1_context, xc->ctx.pkey.key.rsa);
+ br_sha1_out(&sha1_context, xc->pubkey_recv_fingerprint); // copy to fingerprint
+
+ if (!xc->fingerprint_all) {
+ if (0 == memcmp_P(xc->pubkey_recv_fingerprint, xc->fingerprint1, 20)) {
+ return 0;
+ }
+ if (0 == memcmp_P(xc->pubkey_recv_fingerprint, xc->fingerprint2, 20)) {
+ return 0;
+ }
+ return 1; // no match, error
+ } else {
+ // Default (no validation at all) or no errors in prior checks = success.
+ return 0;
+ }
+ }
+
+ // Return the public key from the validator (set by x509_minimal)
+ static const br_x509_pkey *pubkeyfingerprint_get_pkey(const br_x509_class *const *ctx, unsigned *usages) {
+ const br_x509_pubkeyfingerprint_context *xc = (const br_x509_pubkeyfingerprint_context *)ctx;
+
+ if (usages != NULL) {
+ *usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN; // I said we were insecure!
+ }
+ return &xc->ctx.pkey;
+ }
+
+ // Set up the x509 insecure data structures for BearSSL core to use.
+ void br_x509_pubkeyfingerprint_init(br_x509_pubkeyfingerprint_context *ctx,
+ const uint8_t *fingerprint1, const uint8_t *fingerprint2,
+ uint8_t *recv_fingerprint,
+ bool fingerprint_all) {
+ static const br_x509_class br_x509_pubkeyfingerprint_vtable PROGMEM = {
+ sizeof(br_x509_pubkeyfingerprint_context),
+ pubkeyfingerprint_start_chain,
+ pubkeyfingerprint_start_cert,
+ pubkeyfingerprint_append,
+ pubkeyfingerprint_end_cert,
+ pubkeyfingerprint_end_chain,
+ pubkeyfingerprint_get_pkey
+ };
+
+ memset(ctx, 0, sizeof * ctx);
+ ctx->vtable = &br_x509_pubkeyfingerprint_vtable;
+ ctx->done_cert = false;
+ ctx->fingerprint1 = fingerprint1;
+ ctx->fingerprint2 = fingerprint2;
+ ctx->pubkey_recv_fingerprint = recv_fingerprint;
+ ctx->fingerprint_all = fingerprint_all;
+ }
+
+ // We limit to a single cipher to reduce footprint
+ // we reference it, don't put in PROGMEM
+ static const uint16_t suites[] = {
+#ifdef USE_MQTT_TLS_FORCE_EC_CIPHER
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+#else
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256
+#endif
+ };
+
+ // Default initializion for our SSL clients
+ static void br_ssl_client_base_init(br_ssl_client_context *cc) {
+ br_ssl_client_zero(cc);
+ // forbid SSL renegociation, as we free the Private Key after handshake
+ br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION);
+
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+ br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0]));
+ br_ssl_client_set_default_rsapub(cc);
+ br_ssl_engine_set_default_rsavrfy(&cc->eng);
+
+ // install hashes
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ // AES CTR/GCM small version, not contstant time (we don't really care here as there is no TPM anyways)
+ br_ssl_engine_set_gcm(&cc->eng, &br_sslrec_in_gcm_vtable, &br_sslrec_out_gcm_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng, &br_aes_small_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng, &br_ghash_ctmul32);
+
+#ifdef USE_MQTT_TLS_FORCE_EC_CIPHER
+ // we support only P256 EC curve for AWS IoT, no EC curve for Letsencrypt unless forced
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15);
+#endif
+ }
+}
+
+// Called by connect() to do the actual SSL setup and handshake.
+// Returns if the SSL handshake succeeded.
+bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
+// #ifdef USE_MQTT_AWS_IOT
+// if ((!_chain_P) || (!_sk_ec_P)) {
+// setLastError(ERR_MISSING_EC_KEY);
+// return false;
+// }
+// #endif
+
+ // Validation context, either full CA validation or checking only fingerprints
+#ifdef USE_MQTT_TLS_CA_CERT
+ br_x509_minimal_context *x509_minimal;
+#else
+ br_x509_pubkeyfingerprint_context *x509_insecure;
+#endif
+
+ LOG_HEAP_SIZE("_connectSSL.start");
+
+ do { // used to exit on Out of Memory error and keep all cleanup code at the same place
+ // ============================================================
+ // allocate Thunk stack, move to alternate stack and initialize
+ stack_thunk_light_add_ref();
+ LOG_HEAP_SIZE("Thunk allocated");
+ DEBUG_BSSL("_connectSSL: start connection\n");
+ _freeSSL();
+ clearLastError();
+ if (!stack_thunk_light_get_stack_bot()) break;
+
+ _ctx_present = true;
+ _eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr
+
+ br_ssl_client_base_init(_sc.get());
+
+ // ============================================================
+ // Allocatte and initialize Decoder Context
+ LOG_HEAP_SIZE("_connectSSL before DecoderContext allocation");
+ // Only failure possible in the installation is OOM
+ #ifdef USE_MQTT_TLS_CA_CERT
+ x509_minimal = (br_x509_minimal_context*) malloc(sizeof(br_x509_minimal_context));
+ if (!x509_minimal) break;
+ br_x509_minimal_init(x509_minimal, &br_sha256_vtable, _ta_P, 1);
+ br_x509_minimal_set_rsa(x509_minimal, br_ssl_engine_get_rsavrfy(_eng));
+ br_x509_minimal_set_hash(x509_minimal, br_sha256_ID, &br_sha256_vtable);
+ br_ssl_engine_set_x509(_eng, &x509_minimal->vtable);
+
+ #else
+ x509_insecure = (br_x509_pubkeyfingerprint_context*) malloc(sizeof(br_x509_pubkeyfingerprint_context));
+ //x509_insecure = std::unique_ptr(new br_x509_pubkeyfingerprint_context);
+ if (!x509_insecure) break;
+ br_x509_pubkeyfingerprint_init(x509_insecure, _fingerprint1, _fingerprint2, _recv_fingerprint, _fingerprint_any);
+ br_ssl_engine_set_x509(_eng, &x509_insecure->vtable);
+ #endif
+ LOG_HEAP_SIZE("_connectSSL after DecoderContext allocation");
+
+ // ============================================================
+ // Set send/receive buffers
+ br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size);
+
+ // ============================================================
+ // allocate Private key if needed, only if USE_MQTT_AWS_IOT
+ LOG_HEAP_SIZE("_connectSSL before PrivKey allocation");
+ #ifdef USE_MQTT_AWS_IOT
+ // ============================================================
+ // Set the EC Private Key, only USE_MQTT_AWS_IOT
+ // limited to P256 curve
+ br_ssl_client_set_single_ec(_sc.get(), _chain_P, 1,
+ _sk_ec_P, _allowed_usages,
+ _cert_issuer_key_type, &br_ec_p256_m15, br_ecdsa_sign_asn1_get_default());
+ #endif // USE_MQTT_AWS_IOT
+
+ // ============================================================
+ // Start TLS connection, ALL
+ if (!br_ssl_client_reset(_sc.get(), hostName, 0)) break;
+
+ auto ret = _wait_for_handshake();
+ #ifdef DEBUG_ESP_SSL
+ if (!ret) {
+ DEBUG_BSSL("Couldn't connect. Error = %d\n", getLastError());
+ } else {
+ DEBUG_BSSL("Connected! MFLNStatus = %d\n", getMFLNStatus());
+ }
+ #endif
+ LOG_HEAP_SIZE("_connectSSL.end");
+ _max_thunkstack_use = stack_thunk_light_get_max_usage();
+ stack_thunk_light_del_ref();
+ //stack_thunk_light_repaint();
+ LOG_HEAP_SIZE("_connectSSL.end, freeing StackThunk");
+
+ #ifdef USE_MQTT_TLS_CA_CERT
+ free(x509_minimal);
+ #else
+ free(x509_insecure);
+ #endif
+ LOG_HEAP_SIZE("_connectSSL after release of Priv Key");
+ return ret;
+ } while (0);
+
+ // ============================================================
+ // if we arrived here, this means we had an OOM error, cleaning up
+ setLastError(ERR_OOM);
+ DEBUG_BSSL("_connectSSL: Out of memory\n");
+ stack_thunk_light_del_ref();
+#ifdef USE_MQTT_TLS_CA_CERT
+ free(x509_minimal);
+#else
+ free(x509_insecure);
+#endif
+ LOG_HEAP_SIZE("_connectSSL clean_on_error");
+ return false;
+}
+
+};
+
+#include "t_bearssl_tasmota_config.h"
+
+#endif // USE_TLS
diff --git a/tasmota/WiFiClientSecureLightBearSSL.h b/tasmota/WiFiClientSecureLightBearSSL.h
old mode 100644
new mode 100755
index 5dd0df35e..e5908275e
--- a/tasmota/WiFiClientSecureLightBearSSL.h
+++ b/tasmota/WiFiClientSecureLightBearSSL.h
@@ -1,221 +1,221 @@
-/*
- WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
- - Mostly compatible with Arduino WiFi shield library and standard
- WiFiClient/ServerSecure (except for certificate handling).
-
- Copyright (c) 2018 Earle F. Philhower, III
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
-#include
-
-#ifndef wificlientlightbearssl_h
-#define wificlientlightbearssl_h
-#if defined(USE_MQTT_TLS) || defined (USE_SENDMAIL)
-#include
-#include "WiFiClient.h"
-#include
-
-namespace BearSSL {
-
-class WiFiClientSecure_light : public WiFiClient {
- public:
- WiFiClientSecure_light(int recv, int xmit);
- ~WiFiClientSecure_light() override;
-
- void allocateBuffers(void);
-
- int connect(IPAddress ip, uint16_t port) override;
- int connect(const char* name, uint16_t port) override;
-
- uint8_t connected() override;
- size_t write(const uint8_t *buf, size_t size) override;
- size_t write_P(PGM_P buf, size_t size) override;
- size_t write(const char *buf) {
- return write((const uint8_t*)buf, strlen(buf));
- }
- size_t write_P(const char *buf) {
- return write_P((PGM_P)buf, strlen_P(buf));
- }
- size_t write(Stream& stream); // Note this is not virtual
- int read(uint8_t *buf, size_t size) override;
- int available() override;
- int read() override;
- int peek() override;
- size_t peekBytes(uint8_t *buffer, size_t length) override;
- bool flush(unsigned int maxWaitMs);
- bool stop(unsigned int maxWaitMs);
- void flush() override { (void)flush(0); }
- void stop() override { (void)stop(0); }
-
- // Only check SHA1 fingerprint of public key
- void setPubKeyFingerprint(const uint8_t *f1, const uint8_t *f2,
- bool f_any = false) {
- _fingerprint1 = f1;
- _fingerprint2 = f2;
- _fingerprint_any = f_any;
- }
- const uint8_t * getRecvPubKeyFingerprint(void) {
- return _recv_fingerprint;
- }
-
- void setClientECCert(const br_x509_certificate *cert, const br_ec_private_key *sk,
- unsigned allowed_usages, unsigned cert_issuer_key_type);
-
- void setTrustAnchor(const br_x509_trust_anchor *ta);
-
- // Sets the requested buffer size for transmit and receive
- void setBufferSizes(int recv, int xmit);
-
- // Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection)
- int getMFLNStatus() {
- return connected() && br_ssl_engine_get_mfln_negotiated(_eng);
- }
-
- int32_t getLastError(void) {
- if (_last_error) {
- return _last_error;
- } else {
- return br_ssl_engine_last_error(_eng);
- }
- }
- inline void setLastError(int32_t err) {
- _last_error = err;
- }
- inline void clearLastError(void) {
- _last_error = 0;
- }
- inline size_t getMaxThunkStackUse(void) {
- return _max_thunkstack_use;
- }
-
- private:
- void _clear();
- bool _ctx_present;
- std::shared_ptr _sc;
- inline bool ctx_present() {
- return _ctx_present;
- }
- br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts
- std::shared_ptr _iobuf_in;
- std::shared_ptr _iobuf_out;
- time_t _now;
- int _iobuf_in_size;
- int _iobuf_out_size;
- bool _handshake_done;
- uint64_t _last_error;
-
- bool _fingerprint_any; // accept all fingerprints
- const uint8_t *_fingerprint1; // fingerprint1 to be checked against
- const uint8_t *_fingerprint2; // fingerprint2 to be checked against
- uint8_t _recv_fingerprint[20]; // fingerprint received
-
- unsigned char *_recvapp_buf;
- size_t _recvapp_len;
-
- bool _clientConnected(); // Is the underlying socket alive?
- bool _connectSSL(const char *hostName); // Do initial SSL handshake
- void _freeSSL();
- int _run_until(unsigned target, bool blocking = true);
- size_t _write(const uint8_t *buf, size_t size, bool pmem);
- bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting
-
- // Optional client certificate
- const br_x509_certificate *_chain_P; // PROGMEM certificate
- const br_ec_private_key *_sk_ec_P; // PROGMEM private key
- const br_x509_trust_anchor *_ta_P; // PROGMEM server CA
- unsigned _allowed_usages;
- unsigned _cert_issuer_key_type;
-
- // record the maximum use of ThunkStack for monitoring
- size_t _max_thunkstack_use;
-
-};
-
-#define ERR_OOM -1000
-#define ERR_CANT_RESOLVE_IP -1001
-#define ERR_TCP_CONNECT -1002
-#define ERR_MISSING_EC_KEY -1003
-#define ERR_MISSING_CA -1004
-
-// For reference, BearSSL error codes:
-// #define BR_ERR_OK 0
-// #define BR_ERR_BAD_PARAM 1
-// #define BR_ERR_BAD_STATE 2
-// #define BR_ERR_UNSUPPORTED_VERSION 3
-// #define BR_ERR_BAD_VERSION 4
-// #define BR_ERR_BAD_LENGTH 5
-// #define BR_ERR_TOO_LARGE 6
-// #define BR_ERR_BAD_MAC 7
-// #define BR_ERR_NO_RANDOM 8
-// #define BR_ERR_UNKNOWN_TYPE 9
-// #define BR_ERR_UNEXPECTED 10
-// #define BR_ERR_BAD_CCS 12
-// #define BR_ERR_BAD_ALERT 13
-// #define BR_ERR_BAD_HANDSHAKE 14
-// #define BR_ERR_OVERSIZED_ID 15
-// #define BR_ERR_BAD_CIPHER_SUITE 16
-// #define BR_ERR_BAD_COMPRESSION 17
-// #define BR_ERR_BAD_FRAGLEN 18
-// #define BR_ERR_BAD_SECRENEG 19
-// #define BR_ERR_EXTRA_EXTENSION 20
-// #define BR_ERR_BAD_SNI 21
-// #define BR_ERR_BAD_HELLO_DONE 22
-// #define BR_ERR_LIMIT_EXCEEDED 23
-// #define BR_ERR_BAD_FINISHED 24
-// #define BR_ERR_RESUME_MISMATCH 25
-// #define BR_ERR_INVALID_ALGORITHM 26
-// #define BR_ERR_BAD_SIGNATURE 27
-// #define BR_ERR_WRONG_KEY_USAGE 28
-// #define BR_ERR_NO_CLIENT_AUTH 29
-// #define BR_ERR_IO 31
-// #define BR_ERR_RECV_FATAL_ALERT 256
-// #define BR_ERR_SEND_FATAL_ALERT 512
-// #define BR_ERR_X509_OK 32
-// #define BR_ERR_X509_INVALID_VALUE 33
-// #define BR_ERR_X509_TRUNCATED 34
-// #define BR_ERR_X509_EMPTY_CHAIN 35
-// #define BR_ERR_X509_INNER_TRUNC 36
-// #define BR_ERR_X509_BAD_TAG_CLASS 37
-// #define BR_ERR_X509_BAD_TAG_VALUE 38
-// #define BR_ERR_X509_INDEFINITE_LENGTH 39
-// #define BR_ERR_X509_EXTRA_ELEMENT 40
-// #define BR_ERR_X509_UNEXPECTED 41
-// #define BR_ERR_X509_NOT_CONSTRUCTED 42
-// #define BR_ERR_X509_NOT_PRIMITIVE 43
-// #define BR_ERR_X509_PARTIAL_BYTE 44
-// #define BR_ERR_X509_BAD_BOOLEAN 45
-// #define BR_ERR_X509_OVERFLOW 46
-// #define BR_ERR_X509_BAD_DN 47
-// #define BR_ERR_X509_BAD_TIME 48
-// #define BR_ERR_X509_UNSUPPORTED 49
-// #define BR_ERR_X509_LIMIT_EXCEEDED 50
-// #define BR_ERR_X509_WRONG_KEY_TYPE 51
-// #define BR_ERR_X509_BAD_SIGNATURE 52
-// #define BR_ERR_X509_TIME_UNKNOWN 53
-// #define BR_ERR_X509_EXPIRED 54
-// #define BR_ERR_X509_DN_MISMATCH 55
-// #define BR_ERR_X509_BAD_SERVER_NAME 56
-// #define BR_ERR_X509_CRITICAL_EXTENSION 57
-// #define BR_ERR_X509_NOT_CA 58
-// #define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59
-// #define BR_ERR_X509_WEAK_PUBLIC_KEY 60
-// #define BR_ERR_X509_NOT_TRUSTED 62
-
-};
-
-#endif // USE_MQTT_TLS
-#endif // wificlientlightbearssl_h
+/*
+ WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
+ - Mostly compatible with Arduino WiFi shield library and standard
+ WiFiClient/ServerSecure (except for certificate handling).
+
+ Copyright (c) 2018 Earle F. Philhower, III
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include
+
+#ifndef wificlientlightbearssl_h
+#define wificlientlightbearssl_h
+#ifdef USE_TLS
+#include
+#include "WiFiClient.h"
+#include
+
+namespace BearSSL {
+
+class WiFiClientSecure_light : public WiFiClient {
+ public:
+ WiFiClientSecure_light(int recv, int xmit);
+ ~WiFiClientSecure_light() override;
+
+ void allocateBuffers(void);
+
+ int connect(IPAddress ip, uint16_t port) override;
+ int connect(const char* name, uint16_t port) override;
+
+ uint8_t connected() override;
+ size_t write(const uint8_t *buf, size_t size) override;
+ size_t write_P(PGM_P buf, size_t size) override;
+ size_t write(const char *buf) {
+ return write((const uint8_t*)buf, strlen(buf));
+ }
+ size_t write_P(const char *buf) {
+ return write_P((PGM_P)buf, strlen_P(buf));
+ }
+ size_t write(Stream& stream); // Note this is not virtual
+ int read(uint8_t *buf, size_t size) override;
+ int available() override;
+ int read() override;
+ int peek() override;
+ size_t peekBytes(uint8_t *buffer, size_t length) override;
+ bool flush(unsigned int maxWaitMs);
+ bool stop(unsigned int maxWaitMs);
+ void flush() override { (void)flush(0); }
+ void stop() override { (void)stop(0); }
+
+ // Only check SHA1 fingerprint of public key
+ void setPubKeyFingerprint(const uint8_t *f1, const uint8_t *f2,
+ bool f_any = false) {
+ _fingerprint1 = f1;
+ _fingerprint2 = f2;
+ _fingerprint_any = f_any;
+ }
+ const uint8_t * getRecvPubKeyFingerprint(void) {
+ return _recv_fingerprint;
+ }
+
+ void setClientECCert(const br_x509_certificate *cert, const br_ec_private_key *sk,
+ unsigned allowed_usages, unsigned cert_issuer_key_type);
+
+ void setTrustAnchor(const br_x509_trust_anchor *ta);
+
+ // Sets the requested buffer size for transmit and receive
+ void setBufferSizes(int recv, int xmit);
+
+ // Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection)
+ int getMFLNStatus() {
+ return connected() && br_ssl_engine_get_mfln_negotiated(_eng);
+ }
+
+ int32_t getLastError(void) {
+ if (_last_error) {
+ return _last_error;
+ } else {
+ return br_ssl_engine_last_error(_eng);
+ }
+ }
+ inline void setLastError(int32_t err) {
+ _last_error = err;
+ }
+ inline void clearLastError(void) {
+ _last_error = 0;
+ }
+ inline size_t getMaxThunkStackUse(void) {
+ return _max_thunkstack_use;
+ }
+
+ private:
+ void _clear();
+ bool _ctx_present;
+ std::shared_ptr _sc;
+ inline bool ctx_present() {
+ return _ctx_present;
+ }
+ br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts
+ std::shared_ptr _iobuf_in;
+ std::shared_ptr _iobuf_out;
+ time_t _now;
+ int _iobuf_in_size;
+ int _iobuf_out_size;
+ bool _handshake_done;
+ uint64_t _last_error;
+
+ bool _fingerprint_any; // accept all fingerprints
+ const uint8_t *_fingerprint1; // fingerprint1 to be checked against
+ const uint8_t *_fingerprint2; // fingerprint2 to be checked against
+ uint8_t _recv_fingerprint[20]; // fingerprint received
+
+ unsigned char *_recvapp_buf;
+ size_t _recvapp_len;
+
+ bool _clientConnected(); // Is the underlying socket alive?
+ bool _connectSSL(const char *hostName); // Do initial SSL handshake
+ void _freeSSL();
+ int _run_until(unsigned target, bool blocking = true);
+ size_t _write(const uint8_t *buf, size_t size, bool pmem);
+ bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting
+
+ // Optional client certificate
+ const br_x509_certificate *_chain_P; // PROGMEM certificate
+ const br_ec_private_key *_sk_ec_P; // PROGMEM private key
+ const br_x509_trust_anchor *_ta_P; // PROGMEM server CA
+ unsigned _allowed_usages;
+ unsigned _cert_issuer_key_type;
+
+ // record the maximum use of ThunkStack for monitoring
+ size_t _max_thunkstack_use;
+
+};
+
+#define ERR_OOM -1000
+#define ERR_CANT_RESOLVE_IP -1001
+#define ERR_TCP_CONNECT -1002
+// #define ERR_MISSING_EC_KEY -1003 // deprecated, AWS IoT is not called if the private key is not present
+#define ERR_MISSING_CA -1004
+
+// For reference, BearSSL error codes:
+// #define BR_ERR_OK 0
+// #define BR_ERR_BAD_PARAM 1
+// #define BR_ERR_BAD_STATE 2
+// #define BR_ERR_UNSUPPORTED_VERSION 3
+// #define BR_ERR_BAD_VERSION 4
+// #define BR_ERR_BAD_LENGTH 5
+// #define BR_ERR_TOO_LARGE 6
+// #define BR_ERR_BAD_MAC 7
+// #define BR_ERR_NO_RANDOM 8
+// #define BR_ERR_UNKNOWN_TYPE 9
+// #define BR_ERR_UNEXPECTED 10
+// #define BR_ERR_BAD_CCS 12
+// #define BR_ERR_BAD_ALERT 13
+// #define BR_ERR_BAD_HANDSHAKE 14
+// #define BR_ERR_OVERSIZED_ID 15
+// #define BR_ERR_BAD_CIPHER_SUITE 16
+// #define BR_ERR_BAD_COMPRESSION 17
+// #define BR_ERR_BAD_FRAGLEN 18
+// #define BR_ERR_BAD_SECRENEG 19
+// #define BR_ERR_EXTRA_EXTENSION 20
+// #define BR_ERR_BAD_SNI 21
+// #define BR_ERR_BAD_HELLO_DONE 22
+// #define BR_ERR_LIMIT_EXCEEDED 23
+// #define BR_ERR_BAD_FINISHED 24
+// #define BR_ERR_RESUME_MISMATCH 25
+// #define BR_ERR_INVALID_ALGORITHM 26
+// #define BR_ERR_BAD_SIGNATURE 27
+// #define BR_ERR_WRONG_KEY_USAGE 28
+// #define BR_ERR_NO_CLIENT_AUTH 29
+// #define BR_ERR_IO 31
+// #define BR_ERR_RECV_FATAL_ALERT 256
+// #define BR_ERR_SEND_FATAL_ALERT 512
+// #define BR_ERR_X509_OK 32
+// #define BR_ERR_X509_INVALID_VALUE 33
+// #define BR_ERR_X509_TRUNCATED 34
+// #define BR_ERR_X509_EMPTY_CHAIN 35
+// #define BR_ERR_X509_INNER_TRUNC 36
+// #define BR_ERR_X509_BAD_TAG_CLASS 37
+// #define BR_ERR_X509_BAD_TAG_VALUE 38
+// #define BR_ERR_X509_INDEFINITE_LENGTH 39
+// #define BR_ERR_X509_EXTRA_ELEMENT 40
+// #define BR_ERR_X509_UNEXPECTED 41
+// #define BR_ERR_X509_NOT_CONSTRUCTED 42
+// #define BR_ERR_X509_NOT_PRIMITIVE 43
+// #define BR_ERR_X509_PARTIAL_BYTE 44
+// #define BR_ERR_X509_BAD_BOOLEAN 45
+// #define BR_ERR_X509_OVERFLOW 46
+// #define BR_ERR_X509_BAD_DN 47
+// #define BR_ERR_X509_BAD_TIME 48
+// #define BR_ERR_X509_UNSUPPORTED 49
+// #define BR_ERR_X509_LIMIT_EXCEEDED 50
+// #define BR_ERR_X509_WRONG_KEY_TYPE 51
+// #define BR_ERR_X509_BAD_SIGNATURE 52
+// #define BR_ERR_X509_TIME_UNKNOWN 53
+// #define BR_ERR_X509_EXPIRED 54
+// #define BR_ERR_X509_DN_MISMATCH 55
+// #define BR_ERR_X509_BAD_SERVER_NAME 56
+// #define BR_ERR_X509_CRITICAL_EXTENSION 57
+// #define BR_ERR_X509_NOT_CA 58
+// #define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59
+// #define BR_ERR_X509_WEAK_PUBLIC_KEY 60
+// #define BR_ERR_X509_NOT_TRUSTED 62
+
+};
+
+#endif // USE_TLS
+#endif // wificlientlightbearssl_h
diff --git a/tasmota/i18n.h b/tasmota/i18n.h
index 01122fabd..ccbb6b399 100644
--- a/tasmota/i18n.h
+++ b/tasmota/i18n.h
@@ -271,6 +271,8 @@
#define D_CMND_SSID "SSId"
#define D_CMND_PASSWORD "Password"
#define D_CMND_HOSTNAME "Hostname"
+#define D_CMND_WIFI "Wifi"
+#define D_CMND_ETHERNET "Ethernet"
#define D_CMND_WIFICONFIG "WifiConfig"
#define D_WCFG_0_RESTART "Restart"
#define D_WCFG_2_WIFIMANAGER "WifiManager"
@@ -503,10 +505,14 @@
#define D_CMND_ZIGBEE_RESET "Reset"
#define D_JSON_ZIGBEE_CC2530 "CC2530"
#define D_CMND_ZIGBEEZNPRECEIVE "ZNPReceive" // only for debug
+#define D_CMND_ZIGBEE_EZSP_RECEIVE "EZSPReceive" // only for debug
#define D_CMND_ZIGBEEZNPSEND "ZNPSend"
+#define D_CMND_ZIGBEE_EZSP_SEND "EZSPSend"
#define D_JSON_ZIGBEE_STATE "ZbState"
#define D_JSON_ZIGBEEZNPRECEIVED "ZbZNPReceived"
+ #define D_JSON_ZIGBEE_EZSP_RECEIVED "ZbEZSPReceived"
#define D_JSON_ZIGBEEZNPSENT "ZbZNPSent"
+ #define D_JSON_ZIGBEE_EZSP_SENT "ZbEZSPSent"
#define D_JSON_ZIGBEEZCL_RECEIVED "ZbZCLReceived"
#define D_JSON_ZIGBEEZCL_RAW_RECEIVED "ZbZCLRawReceived"
#define D_JSON_ZIGBEE_DEVICE "Device"
@@ -641,6 +647,7 @@
#define D_LOG_UPNP "UPP: " // UPnP
#define D_LOG_WIFI "WIF: " // Wifi
#define D_LOG_ZIGBEE "ZIG: " // Zigbee
+#define D_LOG_TCP "TCP: " // TCP bridge
/********************************************************************************************/
diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h
index 769b9f66a..165e4f82a 100644
--- a/tasmota/language/bg_BG.h
+++ b/tasmota/language/bg_BG.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Подобрена комуникация"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Използвана енергия днес"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h
index 64d8e32b0..7b53e6274 100644
--- a/tasmota/language/cs_CZ.h
+++ b/tasmota/language/cs_CZ.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Spotřeba Dnes"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h
index 7cc9d6579..4804ea7ba 100644
--- a/tasmota/language/de_DE.h
+++ b/tasmota/language/de_DE.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Erweiterte Kommunikation"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energie heute"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h
index 92769256f..3efac89e8 100644
--- a/tasmota/language/el_GR.h
+++ b/tasmota/language/el_GR.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Βελτίωση επικοινωνίας"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Ενέργεια σήμερα"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h
index e5fc07fa5..1dd0429d8 100644
--- a/tasmota/language/en_GB.h
+++ b/tasmota/language/en_GB.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energy Today"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h
index ff2eda915..e0141cf83 100644
--- a/tasmota/language/es_ES.h
+++ b/tasmota/language/es_ES.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Mejora de Comunicación"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX ESCENA TX"
+#define D_KNX_RX_SCENE "KNX ESCENA RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energía Hoy"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h
index 38c160831..28e9e28b9 100644
--- a/tasmota/language/fr_FR.h
+++ b/tasmota/language/fr_FR.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Amélioration de la communication"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX Scène TX"
+#define D_KNX_RX_SCENE "KNX Scène RX"
// xsns_03_energy.ino
#define D_ENERGY_TODAY "Énergie aujourd'hui"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "Hibernation"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Esclave TX"
-#define D_SENSOR_SLAVE_RX "Esclave RX"
-#define D_SENSOR_SLAVE_RESET "Esclave Rst"
+#define D_SENSOR_CLIENT_TX "Esclave TX"
+#define D_SENSOR_CLIENT_RX "Esclave RX"
+#define D_SENSOR_CLIENT_RESET "Esclave Rst"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h
index 59f2db4cb..7cbc64acf 100644
--- a/tasmota/language/he_HE.h
+++ b/tasmota/language/he_HE.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "שיפור התקשורת"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "צריכה יומית"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h
index d976eecb4..07dfe6349 100644
--- a/tasmota/language/hu_HU.h
+++ b/tasmota/language/hu_HU.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Mai energia"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h
index 6fa190eed..ebd7addfe 100644
--- a/tasmota/language/it_IT.h
+++ b/tasmota/language/it_IT.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Miglioramento comunicazione"
#define D_KNX_TX_SLOT "KNX - TX"
#define D_KNX_RX_SLOT "KNX - RX"
+#define D_KNX_TX_SCENE "Scena - TX"
+#define D_KNX_RX_SCENE "Scena - RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia - oggi"
@@ -663,16 +665,16 @@
#define D_SENSOR_SM2135_DAT "SM2135 - DATI"
#define D_SENSOR_DEEPSLEEP "Deep sleep"
#define D_SENSOR_EXS_ENABLE "EXS - Abilita"
-#define D_SENSOR_SLAVE_TX "Slave - TX"
-#define D_SENSOR_SLAVE_RX "Slave - RX"
-#define D_SENSOR_SLAVE_RESET "Slave - RST"
+#define D_SENSOR_CLIENT_TX "Client - TX"
+#define D_SENSOR_CLIENT_RX "Client - RX"
+#define D_SENSOR_CLIENT_RESET "Client - RST"
#define D_SENSOR_GPS_RX "GPS - RX"
#define D_SENSOR_GPS_TX "GPS - TX"
#define D_SENSOR_HM10_RX "HM10 - RX"
#define D_SENSOR_HM10_TX "HM10 - TX"
#define D_SENSOR_LE01MR_RX "LE-01MR - RX"
#define D_SENSOR_LE01MR_TX "LE-01MR - TX"
-#define D_SENSOR_BL0940_RX "BL0940 Rx"
+#define D_SENSOR_BL0940_RX "BL0940 - RX"
#define D_SENSOR_CC1101_GDO0 "CC1101 - GDO0"
#define D_SENSOR_CC1101_GDO2 "CC1101 - GDO2"
#define D_SENSOR_HRXL_RX "HRXL - RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "Velocità vento"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP - TX"
+#define D_SENSOR_TCP_RXD "TCP - RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h
index a3a032086..0a4cb7633 100644
--- a/tasmota/language/ko_KO.h
+++ b/tasmota/language/ko_KO.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "커뮤니케이션 강화"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "금일 전력 사용량"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h
index 8ce2fc338..819b39045 100644
--- a/tasmota/language/nl_NL.h
+++ b/tasmota/language/nl_NL.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Verbeter verbinding"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Verbruik vandaag"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h
index 676297b48..2cb92290e 100644
--- a/tasmota/language/pl_PL.h
+++ b/tasmota/language/pl_PL.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Rozszerzenia"
#define D_KNX_TX_SLOT "Gniazdo TX"
#define D_KNX_RX_SLOT "Gniazdo RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia dzisiaj"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "Głęboko uśpiony"
#define D_SENSOR_EXS_ENABLE "Załącz EXS"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h
index 3babc17ec..5e866f809 100644
--- a/tasmota/language/pt_BR.h
+++ b/tasmota/language/pt_BR.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Melhoria da comunicação"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Consumo energético de hoje"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h
index 2a0ad139f..af5e2f7aa 100644
--- a/tasmota/language/pt_PT.h
+++ b/tasmota/language/pt_PT.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Melhoria de Comunicação"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Consumo energético de hoje"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h
index e80dc8bc4..3e8418960 100644
--- a/tasmota/language/ro_RO.h
+++ b/tasmota/language/ro_RO.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Îmbunătățire Communicație"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia de Azi"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h
index a037ff08f..af5ef942d 100644
--- a/tasmota/language/ru_RU.h
+++ b/tasmota/language/ru_RU.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Энергия Сегодня"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "А"
diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h
index c016a0c8e..06251277c 100644
--- a/tasmota/language/sk_SK.h
+++ b/tasmota/language/sk_SK.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Spotreba dnes"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h
index ff119f953..74c30ef32 100644
--- a/tasmota/language/sv_SE.h
+++ b/tasmota/language/sv_SE.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Kommuniceringsförbättring"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energi idag"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h
index e744e97e8..97a03b15b 100644
--- a/tasmota/language/tr_TR.h
+++ b/tasmota/language/tr_TR.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energy Today"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h
index 4d4e25f44..07a60ee5b 100644
--- a/tasmota/language/uk_UA.h
+++ b/tasmota/language/uk_UA.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Підвищення зв'язку"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Енергія Сьогодні"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "А"
diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h
index b5f54991a..92dc25766 100644
--- a/tasmota/language/zh_CN.h
+++ b/tasmota/language/zh_CN.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "通讯增强"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "今日用电量"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "安"
diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h
index 1d5ed6801..91339b304 100644
--- a/tasmota/language/zh_TW.h
+++ b/tasmota/language/zh_TW.h
@@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
+#define D_KNX_TX_SCENE "KNX SCENE TX"
+#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "今日用電量"
@@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
-#define D_SENSOR_SLAVE_TX "Slave TX"
-#define D_SENSOR_SLAVE_RX "Slave RX"
-#define D_SENSOR_SLAVE_RESET "Slave RST"
+#define D_SENSOR_CLIENT_TX "Client TX"
+#define D_SENSOR_CLIENT_RX "Client RX"
+#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
+#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
+#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
+#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
+#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
+#define D_SENSOR_TCP_TXD "TCP Tx"
+#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "安"
diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h
index ae9a66c66..4f5623de1 100644
--- a/tasmota/my_user_config.h
+++ b/tasmota/my_user_config.h
@@ -50,7 +50,12 @@
#define PROJECT "tasmota" // PROJECT is used as the default topic delimiter
// If not selected the default will be SONOFF_BASIC
-//#define MODULE SONOFF_BASIC // [Module] Select default model from tasmota_template.h
+//#define MODULE SONOFF_BASIC // [Module] Select default module from tasmota_template.h
+#ifdef ESP8266
+#define FALLBACK_MODULE SONOFF_BASIC // [Module2] Select default module on fast reboot where USER_MODULE is user template
+#else // ESP32
+#define FALLBACK_MODULE WEMOS // [Module2] Select default module on fast reboot where USER_MODULE is user template
+#endif
#define SAVE_DATA 1 // [SaveData] Save changed parameters to Flash (0 = disable, 1 - 3600 seconds)
#define SAVE_STATE true // [SetOption0] Save changed power state to Flash (false = disable, true = enable)
@@ -135,6 +140,8 @@
// -- MQTT - Home Assistant Discovery -------------
#define HOME_ASSISTANT_DISCOVERY_ENABLE false // [SetOption19] Home Assistant Discovery (false = Disable, true = Enable)
#define HASS_AS_LIGHT false // [SetOption30] Enforce HAss autodiscovery as light
+//#define DEEPSLEEP_LWT_HA_DISCOVERY // Enable LWT topic and its payloads for read-only sensors (Status sensor not included) and binary_sensors on HAss Discovery (Commented out: all read-only sensors and binary_sensors
+ // won't be shown as OFFLINE on Home Assistant when the device is DeepSleeping - NOTE: This is only for read-only sensors and binary_sensors, relays will be shown as OFFLINE)
// -- MQTT - Options ------------------------------
#define MQTT_RESULT_COMMAND false // [SetOption4] Switch between MQTT RESULT or COMMAND
@@ -367,6 +374,11 @@
// Full documentation here: https://github.com/arendst/Tasmota/wiki/AWS-IoT
// #define USE_4K_RSA // Support 4096 bits certificates, instead of 2048
+// -- Telegram Protocol ---------------------------
+//#define USE_TELEGRAM // Support for Telegram protocol (+49k code, +7.0k mem and +4.8k additional during connection handshake)
+ #define USE_TELEGRAM_FINGERPRINT "\xB2\x72\x47\xA6\x69\x8C\x3C\x69\xF9\x58\x6C\xF3\x60\x02\xFB\x83\xFA\x8B\x1F\x23" // Telegram api.telegram.org TLS public key fingerpring
+// #define USE_MQTT_TLS_CA_CERT // Use certificate instead of fingerprint
+
// -- KNX IP Protocol -----------------------------
//#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem)
#define USE_KNX_WEB_MENU // Enable KNX WEB MENU (+8.3k code, +144 mem)
@@ -522,6 +534,7 @@
// #define USE_VEML6075 // [I2cDriver49] Enable VEML6075 UVA/UVB/UVINDEX Sensor (I2C address 0x10) (+2k1 code)
// #define USE_VEML7700 // [I2cDriver50] Enable VEML7700 Ambient Light sensor (I2C addresses 0x10) (+4k5 code)
// #define USE_MCP9808 // [I2cDriver51] Enable MCP9808 temperature sensor (I2C addresses 0x18 - 0x1F) (+0k9 code)
+// #define USE_HP303B // [I2cDriver52] Enable HP303B temperature and pressure sensor (I2C address 0x76 or 0x77) (+6k2 code)
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
@@ -571,6 +584,7 @@
#define STARTING_OFFSET 30 // Turn on NovaSDS XX-seconds before tele_period is reached
//#define USE_HPMA // Add support for Honeywell HPMA115S0 particle concentration sensor (+1k4)
#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code)
+//#define USE_TCP_BRIDGE // Add support for Serial to TCP bridge (+1.3k code)
//#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop
#define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max)
//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger (+1k6 code)
@@ -583,14 +597,11 @@
//#define USE_GPS // Add support for GPS and NTP Server for becoming Stratus 1 Time Source (+3k1 code, +132 bytes RAM)
// #define USE_FLOG // Add support for GPS logging in OTA's Flash (Experimental) (+2k9 code, +8 bytes RAM)
//#define USE_HM10 // (ESP8266 only) Add support for HM-10 as a BLE-bridge (+9k3 code)
-//#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
//#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
-//#define USE_TASMOTA_SLAVE // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k6 code, 64 mem)
- #define USE_TASMOTA_SLAVE_FLASH_SPEED 57600 // Usually 57600 for 3.3V variants and 115200 for 5V variants
- #define USE_TASMOTA_SLAVE_SERIAL_SPEED 57600 // Depends on the sketch that is running on the Uno/Pro Mini
+//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k6 code, 64 mem)
+ #define USE_TASMOTA_CLIENT_FLASH_SPEED 57600 // Usually 57600 for 3.3V variants and 115200 for 5V variants
+ #define USE_TASMOTA_CLIENT_SERIAL_SPEED 57600 // Depends on the sketch that is running on the Uno/Pro Mini
//#define USE_OPENTHERM // Add support for OpenTherm (+15k code)
-#define USE_TELEINFO // Add support for Teleinfo via serial RX interface
- //#define USE_TELEINFO_STANDARD // Use standard mode (9600 bps) else it's historical mode (1200 bps)
// -- Power monitoring sensors --------------------
#define USE_ENERGY_MARGIN_DETECTION // Add support for Energy Margin detection (+1k6 code)
@@ -614,6 +625,8 @@
#define LE01MR_SPEED 9600 // LE-01MR modbus baudrate (default: 9600)
#define LE01MR_ADDR 1 // LE-01MR modbus address (default: 0x01)
#define USE_BL0940 // Add support for BL0940 Energy monitor as used in Blitzwolf SHP-10 (+1k6 code)
+//#define USE_TELEINFO // Add support for Teleinfo via serial RX interface (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM)
+// #define USE_TELEINFO_STANDARD // Use standard mode (9600 bps) else it's historical mode (1200 bps)
// -- Low level interface devices -----------------
#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor (1k6 code)
@@ -624,6 +637,7 @@
#define MAX31865_PTD_RES 100 // Nominal PTD resistance at 0°C (100Ω for a PT100, 1000Ω for a PT1000, YMMV!)
#define MAX31865_REF_RES 430 // Reference resistor (Usually 430Ω for a PT100, 4300Ω for a PT1000)
#define MAX31865_PTD_BIAS 0 // To calibrate your not-so-good PTD
+//#define USE_LMT01 // Add support for TI LMT01 temperature sensor, count pulses on single GPIO (+0k5 code)
// -- IR Remote features - all protocols from IRremoteESP8266 --------------------------
// IR Full Protocols mode is activated through platform.io only.
@@ -648,6 +662,9 @@
// -- Zigbee interface ----------------------------
//#define USE_ZIGBEE // Enable serial communication with Zigbee CC2530 flashed with ZNP (+49k code, +3k mem)
+ #define USE_ZIGBEE_ZNP // Enable ZNP protocol, needed for CC2530 based devices
+ // #define USE_ZIGBEE_EZSP // [EXPERIMENTAL - DO NOT USE] Enable EZSP protocol, needed for EFR32 EmberZNet based devices, like Sonoff Zigbee bridge
+ // Note: USE_ZIGBEE_ZNP and USE_ZIGBEE_EZSP are mutually incompatible, you must select exactly one
#define USE_ZIGBEE_PANID 0x1A63 // arbitrary PAN ID for Zigbee network, must be unique in the home
// if PANID == 0xFFFF, then the device will act as a Zigbee router, the parameters below are ignored
// if PANID == 0xFFFE, then the device will act as a Zigbee end-device (non-router), the parameters below are ignored
@@ -657,6 +674,8 @@
#define USE_ZIGBEE_PRECFGKEY_H 0x0D0C0A0806040200L // note: changing requires to re-pair all devices
#define USE_ZIGBEE_COALESCE_ATTR_TIMER 350 // timer to coalesce attribute values (in ms)
+ #define USE_ZIGBEE_MODELID "Tasmota Z2T" // reported "ModelId" (cluster 0000 / attribute 0005)
+ #define USE_ZIGBEE_MANUFACTURER "Tasmota" // reported "Manufacturer" (cluster 0000 / attribute 0004)
// -- Other sensors/drivers -----------------------
@@ -716,6 +735,28 @@
// -- End of general directives -------------------
+/*********************************************************************************************\
+ * ESP32 only features
+\*********************************************************************************************/
+
+#ifdef ESP32
+
+//#define USE_ETHERNET // Add support for ethernet (Currently fixed for Olimex ESP32-PoE)
+ // Olimex ESP32-PoE
+ #define ETH_TYPE 0 // [EthType] 0 = ETH_PHY_LAN8720, 1 = ETH_PHY_TLK110, 2 = ETH_PHY_IP101
+ #define ETH_ADDR 0 // [EthAddress] 0 = PHY0 .. 31 = PHY31
+ #define ETH_CLKMODE 3 // [EthClockMode] 0 = ETH_CLOCK_GPIO0_IN, 1 = ETH_CLOCK_GPIO0_OUT, 2 = ETH_CLOCK_GPIO16_OUT, 3 = ETH_CLOCK_GPIO17_OUT
+ // wESP32-PoE
+// #define ETH_TYPE 0 // [EthType] 0 = ETH_PHY_LAN8720, 1 = ETH_PHY_TLK110, 2 = ETH_PHY_IP101
+// #define ETH_ADDR 0 // [EthAddress] 0 = PHY0 .. 31 = PHY31
+// #define ETH_CLKMODE 0 // [EthClockMode] 0 = ETH_CLOCK_GPIO0_IN, 1 = ETH_CLOCK_GPIO0_OUT, 2 = ETH_CLOCK_GPIO16_OUT, 3 = ETH_CLOCK_GPIO17_OUT
+
+//#define USE_SPI // Add support for hardware SPI
+//#define USE_MI_ESP32 // Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
+//#define USE_WEBCAM // Add support for webcam
+
+#endif
+
/*********************************************************************************************\
* Debug features
\*********************************************************************************************/
@@ -755,4 +796,16 @@
#error "Select either USE_RULES or USE_SCRIPT. They can't both be used at the same time"
#endif
+/*********************************************************************************************\
+ * Post-process compile options for TLS
+\*********************************************************************************************/
+
+#if defined(USE_MQTT_TLS) || defined(USE_SENDMAIL) || defined(USE_TELEGRAM)
+ #define USE_TLS // flag indicates we need to include TLS code
+
+ #if defined(USE_MQTT_AWS_IOT) || defined(USE_TELEGRAM)
+ #define USE_MQTT_TLS_FORCE_EC_CIPHER // AWS IoT and TELEGRAM require EC Cipher
+ #endif
+#endif
+
#endif // _MY_USER_CONFIG_H_
diff --git a/tasmota/settings.h b/tasmota/settings.h
index 1b0cc0951..0704f426f 100644
--- a/tasmota/settings.h
+++ b/tasmota/settings.h
@@ -114,8 +114,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t pwm_ct_mode : 1; // bit 10 (v8.2.0.4) - SetOption92 - Set PWM Mode from regular PWM to ColorTemp control (Xiaomi Philips ...)
uint32_t compress_rules_cpu : 1; // bit 11 (v8.2.0.6) - SetOption93 - Keep uncompressed rules in memory to avoid CPU load of uncompressing at each tick
uint32_t max6675 : 1; // bit 12 (v8.3.1.2) - SetOption94 - Implement simpler MAX6675 protocol instead of MAX31855
- uint32_t spare13 : 1;
- uint32_t spare14 : 1;
+ uint32_t network_wifi : 1; // bit 13 (v8.3.1.3) - CMND_WIFI
+ uint32_t network_ethernet : 1; // bit 14 (v8.3.1.3) = CMND_ETHERNET
uint32_t spare15 : 1;
uint32_t spare16 : 1;
uint32_t spare17 : 1;
@@ -392,12 +392,13 @@ struct {
#else // ESP32
myio my_gp; // 3AC - 2 x 40 bytes (ESP32)
mytmplt user_template; // 3FC - 2 x 37 bytes (ESP32)
+ uint8_t eth_type; // 446
+ uint8_t eth_clk_mode; // 447
- uint8_t free_esp32_446[6]; // 446
+ uint8_t free_esp32_448[4]; // 448
WebCamCfg webcam_config; // 44C
-
- uint8_t free_esp32_450[1]; // 450
+ uint8_t eth_address; // 450
#endif // ESP8266 - ESP32
char serial_delimiter; // 451
@@ -566,10 +567,12 @@ struct {
uint16_t windmeter_pulse_debounce; // F3A
int16_t windmeter_speed_factor; // F3C
uint8_t windmeter_tele_pchange; // F3E
- uint8_t ledpwm_on; // F3F
- uint8_t ledpwm_off; // F40
+ uint8_t ledpwm_on; // F3F
+ uint8_t ledpwm_off; // F40
+ uint8_t tcp_baudrate; // F41
+ uint8_t fallback_module; // F42
- uint8_t free_f42[119]; // F41 - Decrement if adding new Setting variables just above and below
+ uint8_t free_f43[117]; // F43 - Decrement if adding new Setting variables just above and below
// Only 32 bit boundary variables below
uint16_t pulse_counter_debounce_low; // FB8
@@ -647,13 +650,14 @@ struct XDRVMAILBOX {
} XdrvMailbox;
#ifdef USE_SHUTTER
-const uint8_t MAX_RULES_FLAG = 10; // Number of bits used in RulesBitfield (tricky I know...)
+const uint8_t MAX_RULES_FLAG = 11; // Number of bits used in RulesBitfield (tricky I know...)
#else
-const uint8_t MAX_RULES_FLAG = 8; // Number of bits used in RulesBitfield (tricky I know...)
+const uint8_t MAX_RULES_FLAG = 9; // Number of bits used in RulesBitfield (tricky I know...)
#endif // USE_SHUTTER
typedef union { // Restricted by MISRA-C Rule 18.4 but so useful...
uint16_t data; // Allow bit manipulation
struct {
+ uint16_t system_init : 1; // Changing layout here needs adjustments in xdrv_10_rules.ino too
uint16_t system_boot : 1;
uint16_t time_init : 1;
uint16_t time_set : 1;
@@ -664,7 +668,6 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint16_t http_init : 1;
uint16_t shutter_moved : 1;
uint16_t shutter_moving : 1;
- uint16_t spare10 : 1;
uint16_t spare11 : 1;
uint16_t spare12 : 1;
uint16_t spare13 : 1;
@@ -676,10 +679,10 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
typedef union {
uint8_t data;
struct {
- uint8_t wifi_down : 1;
+ uint8_t network_down : 1;
uint8_t mqtt_down : 1;
- uint8_t spare02 : 1;
- uint8_t spare03 : 1;
+ uint8_t wifi_down : 1;
+ uint8_t eth_down : 1;
uint8_t spare04 : 1;
uint8_t spare05 : 1;
uint8_t spare06 : 1;
diff --git a/tasmota/settings.ino b/tasmota/settings.ino
index f8aa19ab9..d7ede5f25 100644
--- a/tasmota/settings.ino
+++ b/tasmota/settings.ino
@@ -768,6 +768,7 @@ void SettingsDefaultSet2(void)
// flag.interlock |= 0;
Settings.interlock[0] = 0xFF; // Legacy support using all relays in one interlock group
Settings.module = MODULE;
+ Settings.fallback_module = FALLBACK_MODULE;
ModuleDefault(WEMOS);
// for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) { Settings.my_gp.io[i] = GPIO_NONE; }
SettingsUpdateText(SET_FRIENDLYNAME1, PSTR(FRIENDLY_NAME));
@@ -798,7 +799,16 @@ void SettingsDefaultSet2(void)
Settings.serial_delimiter = 0xff;
Settings.seriallog_level = SERIAL_LOG_LEVEL;
+ // Ethernet
+ flag4.network_ethernet |= 1;
+#ifdef ESP32
+ Settings.eth_type = ETH_TYPE;
+ Settings.eth_clk_mode = ETH_CLKMODE;
+ Settings.eth_address = ETH_ADDR;
+#endif
+
// Wifi
+ flag4.network_wifi |= 1;
flag3.use_wifi_scan |= WIFI_SCAN_AT_RESTART;
flag3.use_wifi_rescan |= WIFI_SCAN_REGULARLY;
Settings.wifi_output_power = 170;
@@ -1439,6 +1449,20 @@ void SettingsDelta(void)
Settings.ledpwm_on = 255;
Settings.ledpwm_mask = 0;
}
+ if (Settings.version < 0x08030104) {
+ Settings.flag4.network_wifi = 1;
+ Settings.flag4.network_ethernet = 1;
+ }
+#ifdef ESP32
+ if (Settings.version < 0x08030105) {
+ Settings.eth_type = ETH_TYPE;
+ Settings.eth_clk_mode = ETH_CLKMODE;
+ Settings.eth_address = ETH_ADDR;
+ }
+#endif
+ if (Settings.version < 0x08030106) {
+ Settings.fallback_module = FALLBACK_MODULE;
+ }
Settings.version = VERSION;
SettingsSave(1);
diff --git a/tasmota/support.ino b/tasmota/support.ino
index 8d915cf05..87cd0ce5e 100644
--- a/tasmota/support.ino
+++ b/tasmota/support.ino
@@ -156,7 +156,7 @@ float CharToFloat(const char *str)
signed char sign = 1;
if (*pt == '-') { sign = -1; }
- if (*pt == '-' || *pt=='+') { pt++; } // Skip any sign
+ if (*pt == '-' || *pt == '+') { pt++; } // Skip any sign
float left = 0;
if (*pt != '.') {
@@ -167,6 +167,9 @@ float CharToFloat(const char *str)
float right = 0;
if (*pt == '.') {
pt++;
+ uint32_t max_decimals = 0;
+ while ((max_decimals < 8) && isdigit(pt[max_decimals])) { max_decimals++; }
+ pt[max_decimals] = '\0'; // Limit decimals to float max of 8
right = atoi(pt); // Decimal part
while (isdigit(*pt)) {
pt++;
@@ -687,9 +690,9 @@ void ResetGlobalValues(void)
{
if ((uptime - global_update) > GLOBAL_VALUES_VALID) { // Reset after 5 minutes
global_update = 0;
- global_temperature = 9999;
- global_humidity = 0;
- global_pressure = 0;
+ global_temperature = NAN;
+ global_humidity = 0.0f;
+ global_pressure = 0.0f;
}
}
@@ -997,7 +1000,7 @@ char* ResponseGetTime(uint32_t format, char* time_str)
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":%u"), UtcTime());
break;
case 3:
- snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s.%03d\""), GetDateAndTime(DT_LOCAL).c_str(), RtcMillis());
+ snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL_MILLIS).c_str());
break;
default:
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
@@ -1356,7 +1359,15 @@ bool JsonTemplate(const char* dataBuf)
}
if (obj[D_JSON_GPIO].success()) {
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
+#ifdef ESP8266
Settings.user_template.gp.io[i] = obj[D_JSON_GPIO][i] | 0;
+#else // ESP32
+ uint16_t gpio = obj[D_JSON_GPIO][i] | 0;
+ if (gpio == (AGPIO(GPIO_NONE) +1)) {
+ gpio = AGPIO(GPIO_USER);
+ }
+ Settings.user_template.gp.io[i] = gpio;
+#endif
}
}
if (obj[D_JSON_FLAG].success()) {
@@ -1375,7 +1386,15 @@ void TemplateJson(void)
{
Response_P(PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), SettingsText(SET_TEMPLATE_NAME));
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
+#ifdef ESP8266
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Settings.user_template.gp.io[i]);
+#else // ESP32
+ uint16_t gpio = Settings.user_template.gp.io[i];
+ if (gpio == AGPIO(GPIO_USER)) {
+ gpio = AGPIO(GPIO_NONE) +1;
+ }
+ ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", gpio);
+#endif
}
ResponseAppend_P(PSTR("],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), Settings.user_template.flag, Settings.user_template_base +1);
}
@@ -1601,8 +1620,8 @@ void I2cScan(char *devs, unsigned int devs_len)
// Return error codes defined in twi.h and core_esp8266_si2c.c
// I2C_OK 0
// I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover
- // I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond slave clock stretch time
- // I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by slave/another_master after n bits
+ // I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond client clock stretch time
+ // I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by client/another_master after n bits
// I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master?
uint8_t error = 0;
@@ -1738,7 +1757,7 @@ void Syslog(void)
}
if (PortUdp.beginPacket(syslog_host_addr, Settings.syslog_port)) {
char syslog_preamble[64]; // Hostname + Id
- snprintf_P(syslog_preamble, sizeof(syslog_preamble), PSTR("%s ESP-"), my_hostname);
+ snprintf_P(syslog_preamble, sizeof(syslog_preamble), PSTR("%s ESP-"), NetworkHostname());
memmove(log_data + strlen(syslog_preamble), log_data, sizeof(log_data) - strlen(syslog_preamble));
log_data[sizeof(log_data) -1] = '\0';
memcpy(log_data, syslog_preamble, strlen(syslog_preamble));
@@ -1785,7 +1804,7 @@ void AddLog(uint32_t loglevel)
!global_state.mqtt_down &&
(loglevel <= Settings.mqttlog_level)) { MqttPublishLogging(mxtime); }
- if (!global_state.wifi_down &&
+ if (!global_state.network_down &&
(loglevel <= syslog_level)) { Syslog(); }
prepped_loglevel = 0;
diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino
index abda76482..a901b380d 100644
--- a/tasmota/support_command.ino
+++ b/tasmota/support_command.ino
@@ -27,7 +27,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix
D_CMND_SERIALDELIMITER "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|"
D_CMND_DEVICENAME "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TELEPERIOD "|" D_CMND_RESET "|" D_CMND_TIME "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|"
D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_LEDMASK "|" D_CMND_LEDPWM_ON "|" D_CMND_LEDPWM_OFF "|" D_CMND_LEDPWM_MODE "|"
- D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|"
+ D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|" D_CMND_WIFI "|"
#ifdef USE_I2C
D_CMND_I2CSCAN "|" D_CMND_I2CDRIVER "|"
#endif
@@ -54,7 +54,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = {
&CmndSerialDelimiter, &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig,
&CmndDevicename, &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd,
&CmndTimeDst, &CmndAltitude, &CmndLedPower, &CmndLedState, &CmndLedMask, &CmndLedPwmOn, &CmndLedPwmOff, &CmndLedPwmMode,
- &CmndWifiPower, &CmndTempOffset, &CmndHumOffset, &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum,
+ &CmndWifiPower, &CmndTempOffset, &CmndHumOffset, &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, &CmndWifi,
#ifdef USE_I2C
&CmndI2cScan, CmndI2cDriver,
#endif
@@ -499,8 +499,8 @@ void CmndStatus(void)
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_GATEWAY "\":\"%s\",\""
D_JSON_SUBNETMASK "\":\"%s\",\"" D_JSON_DNSSERVER "\":\"%s\",\"" D_JSON_MAC "\":\"%s\",\""
D_CMND_WEBSERVER "\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"),
- my_hostname, WiFi.localIP().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(),
- IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(), WiFi.macAddress().c_str(),
+ NetworkHostname(), NetworkAddress().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(),
+ IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(), NetworkMacAddress().c_str(),
Settings.webserver, Settings.sta_config, WifiGetOutputPower().c_str());
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "5"));
}
@@ -626,7 +626,7 @@ void CmndGlobalTemp(void)
if (!isnan(temperature) && Settings.flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit
temperature = (temperature - 32) / 1.8; // Celsius
}
- if ((temperature >= -50.0) && (temperature <= 100.0)) {
+ if ((temperature >= -50.0f) && (temperature <= 100.0f)) {
ConvertTemp(temperature);
global_update = 1; // Keep global values just entered valid
}
@@ -1018,18 +1018,29 @@ void CmndModule(void)
present = ValidTemplateModule(XdrvMailbox.payload);
}
if (present) {
- Settings.last_module = Settings.module;
- Settings.module = XdrvMailbox.payload;
- SetModuleType();
- if (Settings.last_module != XdrvMailbox.payload) {
- for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
- Settings.my_gp.io[i] = GPIO_NONE;
+ if (XdrvMailbox.index == 2) {
+ Settings.fallback_module = XdrvMailbox.payload;
+ } else {
+ Settings.last_module = Settings.module;
+ Settings.module = XdrvMailbox.payload;
+ SetModuleType();
+ if (Settings.last_module != XdrvMailbox.payload) {
+ for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
+ Settings.my_gp.io[i] = GPIO_NONE;
+ }
}
+ restart_flag = 2;
}
- restart_flag = 2;
}
}
- Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, ModuleNr(), ModuleName().c_str());
+ uint8_t module_real = Settings.module;
+ uint8_t module_number = ModuleNr();
+ if (XdrvMailbox.index == 2) {
+ module_real = Settings.fallback_module;
+ module_number = (USER_MODULE == Settings.fallback_module) ? 0 : Settings.fallback_module +1;
+ strcat(XdrvMailbox.command, "2");
+ }
+ Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, module_number, AnyModuleName(module_real).c_str());
}
void CmndModules(void)
@@ -1497,6 +1508,15 @@ void CmndWifiConfig(void)
Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, Settings.sta_config, GetTextIndexed(stemp1, sizeof(stemp1), Settings.sta_config, kWifiConfig));
}
+void CmndWifi(void)
+{
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
+ Settings.flag4.network_wifi = XdrvMailbox.payload;
+ restart_flag = 2;
+ }
+ ResponseCmndStateText(Settings.flag4.network_wifi);
+}
+
void CmndDevicename(void)
{
if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) {
diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino
index 3fcd029bf..abd5f4236 100644
--- a/tasmota/support_features.ino
+++ b/tasmota/support_features.ino
@@ -477,8 +477,8 @@ void GetFeatures(void)
#ifdef USE_EXS_DIMMER
feature5 |= 0x00008000; // xdrv_30_exs_dimmer.ino
#endif
-#ifdef USE_TASMOTA_SLAVE
- feature5 |= 0x00010000; // xdrv_31_arduino_slave.ino
+#ifdef USE_TASMOTA_CLIENT
+ feature5 |= 0x00010000; // xdrv_31_tasmota_client.ino
#endif
#ifdef USE_HIH6
feature5 |= 0x00020000; // xsns_55_hih_series.ino
@@ -575,14 +575,21 @@ void GetFeatures(void)
#ifdef USE_BL0940
feature6 |= 0x00004000; // xnrg_14_bl0940.ino
#endif
-#ifdef USE_TELEINFO
- feature6 |= 0x00008000; // xnrg_15_teleinfo.ino
+#ifdef USE_TELEGRAM
+ feature6 |= 0x00008000; // xdrv_40_telegram.ino
+#endif
+#ifdef USE_HP303B
+ feature6 |= 0x00010000; // xsns_73_hp303b.ino
+#endif
+#ifdef USE_TCP_BRIDGE
+ feature6 |= 0x00020000; // xdrv_41_tcp_bridge.ino
+#endif
+#ifdef USE_TELEINFO
+ feature6 |= 0x00040000; // xnrg_15_teleinfo.ino
+#endif
+#ifdef USE_LMT01
+ feature6 |= 0x00080000; // xsns_74_lmt01.ino
#endif
-
-// feature6 |= 0x00010000;
-// feature6 |= 0x00020000;
-// feature6 |= 0x00040000;
-// feature6 |= 0x00080000;
// feature6 |= 0x00100000;
// feature6 |= 0x00200000;
@@ -596,8 +603,10 @@ void GetFeatures(void)
// feature6 |= 0x10000000;
// feature6 |= 0x20000000;
-// feature6 |= 0x40000000;
+#ifdef USE_ETHERNET
+ feature6 |= 0x40000000; // xdrv_82_ethernet.ino
+#endif
#ifdef USE_WEBCAM
- feature6 |= 0x80000000;
+ feature6 |= 0x80000000; // xdrv_81_webcam.ino
#endif
}
diff --git a/tasmota/support_network.ino b/tasmota/support_network.ino
new file mode 100644
index 000000000..4f6da4d88
--- /dev/null
+++ b/tasmota/support_network.ino
@@ -0,0 +1,128 @@
+/*
+ support_network.ino - Network support for Tasmota
+
+ Copyright (C) 2020 Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+/*********************************************************************************************\
+ * MDNS
+\*********************************************************************************************/
+
+struct {
+ uint8_t begun = 0; // mDNS active
+} Mdns;
+
+#ifdef USE_DISCOVERY
+void StartMdns(void) {
+ if (Settings.flag3.mdns_enabled) { // SetOption55 - Control mDNS service
+ if (!Mdns.begun) {
+// if (mdns_delayed_start) {
+// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION));
+// mdns_delayed_start--;
+// } else {
+// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
+ Mdns.begun = (uint8_t)MDNS.begin(my_hostname);
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Mdns.begun) ? D_INITIALIZED : D_FAILED);
+// }
+ }
+ }
+}
+
+#ifdef MQTT_HOST_DISCOVERY
+void MqttDiscoverServer(void)
+{
+ if (!Mdns.begun) { return; }
+
+ int n = MDNS.queryService("mqtt", "tcp"); // Search for mqtt service
+
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n);
+
+ if (n > 0) {
+ uint32_t i = 0; // If the hostname isn't set, use the first record found.
+#ifdef MDNS_HOSTNAME
+ for (i = n; i > 0; i--) { // Search from last to first and use first if not found
+ if (!strcmp(MDNS.hostname(i).c_str(), MDNS_HOSTNAME)) {
+ break; // Stop at matching record
+ }
+ }
+#endif // MDNS_HOSTNAME
+ SettingsUpdateText(SET_MQTT_HOST, MDNS.IP(i).toString().c_str());
+ Settings.mqtt_port = MDNS.port(i);
+
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"), MDNS.hostname(i).c_str(), SettingsText(SET_MQTT_HOST), Settings.mqtt_port);
+ }
+}
+#endif // MQTT_HOST_DISCOVERY
+
+#ifdef WEBSERVER_ADVERTISE
+void MdnsAddServiceHttp(void) {
+ if (1 == Mdns.begun) {
+ Mdns.begun = 2;
+ MDNS.addService("http", "tcp", WEB_PORT);
+ }
+}
+
+void MdnsUpdate(void) {
+ if (2 == Mdns.begun) {
+ MDNS.update();
+ AddLog_P(LOG_LEVEL_DEBUG_MORE, D_LOG_MDNS, "MDNS.update");
+ }
+}
+#endif // WEBSERVER_ADVERTISE
+#endif // USE_DISCOVERY
+
+/*********************************************************************************************\
+ * Global network parameters
+\*********************************************************************************************/
+
+char* NetworkHostname(void) {
+ if (global_state.eth_down) {
+ return my_hostname;
+ }
+#ifdef ESP32
+#ifdef USE_ETHERNET
+ else {
+ return EthernetHostname();
+ }
+#endif
+#endif
+}
+
+IPAddress NetworkAddress(void) {
+ if (global_state.eth_down) {
+ return WiFi.localIP();
+ }
+#ifdef ESP32
+#ifdef USE_ETHERNET
+ else {
+ return EthernetLocalIP();
+ }
+#endif
+#endif
+}
+
+String NetworkMacAddress(void) {
+ if (global_state.eth_down) {
+ return WiFi.macAddress();
+ }
+#ifdef ESP32
+#ifdef USE_ETHERNET
+ else {
+ return EthernetMacAddress();
+ }
+#endif
+#endif
+}
diff --git a/tasmota/support_rtc.ino b/tasmota/support_rtc.ino
index e918ae99d..25ad82435 100644
--- a/tasmota/support_rtc.ino
+++ b/tasmota/support_rtc.ino
@@ -206,6 +206,14 @@ String GetDateAndTime(uint8_t time_type)
break;
}
String dt = GetDT(time); // 2017-03-07T11:08:02
+
+ if (DT_LOCAL_MILLIS == time_type) {
+ char ms[10];
+ snprintf_P(ms, sizeof(ms), PSTR(".%03d"), RtcMillis());
+ dt += ms;
+ time_type = DT_LOCAL;
+ }
+
if (Settings.flag3.time_append_timezone && (DT_LOCAL == time_type)) { // SetOption52 - Append timezone to JSON time
dt += GetTimeZone(); // 2017-03-07T11:08:02-07:00
}
@@ -371,7 +379,7 @@ void RtcSecond(void)
Rtc.millis = millis();
if (!Rtc.user_time_entry) {
- if (!global_state.wifi_down) {
+ if (!global_state.network_down) {
uint8_t uptime_minute = (uptime / 60) % 60; // 0 .. 59
if ((Rtc.ntp_sync_minute > 59) && (uptime_minute > 2)) {
Rtc.ntp_sync_minute = 1; // If sync prepare for a new cycle
diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino
index 3cbfb497c..4843cd884 100644
--- a/tasmota/support_tasmota.ino
+++ b/tasmota/support_tasmota.ino
@@ -684,10 +684,14 @@ void MqttShowState(void)
MqttShowPWMState();
}
- int32_t rssi = WiFi.RSSI();
- ResponseAppend_P(PSTR(",\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d,\"" D_JSON_SIGNAL "\":%d,\"" D_JSON_LINK_COUNT "\":%d,\"" D_JSON_DOWNTIME "\":\"%s\"}}"),
- Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WiFi.BSSIDstr().c_str(), WiFi.channel(),
- WifiGetRssiAsQuality(rssi), rssi, WifiLinkCount(), WifiDowntime().c_str());
+ if (!global_state.wifi_down) {
+ int32_t rssi = WiFi.RSSI();
+ ResponseAppend_P(PSTR(",\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d,\"" D_JSON_SIGNAL "\":%d,\"" D_JSON_LINK_COUNT "\":%d,\"" D_JSON_DOWNTIME "\":\"%s\"}"),
+ Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WiFi.BSSIDstr().c_str(), WiFi.channel(),
+ WifiGetRssiAsQuality(rssi), rssi, WifiLinkCount(), WifiDowntime().c_str());
+ }
+
+ ResponseJsonEnd();
}
void MqttPublishTeleState(void)
@@ -824,7 +828,7 @@ void PerformEverySecond(void)
if (Settings.tele_period) {
if (tele_period >= 9999) {
- if (!global_state.wifi_down) {
+ if (!global_state.network_down) {
tele_period = 0; // Allow teleperiod once wifi is connected
}
} else {
@@ -916,10 +920,12 @@ void Every250mSeconds(void)
state_250mS++;
state_250mS &= 0x3;
- if (!Settings.flag.global_state) { // Problem blinkyblinky enabled - SetOption31 - Control link led blinking
- if (global_state.data) { // Any problem
+ global_state.network_down = (global_state.wifi_down && global_state.eth_down);
+
+ if (!Settings.flag.global_state && !global_state.network_down) { // SetOption31 - Control link led blinking
+ if (global_state.data &0x03) { // Any problem
if (global_state.mqtt_down) { blinkinterval = 7; } // MQTT problem so blink every 2 seconds (slowest)
- if (global_state.wifi_down) { blinkinterval = 3; } // Wifi problem so blink every second (slow)
+ if (global_state.network_down) { blinkinterval = 3; } // Network problem so blink every second (slow)
blinks = 201; // Allow only a single blink in case the problem is solved
}
}
@@ -1151,11 +1157,75 @@ void Every250mSeconds(void)
}
break;
case 2: // Every x.5 second
- WifiCheck(wifi_state_flag);
- wifi_state_flag = WIFI_RESTART;
+ if (Settings.flag4.network_wifi) {
+ WifiCheck(wifi_state_flag);
+ wifi_state_flag = WIFI_RESTART;
+ }
break;
case 3: // Every x.75 second
- if (!global_state.wifi_down) { MqttCheck(); }
+ if (!global_state.network_down) {
+#ifdef FIRMWARE_MINIMAL
+ if (1 == RtcSettings.ota_loader) {
+ RtcSettings.ota_loader = 0;
+ ota_state_flag = 3;
+ }
+#endif // FIRMWARE_MINIMAL
+
+#ifdef USE_DISCOVERY
+ StartMdns();
+#endif // USE_DISCOVERY
+
+#ifdef USE_WEBSERVER
+ if (Settings.webserver) {
+
+#ifdef ESP8266
+ StartWebserver(Settings.webserver, WiFi.localIP());
+#else // ESP32
+#ifdef USE_ETHERNET
+ StartWebserver(Settings.webserver, (EthernetLocalIP()) ? EthernetLocalIP() : WiFi.localIP());
+#else
+ StartWebserver(Settings.webserver, WiFi.localIP());
+#endif
+#endif
+
+#ifdef USE_DISCOVERY
+#ifdef WEBSERVER_ADVERTISE
+ MdnsAddServiceHttp();
+#endif // WEBSERVER_ADVERTISE
+#endif // USE_DISCOVERY
+ } else {
+ StopWebserver();
+ }
+#ifdef USE_EMULATION
+ if (Settings.flag2.emulation) { UdpConnect(); }
+#endif // USE_EMULATION
+#endif // USE_WEBSERVER
+
+#ifdef USE_DEVICE_GROUPS
+ DeviceGroupsStart();
+#endif // USE_DEVICE_GROUPS
+
+#ifdef USE_KNX
+ if (!knx_started && Settings.flag.knx_enabled) { // CMND_KNX_ENABLED
+ KNXStart();
+ knx_started = true;
+ }
+#endif // USE_KNX
+
+ MqttCheck();
+ } else {
+#ifdef USE_EMULATION
+ UdpDisconnect();
+#endif // USE_EMULATION
+
+#ifdef USE_DEVICE_GROUPS
+ DeviceGroupsStop();
+#endif // USE_DEVICE_GROUPS
+
+#ifdef USE_KNX
+ knx_started = false;
+#endif // USE_KNX
+ }
break;
}
}
@@ -1174,7 +1244,7 @@ uint16_t arduino_ota_progress_dot_count = 0;
void ArduinoOTAInit(void)
{
ArduinoOTA.setPort(8266);
- ArduinoOTA.setHostname(my_hostname);
+ ArduinoOTA.setHostname(NetworkHostname());
if (strlen(SettingsText(SET_WEBPWD))) {
ArduinoOTA.setPassword(SettingsText(SET_WEBPWD));
}
diff --git a/tasmota/support_wifi.ino b/tasmota/support_wifi.ino
index c42e1d49a..75de2523f 100644
--- a/tasmota/support_wifi.ino
+++ b/tasmota/support_wifi.ino
@@ -52,7 +52,6 @@ struct WIFI {
uint8_t status;
uint8_t config_type = 0;
uint8_t config_counter = 0;
- uint8_t mdns_begun = 0; // mDNS active
uint8_t scan_state;
uint8_t bssid[6];
int8_t best_network_db;
@@ -352,6 +351,9 @@ void WifiSetState(uint8_t state)
}
}
global_state.wifi_down = state ^1;
+ if (!global_state.wifi_down) {
+ global_state.network_down = 0;
+ }
}
#if LWIP_IPV6
@@ -410,10 +412,7 @@ void WifiCheckIp(void)
Wifi.status = WL_CONNECTED;
#ifdef USE_DISCOVERY
#ifdef WEBSERVER_ADVERTISE
- if (2 == Wifi.mdns_begun) {
- MDNS.update();
- AddLog_P(LOG_LEVEL_DEBUG_MORE, D_LOG_MDNS, "MDNS.update");
- }
+ MdnsUpdate();
#endif // USE_DISCOVERY
#endif // WEBSERVER_ADVERTISE
} else {
@@ -529,75 +528,14 @@ void WifiCheck(uint8_t param)
if ((WL_CONNECTED == WiFi.status()) && (static_cast(WiFi.localIP()) != 0) && !Wifi.config_type) {
#endif // LWIP_IPV6=1
WifiSetState(1);
-
if (Settings.flag3.use_wifi_rescan) { // SetOption57 - Scan wifi network every 44 minutes for configured AP's
if (!(uptime % (60 * WIFI_RESCAN_MINUTES))) {
Wifi.scan_state = 2;
}
}
-
-#ifdef FIRMWARE_MINIMAL
- if (1 == RtcSettings.ota_loader) {
- RtcSettings.ota_loader = 0;
- ota_state_flag = 3;
- }
-#endif // FIRMWARE_MINIMAL
-
-#ifdef USE_DISCOVERY
- if (Settings.flag3.mdns_enabled) { // SetOption55 - Control mDNS service
- if (!Wifi.mdns_begun) {
-// if (mdns_delayed_start) {
-// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION));
-// mdns_delayed_start--;
-// } else {
-// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
- Wifi.mdns_begun = (uint8_t)MDNS.begin(my_hostname);
- AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Wifi.mdns_begun) ? D_INITIALIZED : D_FAILED);
-// }
- }
- }
-#endif // USE_DISCOVERY
-
-#ifdef USE_WEBSERVER
- if (Settings.webserver) {
- StartWebserver(Settings.webserver, WiFi.localIP());
-#ifdef USE_DISCOVERY
-#ifdef WEBSERVER_ADVERTISE
- if (1 == Wifi.mdns_begun) {
- Wifi.mdns_begun = 2;
- MDNS.addService("http", "tcp", WEB_PORT);
- }
-#endif // WEBSERVER_ADVERTISE
-#endif // USE_DISCOVERY
- } else {
- StopWebserver();
- }
-#ifdef USE_EMULATION
- if (Settings.flag2.emulation) { UdpConnect(); }
-#endif // USE_EMULATION
-#endif // USE_WEBSERVER
-#ifdef USE_DEVICE_GROUPS
- DeviceGroupsStart();
-#endif // USE_DEVICE_GROUPS
-#ifdef USE_KNX
- if (!knx_started && Settings.flag.knx_enabled) { // CMND_KNX_ENABLED
- KNXStart();
- knx_started = true;
- }
-#endif // USE_KNX
-
} else {
WifiSetState(0);
-#ifdef USE_EMULATION
- UdpDisconnect();
-#endif // USE_EMULATION
-#ifdef USE_DEVICE_GROUPS
- DeviceGroupsStop();
-#endif // USE_DEVICE_GROUPS
- Wifi.mdns_begun = 0;
-#ifdef USE_KNX
- knx_started = false;
-#endif // USE_KNX
+ Mdns.begun = 0;
}
}
}
@@ -652,6 +590,8 @@ RF_PRE_INIT()
void WifiConnect(void)
{
+ if (!Settings.flag4.network_wifi) { return; }
+
WifiSetState(0);
WifiSetOutputPower();
WiFi.persistent(false); // Solve possible wifi init errors
@@ -760,4 +700,4 @@ void wifiKeepAlive(void) {
SetNextTimeInterval(wifiTimer, wifiTimerSec * 1000);
}
}
-#endif // ARDUINO_ESP8266_RELEASE_2_3_0
\ No newline at end of file
+#endif // ARDUINO_ESP8266_RELEASE_2_3_0
diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h
index c3913e8a1..4eceddb5c 100644
--- a/tasmota/tasmota.h
+++ b/tasmota/tasmota.h
@@ -203,7 +203,8 @@ const uint32_t LOOP_SLEEP_DELAY = 50; // Lowest number of milliseconds to
#define KNX_SLOT3 28
#define KNX_SLOT4 29
#define KNX_SLOT5 30
-#define KNX_MAX_device_param 30
+#define KNX_SCENE 31
+#define KNX_MAX_device_param 31
#define MAX_KNXTX_CMNDS 5
/*********************************************************************************************\
@@ -214,7 +215,7 @@ enum WeekInMonthOptions {Last, First, Second, Third, Fourth};
enum DayOfTheWeekOptions {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat};
enum MonthNamesOptions {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
enum HemisphereOptions {North, South};
-enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_LOCALNOTZ, DT_DST, DT_STD, DT_RESTART, DT_ENERGY, DT_BOOTCOUNT };
+enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_LOCALNOTZ, DT_DST, DT_STD, DT_RESTART, DT_ENERGY, DT_BOOTCOUNT, DT_LOCAL_MILLIS };
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
@@ -293,7 +294,7 @@ enum SettingsTextIndex { SET_OTAURL,
SET_TEMPLATE_NAME,
SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4,
SET_DEVICENAME,
- SET_TELEGRAMTOKEN,
+ SET_TELEGRAM_TOKEN, SET_TELEGRAM_CHATID,
SET_MAX };
enum DevGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYPE_UPDATE_COMMAND };
@@ -321,9 +322,10 @@ enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER,
- SRC_THERMOSTAT, SRC_MAX };
+ SRC_THERMOSTAT, SRC_CHAT, SRC_MAX };
const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|"
- "Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|Thermostat";
+ "Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|"
+ "Thermostat|Chat";
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };
@@ -344,10 +346,10 @@ const SerConfu8 kTasmotaSerialConfig[] PROGMEM = {
SERIAL_5O2, SERIAL_6O2, SERIAL_7O2, SERIAL_8O2
};
-enum TuyaSupportedFunctions { TUYA_MCU_FUNC_NONE, TUYA_MCU_FUNC_SWT1 = 1, TUYA_MCU_FUNC_SWT2, TUYA_MCU_FUNC_SWT3, TUYA_MCU_FUNC_SWT4,
- TUYA_MCU_FUNC_REL1 = 11, TUYA_MCU_FUNC_REL2, TUYA_MCU_FUNC_REL3, TUYA_MCU_FUNC_REL4, TUYA_MCU_FUNC_REL5,
+enum TuyaSupportedFunctions { TUYA_MCU_FUNC_NONE, TUYA_MCU_FUNC_SWT1 = 1, TUYA_MCU_FUNC_SWT2, TUYA_MCU_FUNC_SWT3, TUYA_MCU_FUNC_SWT4,
+ TUYA_MCU_FUNC_REL1 = 11, TUYA_MCU_FUNC_REL2, TUYA_MCU_FUNC_REL3, TUYA_MCU_FUNC_REL4, TUYA_MCU_FUNC_REL5,
TUYA_MCU_FUNC_REL6, TUYA_MCU_FUNC_REL7, TUYA_MCU_FUNC_REL8, TUYA_MCU_FUNC_DIMMER = 21, TUYA_MCU_FUNC_POWER = 31,
- TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE,
+ TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE,
TUYA_MCU_FUNC_REL1_INV = 41, TUYA_MCU_FUNC_REL2_INV, TUYA_MCU_FUNC_REL3_INV, TUYA_MCU_FUNC_REL4_INV, TUYA_MCU_FUNC_REL5_INV,
TUYA_MCU_FUNC_REL6_INV, TUYA_MCU_FUNC_REL7_INV, TUYA_MCU_FUNC_REL8_INV, TUYA_MCU_FUNC_LOWPOWER_MODE = 51, TUYA_MCU_FUNC_LAST = 255
};
diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino
index ecf1127ec..abc95d5d9 100644
--- a/tasmota/tasmota.ino
+++ b/tasmota/tasmota.ino
@@ -36,9 +36,9 @@
#include "tasmota_version.h" // Tasmota version information
#include "tasmota.h" // Enumeration used in my_user_config.h
#include "my_user_config.h" // Fixed user configurable options
-#ifdef USE_MQTT_TLS
+#ifdef USE_TLS
#include // We need to include before "tasmota_globals.h" to take precedence over the BearSSL version in Arduino
-#endif // USE_MQTT_TLS
+#endif // USE_TLS
#include "tasmota_globals.h" // Function prototypes and global configuration
#include "i18n.h" // Language support configured by my_user_config.h
#include "tasmota_template.h" // Hardware configuration
@@ -111,9 +111,9 @@ uint32_t uptime = 0; // Counting every second until 42949
uint32_t loop_load_avg = 0; // Indicative loop load average
uint32_t global_update = 0; // Timestamp of last global temperature and humidity update
uint32_t web_log_index = 1; // Index in Web log buffer (should never be 0)
-float global_temperature = 9999; // Provide a global temperature to be used by some sensors
-float global_humidity = 0; // Provide a global humidity to be used by some sensors
-float global_pressure = 0; // Provide a global pressure to be used by some sensors
+float global_temperature = NAN; // Provide a global temperature to be used by some sensors
+float global_humidity = 0.0f; // Provide a global humidity to be used by some sensors
+float global_pressure = 0.0f; // Provide a global pressure to be used by some sensors
uint16_t tele_period = 9999; // Tele period timer
uint16_t blink_counter = 0; // Number of blink cycles
uint16_t seriallog_timer = 0; // Timer to disable Seriallog
@@ -205,7 +205,7 @@ void setup(void) {
#endif
#endif
- global_state.data = 3; // Init global state (wifi_down, mqtt_down) to solve possible network issues
+ global_state.data = 0xF; // Init global state (wifi_down, mqtt_down) to solve possible network issues
RtcRebootLoad();
if (!RtcRebootValid()) {
@@ -278,12 +278,8 @@ void setup(void) {
#endif
}
if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +4) { // Restarted 6 times
-#ifdef ESP8266
- Settings.module = SONOFF_BASIC; // Reset module to Sonoff Basic
- // Settings.last_module = SONOFF_BASIC;
-#else // ESP32
- Settings.module = WEMOS; // Reset module to Wemos
-#endif // ESP8266 - ESP32
+ Settings.module = Settings.fallback_module; // Reset module to fallback module
+// Settings.last_module = Settings.fallback_module;
}
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_LOG_SOME_SETTINGS_RESET " (%d)"), RtcReboot.fast_reboot_count);
}
@@ -322,6 +318,11 @@ void setup(void) {
XdrvCall(FUNC_INIT);
XsnsCall(FUNC_INIT);
+#ifdef USE_SCRIPT
+ Run_Scripter(">BS",3,0);
+#endif
+
+ rules_flag.system_init = 1;
}
void BacklogLoop(void) {
@@ -411,7 +412,7 @@ void loop(void) {
if (my_activity < (uint32_t)ssleep) {
SleepDelay((uint32_t)ssleep - my_activity); // Provide time for background tasks like wifi
} else {
- if (global_state.wifi_down) {
+ if (global_state.network_down) {
SleepDelay(my_activity /2); // If wifi down and my_activity > setoption36 then force loop delay to 1/3 of my_activity period
}
}
diff --git a/tasmota/tasmota_ca.ino b/tasmota/tasmota_ca.ino
index 8e75f891e..1db0a8c63 100644
--- a/tasmota/tasmota_ca.ino
+++ b/tasmota/tasmota_ca.ino
@@ -21,9 +21,8 @@
// Please use fingerprint validation instead
// However, the CA are available below for future use if it appears to be useful
-#ifdef USE_MQTT_TLS_CA_CERT
+#if defined(USE_TLS) && defined(USE_MQTT_TLS_CA_CERT)
-#ifndef USE_MQTT_AWS_IOT
/*********************************************************************************************\
* LetsEncrypt IdenTrust DST Root CA X3 certificate, RSA 2048 bits SHA 256, valid until 20210417
*
@@ -35,7 +34,7 @@
* remove "static" and add "PROGMEM"
\*********************************************************************************************/
-static const unsigned char PROGMEM TA0_DN[] = {
+static const unsigned char PROGMEM LetsEncrypt_DN[] = {
0x30, 0x4A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x0D, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72,
@@ -45,7 +44,7 @@ static const unsigned char PROGMEM TA0_DN[] = {
0x79, 0x20, 0x58, 0x33
};
-static const unsigned char PROGMEM TA0_RSA_N[] = {
+static const unsigned char PROGMEM LetsEncrypt_RSA_N[] = {
0x9C, 0xD3, 0x0C, 0xF0, 0x5A, 0xE5, 0x2E, 0x47, 0xB7, 0x72, 0x5D, 0x37,
0x83, 0xB3, 0x68, 0x63, 0x30, 0xEA, 0xD7, 0x35, 0x26, 0x19, 0x25, 0xE1,
0xBD, 0xBE, 0x35, 0xF1, 0x70, 0x92, 0x2F, 0xB7, 0xB8, 0x4B, 0x41, 0x05,
@@ -70,27 +69,22 @@ static const unsigned char PROGMEM TA0_RSA_N[] = {
0xD8, 0x7D, 0xC3, 0x93
};
-static const unsigned char TA0_RSA_E[] = {
+static const unsigned char LetsEncrypt_RSA_E[] = {
0x01, 0x00, 0x01
};
static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = {
- { (unsigned char *)TA0_DN, sizeof TA0_DN },
+ { (unsigned char *)LetsEncrypt_DN, sizeof LetsEncrypt_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ .rsa = {
- (unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N,
- (unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E,
+ (unsigned char *)LetsEncrypt_RSA_N, sizeof LetsEncrypt_RSA_N,
+ (unsigned char *)LetsEncrypt_RSA_E, sizeof LetsEncrypt_RSA_E,
} }
}
};
-#define TAs_NUM 1
-
-#endif // not USE_MQTT_AWS_IOT
-
-#ifdef USE_MQTT_AWS_IOT
/*********************************************************************************************\
* Amazon Root CA, RSA 2048 bits SHA 256, valid until 20380117
*
@@ -103,7 +97,7 @@ static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = {
\*********************************************************************************************/
-const unsigned char PROGMEM TA0_DN[] = {
+const unsigned char PROGMEM AmazonRootCA1_DN[] = {
0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17,
@@ -111,7 +105,7 @@ const unsigned char PROGMEM TA0_DN[] = {
0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31
};
-const unsigned char PROGMEM TA0_RSA_N[] = {
+const unsigned char PROGMEM AmazonRootCA1_RSA_N[] = {
0xB2, 0x78, 0x80, 0x71, 0xCA, 0x78, 0xD5, 0xE3, 0x71, 0xAF, 0x47, 0x80,
0x50, 0x74, 0x7D, 0x6E, 0xD8, 0xD7, 0x88, 0x76, 0xF4, 0x99, 0x68, 0xF7,
0x58, 0x21, 0x60, 0xF9, 0x74, 0x84, 0x01, 0x2F, 0xAC, 0x02, 0x2D, 0x86,
@@ -136,24 +130,79 @@ const unsigned char PROGMEM TA0_RSA_N[] = {
0x9A, 0xC8, 0xAA, 0x0D
};
-static const unsigned char PROGMEM TA0_RSA_E[] = {
+static const unsigned char PROGMEM AmazonRootCA1_RSA_E[] = {
0x01, 0x00, 0x01
};
const br_x509_trust_anchor PROGMEM AmazonRootCA1_TA = {
- { (unsigned char *)TA0_DN, sizeof TA0_DN },
+ { (unsigned char *)AmazonRootCA1_DN, sizeof AmazonRootCA1_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ .rsa = {
- (unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N,
- (unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E,
+ (unsigned char *)AmazonRootCA1_RSA_N, sizeof AmazonRootCA1_RSA_N,
+ (unsigned char *)AmazonRootCA1_RSA_E, sizeof AmazonRootCA1_RSA_E,
} }
}
};
-#define TAs_NUM 1
+// we add a separate CA for telegram
+/*********************************************************************************************\
+ * GoDaddy Daddy Secure Certificate Authority - G2, RSA 2048 bits SHA 256, valid until 20220523
+ *
+ * to convert do: "brssl ta GoDaddyCA.pem"
+ * then copy and paste below, chain the generic names to the same as below
+ * remove "static" and add "PROGMEM"
+\*********************************************************************************************/
-#endif // USE_MQTT_AWS_IOT
+const unsigned char GoDaddyCAG2_DN[] PROGMEM = {
+ 0x30, 0x3E, 0x31, 0x21, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13,
+ 0x18, 0x44, 0x6F, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x43, 0x6F, 0x6E, 0x74,
+ 0x72, 0x6F, 0x6C, 0x20, 0x56, 0x61, 0x6C, 0x69, 0x64, 0x61, 0x74, 0x65,
+ 0x64, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10,
+ 0x61, 0x70, 0x69, 0x2E, 0x74, 0x65, 0x6C, 0x65, 0x67, 0x72, 0x61, 0x6D,
+ 0x2E, 0x6F, 0x72, 0x67
+};
-#endif // USE_MQTT_TLS_CA_CERT
+const unsigned char GoDaddyCAG2_RSA_N[] PROGMEM = {
+ 0xB4, 0xA3, 0x16, 0x9E, 0x5C, 0x57, 0xC9, 0x89, 0x65, 0xED, 0xEA, 0x78,
+ 0x0B, 0xAE, 0x8A, 0x58, 0x2F, 0xAE, 0x5A, 0xC8, 0x6E, 0x49, 0x8D, 0xFC,
+ 0x57, 0xA5, 0x98, 0x88, 0x78, 0x2E, 0x0B, 0x3C, 0x40, 0x3C, 0x21, 0x2E,
+ 0x9A, 0x94, 0x98, 0x33, 0xA7, 0xE3, 0x42, 0xA7, 0x85, 0xFA, 0xD0, 0x73,
+ 0x84, 0x01, 0x1C, 0x72, 0x39, 0x37, 0x23, 0xB5, 0x56, 0x1D, 0x43, 0xA5,
+ 0x71, 0x14, 0x08, 0x24, 0xA5, 0x39, 0xCC, 0xDE, 0x58, 0x53, 0x94, 0x8E,
+ 0x2A, 0x42, 0xA7, 0x4E, 0x2D, 0x07, 0x32, 0x9E, 0xBA, 0x8B, 0xD3, 0x2A,
+ 0xA9, 0x9E, 0xC0, 0xE3, 0xCE, 0x9A, 0x10, 0x96, 0x45, 0x58, 0x7A, 0xC7,
+ 0x1E, 0x45, 0x14, 0x23, 0x92, 0xBB, 0x54, 0x82, 0x88, 0x94, 0x49, 0xB6,
+ 0xBE, 0x81, 0x21, 0x00, 0x29, 0x6D, 0xC9, 0xCE, 0x8B, 0x39, 0x3A, 0xDC,
+ 0x35, 0x15, 0xD9, 0xEB, 0x47, 0x9C, 0xEF, 0xBA, 0x09, 0x0E, 0x16, 0xE4,
+ 0xD9, 0xEB, 0x72, 0x30, 0xFA, 0x49, 0xAB, 0x98, 0x31, 0x7C, 0xB3, 0xAC,
+ 0x2B, 0x29, 0x91, 0x87, 0x08, 0x41, 0x72, 0x5E, 0x35, 0xC7, 0x87, 0x04,
+ 0x22, 0xF5, 0x48, 0x76, 0x30, 0x6D, 0x88, 0xDF, 0xF2, 0xA5, 0x29, 0x13,
+ 0x70, 0xB3, 0x87, 0x02, 0xD5, 0x6B, 0x58, 0xB1, 0xE8, 0x73, 0xC7, 0xE4,
+ 0xEF, 0x79, 0x86, 0xA4, 0x07, 0x5F, 0x67, 0xB4, 0x79, 0x8D, 0xA4, 0x25,
+ 0x01, 0x82, 0x8C, 0xE0, 0x30, 0x17, 0xCB, 0x4B, 0x5C, 0xFB, 0xEB, 0x4C,
+ 0x12, 0x51, 0xB9, 0xC9, 0x04, 0x1F, 0x7E, 0xD2, 0xF8, 0xBA, 0xF5, 0x35,
+ 0x8D, 0x8A, 0x1C, 0x37, 0x82, 0xF0, 0x15, 0x73, 0x00, 0x6E, 0x3D, 0x1C,
+ 0x76, 0x8B, 0x01, 0x74, 0x81, 0x3D, 0xE4, 0x2C, 0xA7, 0xCC, 0x2F, 0x66,
+ 0xDC, 0x44, 0xA8, 0x27, 0x3F, 0xEA, 0xD0, 0xA7, 0xA8, 0xF1, 0xCB, 0xEA,
+ 0xDA, 0x07, 0x38, 0xBD
+};
+
+const unsigned char GoDaddyCAG2_RSA_E[] PROGMEM = {
+ 0x01, 0x00, 0x01
+};
+
+const br_x509_trust_anchor GoDaddyCAG2_TA PROGMEM = {
+ { (unsigned char *)GoDaddyCAG2_DN, sizeof GoDaddyCAG2_DN },
+ 0,
+ {
+ BR_KEYTYPE_RSA,
+ { .rsa = {
+ (unsigned char *)GoDaddyCAG2_RSA_N, sizeof GoDaddyCAG2_RSA_N,
+ (unsigned char *)GoDaddyCAG2_RSA_E, sizeof GoDaddyCAG2_RSA_E,
+ } }
+ }
+};
+
+#endif // defined(USE_TLS) && defined(USE_MQTT_TLS_CA_CERT)
diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h
index 2af371976..10f183ec5 100644
--- a/tasmota/tasmota_configurations.h
+++ b/tasmota/tasmota_configurations.h
@@ -152,9 +152,10 @@
#define USE_HM10 // (ESP8266 only) Add support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
//#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
-//#define USE_TASMOTA_SLAVE // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
+//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
//#define USE_OPENTHERM // Add support for OpenTherm (+15k code)
//#define USE_MCP9808 // Add support for MCP9808 temperature sensor (+0k9 code)
+//#define USE_HP303B // Add support for HP303B temperature and pressure sensor (I2C address 0x76 or 0x77) (+6k2 code)
#define USE_ENERGY_SENSOR // Add energy sensors (-14k code)
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
@@ -167,7 +168,7 @@
#define USE_DDSU666 // Add support for Chint DDSU666 Modbus energy monitor (+0k6 code)
//#define USE_SOLAX_X1 // Add support for Solax X1 series Modbus log info (+3k1 code)
//#define USE_LE01MR // Add support for F&F LE-01MR modbus energy meter (+2k code)
-//#define USE_TELEINFO // Add support for French Energy Provider metering telemetry
+//#define USE_TELEINFO // Add support for French Energy Provider metering telemetry (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM)
#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
#define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI
@@ -175,6 +176,7 @@
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram)
#define USE_IR_RECEIVE // Support for IR receiver (+5k5 code, 264 iram)
+#define USE_LMT01 // Add support for TI LMT01 temperature sensor, count pulses on single GPIO (+0k5 code)
#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code)
#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code)
#define USE_HX711 // Add support for HX711 load cell (+1k5 code)
@@ -381,7 +383,7 @@
#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
-#undef USE_TASMOTA_SLAVE // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
+#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
//#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
@@ -486,7 +488,7 @@
#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
-#undef USE_TASMOTA_SLAVE // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
+#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
//#undef USE_ENERGY_SENSOR // Disable energy sensors
@@ -613,7 +615,7 @@
#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
-#undef USE_TASMOTA_SLAVE // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
+#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
#undef USE_ENERGY_SENSOR // Disable energy sensors
diff --git a/tasmota/tasmota_globals.h b/tasmota/tasmota_globals.h
index 44826fa64..620c6ff68 100644
--- a/tasmota/tasmota_globals.h
+++ b/tasmota/tasmota_globals.h
@@ -43,6 +43,16 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack, uint32_t stack_end);
extern "C" void resetPins();
+#ifdef ESP32
+
+#ifdef USE_ETHERNET
+IPAddress EthernetLocalIP(void);
+char* EthernetHostname(void);
+String EthernetMacAddress(void);
+#endif
+
+#endif // ESP32
+
/*********************************************************************************************\
* Preconfigured configurations
\*********************************************************************************************/
@@ -59,6 +69,18 @@ extern "C" void resetPins();
#ifdef USE_EMULATION_WEMO
#define USE_EMULATION
#endif
+
+// Convert legacy slave to client
+#ifdef USE_TASMOTA_SLAVE
+#define USE_TASMOTA_CLIENT
+#endif
+#ifdef USE_TASMOTA_SLAVE_FLASH_SPEED
+#define USE_TASMOTA_CLIENT_FLASH_SPEED USE_TASMOTA_SLAVE_FLASH_SPEED
+#endif
+#ifdef USE_TASMOTA_SLAVE_SERIAL_SPEED
+#define USE_TASMOTA_CLIENT_SERIAL_SPEED USE_TASMOTA_SLAVE_SERIAL_SPEED
+#endif
+
// See https://github.com/esp8266/Arduino/pull/4889
#undef NO_EXTRA_4K_HEAP // Allocate 4k heap for WPS in ESP8166/Arduino core v2.4.2 (was always allocated in previous versions)
@@ -88,7 +110,7 @@ extern "C" void resetPins();
const uint16_t WEB_LOG_SIZE = 4000; // Max number of characters in weblog
#endif
-#if defined(USE_MQTT_TLS) && defined(ARDUINO_ESP8266_RELEASE_2_3_0)
+#if defined(USE_TLS) && defined(ARDUINO_ESP8266_RELEASE_2_3_0)
#error "TLS is no more supported on Core 2.3.0, use 2.4.2 or higher."
#endif
@@ -277,6 +299,9 @@ const char kWebColors[] PROGMEM =
#ifndef MODULE
#define MODULE SONOFF_BASIC // [Module] Select default model
#endif
+#ifndef FALLBACK_MODULE
+#define FALLBACK_MODULE SONOFF_BASIC // [Module2] Select default module on fast reboot where USER_MODULE is user template
+#endif
#ifndef ARDUINO_ESP8266_RELEASE
#define ARDUINO_CORE_RELEASE "STAGE"
@@ -291,6 +316,9 @@ const char kWebColors[] PROGMEM =
#ifndef MODULE
#define MODULE WEMOS // [Module] Select default model
#endif
+#ifndef FALLBACK_MODULE
+#define FALLBACK_MODULE WEMOS // [Module2] Select default module on fast reboot where USER_MODULE is user template
+#endif
#ifndef ARDUINO_ESP32_RELEASE
#define ARDUINO_CORE_RELEASE "STAGE"
diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h
index a0146aece..bd1c009de 100644
--- a/tasmota/tasmota_template.h
+++ b/tasmota/tasmota_template.h
@@ -137,8 +137,8 @@ enum UserSelectablePins {
GPIO_TUYA_RX, // Tuya Serial interface
GPIO_MGC3130_XFER, // MGC3130 Transfer
GPIO_MGC3130_RESET, // MGC3130 Reset
- GPIO_SSPI_MISO, // Software SPI Master Input Slave Output
- GPIO_SSPI_MOSI, // Software SPI Master Output Slave Input
+ GPIO_SSPI_MISO, // Software SPI Master Input Client Output
+ GPIO_SSPI_MOSI, // Software SPI Master Output Client Input
GPIO_SSPI_SCLK, // Software SPI Serial Clock
GPIO_SSPI_CS, // Software SPI Chip Select
GPIO_SSPI_DC, // Software SPI Data or Command
@@ -210,10 +210,10 @@ enum UserSelectablePins {
GPIO_SM2135_DAT, // SM2135 Dat
GPIO_DEEPSLEEP, // Kill switch for deepsleep
GPIO_EXS_ENABLE, // EXS MCU Enable
- GPIO_TASMOTASLAVE_TXD, // Slave TX
- GPIO_TASMOTASLAVE_RXD, // Slave RX
- GPIO_TASMOTASLAVE_RST, // Slave Reset Pin
- GPIO_TASMOTASLAVE_RST_INV, // Slave Reset Inverted
+ GPIO_TASMOTACLIENT_TXD, // Client TX
+ GPIO_TASMOTACLIENT_RXD, // Client RX
+ GPIO_TASMOTACLIENT_RST, // Client Reset Pin
+ GPIO_TASMOTACLIENT_RST_INV, // Client Reset Inverted
GPIO_HPMA_RX, // Honeywell HPMA115S0 Serial interface
GPIO_HPMA_TX, // Honeywell HPMA115S0 Serial interface
GPIO_GPS_RX, // GPS serial interface
@@ -234,8 +234,11 @@ enum UserSelectablePins {
GPIO_BOILER_OT_TX, // OpenTherm Boiler TX pin
GPIO_WINDMETER_SPEED, // WindMeter speed counter pin
GPIO_BL0940_RX, // BL0940 serial interface
- GPIO_TELEINFO_RX, // BL0940 serial interface
- GPIO_TELEINFO_ENABLE, // BL0940 serial interface
+ GPIO_TCP_TX, // TCP Serial bridge
+ GPIO_TCP_RX, // TCP Serial bridge
+ GPIO_TELEINFO_RX, // TELEINFO serial interface
+ GPIO_TELEINFO_ENABLE,// TELEINFO Enable PIN
+ GPIO_LMT01, // LMT01 input counting pin
GPIO_SENSOR_END };
// Programmer selectable GPIO functionality
@@ -314,7 +317,7 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|"
D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|"
D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|"
- D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" D_SENSOR_SLAVE_RESET "i|"
+ D_SENSOR_CLIENT_TX "|" D_SENSOR_CLIENT_RX "|" D_SENSOR_CLIENT_RESET "|" D_SENSOR_CLIENT_RESET "i|"
D_SENSOR_HPMA_RX "|" D_SENSOR_HPMA_TX "|"
D_SENSOR_GPS_RX "|" D_SENSOR_GPS_TX "|"
D_SENSOR_DS18X20 "o|" D_SENSOR_DHT11 "o|"
@@ -326,8 +329,10 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_AS3935 "|" D_SENSOR_PMS5003_TX "|"
D_SENSOR_BOILER_OT_RX "|" D_SENSOR_BOILER_OT_TX "|"
D_SENSOR_WINDMETER_SPEED "|"
- D_SENSOR_BL0940_RX "|"
- D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE
+ D_SENSOR_BL0940_RX "|"
+ D_SENSOR_TCP_TXD "|" D_SENSOR_TCP_RXD "|"
+ D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE "|"
+ D_SENSOR_LMT01_PULSE
;
const char kSensorNamesFixed[] PROGMEM =
@@ -427,8 +432,8 @@ const uint8_t kGpioNiceList[] PROGMEM = {
#ifdef USE_SPI
GPIO_SPI_CS, // SPI Chip Select
GPIO_SPI_DC, // SPI Data Direction
- GPIO_SSPI_MISO, // Software SPI Master Input Slave Output
- GPIO_SSPI_MOSI, // Software SPI Master Output Slave Input
+ GPIO_SSPI_MISO, // Software SPI Master Input Client Output
+ GPIO_SSPI_MOSI, // Software SPI Master Output Client Input
GPIO_SSPI_SCLK, // Software SPI Serial Clock
GPIO_SSPI_CS, // Software SPI Chip Select
GPIO_SSPI_DC, // Software SPI Data or Command
@@ -447,6 +452,9 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_DSB, // Single wire DS18B20 or DS18S20
GPIO_DSB_OUT, // Pseudo Single wire DS18B20 or DS18S20
#endif
+#ifdef USE_LMT01 // LMT01, count pulses on GPIO
+ GPIO_LMT01,
+#endif
// Light
#ifdef USE_LIGHT
@@ -577,6 +585,10 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_SBR_TX, // Serial Bridge Serial interface
GPIO_SBR_RX, // Serial Bridge Serial interface
#endif
+#ifdef USE_TCP_BRIDGE
+ GPIO_TCP_TX, // TCP Serial bridge
+ GPIO_TCP_RX, // TCP Serial bridge
+#endif
#ifdef USE_ZIGBEE
GPIO_ZIGBEE_TX, // Zigbee Serial interface
GPIO_ZIGBEE_RX, // Zigbee Serial interface
@@ -618,11 +630,11 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_PN532_TXD, // PN532 HSU Tx
GPIO_PN532_RXD, // PN532 HSU Rx
#endif
-#ifdef USE_TASMOTA_SLAVE
- GPIO_TASMOTASLAVE_TXD, // Tasmota Slave TX
- GPIO_TASMOTASLAVE_RXD, // Tasmota Slave RX
- GPIO_TASMOTASLAVE_RST, // Tasmota Slave Reset
- GPIO_TASMOTASLAVE_RST_INV, // Tasmota Slave Reset Inverted
+#ifdef USE_TASMOTA_CLIENT
+ GPIO_TASMOTACLIENT_TXD, // Tasmota Client TX
+ GPIO_TASMOTACLIENT_RXD, // Tasmota Client RX
+ GPIO_TASMOTACLIENT_RST, // Tasmota Client Reset
+ GPIO_TASMOTACLIENT_RST_INV, // Tasmota Client Reset Inverted
#endif
#ifdef USE_RDM6300
GPIO_RDM6300_RX,
@@ -689,7 +701,6 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_TELEINFO_RX,
GPIO_TELEINFO_ENABLE,
#endif
-
};
/********************************************************************************************/
@@ -777,8 +788,8 @@ enum SupportedModules {
SUPLA1, WITTY, YUNSHAN, MAGICHOME, LUANIHVIO, KMC_70011, ARILUX_LC01, ARILUX_LC11, SONOFF_DUAL_R2, ARILUX_LC06,
SONOFF_S31, ZENGGE_ZF_WF017, SONOFF_POW_R2, SONOFF_IFAN02, BLITZWOLF_BWSHP, SHELLY1, SHELLY2, PHILIPS, NEO_COOLCAM, ESP_SWITCH,
OBI, TECKIN, APLIC_WDP303075, TUYA_DIMMER, GOSUND, ARMTRONIX_DIMMERS, SK03_TUYA, PS_16_DZ, TECKIN_US, MANZOKU_EU_4,
- OBI2, YTF_IR_BRIDGE, DIGOO, KA10, ZX2820, MI_DESK_LAMP, SP10, WAGA, SYF05, SONOFF_L1,
- SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1, DENKY,
+ OBI2, YTF_IR_BRIDGE, DIGOO, KA10, ZX2820, MI_DESK_LAMP, SP10, WAGA, SYF05, SONOFF_L1,
+ SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1,
MAXMODULE};
#define USER_MODULE 255
@@ -791,7 +802,7 @@ const char kModuleNames[] PROGMEM =
"Sonoff S31|Zengge WF017|Sonoff Pow R2|Sonoff iFan02|BlitzWolf SHP|Shelly 1|Shelly 2|Xiaomi Philips|Neo Coolcam|ESP Switch|"
"OBI Socket|Teckin|AplicWDP303075|Tuya MCU|Gosund SP1 v23|ARMTR Dimmer|SK03 Outdoor|PS-16-DZ|Teckin US|Manzoku strip|"
"OBI Socket 2|YTF IR Bridge|Digoo DG-SP202|KA10|Luminea ZX2820|Mi Desk Lamp|SP10|WAGA CHCZ02MB|SYF05|Sonoff L1|"
- "Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1|Denky (Teleinfo)"
+ "Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1"
;
const uint8_t kModuleNiceList[] PROGMEM = {
@@ -2174,26 +2185,6 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_LED1_INV, // GPIO13 WiFi Blue Led - Link and Power status
0, 0, 0, 0
},
- { // Denky (Teleinfo) Any ESP8266 device
- GPIO_WS2812, // GPIO00 WS2812 RGB LED
- GPIO_USER, // GPIO01 TX Serial RXD
- GPIO_USER, // GPIO02 D4 Wemos DHT Shield
- GPIO_TELEINFO_RX, // GPIO03 Smart Meter RX Serial
- GPIO_I2C_SDA, // GPIO04 D2 Wemos I2C SDA
- GPIO_I2C_SCL, // GPIO05 D1 Wemos I2C SCL
- // GPIO06 (SD_CLK Flash)
- // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT)
- // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT)
- GPIO_USER, // GPIO09 (SD_DATA2 Flash QIO or ESP8285)
- GPIO_USER, // GPIO10 (SD_DATA3 Flash QIO or ESP8285)
- // GPIO11 (SD_CMD Flash)
- GPIO_USER, // GPIO12 D6
- GPIO_USER, // GPIO13 D7
- GPIO_USER, // GPIO14 D5
- GPIO_USER, // GPIO15 D8
- GPIO_USER, // GPIO16 D0 Wemos Wake
- ADC0_USER // ADC0 A0 Analog input
- },
{ // SONOFF_IFAN03 - Sonoff iFan03 (ESP8285)
GPIO_KEY1, // GPIO00 WIFI_KEY0 Button 1
GPIO_TXD, // GPIO01 ESP_TXD Serial RXD connection to P0.5 of RF microcontroller
@@ -2278,10 +2269,8 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_LED1_INV, // GPIO13 WiFi Blue Led - Link and Power status
0, 0, 0, 0
}
-
};
-
#endif // ESP8266
#ifdef ESP32
diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h
index 6571dec1c..1db249ed3 100644
--- a/tasmota/tasmota_template_ESP32.h
+++ b/tasmota/tasmota_template_ESP32.h
@@ -102,8 +102,8 @@ enum UserSelectablePins {
GPIO_SM2135_CLK, GPIO_SM2135_DAT, // SM2135 PWM controller
GPIO_DEEPSLEEP, // Kill switch for deepsleep
GPIO_EXS_ENABLE, // EXS MCU Enable
- GPIO_TASMOTASLAVE_TXD, GPIO_TASMOTASLAVE_RXD, // Slave Serial interface
- GPIO_TASMOTASLAVE_RST, GPIO_TASMOTASLAVE_RST_INV, // Slave Reset
+ GPIO_TASMOTACLIENT_TXD, GPIO_TASMOTACLIENT_RXD, // Client Serial interface
+ GPIO_TASMOTACLIENT_RST, GPIO_TASMOTACLIENT_RST_INV, // Client Reset
GPIO_HPMA_RX, GPIO_HPMA_TX, // Honeywell HPMA115S0 Serial interface
GPIO_GPS_RX, GPIO_GPS_TX, // GPS Serial interface
GPIO_HM10_RX, GPIO_HM10_TX, // HM10-BLE-Mijia-bridge Serial interface
@@ -133,6 +133,7 @@ enum UserSelectablePins {
GPIO_ETH_PHY_POWER, GPIO_ETH_PHY_MDC, GPIO_ETH_PHY_MDIO, // Ethernet
GPIO_TELEINFO_RX, // Teleinfo telemetry data receive pin
GPIO_TELEINFO_ENABLE, // Teleinfo Enable Receive Pin
+ GPIO_LMT01, // LMT01 input counting pin
GPIO_SENSOR_END };
enum ProgramSelectablePins {
@@ -199,7 +200,7 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|"
D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|"
D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|"
- D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" D_SENSOR_SLAVE_RESET "_i|"
+ D_SENSOR_CLIENT_TX "|" D_SENSOR_CLIENT_RX "|" D_SENSOR_CLIENT_RESET "|" D_SENSOR_CLIENT_RESET "_i|"
D_SENSOR_HPMA_RX "|" D_SENSOR_HPMA_TX "|"
D_SENSOR_GPS_RX "|" D_SENSOR_GPS_TX "|"
D_SENSOR_HM10_RX "|" D_SENSOR_HM10_TX "|"
@@ -225,7 +226,8 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_BL0940_RX "|"
D_SENSOR_TCP_TXD "|" D_SENSOR_TCP_RXD "|"
D_SENSOR_ETH_PHY_POWER "|" D_SENSOR_ETH_PHY_MDC "|" D_SENSOR_ETH_PHY_MDIO "|"
- D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE
+ D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE "|"
+ D_SENSOR_LMT01_PULSE
;
const char kSensorNamesFixed[] PROGMEM =
@@ -269,8 +271,8 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_SPI_CLK), // SPI Clk
AGPIO(GPIO_SPI_CS), // SPI Chip Select
AGPIO(GPIO_SPI_DC), // SPI Data Direction
- AGPIO(GPIO_SSPI_MISO), // Software SPI Master Input Slave Output
- AGPIO(GPIO_SSPI_MOSI), // Software SPI Master Output Slave Input
+ AGPIO(GPIO_SSPI_MISO), // Software SPI Master Input Client Output
+ AGPIO(GPIO_SSPI_MOSI), // Software SPI Master Output Client Input
AGPIO(GPIO_SSPI_SCLK), // Software SPI Serial Clock
AGPIO(GPIO_SSPI_CS), // Software SPI Chip Select
AGPIO(GPIO_SSPI_DC), // Software SPI Data or Command
@@ -293,6 +295,9 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_DSB), // Single wire DS18B20 or DS18S20
AGPIO(GPIO_DSB_OUT), // Pseudo Single wire DS18B20 or DS18S20
#endif
+#ifdef USE_LMT01
+ AGPIO(GPIO_LMT01), // LMT01, count pulses on GPIO
+#endif
// Light
#ifdef USE_LIGHT
@@ -468,11 +473,11 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_PN532_TXD), // PN532 HSU Tx
AGPIO(GPIO_PN532_RXD), // PN532 HSU Rx
#endif
-#ifdef USE_TASMOTA_SLAVE
- AGPIO(GPIO_TASMOTASLAVE_TXD), // Tasmota Slave TX
- AGPIO(GPIO_TASMOTASLAVE_RXD), // Tasmota Slave RX
- AGPIO(GPIO_TASMOTASLAVE_RST), // Tasmota Slave Reset
- AGPIO(GPIO_TASMOTASLAVE_RST_INV), // Tasmota Slave Reset Inverted
+#ifdef USE_TASMOTA_CLIENT
+ AGPIO(GPIO_TASMOTACLIENT_TXD), // Tasmota Client TX
+ AGPIO(GPIO_TASMOTACLIENT_RXD), // Tasmota Client RX
+ AGPIO(GPIO_TASMOTACLIENT_RST), // Tasmota Client Reset
+ AGPIO(GPIO_TASMOTACLIENT_RST_INV), // Tasmota Client Reset Inverted
#endif
#ifdef USE_RDM6300
AGPIO(GPIO_RDM6300_RX),
@@ -685,12 +690,12 @@ const mytmplt kModules PROGMEM =
/*********************************************************************************************\
Known templates
-{"NAME":"AITHINKER CAM","GPIO":[4992,65504,65504,65504,65504,5088,65504,65504,65504,65504,65504,65504,65504,65504,5089,5090,0,5091,5184,5152,0,5120,5024,5056,0,0,0,0,4928,65504,5094,5095,5092,0,0,5093],"FLAG":0,"BASE":1}
-{"NAME":"Olimex ESP32-PoE","GPIO":[65504,65504,65504,65504,65504,65504,0,0,5536,65504,65504,65504,65504,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,65504,65504,65504,65504,65504,0,0,65504],"FLAG":0,"BASE":1}
+{"NAME":"AITHINKER CAM","GPIO":[4992,1,1,1,1,5088,1,1,1,1,1,1,1,1,5089,5090,0,5091,5184,5152,0,5120,5024,5056,0,0,0,0,4928,1,5094,5095,5092,0,0,5093],"FLAG":0,"BASE":1}
+{"NAME":"Olimex ESP32-PoE","GPIO":[1,1,1,1,1,1,0,0,5536,1,1,1,1,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
+{"NAME":"wESP32","GPIO":[1,1,1,1,1,1,0,0,0,1,1,1,5568,5600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
\*********************************************************************************************/
-
#endif // ESP32
#endif // _TASMOTA_TEMPLATE_ESP32_H_
diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h
index 1b21293b2..6b64471b0 100644
--- a/tasmota/tasmota_version.h
+++ b/tasmota/tasmota_version.h
@@ -20,7 +20,7 @@
#ifndef _TASMOTA_VERSION_H_
#define _TASMOTA_VERSION_H_
-const uint32_t VERSION = 0x08030102;
+const uint32_t VERSION = 0x08030106;
// Lowest compatible version
const uint32_t VERSION_COMPATIBLE = 0x07010006;
diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino
index 7fcd82a9f..d18368431 100644
--- a/tasmota/xdrv_01_webserver.ino
+++ b/tasmota/xdrv_01_webserver.ino
@@ -44,7 +44,7 @@ const uint16_t HTTP_OTA_RESTART_RECONNECT_TIME = 28000; // milliseconds - Allow
uint8_t *efm8bb1_update = nullptr;
#endif // USE_RF_FLASH
-enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTASLAVE };
+enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTACLIENT };
static const char * HEADER_KEYS[] = { "User-Agent", };
@@ -868,10 +868,16 @@ void StartWebserver(int type, IPAddress ipweb)
if (Web.state != type) {
#if LWIP_IPV6
String ipv6_addr = WifiGetIPv6();
- if(ipv6_addr!="") AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str(),ipv6_addr.c_str());
- else AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str());
+ if (ipv6_addr!="") {
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "),
+ NetworkHostname(), (Mdns.begun) ? ".local" : "", ipweb.toString().c_str(), ipv6_addr.c_str());
+ } else {
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
+ NetworkHostname(), (Mdns.begun) ? ".local" : "", ipweb.toString().c_str());
+ }
#else
- AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str());
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
+ NetworkHostname(), (Mdns.begun) ? ".local" : "", ipweb.toString().c_str());
#endif // LWIP_IPV6 = 1
rules_flag.http_init = 1;
}
@@ -1151,8 +1157,8 @@ void WSContentSendStyle_P(const char* formatP, ...)
bool lip = (static_cast(WiFi.localIP()) != 0);
bool sip = (static_cast(WiFi.softAPIP()) != 0);
WSContentSend_P(PSTR("%s%s (%s%s%s)
"), // tasmota.local (192.168.2.12, 192.168.4.1)
- my_hostname,
- (Wifi.mdns_begun) ? ".local" : "",
+ NetworkHostname(),
+ (Mdns.begun) ? ".local" : "",
(lip) ? WiFi.localIP().toString().c_str() : "",
(lip && sip) ? ", " : "",
(sip) ? WiFi.softAPIP().toString().c_str() : "");
@@ -2016,8 +2022,8 @@ void ModuleSaveSettings(void)
/*-------------------------------------------------------------------------------------------*/
-const char kUnescapeCode[] = "&><\"\'";
-const char kEscapeCode[] PROGMEM = "&|>|<|"|'";
+const char kUnescapeCode[] = "&><\"\'\\";
+const char kEscapeCode[] PROGMEM = "&|>|<|"|'|\";
String HtmlEscape(const String unescaped) {
char escaped[10];
@@ -2321,22 +2327,6 @@ void OtherSaveSettings(void)
}
AddLog_P(LOG_LEVEL_INFO, message);
-/*
- // This sometimes provides intermittent watchdog
- bool template_activate = Webserver->hasArg("t2"); // Try this to tackle intermittent watchdog after execution of Template command
- WebGetArg("t1", tmp, sizeof(tmp));
- if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255}
- char svalue[128];
- snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_TEMPLATE " %s"), tmp);
- ExecuteWebCommand(svalue, SRC_WEBGUI);
-
- if (template_activate) {
- snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_MODULE " 0"));
- ExecuteWebCommand(svalue, SRC_WEBGUI);
- }
- }
- // Try async execution of commands
-*/
WebGetArg("t1", tmp, sizeof(tmp));
if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255}
snprintf_P(message, sizeof(message), PSTR(D_CMND_BACKLOG " " D_CMND_TEMPLATE " %s%s"), tmp, (Webserver->hasArg("t2")) ? "; " D_CMND_MODULE " 0" : "");
@@ -2471,26 +2461,42 @@ void HandleInformation(void)
WSContentSend_P(PSTR("}1" D_FRIENDLY_NAME " %d}2%s"), i +1, SettingsText(SET_FRIENDLYNAME1 +i));
}
WSContentSend_P(PSTR("}1}2 ")); // Empty line
- int32_t rssi = WiFi.RSSI();
- WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WifiGetRssiAsQuality(rssi), rssi);
- WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "");
+#ifdef ESP32
+#ifdef USE_ETHERNET
+ if (static_cast(EthernetLocalIP()) != 0) {
+ WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? ".local" : "");
+ WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), EthernetMacAddress().c_str());
+ WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (eth)}2%s"), EthernetLocalIP().toString().c_str());
+ WSContentSend_P(PSTR("}1
}2
"));
+ }
+#endif
+#endif
+ if (Settings.flag4.network_wifi) {
+ int32_t rssi = WiFi.RSSI();
+ WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings.sta_active)).c_str(), WifiGetRssiAsQuality(rssi), rssi);
+ WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), my_hostname, (Mdns.begun) ? ".local" : "");
#if LWIP_IPV6
String ipv6_addr = WifiGetIPv6();
- if(ipv6_addr != ""){
+ if (ipv6_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Address }2%s"), ipv6_addr.c_str());
}
#endif
- if (static_cast(WiFi.localIP()) != 0) {
- WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.localIP().toString().c_str());
+ if (static_cast(WiFi.localIP()) != 0) {
+ WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str());
+ WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (wifi)}2%s"), WiFi.localIP().toString().c_str());
+ WSContentSend_P(PSTR("}1
}2
"));
+ }
+ }
+ if (!global_state.network_down) {
WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), IPAddress(Settings.ip_address[1]).toString().c_str());
WSContentSend_P(PSTR("}1" D_SUBNET_MASK "}2%s"), IPAddress(Settings.ip_address[2]).toString().c_str());
WSContentSend_P(PSTR("}1" D_DNS_SERVER "}2%s"), IPAddress(Settings.ip_address[3]).toString().c_str());
- WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str());
}
- if (static_cast(WiFi.softAPIP()) != 0) {
- WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.softAPIP().toString().c_str());
- WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), WiFi.softAPIP().toString().c_str());
+ if ((WiFi.getMode() >= WIFI_AP) && (static_cast(WiFi.softAPIP()) != 0)) {
+ WSContentSend_P(PSTR("}1
}2
"));
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.softAPmacAddress().c_str());
+ WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (AP)}2%s"), WiFi.softAPIP().toString().c_str());
+ WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), WiFi.softAPIP().toString().c_str());
}
WSContentSend_P(PSTR("}1}2 ")); // Empty line
if (Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT
@@ -2645,8 +2651,8 @@ void HandleUploadDone(void)
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "
"), WebColor(COL_TEXT_SUCCESS));
WSContentSend_P(HTTP_MSG_RSTRT);
ShowWebSource(SRC_WEBGUI);
-#ifdef USE_TASMOTA_SLAVE
- if (TasmotaSlave_GetFlagFlashing()) {
+#ifdef USE_TASMOTA_CLIENT
+ if (TasmotaClient_GetFlagFlashing()) {
restart_flag = 0;
} else { // It was a normal firmware file, or we are ready to restart device
restart_flag = 2;
@@ -2659,9 +2665,9 @@ void HandleUploadDone(void)
WSContentSend_P(PSTR("
"));
WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
-#ifdef USE_TASMOTA_SLAVE
- if (TasmotaSlave_GetFlagFlashing()) {
- TasmotaSlave_Flash();
+#ifdef USE_TASMOTA_CLIENT
+ if (TasmotaClient_GetFlagFlashing()) {
+ TasmotaClient_Flash();
}
#endif
}
@@ -2731,11 +2737,11 @@ void HandleUploadLoop(void)
if (Web.upload_error != 0) { return; }
} else
#endif // USE_RF_FLASH
-#ifdef USE_TASMOTA_SLAVE
- if ((WEMOS == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a ARDUINO SLAVE hex file
+#ifdef USE_TASMOTA_CLIENT
+ if ((WEMOS == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a ARDUINO CLIENT hex file
Update.end(); // End esp8266 update session
- Web.upload_file_type = UPL_TASMOTASLAVE;
- Web.upload_error = TasmotaSlave_UpdateInit(); // 0
+ Web.upload_file_type = UPL_TASMOTACLIENT;
+ Web.upload_error = TasmotaClient_UpdateInit(); // 0
if (Web.upload_error != 0) { return; }
} else
#endif
@@ -2799,9 +2805,9 @@ void HandleUploadLoop(void)
}
}
#endif // USE_RF_FLASH
-#ifdef USE_TASMOTA_SLAVE
- else if (UPL_TASMOTASLAVE == Web.upload_file_type) {
- TasmotaSlave_WriteBuffer(upload.buf, upload.currentSize);
+#ifdef USE_TASMOTA_CLIENT
+ else if (UPL_TASMOTACLIENT == Web.upload_file_type) {
+ TasmotaClient_WriteBuffer(upload.buf, upload.currentSize);
}
#endif
else { // firmware
@@ -2865,10 +2871,10 @@ void HandleUploadLoop(void)
Web.upload_file_type = UPL_TASMOTA;
}
#endif // USE_RF_FLASH
-#ifdef USE_TASMOTA_SLAVE
- else if (UPL_TASMOTASLAVE == Web.upload_file_type) {
+#ifdef USE_TASMOTA_CLIENT
+ else if (UPL_TASMOTACLIENT == Web.upload_file_type) {
// Done writing the hex to SPI flash
- TasmotaSlave_SetFlagFlashing(true); // So we know on upload success page if it needs to flash hex or do a normal restart
+ TasmotaClient_SetFlagFlashing(true); // So we know on upload success page if it needs to flash hex or do a normal restart
Web.upload_file_type = UPL_TASMOTA;
}
#endif
@@ -3288,7 +3294,7 @@ void CmndWebServer(void)
}
if (Settings.webserver) {
Response_P(PSTR("{\"" D_CMND_WEBSERVER "\":\"" D_JSON_ACTIVE_FOR " %s " D_JSON_ON_DEVICE " %s " D_JSON_WITH_IP_ADDRESS " %s\"}"),
- (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str());
+ (2 == Settings.webserver) ? D_ADMIN : D_USER, NetworkHostname(), NetworkAddress().toString().c_str());
} else {
ResponseCmndStateText(0);
}
diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino
index 9e06f4e90..7a7eae075 100644
--- a/tasmota/xdrv_02_mqtt.ino
+++ b/tasmota/xdrv_02_mqtt.ino
@@ -123,34 +123,6 @@ void MakeValidMqtt(uint32_t option, char* str)
}
}
-#ifdef USE_DISCOVERY
-#ifdef MQTT_HOST_DISCOVERY
-void MqttDiscoverServer(void)
-{
- if (!Wifi.mdns_begun) { return; }
-
- int n = MDNS.queryService("mqtt", "tcp"); // Search for mqtt service
-
- AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n);
-
- if (n > 0) {
- uint32_t i = 0; // If the hostname isn't set, use the first record found.
-#ifdef MDNS_HOSTNAME
- for (i = n; i > 0; i--) { // Search from last to first and use first if not found
- if (!strcmp(MDNS.hostname(i).c_str(), MDNS_HOSTNAME)) {
- break; // Stop at matching record
- }
- }
-#endif // MDNS_HOSTNAME
- SettingsUpdateText(SET_MQTT_HOST, MDNS.IP(i).toString().c_str());
- Settings.mqtt_port = MDNS.port(i);
-
- AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"), MDNS.hostname(i).c_str(), SettingsText(SET_MQTT_HOST), Settings.mqtt_port);
- }
-}
-#endif // MQTT_HOST_DISCOVERY
-#endif // USE_DISCOVERY
-
/*********************************************************************************************\
* MQTT driver specific code need to provide the following functions:
*
@@ -539,10 +511,10 @@ void MqttConnected(void)
if (Settings.webserver) {
#if LWIP_IPV6
Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"IPv6Address\":\"%s\"}"),
- (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str(),WifiGetIPv6().c_str());
+ (2 == Settings.webserver) ? D_ADMIN : D_USER, NetworkHostname(), NetworkAddress().toString().c_str(), WifiGetIPv6().c_str());
#else
Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"),
- (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str());
+ (2 == Settings.webserver) ? D_ADMIN : D_USER, NetworkHostname(), NetworkAddress().toString().c_str());
#endif // LWIP_IPV6 = 1
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "2"));
}
diff --git a/tasmota/xdrv_03_energy.ino b/tasmota/xdrv_03_energy.ino
index f5e4a729d..b84d69407 100644
--- a/tasmota/xdrv_03_energy.ino
+++ b/tasmota/xdrv_03_energy.ino
@@ -459,7 +459,12 @@ void EnergyEverySecond(void)
{
// Overtemp check
if (global_update) {
- if (power && (global_temperature != 9999) && (global_temperature > Settings.param[P_OVER_TEMP])) { // Device overtemp, turn off relays
+ if (power && !isnan(global_temperature) && (global_temperature > (float)Settings.param[P_OVER_TEMP])) { // Device overtemp, turn off relays
+
+ char temperature[33];
+ dtostrfd(global_temperature, 1, temperature);
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NRG: GlobTemp %s"), temperature);
+
SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP);
}
}
@@ -1137,6 +1142,9 @@ bool Xdrv03(uint8_t function)
case FUNC_EVERY_250_MSECOND:
XnrgCall(FUNC_EVERY_250_MSECOND);
break;
+ case FUNC_EVERY_SECOND:
+ XnrgCall(FUNC_EVERY_SECOND);
+ break;
case FUNC_SERIAL:
result = XnrgCall(FUNC_SERIAL);
break;
diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino
index 1d6ac6a58..a8eaf9629 100644
--- a/tasmota/xdrv_04_light.ino
+++ b/tasmota/xdrv_04_light.ino
@@ -1555,10 +1555,10 @@ void LightState(uint8_t append)
if (!Light.pwm_multi_channels) {
if (unlinked) {
// RGB and W are unlinked, we display the second Power/Dimmer
- ResponseAppend_P(PSTR("\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d"
- ",\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d"),
- Light.device, GetStateText(Light.power & 1), Light.device, light_state.getDimmer(1),
- Light.device + 1, GetStateText(Light.power & 2 ? 1 : 0), Light.device + 1, light_state.getDimmer(2));
+ ResponseAppend_P(PSTR("\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "1\":%d"
+ ",\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "2\":%d"),
+ Light.device, GetStateText(Light.power & 1), light_state.getDimmer(1),
+ Light.device + 1, GetStateText(Light.power & 2 ? 1 : 0), light_state.getDimmer(2));
} else {
GetPowerDevice(scommand, Light.device, sizeof(scommand), Settings.flag.device_index_enable); // SetOption26 - Switch between POWER or POWER1
ResponseAppend_P(PSTR("\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d"), scommand, GetStateText(Light.power & 1),
diff --git a/tasmota/xdrv_10_rules.ino b/tasmota/xdrv_10_rules.ino
index 10c4c22e8..37300d03c 100644
--- a/tasmota/xdrv_10_rules.ino
+++ b/tasmota/xdrv_10_rules.ino
@@ -887,17 +887,18 @@ void RulesEvery50ms(void)
rules_flag.data ^= mask;
json_event[0] = '\0';
switch (i) {
- case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break;
- case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), MinutesPastMidnight()); break;
- case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), MinutesPastMidnight()); break;
- case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break;
- case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
- case 5: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break;
- case 6: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
- case 7: strncpy_P(json_event, PSTR("{\"HTTP\":{\"Initialized\":1}}"), sizeof(json_event)); break;
+ case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Init\":1}}"), sizeof(json_event)); break;
+ case 1: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break;
+ case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), MinutesPastMidnight()); break;
+ case 3: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), MinutesPastMidnight()); break;
+ case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break;
+ case 5: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
+ case 6: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break;
+ case 7: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
+ case 8: strncpy_P(json_event, PSTR("{\"HTTP\":{\"Initialized\":1}}"), sizeof(json_event)); break;
#ifdef USE_SHUTTER
- case 8: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moved\":1}}"), sizeof(json_event)); break;
- case 9: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moving\":1}}"), sizeof(json_event)); break;
+ case 9: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moved\":1}}"), sizeof(json_event)); break;
+ case 10: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moving\":1}}"), sizeof(json_event)); break;
#endif // USE_SHUTTER
}
if (json_event[0]) {
diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino
index 5a79d50b5..921433a6d 100755
--- a/tasmota/xdrv_10_scripter.ino
+++ b/tasmota/xdrv_10_scripter.ino
@@ -26,7 +26,6 @@ uses about 17 k of flash
to do
optimize code for space
-g:var gloabal vars (via udp broadcast)
remarks
@@ -68,6 +67,8 @@ keywords if then else endif, or, and are better readable for beginners (others m
uint32_t EncodeLightId(uint8_t relay_id);
uint32_t DecodeLightId(uint32_t hue_id);
+
+
// solve conficting defines
// highest priority
#ifdef USE_SCRIPT_FATFS
@@ -119,6 +120,31 @@ uint32_t DecodeLightId(uint32_t hue_id);
#endif
#endif // USE_UNISHOX_COMPRESSION
+#ifdef USE_SCRIPT_TIMER
+#include
+Ticker Script_ticker1;
+Ticker Script_ticker2;
+Ticker Script_ticker3;
+Ticker Script_ticker4;
+
+void Script_ticker1_end(void) {
+ Script_ticker1.detach();
+ Run_Scripter(">ti1", 4,0);
+}
+void Script_ticker2_end(void) {
+ Script_ticker2.detach();
+ Run_Scripter(">ti2", 4,0);
+}
+void Script_ticker3_end(void) {
+ Script_ticker3.detach();
+ Run_Scripter(">ti3", 4,0);
+}
+void Script_ticker4_end(void) {
+ Script_ticker4.detach();
+ Run_Scripter(">ti4", 4,0);
+}
+#endif
+
#if defined(LITTLEFS_SCRIPT_SIZE) || (USE_SCRIPT_FATFS==-1)
#ifdef ESP32
@@ -237,7 +263,11 @@ extern VButton *buttons[MAXBUTTONS];
#endif
typedef union {
+#ifdef USE_SCRIPT_GLOBVARS
+ uint16_t data;
+#else
uint8_t data;
+#endif
struct {
uint8_t is_string : 1; // string or number
uint8_t is_permanent : 1;
@@ -247,6 +277,9 @@ typedef union {
uint8_t settable : 1;
uint8_t is_filter : 1;
uint8_t constant : 1;
+#ifdef USE_SCRIPT_GLOBVARS
+ uint8_t global : 1;
+#endif
};
} SCRIPT_TYPE;
@@ -276,6 +309,32 @@ typedef union {
};
} FILE_FLAGS;
+typedef union {
+ uint8_t data;
+ struct {
+ uint8_t nutu8 : 1;
+ uint8_t nutu7 : 1;
+ uint8_t nutu6 : 1;
+ uint8_t nutu5 : 1;
+ uint8_t nutu4 : 1;
+ uint8_t nutu3 : 1;
+ uint8_t udp_connected : 1;
+ uint8_t udp_used : 1;
+ };
+} UDP_FLAGS;
+
+
+#define NUM_RES 0xfe
+#define STR_RES 0xfd
+#define VAR_NV 0xff
+
+#define NTYPE 0
+#define STYPE 0x80
+
+#ifndef FLT_MAX
+#define FLT_MAX 99999999
+#endif
+
#define SFS_MAX 4
// global memory
struct SCRIPT_MEM {
@@ -308,12 +367,19 @@ struct SCRIPT_MEM {
uint8_t script_sd_found;
char flink[2][14];
#endif
+#ifdef USE_SCRIPT_GLOBVARS
+ UDP_FLAGS udp_flags;
+#endif
} glob_script_mem;
+#ifdef USE_SCRIPT_GLOBVARS
+IPAddress last_udp_ip;
+#endif
int16_t last_findex;
uint8_t tasm_cmd_activ=0;
uint8_t fast_script=0;
+uint8_t glob_script=0;
uint32_t script_lastmillis;
@@ -331,7 +397,7 @@ void ScriptEverySecond(void) {
if (bitRead(Settings.rule_enabled, 0)) {
struct T_INDEX *vtp=glob_script_mem.type;
- float delta=(millis()-script_lastmillis)/1000;
+ float delta=(millis()-script_lastmillis)/1000.0;
script_lastmillis=millis();
for (uint8_t count=0; countG",-2,0);
+ }
+#endif
+
return 0;
}
+#ifdef USE_SCRIPT_GLOBVARS
+#define SCRIPT_UDP_BUFFER_SIZE 128
+#define SCRIPT_UDP_PORT 1999
+IPAddress script_udp_remote_ip;
+
+void Script_Init_UDP() {
+ if (global_state.network_down) return;
+ if (glob_script_mem.udp_flags.udp_connected) return;
+
+ if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), SCRIPT_UDP_PORT)) {
+ AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP "SCRIPT UDP started"));
+ glob_script_mem.udp_flags.udp_connected = 1;
+ } else {
+ AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP "SCRIPT UDP failed"));
+ glob_script_mem.udp_flags.udp_connected = 0;
+ }
+}
+void Script_PollUdp(void) {
+ if (!glob_script_mem.udp_flags.udp_used) return;
+ if (glob_script_mem.udp_flags.udp_connected ) {
+ while (PortUdp.parsePacket()) {
+ char packet_buffer[SCRIPT_UDP_BUFFER_SIZE];
+ int32_t len = PortUdp.read(packet_buffer, SCRIPT_UDP_BUFFER_SIZE -1);
+ packet_buffer[len] = 0;
+ script_udp_remote_ip = PortUdp.remoteIP();
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("UDP: Packet %s - %d - %s"), packet_buffer, len, script_udp_remote_ip.toString().c_str());
+ char *lp=packet_buffer;
+ if (!strncmp(lp,"=>",2)) {
+ lp+=2;
+ char *cp=strchr(lp,'=');
+ if (cp) {
+ char vnam[32];
+ for (uint32_t count=0; countG",2,0);
+ }
+ }
+ }
+ }
+ optimistic_yield(100);
+ }
+ } else {
+ Script_Init_UDP();
+ }
+}
+
+void script_udp_sendvar(char *vname,float *fp,char *sp) {
+ if (!glob_script_mem.udp_flags.udp_used) return;
+ if (!glob_script_mem.udp_flags.udp_connected) return;
+
+ char sbuf[SCRIPT_MAXSSIZE+4];
+ strcpy(sbuf,"=>");
+ strcat(sbuf,vname);
+ strcat(sbuf,"=");
+ if (fp) {
+ char flstr[16];
+ dtostrfd(*fp,8,flstr);
+ strcat(sbuf,flstr);
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("num var updated - %s"),sbuf);
+ } else {
+ strcat(sbuf,sp);
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("string var updated - %s"),sbuf);
+ }
+ PortUdp.beginPacket(IPAddress(239,255,255,250), SCRIPT_UDP_PORT);
+ // Udp.print(String("RET UC: ") + String(recv_Packet));
+ PortUdp.write((const uint8_t*)sbuf,strlen(sbuf));
+ PortUdp.endPacket();
+}
+
+#endif
+
#ifdef USE_LIGHT
#ifdef USE_WS2812
void ws2812_set_array(float *array ,uint32_t len, uint32_t offset) {
@@ -723,16 +901,7 @@ void ws2812_set_array(float *array ,uint32_t len, uint32_t offset) {
#endif
#endif
-#define NUM_RES 0xfe
-#define STR_RES 0xfd
-#define VAR_NV 0xff
-#define NTYPE 0
-#define STYPE 0x80
-
-#ifndef FLT_MAX
-#define FLT_MAX 99999999
-#endif
float median_array(float *array,uint8_t len) {
uint8_t ind[len];
@@ -1011,6 +1180,37 @@ uint32_t MeasurePulseTime(int32_t in) {
}
#endif // USE_ANGLE_FUNC
+#ifdef USE_SCRIPT_GLOBVARS
+uint32_t match_vars(char *dvnam, float **fp, char **sp, uint32_t *ind) {
+ uint16_t olen=strlen(dvnam);
+ struct T_INDEX *vtp=glob_script_mem.type;
+ for (uint32_t count=0; count ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number
// no flash strings here for performance reasons!!!
char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,JsonObject *jo) {
@@ -1703,6 +1903,20 @@ chknext:
if (sp) strlcpy(sp,SettingsText(SET_MQTT_GRP_TOPIC),glob_script_mem.max_ssize);
goto strexit;
}
+
+#ifdef SCRIPT_GET_HTTPS_JP
+ if (!strncmp(vname,"gjp(",4)) {
+ char host[SCRIPT_MAXSSIZE];
+ lp=GetStringResult(lp+4,OPER_EQU,host,0);
+ SCRIPT_SKIP_SPACES
+ char path[SCRIPT_MAXSSIZE];
+ lp=GetStringResult(lp,OPER_EQU,path,0);
+ fvar=call2https(host,path);
+ lp++;
+ len=0;
+ goto exit;
+ }
+#endif
break;
case 'h':
if (!strncmp(vname,"hours",5)) {
@@ -1765,12 +1979,40 @@ chknext:
len=0;
goto exit;
}
+ if (!strncmp(vname,"is(",3)) {
+ lp=GetNumericResult(lp+3,OPER_EQU,&fvar,0);
+ SCRIPT_SKIP_SPACES
+ if (*lp!='"') {
+ break;
+ }
+ lp++;
+ char *sstr=lp;
+ for (uint32_t cnt=0; cnt<256; cnt++) {
+ if (lp[cnt]='\n' || lp[cnt]=='"') {
+ lp+=cnt+1;
+ break;
+ }
+ }
+ char str[SCRIPT_MAXSSIZE];
+ GetTextIndexed(str, sizeof(str), fvar, sstr);
+ lp++;
+ if (sp) strlcpy(sp,str,glob_script_mem.max_ssize);
+ fvar=0;
+ len=0;
+ goto exit;
+ }
break;
case 'l':
if (!strncmp(vname,"lip",3)) {
if (sp) strlcpy(sp,(const char*)WiFi.localIP().toString().c_str(),glob_script_mem.max_ssize);
goto strexit;
}
+#ifdef USE_SCRIPT_GLOBVARS
+ if (!strncmp(vname,"luip",4)) {
+ if (sp) strlcpy(sp,IPAddressToString(last_udp_ip),glob_script_mem.max_ssize);
+ goto strexit;
+ }
+#endif
if (!strncmp(vname,"loglvl",6)) {
fvar=glob_script_mem.script_loglevel;
tind->index=SCRIPT_LOGLEVEL;
@@ -2209,6 +2451,41 @@ chknext:
if (sp) strlcpy(sp,SettingsText(SET_MQTT_TOPIC),glob_script_mem.max_ssize);
goto strexit;
}
+#ifdef USE_SCRIPT_TIMER
+ if (!strncmp(vname,"ts1(",4)) {
+ lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0);
+ if (fvar<10) fvar=10;
+ Script_ticker1.attach_ms(fvar, Script_ticker1_end);
+ lp++;
+ len=0;
+ goto exit;
+ }
+ if (!strncmp(vname,"ts2(",4)) {
+ lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0);
+ if (fvar<10) fvar=10;
+ Script_ticker2.attach_ms(fvar, Script_ticker2_end);
+ lp++;
+ len=0;
+ goto exit;
+ }
+ if (!strncmp(vname,"ts3(",4)) {
+ lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0);
+ if (fvar<10) fvar=10;
+ Script_ticker3.attach_ms(fvar, Script_ticker3_end);
+ lp++;
+ len=0;
+ goto exit;
+ }
+ if (!strncmp(vname,"ts4(",4)) {
+ lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0);
+ if (fvar<10) fvar=10;
+ Script_ticker4.attach_ms(fvar, Script_ticker4_end);
+ lp++;
+ len=0;
+ goto exit;
+ }
+#endif // USE_SCRIPT_TIMER
+
#ifdef USE_DISPLAY
#ifdef USE_TOUCH_BUTTONS
if (!strncmp(vname,"tbut[",5)) {
@@ -3167,7 +3444,7 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
if (!if_exe[ifstck] && if_state[ifstck]!=1) goto next_line;
#ifdef IFTHEN_DEBUG
- sprintf(tbuff,"stack=%d,exe=%d,state=%d,cmpres=%d execute line: ",ifstck,if_exe[ifstck],if_state[ifstck],if_result[ifstck]);
+ sdtoff(tbuff,"stack=%d,exe=%d,state=%d,cmpres=%d execute line: ",ifstck,if_exe[ifstck],if_state[ifstck],if_result[ifstck]);
toLogEOL(tbuff,lp);
#endif
@@ -3382,8 +3659,16 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
}
goto next_line;
} else {
+ char *vnp=lp;
lp=isvar(lp,&vtype,&ind,&sysvar,0,0);
if (vtype!=VAR_NV) {
+#ifdef USE_SCRIPT_GLOBVARS
+ char varname[16];
+ uint32_t vnl=(uint32_t)lp-(uint32)vnp;
+ strncpy(varname,vnp,vnl);
+ varname[vnl]=0;
+#endif
+
// found variable as result
globvindex=ind.index; // save destination var index here
globaindex=last_findex;
@@ -3451,6 +3736,11 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
}
// var was changed
glob_script_mem.type[globvindex].bits.changed=1;
+#ifdef USE_SCRIPT_GLOBVARS
+ if (glob_script_mem.type[globvindex].bits.global) {
+ script_udp_sendvar(varname,dfvar,0);
+ }
+#endif
if (glob_script_mem.type[globvindex].bits.is_filter) {
if (globaindex>=0) {
Set_MFVal(glob_script_mem.type[globvindex].index,globaindex,*dfvar);
@@ -3492,6 +3782,11 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
if (!glob_script_mem.var_not_found) {
// var was changed
glob_script_mem.type[globvindex].bits.changed=1;
+#ifdef USE_SCRIPT_GLOBVARS
+ if (glob_script_mem.type[globvindex].bits.global) {
+ script_udp_sendvar(varname,0,str);
+ }
+#endif
if (lastop==OPER_EQU) {
strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize);
} else if (lastop==OPER_PLSEQU) {
@@ -3979,8 +4274,7 @@ void ListDir(char *path, uint8_t depth) {
char path[48];
-void Script_FileUploadConfiguration(void)
-{
+void Script_FileUploadConfiguration(void) {
uint8_t depth=0;
strcpy(path,"/");
@@ -3995,17 +4289,6 @@ void Script_FileUploadConfiguration(void)
}
}
- void ScriptFileUploadSuccess(void) {
- WSContentStart_P(S_INFORMATION);
- WSContentSendStyle();
- WSContentSend_P(PSTR("" D_UPLOAD " " D_SUCCESSFUL "
"), WebColor(COL_TEXT_SUCCESS));
- WSContentSend_P(PSTR("
"));
- WSContentSend_P(PSTR("
"),"/upl",D_UPL_DONE);
- //WSContentSpaceButton(BUTTON_MAIN);
- WSContentStop();
- }
-
WSContentStart_P(S_SCRIPT_FILE_UPLOAD);
WSContentSendStyle();
WSContentSend_P(HTTP_FORM_FILE_UPLOAD,D_SDCARD_DIR);
@@ -4023,13 +4306,22 @@ void Script_FileUploadConfiguration(void)
Web.upload_error = 0;
}
+void ScriptFileUploadSuccess(void) {
+ WSContentStart_P(S_INFORMATION);
+ WSContentSendStyle();
+ WSContentSend_P(PSTR("" D_UPLOAD " " D_SUCCESSFUL "
"), WebColor(COL_TEXT_SUCCESS));
+ WSContentSend_P(PSTR("
"));
+ WSContentSend_P(PSTR(""),"/upl",D_UPL_DONE);
+ //WSContentSpaceButton(BUTTON_MAIN);
+ WSContentStop();
+}
+
+
File upload_file;
-
void script_upload(void) {
-
//AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: file upload"));
-
HTTPUpload& upload = Webserver->upload();
if (upload.status == UPLOAD_FILE_START) {
char npath[48];
@@ -4601,9 +4893,11 @@ void Script_Check_Hue(String *response) {
}
else {
if (hue_devs>0) *response+=",\"";
+ else *response+="\"";
}
*response+=String(EncodeLightId(hue_devs+devices_present+1))+"\":";
Script_HueStatus(response,hue_devs);
+ //AddLog_P2(LOG_LEVEL_INFO, PSTR("Hue: %s - %d "),response->c_str(), hue_devs);
}
hue_devs++;
@@ -5902,6 +6196,62 @@ uint32_t scripter_create_task(uint32_t num, uint32_t time, uint32_t core) {
#endif // USE_SCRIPT_TASK
#endif // ESP32
+
+#ifdef SCRIPT_GET_HTTPS_JP
+#ifdef ESP8266
+#include "WiFiClientSecureLightBearSSL.h"
+#else
+#include
+#endif
+
+// get tesla powerwall info page json string
+uint32_t call2https(const char *host, const char *path) {
+ if (global_state.wifi_down) return 1;
+ uint32_t status=0;
+#ifdef ESP32
+ WiFiClientSecure *httpsClient;
+ httpsClient = new WiFiClientSecure;
+#else
+ BearSSL::WiFiClientSecure_light *httpsClient;
+ httpsClient = new BearSSL::WiFiClientSecure_light(1024, 1024);
+#endif
+
+ httpsClient->setTimeout(1500);
+
+ int retry = 0;
+ String result;
+ while ((!httpsClient->connect(host, 443)) && (retry < 5)) {
+ delay(100);
+ retry++;
+ }
+ if (retry == 5) {
+ return 2;
+ }
+ String request = String("GET ") + path +
+ " HTTP/1.1\r\n" +
+ "Host: " + host +
+ "\r\n" + "Connection: close\r\n\r\n";
+ httpsClient->print(request);
+
+ while (httpsClient->connected()) {
+ String line = httpsClient->readStringUntil('\n');
+ if (line == "\r") {
+ break;
+ }
+ }
+ while (httpsClient->available()) {
+ String line = httpsClient->readStringUntil('\n');
+ if (line!="") {
+ result += line;
+ }
+ }
+ httpsClient->stop();
+ Run_Scripter(">jp",3,(char*)result.c_str());
+ return 0;
+}
+
+#endif // SCRIPT_GET_HTTPS_JP
+
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
@@ -6139,6 +6489,12 @@ bool Xdrv10(uint8_t function)
break;
#endif
+#ifdef USE_SCRIPT_GLOBVARS
+ case FUNC_LOOP:
+ Script_PollUdp();
+ break;
+#endif
+
}
return result;
}
diff --git a/tasmota/xdrv_11_knx.ino b/tasmota/xdrv_11_knx.ino
index 47b62547d..d6fef25fe 100644
--- a/tasmota/xdrv_11_knx.ino
+++ b/tasmota/xdrv_11_knx.ino
@@ -114,6 +114,7 @@ device_parameters_t device_param[] = {
{ KNX_SLOT3 , false, false, KNX_Empty },
{ KNX_SLOT4 , false, false, KNX_Empty },
{ KNX_SLOT5 , false, false, KNX_Empty },
+ { KNX_SCENE , false, false, KNX_Empty },
{ KNX_Empty, false, false, KNX_Empty}
};
@@ -149,6 +150,7 @@ const char * device_param_ga[] = {
D_KNX_TX_SLOT " 3",
D_KNX_TX_SLOT " 4",
D_KNX_TX_SLOT " 5",
+ D_KNX_TX_SCENE ,
nullptr
};
@@ -184,6 +186,7 @@ const char *device_param_cb[] = {
D_KNX_RX_SLOT " 3",
D_KNX_RX_SLOT " 4",
D_KNX_RX_SLOT " 5",
+ D_KNX_RX_SCENE ,
nullptr
};
@@ -196,12 +199,14 @@ const char *device_param_cb[] = {
#define D_CMND_KNX_PA "_PA"
#define D_CMND_KNX_GA "_GA"
#define D_CMND_KNX_CB "_CB"
+#define D_CMND_KNXTXSCENE "Tx_Scene"
+
const char kKnxCommands[] PROGMEM = D_PRFX_KNX "|" // Prefix
- D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" D_CMND_KNX_ENHANCED "|" D_CMND_KNX_PA "|" D_CMND_KNX_GA "|" D_CMND_KNX_CB ;
+ D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" D_CMND_KNX_ENHANCED "|" D_CMND_KNX_PA "|" D_CMND_KNX_GA "|" D_CMND_KNX_CB "|" D_CMND_KNXTXSCENE ;
void (* const KnxCommand[])(void) PROGMEM = {
- &CmndKnxTxCmnd, &CmndKnxTxVal, &CmndKnxEnabled, &CmndKnxEnhanced, &CmndKnxPa, &CmndKnxGa, &CmndKnxCb };
+ &CmndKnxTxCmnd, &CmndKnxTxVal, &CmndKnxEnabled, &CmndKnxEnhanced, &CmndKnxPa, &CmndKnxGa, &CmndKnxCb, &CmndKnxTxScene };
uint8_t KNX_GA_Search( uint8_t param, uint8_t start = 0 )
{
@@ -518,6 +523,7 @@ void KNX_INIT(void)
device_param[KNX_SLOT3-1].show = true;
device_param[KNX_SLOT4-1].show = true;
device_param[KNX_SLOT5-1].show = true;
+ device_param[KNX_SCENE-1].show = true;
#endif
// Delete from KNX settings all configuration is not anymore related to this device
@@ -557,7 +563,11 @@ void KNX_CB_Action(message_t const &msg, void *arg)
if (msg.data_len == 1) {
// COMMAND
sprintf(tempchar,"%d",msg.data[0]);
- } else {
+ } else if (chan->type == KNX_SCENE) {
+ // VALUE
+ uint8_t tempvar = knx.data_to_1byte_uint(msg.data);
+ dtostrfd(tempvar,2,tempchar);
+ } else {
// VALUE
float tempvar = knx.data_to_2byte_float(msg.data);
dtostrfd(tempvar,2,tempchar);
@@ -602,6 +612,18 @@ void KNX_CB_Action(message_t const &msg, void *arg)
}
}
}
+ else if (chan->type == KNX_SCENE) // KNX RX SCENE SLOT (write command)
+ {
+ if (!toggle_inhibit) {
+ char command[25];
+ // Value received
+ snprintf_P(command, sizeof(command), PSTR("event KNX_SCENE=%s"), tempchar);
+ ExecuteCommand(command, SRC_KNX);
+ if (Settings.flag.knx_enable_enhancement) {
+ toggle_inhibit = TOGGLE_INHIBIT_TIME;
+ }
+ }
+ }
#endif
break;
@@ -1054,6 +1076,31 @@ void CmndKnxTxVal(void)
}
}
+void CmndKnxTxScene(void)
+{
+ if ( (XdrvMailbox.data_len > 0) && Settings.flag.knx_enabled ) {
+ // XdrvMailbox.payload <- scene number to send
+ uint8_t i = KNX_GA_Search(KNX_SCENE);
+ if ( i != KNX_Empty ) {
+ KNX_addr.value = Settings.knx_GA_addr[i];
+
+ uint8_t tempvar = TextToInt(XdrvMailbox.data);
+ dtostrfd(tempvar,0,XdrvMailbox.data);
+
+ knx.write_1byte_uint(KNX_addr, tempvar);
+ if (Settings.flag.knx_enable_enhancement) {
+ knx.write_1byte_uint(KNX_addr, tempvar);
+ knx.write_1byte_uint(KNX_addr, tempvar);
+ }
+
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %s " D_SENT_TO " %d.%d.%d"),
+ device_param_ga[KNX_SCENE-1], XdrvMailbox.data,
+ KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member);
+ ResponseCmndIdxChar (XdrvMailbox.data);
+ }
+ }
+}
+
void CmndKnxEnabled(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
@@ -1208,7 +1255,7 @@ bool Xdrv11(uint8_t function)
bool result = false;
switch (function) {
case FUNC_LOOP:
- if (!global_state.wifi_down) { knx.loop(); } // Process knx events
+ if (!global_state.network_down) { knx.loop(); } // Process knx events
break;
case FUNC_EVERY_50_MSECOND:
if (toggle_inhibit) {
diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino
index 7ede88b44..476d45765 100644
--- a/tasmota/xdrv_12_home_assistant.ino
+++ b/tasmota/xdrv_12_home_assistant.ino
@@ -27,14 +27,14 @@ const char kHAssJsonSensorTypes[] PROGMEM =
D_JSON_APPARENT_POWERUSAGE "|Battery|" D_JSON_CURRENT "|" D_JSON_DISTANCE "|" D_JSON_FREQUENCY "|" D_JSON_HUMIDITY "|" D_JSON_ILLUMINANCE "|"
D_JSON_MOISTURE "|PB0.3|PB0.5|PB1|PB2.5|PB5|PB10|PM1|PM2.5|PM10|" D_JSON_POWERFACTOR "|" D_JSON_POWERUSAGE "|" D_JSON_TOTAL_START_TIME "|"
D_JSON_REACTIVE_POWERUSAGE "|" D_JSON_TODAY "|" D_JSON_TOTAL "|" D_JSON_VOLTAGE "|" D_JSON_WEIGHT "|" D_JSON_YESTERDAY "|"
- D_JSON_CO2 "|" D_JSON_ECO2 "|" D_JSON_TVOC "|";
+ D_JSON_CO2 "|" D_JSON_ECO2 "|" D_JSON_TVOC "|" D_COLOR_RED "|" D_COLOR_GREEN "|" D_COLOR_BLUE"|" D_CCT "|" D_PROXIMITY "|Ambient|";
const char kHAssJsonSensorUnits[] PROGMEM =
"||||"
"VA|%|A|Cm|Hz|%|LX|"
"%|ppd|ppd|ppd|ppd|ppd|ppd|µg/m³|µg/m³|µg/m³|Cos φ|W| |"
"VAr|kWh|kWh|V|Kg|kWh|"
- "ppm|ppm|ppb|";
+ "ppm|ppm|ppb|R|G|B|" D_UNIT_KELVIN "| |LX|";
const char kHAssJsonSensorDevCla[] PROGMEM =
"dev_cla\":\"temperature|ic\":\"mdi:weather-rainy|dev_cla\":\"pressure|dev_cla\":\"pressure|"
@@ -42,61 +42,64 @@ const char kHAssJsonSensorDevCla[] PROGMEM =
"ic\":\"mdi:cup-water|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|"
"ic\":\"mdi:air-filter|ic\":\"mdi:air-filter|ic\":\"mdi:air-filter|ic\":\"mdi:alpha-f-circle-outline|dev_cla\":\"power|ic\":\"mdi:progress-clock|"
"dev_cla\":\"power|dev_cla\":\"power|dev_cla\":\"power|ic\":\"mdi:alpha-v-circle-outline|ic\":\"mdi:scale|dev_cla\":\"power|"
- "ic\":\"mdi:periodic-table-co2|ic\":\"mdi:air-filter|ic\":\"mdi:periodic-table-co2|";
+ "ic\":\"mdi:periodic-table-co2|ic\":\"mdi:air-filter|ic\":\"mdi:periodic-table-co2|"
+ "ic\":\"mdi:palette|ic\":\"mdi:palette|ic\":\"mdi:palette|ic\":\"mdi:temperature-kelvin|ic\":\"mdi:ruler|dev_cla\":\"illuminance|";
//"ic\":\"mdi:weather-windy|ic\":\"mdi:weather-windy|ic\":\"mdi:weather-windy|ic\":\"mdi:weather-windy|"
// List of sensors ready for discovery
-const char HASS_DISCOVER_SENSOR[] PROGMEM =
- ",\"unit_of_meas\":\"%s\",\"%s\"," // unit of measure and class (or icon)
- "\"frc_upd\":true," // force update for better graph representation
- "\"val_tpl\":\"{{value_json['%s']['%s']"; // "COUNTER":{"C1":0} -> {{ value_json['COUNTER']['C1']
-
const char HASS_DISCOVER_BASE[] PROGMEM =
- "{\"name\":\"%s\"," // dualr2 1
- "\"stat_t\":\"%s\"," // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",")
- "\"avty_t\":\"%s\"," // tele/dualr2/LWT
- "\"pl_avail\":\"" D_ONLINE "\"," // Online
- "\"pl_not_avail\":\"" D_OFFLINE "\""; // Offline
+ "{\"name\":\"%s\"," // dualr2 1
+ "\"stat_t\":\"%s\""; // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",")
+
+const char HASS_DISCOVER_SENSOR[] PROGMEM =
+ ",\"unit_of_meas\":\"%s\",\"%s\"," // unit of measure and class (or icon)
+ "\"frc_upd\":true," // force update for better graph representation
+ "\"val_tpl\":\"{{value_json['%s']['%s']"; // "COUNTER":{"C1":0} -> {{ value_json['COUNTER']['C1']
+
+const char HASS_DISCOVER_SENSOR_LWT[] PROGMEM =
+ ",\"avty_t\":\"%s\"," // tele/dualr2/LWT
+ "\"pl_avail\":\"" D_ONLINE "\"," // Online
+ "\"pl_not_avail\":\"" D_OFFLINE "\""; // Offline
const char HASS_DISCOVER_RELAY[] PROGMEM =
- ",\"cmd_t\":\"%s\"," // cmnd/dualr2/POWER2
- "\"val_tpl\":\"{{value_json.%s}}\"," // POWER2
- "\"pl_off\":\"%s\"," // OFF
- "\"pl_on\":\"%s\""; // ON
+ ",\"cmd_t\":\"%s\"," // cmnd/dualr2/POWER2
+ "\"val_tpl\":\"{{value_json.%s}}\"," // POWER2
+ "\"pl_off\":\"%s\"," // OFF
+ "\"pl_on\":\"%s\""; // ON
const char HASS_DISCOVER_BIN_SWITCH[] PROGMEM =
- ",\"val_tpl\":\"{{value_json.%s}}\"," // STATE
- "\"frc_upd\":true," // In ON/OFF case, enable force_update to make automations work
- "\"pl_on\":\"%s\"," // ON
- "\"pl_off\":\"%s\""; // OFF
+ ",\"val_tpl\":\"{{value_json.%s}}\"," // STATE
+ "\"frc_upd\":true," // In ON/OFF case, enable force_update to make automations work
+ "\"pl_on\":\"%s\"," // ON
+ "\"pl_off\":\"%s\""; // OFF
const char HASS_DISCOVER_BIN_PIR[] PROGMEM =
- ",\"val_tpl\":\"{{value_json.%s}}\"," // STATE
- "\"frc_upd\":true," // In ON/OFF case, enable force_update to make automations work
- "\"pl_on\":\"%s\"," // ON
- "\"off_dly\":1"; // Switchmode13 and Switchmode14 doesn't transmit an OFF state.
+ ",\"val_tpl\":\"{{value_json.%s}}\"," // STATE
+ "\"frc_upd\":true," // In ON/OFF case, enable force_update to make automations work
+ "\"pl_on\":\"%s\"," // ON
+ "\"off_dly\":1"; // Switchmode13 and Switchmode14 doesn't transmit an OFF state.
const char HASS_DISCOVER_BASE_LIGHT[] PROGMEM =
- ",\"bri_cmd_t\":\"%s\"," // cmnd/led2/Dimmer
- "\"bri_stat_t\":\"%s\"," // stat/led2/RESULT
- "\"bri_scl\":100," // 100%
- "\"on_cmd_type\":\"%s\"," // power on (first), power on (last), no power on (brightness)
+ ",\"bri_cmd_t\":\"%s\"," // cmnd/led2/Dimmer
+ "\"bri_stat_t\":\"%s\"," // stat/led2/RESULT
+ "\"bri_scl\":100," // 100%
+ "\"on_cmd_type\":\"%s\"," // power on (first), power on (last), no power on (brightness)
"\"bri_val_tpl\":\"{{value_json.%s}}\"";
const char HASS_DISCOVER_LIGHT_COLOR[] PROGMEM =
- ",\"rgb_cmd_t\":\"%s2\"," // cmnd/led2/Color2
- "\"rgb_stat_t\":\"%s\"," // stat/led2/RESULT
+ ",\"rgb_cmd_t\":\"%s2\"," // cmnd/led2/Color2
+ "\"rgb_stat_t\":\"%s\"," // stat/led2/RESULT
"\"rgb_val_tpl\":\"{{value_json." D_CMND_COLOR ".split(',')[0:3]|join(',')}}\"";
const char HASS_DISCOVER_LIGHT_WHITE[] PROGMEM =
- ",\"whit_val_cmd_t\":\"%s\"," // cmnd/led2/White
- "\"whit_val_stat_t\":\"%s\"," // stat/led2/RESULT
+ ",\"whit_val_cmd_t\":\"%s\"," // cmnd/led2/White
+ "\"whit_val_stat_t\":\"%s\"," // stat/led2/RESULT
"\"whit_val_scl\":100,"
"\"whit_val_tpl\":\"{{value_json.Channel[3]}}\"";
const char HASS_DISCOVER_LIGHT_CT[] PROGMEM =
- ",\"clr_temp_cmd_t\":\"%s\"," // cmnd/led2/CT
- "\"clr_temp_stat_t\":\"%s\"," // stat/led2/RESULT
+ ",\"clr_temp_cmd_t\":\"%s\"," // cmnd/led2/CT
+ "\"clr_temp_stat_t\":\"%s\"," // stat/led2/RESULT
"\"clr_temp_val_tpl\":\"{{value_json." D_CMND_COLORTEMPERATURE "}}\"";
const char HASS_DISCOVER_LIGHT_SCHEME[] PROGMEM =
@@ -141,7 +144,7 @@ const char kHAssTriggerStringButtons[] PROGMEM =
"|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|HOLD|";
const char kHAssError1[] PROGMEM =
- "HASS: MQTT discovery failed due to too long topic or friendly name. Please shorten topic and/or friendly name. Failed to format";
+ "HASS: MQTT discovery failed due to too long topic or device/friendly name. Please shorten topic and/or device/friendly name. Failed to format";
const char kHAssError2[] PROGMEM =
"HASS: The configuration of the Relays is wrong, there is a Light that is using an index higher than the number of the validated relay.\n "
@@ -195,13 +198,22 @@ void HAssAnnounceRelayLight(void)
bool ct_light = false; // Controls a CT Light when SetOption37 is >= 128
bool wt_light = false; // Controls a White Light when SetOption37 is >= 128
bool err_flag = false; // When true it blocks the creation of entities if the order of the Relays is not correct to avoid issue with Lights
+ bool TuyaMod = false; // Controls Tuya MCU modules
bool PwmMod = false; // Controls PWM_DIMMER module
+ bool FanMod = false; // Controls SONOFF_IFAN0X modules
uint8_t dimmer = 1;
+ uint8_t valid_relay = 0;
uint8_t max_lights = 1;
+ uint8_t TuyaRel = 0;
+ uint8_t TuyaRelInv = 0;
+ uint8_t TuyaDim = 0;
#ifdef ESP8266
- if (PWM_DIMMER == my_module_type) { PwmMod = true; }
+ if (PWM_DIMMER == my_module_type ) { PwmMod = true; } //
+ if (SONOFF_IFAN02 == my_module_type || SONOFF_IFAN03 == my_module_type) { FanMod = true; }
+ if (SONOFF_DUAL == my_module_type) { valid_relay = 2; }
+ if (TUYA_DIMMER == my_module_type || SK03_TUYA == my_module_type) { TuyaMod = true; }
#endif //ESP8266
// If there is a special Light to be enabled and managed with SetOption68 or SetOption37 >= 128, Discovery calculates the maximum number of entities to be generated in advance
@@ -209,17 +221,21 @@ void HAssAnnounceRelayLight(void)
if (PwmMulti) { max_lights = Light.subtype; }
if (!LightControl) {
- ind_light = 1;
+ ind_light = true;
if (!PwmMulti) { max_lights = 2;}
}
- // Lights types: 0 = LST_NONE / 1 = LST_SINGLE / 2 = LST_COLDWARM / 3 = LST_RGB / 4 = LST_RGBW / 5 = LST_RGBCW
-
for (uint32_t i = 1; i <= MAX_RELAYS; i++)
{
- bool RelayX = PinUsed(GPIO_REL1 +i-1);
- is_topic_light = Settings.flag.hass_light && RelayX || light_type && !RelayX || PwmMod; // SetOption30 - Enforce HAss autodiscovery as light
+#ifdef USE_TUYA_MCU
+ TuyaRel = TuyaGetDpId((TUYA_MCU_FUNC_REL1+ i-1) + active_device - 1);
+ TuyaRelInv = TuyaGetDpId((TUYA_MCU_FUNC_REL1_INV+ i-1) + active_device - 1);
+ TuyaDim = TuyaGetDpId((TUYA_MCU_FUNC_DIMMER) + active_device - 1);
+#endif //USE_TUYA_MCU
+
+ bool RelayX = PinUsed(GPIO_REL1 +i-1) || (valid_relay >= i) || (TuyaRel > 0 && TuyaMod) || (TuyaRelInv > 0 && TuyaMod); // Check if the gpio is configured as Relay or force it for Sonoff DUAL R1 with MCU and Tuya MCU
+ is_topic_light = Settings.flag.hass_light && RelayX || light_type && !RelayX || PwmMod || (TuyaDim > 0 && TuyaMod); // SetOption30 - Enforce HAss autodiscovery as light
mqtt_data[0] = '\0'; // Clear retained message
// Clear "other" topic first in case the device has been reconfigured from light to switch or vice versa
@@ -255,13 +271,14 @@ void HAssAnnounceRelayLight(void)
GetTopic_P(command_topic, CMND, mqtt_topic, value_template);
GetTopic_P(state_topic, TELE, mqtt_topic, D_RSLT_STATE);
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
- Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
+ Response_P(HASS_DISCOVER_BASE, name, state_topic);
+ TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
TryResponseAppend_P(HASS_DISCOVER_RELAY, command_topic, value_template, SettingsText(SET_STATE_TXT1), SettingsText(SET_STATE_TXT2));
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId());
#ifdef USE_LIGHT
if (i >= Light.device) {
- if (!RelayX || PwmMod) {
+ if (!RelayX || PwmMod || (TuyaDim > 0 && TuyaMod)) {
char *brightness_command_topic = stemp1;
strncpy_P(stemp3, Settings.flag.not_power_linked ? PSTR("last") : PSTR("brightness"), sizeof(stemp3)); // SetOption20 - Control power in relation to Dimmer/Color/Ct changes
char channel_num[9];
@@ -411,6 +428,14 @@ void HAssAnnouncerBinSensors(uint8_t device, uint8_t present, uint8_t dual, uint
TryResponseAppend_P(HASS_DISCOVER_BIN_PIR, PSTR(D_RSLT_STATE), SettingsText(SET_STATE_TXT2));
}
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId());
+#ifdef DEEPSLEEP_LWT_HA_DISCOVERY
+ TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
+#else
+ if (Settings.deepsleep == 0)
+ {
+ TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
+ }
+#endif //DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(PSTR("}"));
}
}
@@ -505,7 +530,7 @@ void HAssAnnounceButtons(void)
{
button_present = 1;
} else
-#endif
+#endif // ESP8266
{
if (PinUsed(GPIO_KEY1, button_index)) {
button_present = 1;
@@ -557,12 +582,21 @@ void HAssAnnounceSensor(const char *sensorname, const char *subsensortype, const
char prefix[TOPSZ];
char *state_topic = stemp1;
char *availability_topic = stemp2;
+ //bool LwtSensor = MQTT_LWT_DISCOVERY;
GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_SENSOR));
snprintf_P(name, sizeof(name), PSTR("%s %s %s"), SettingsText(SET_DEVICENAME), sensorname, MultiSubName);
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
- Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
+ Response_P(HASS_DISCOVER_BASE, name, state_topic);
+ #ifdef DEEPSLEEP_LWT_HA_DISCOVERY
+ TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
+#else
+ if (Settings.deepsleep == 0)
+ {
+ TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
+ }
+#endif //DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId());
@@ -629,8 +663,8 @@ void HAssAnnounceSensors(void)
sensordata[0] = '{';
snprintf_P(sensordata, sizeof(sensordata), PSTR("%s}"), sensordata); // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}}
// USE THE FOLLOWING LINE TO TEST JSON
- //snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"HX711\":{\"Weight\":[22,34,1023.4]}}"));
-
+ //snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"APDS9960\":{\"Red\":282,\"Green\":252,\"Blue\":196,\"Ambient\":169,\"CCT\":4217,\"Proximity\":9}}"));
+ //snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"ENERGY\":{\"TotalStartTime\":\"2018-11-23T15:33:47\",\"Total\":0.017,\"TotalTariff\":[0.000,0.017],\"Yesterday\":0.000,\"Today\":0.002,\"ExportActive\":0.000,\"ExportTariff\":[0.000,0.000],\"Period\":0.00,\"Power\":0.00,\"ApparentPower\":7.84,\"ReactivePower\":-7.21,\"Factor\":0.39,\"Frequency\":50.0,\"Voltage\":234.31,\"Current\":0.039,\"ImportActive\":12.580,\"ImportReactive\":0.002,\"ExportReactive\":39.131,\"PhaseAngle\":290.45}}"));
StaticJsonBuffer<500> jsonBuffer;
JsonObject &root = jsonBuffer.parseObject(sensordata);
@@ -703,7 +737,8 @@ void HAssAnnounceDeviceInfoAndStatusSensor(void)
GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_HASS_STATE));
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
- Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
+ Response_P(HASS_DISCOVER_BASE, name, state_topic);
+ TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_HASS_STATUS, state_topic);
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP_getChipId(), SettingsText(SET_DEVICENAME),
ModuleName().c_str(), my_version, my_image);
@@ -812,7 +847,6 @@ void HAssAnyKey(void)
bool Xdrv12(uint8_t function)
{
bool result = false;
-
if (Settings.flag.mqtt_enabled)
{ // SetOption3 - Enable MQTT
switch (function)
@@ -844,10 +878,13 @@ bool Xdrv12(uint8_t function)
case FUNC_MQTT_INIT:
hass_mode = 0; // Discovery only if Settings.flag.hass_discovery is set
hass_init_step = 2; // Delayed discovery
+ // if (!Settings.flag.hass_discovery) {
+ // AddLog_P2(LOG_LEVEL_INFO, PSTR("MQT: homeassistant/49A3BC/Discovery = {\"dev\":{\"ids\":[\"49A3BC\"]},\"cmd_t\":\"cmnd/test1/\",\"Discovery\":0}"));
+ // }
break;
}
}
return result;
}
-#endif // USE_HOME_ASSISTANT
+#endif // USE_HOME_ASSISTANT
\ No newline at end of file
diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino
index 43245c794..20e95eeb1 100644
--- a/tasmota/xdrv_13_display.ino
+++ b/tasmota/xdrv_13_display.ino
@@ -1013,14 +1013,14 @@ void DisplayLogBufferInit(void)
snprintf_P(buffer, sizeof(buffer), PSTR("Display mode %d"), Settings.display_mode);
DisplayLogBufferAdd(buffer);
- snprintf_P(buffer, sizeof(buffer), PSTR(D_CMND_HOSTNAME " %s"), my_hostname);
+ snprintf_P(buffer, sizeof(buffer), PSTR(D_CMND_HOSTNAME " %s"), NetworkHostname());
DisplayLogBufferAdd(buffer);
- snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_SSID " %s"), SettingsText(SET_STASSID1 + Settings.sta_active));
+ snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_MAC " %s"), NetworkMacAddress().c_str());
DisplayLogBufferAdd(buffer);
- snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_MAC " %s"), WiFi.macAddress().c_str());
+ snprintf_P(buffer, sizeof(buffer), PSTR("IP %s"), NetworkAddress().toString().c_str());
DisplayLogBufferAdd(buffer);
if (!global_state.wifi_down) {
- snprintf_P(buffer, sizeof(buffer), PSTR("IP %s"), WiFi.localIP().toString().c_str());
+ snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_SSID " %s"), SettingsText(SET_STASSID1 + Settings.sta_active));
DisplayLogBufferAdd(buffer);
snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_RSSI " %d%%"), WifiGetRssiAsQuality(WiFi.RSSI()));
DisplayLogBufferAdd(buffer);
diff --git a/tasmota/xdrv_23_zigbee_0_constants.ino b/tasmota/xdrv_23_zigbee_0_constants.ino
index 57bf22499..92e88c708 100644
--- a/tasmota/xdrv_23_zigbee_0_constants.ino
+++ b/tasmota/xdrv_23_zigbee_0_constants.ino
@@ -19,6 +19,13 @@
#ifdef USE_ZIGBEE
+#if defined(USE_ZIGBEE_ZNP) && defined(USE_ZIGBEE_EZSP)
+ #error "#define USE_ZIGBEE_ZNP and #define USE_ZIGBEE_EZSP are mutually incompatible"
+#endif
+#if !defined(USE_ZIGBEE_ZNP) && !defined(USE_ZIGBEE_EZSP)
+ #error "You must select one of: #define USE_ZIGBEE_ZNP or #define USE_ZIGBEE_EZSP"
+#endif
+
#define OCCUPANCY "Occupancy" // global define for Aqara
typedef uint64_t Z_IEEEAddress;
@@ -26,6 +33,7 @@ typedef uint16_t Z_ShortAddress;
const uint16_t BAD_SHORTADDR = 0xFFFE;
+#ifdef USE_ZIGBEE_ZNP
enum ZnpCommandType {
Z_POLL = 0x00,
Z_SREQ = 0x20,
@@ -45,6 +53,7 @@ enum ZnpSubsystem {
Z_DEBUG = 0x08,
Z_APP = 0x09
};
+#endif // USE_ZIGBEE_ZNP
// Commands in the SYS subsystem
enum SysCommand {
diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino
index 4297a4375..cbfe822ab 100644
--- a/tasmota/xdrv_23_zigbee_7_statemachine.ino
+++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino
@@ -168,6 +168,8 @@ SBuffer *zigbee_buffer = nullptr;
#define USE_ZIGBEE_CHANNEL_MASK (1 << (USE_ZIGBEE_CHANNEL))
+#ifdef USE_ZIGBEE_ZNP
+
// ZBS_* Zigbee Send
// ZBR_* Zigbee Recv
ZBM(ZBS_RESET, Z_AREQ | Z_SYS, SYS_RESET, 0x00 ) // 410001 SYS_RESET_REQ Hardware reset
@@ -611,6 +613,30 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_STOP(ZIGBEE_LABEL_ABORT)
};
+#endif // USE_ZIGBEE_ZNP
+
+#ifdef USE_ZIGBEE_EZSP
+
+// Update the relevant commands with Settings
+void Z_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_panid, uint64_t zb_precfgkey_l, uint64_t zb_precfgkey_h) {
+}
+
+
+static const Zigbee_Instruction zb_prog[] PROGMEM = {
+ ZI_LABEL(0)
+ ZI_NOOP()
+ ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT)
+ ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT)
+ // ZI_ON_RECV_UNEXPECTED(&Z_Recv_Default)
+ // ZI_WAIT(10500) // wait for 10 seconds for Tasmota to stabilize
+
+ ZI_LABEL(ZIGBEE_LABEL_MAIN_LOOP)
+ ZI_WAIT_FOREVER()
+ ZI_GOTO(ZIGBEE_LABEL_READY)
+};
+
+#endif // USE_ZIGBEE_EZSP
+
uint8_t ZigbeeGetInstructionSize(uint8_t instr) { // in Zigbee_Instruction lines (words)
if (instr >= ZGB_INSTR_12_BYTES) {
return 3;
@@ -770,7 +796,9 @@ void ZigbeeStateMachine_Run(void) {
}
break;
case ZGB_INSTR_SEND:
+#ifdef USE_ZIGBEE_ZNP
ZigbeeZNPSend((uint8_t*) cur_ptr1, cur_d8 /* len */);
+#endif // USE_ZIGBEE_ZNP
break;
case ZGB_INSTR_WAIT_UNTIL:
zigbee.recv_until = true; // and reuse ZGB_INSTR_WAIT_RECV
diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino
index aad2732ca..7e9129d64 100644
--- a/tasmota/xdrv_23_zigbee_8_parsers.ino
+++ b/tasmota/xdrv_23_zigbee_8_parsers.ino
@@ -552,6 +552,7 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) {
return -1;
}
+#ifdef USE_ZIGBEE_ZNP
/*********************************************************************************************\
* Send specific ZNP messages
\*********************************************************************************************/
@@ -589,6 +590,32 @@ void Z_SendAFInfoRequest(uint16_t shortaddr) {
ZigbeeZNPSend(AFInfoReq, sizeof(AFInfoReq));
}
+#endif // USE_ZIGBEE_ZNP
+
+#ifdef USE_ZIGBEE_EZSP
+/*********************************************************************************************\
+ * Send specific EZS¨ messages
+\*********************************************************************************************/
+
+//
+// Send ZDO_IEEE_ADDR_REQ request to get IEEE long address
+//
+void Z_SendIEEEAddrReq(uint16_t shortaddr) {
+}
+
+//
+// Send ACTIVE_EP_REQ to collect active endpoints for this address
+//
+void Z_SendActiveEpReq(uint16_t shortaddr) {
+}
+
+//
+// Send AF Info Request
+//
+void Z_SendAFInfoRequest(uint16_t shortaddr) {
+}
+
+#endif // USE_ZIGBEE_EZSP
/*********************************************************************************************\
* Callbacks
@@ -718,6 +745,8 @@ typedef struct Z_Dispatcher {
ZB_RecvMsgFunc func;
} Z_Dispatcher;
+#ifdef USE_ZIGBEE_ZNP
+
// Ffilters based on ZNP frames
ZBM(AREQ_AF_DATA_CONFIRM, Z_AREQ | Z_AF, AF_DATA_CONFIRM) // 4480
ZBM(AREQ_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) // 4481
@@ -767,6 +796,8 @@ int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
}
}
+#endif // USE_ZIGBEE_ZNP
+
/*********************************************************************************************\
* Functions called by State Machine
\*********************************************************************************************/
@@ -835,8 +866,8 @@ void Z_AutoResponder(uint16_t srcaddr, uint16_t cluster, uint8_t endpoint, const
// responder
switch (cluster) {
case 0x0000:
- if (HasKeyCaseInsensitive(json, PSTR("ModelId"))) { json_out[F("ModelId")] = F("Tasmota Z2T"); }
- if (HasKeyCaseInsensitive(json, PSTR("Manufacturer"))) { json_out[F("Manufacturer")] = F("Tasmota"); }
+ if (HasKeyCaseInsensitive(json, PSTR("ModelId"))) { json_out[F("ModelId")] = F(USE_ZIGBEE_MODELID); }
+ if (HasKeyCaseInsensitive(json, PSTR("Manufacturer"))) { json_out[F("Manufacturer")] = F(USE_ZIGBEE_MANUFACTURER); }
break;
#ifdef USE_LIGHT
case 0x0006:
diff --git a/tasmota/xdrv_23_zigbee_9_impl.ino b/tasmota/xdrv_23_zigbee_9_impl.ino
index 4da0a48f6..1cc5f6efc 100644
--- a/tasmota/xdrv_23_zigbee_9_impl.ino
+++ b/tasmota/xdrv_23_zigbee_9_impl.ino
@@ -21,18 +21,32 @@
#define XDRV_23 23
+#ifdef USE_ZIGBEE_ZNP
const uint32_t ZIGBEE_BUFFER_SIZE = 256; // Max ZNP frame is SOF+LEN+CMD1+CMD2+250+FCS = 255
const uint8_t ZIGBEE_SOF = 0xFE;
const uint8_t ZIGBEE_SOF_ALT = 0xFF;
+#endif // USE_ZIGBEE_ZNP
+
+#ifdef USE_ZIGBEE_EZSP
+const uint32_t ZIGBEE_BUFFER_SIZE = 256;
+const uint8_t ZIGBEE_EZSP_CANCEL = 0x1A; // cancel byte
+const uint8_t ZIGBEE_EZSP_EOF = 0x7E; // end of frame
+const uint8_t ZIGBEE_EZSP_ESCAPE = 0x7D; // escape byte
+#endif // USE_ZIGBEE_EZSP
#include
TasmotaSerial *ZigbeeSerial = nullptr;
const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
- D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEE_PERMITJOIN "|"
- D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|"
- D_CMND_ZIGBEE_PROBE "|" D_CMND_ZIGBEEZNPRECEIVE "|"
+#ifdef USE_ZIGBEE_ZNP
+ D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEEZNPRECEIVE "|"
+#endif // USE_ZIGBEE_ZNP
+#ifdef USE_ZIGBEE_EZSP
+ D_CMND_ZIGBEE_EZSP_SEND "|" D_CMND_ZIGBEE_EZSP_RECEIVE "|"
+#endif // USE_ZIGBEE_EZSP
+ D_CMND_ZIGBEE_PERMITJOIN "|"
+ D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|" D_CMND_ZIGBEE_PROBE "|"
D_CMND_ZIGBEE_FORGET "|" D_CMND_ZIGBEE_SAVE "|" D_CMND_ZIGBEE_NAME "|"
D_CMND_ZIGBEE_BIND "|" D_CMND_ZIGBEE_UNBIND "|" D_CMND_ZIGBEE_PING "|" D_CMND_ZIGBEE_MODELID "|"
D_CMND_ZIGBEE_LIGHT "|" D_CMND_ZIGBEE_RESTORE "|" D_CMND_ZIGBEE_BIND_STATE "|"
@@ -40,9 +54,14 @@ const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
;
void (* const ZigbeeCommand[])(void) PROGMEM = {
- &CmndZbZNPSend, &CmndZbPermitJoin,
- &CmndZbStatus, &CmndZbReset, &CmndZbSend,
- &CmndZbProbe, &CmndZbZNPReceive,
+#ifdef USE_ZIGBEE_ZNP
+ &CmndZbZNPSend, &CmndZbZNPReceive,
+#endif // USE_ZIGBEE_ZNP
+#ifdef USE_ZIGBEE_EZSP
+ &CmndZbEZSPSend, &CmndZbEZSPReceive,
+#endif // USE_ZIGBEE_EZSP
+ &CmndZbPermitJoin,
+ &CmndZbStatus, &CmndZbReset, &CmndZbSend, &CmndZbProbe,
&CmndZbForget, &CmndZbSave, &CmndZbName,
&CmndZbBind, &CmndZbUnbind, &CmndZbPing, &CmndZbModelId,
&CmndZbLight, &CmndZbRestore, &CmndZbBindState,
@@ -52,11 +71,12 @@ void (* const ZigbeeCommand[])(void) PROGMEM = {
//
// Called at event loop, checks for incoming data from the CC2530
//
-void ZigbeeInputLoop(void)
-{
- static uint32_t zigbee_polling_window = 0;
+void ZigbeeInputLoop(void) {
+
+#ifdef USE_ZIGBEE_ZNP
+ static uint32_t zigbee_polling_window = 0; // number of milliseconds since first byte
static uint8_t fcs = ZIGBEE_SOF;
- static uint32_t zigbee_frame_len = 5; // minimal zigbee frame lenght, will be updated when buf[1] is read
+ static uint32_t zigbee_frame_len = 5; // minimal zigbee frame length, will be updated when buf[1] is read
// Receive only valid ZNP frames:
// 00 - SOF = 0xFE
// 01 - Length of Data Field - 0..250
@@ -140,6 +160,127 @@ void ZigbeeInputLoop(void)
}
zigbee_buffer->setLen(0); // empty buffer
}
+#endif // USE_ZIGBEE_ZNP
+
+#ifdef USE_ZIGBEE_EZSP
+ static uint32_t zigbee_polling_window = 0; // number of milliseconds since first byte
+ bool escape = false; // was the previous byte an escape?
+ bool frame_complete = false; // frame is ready and complete
+ // Receive only valid EZSP frames:
+ // 1A - Cancel - cancel all previous bytes
+ // 7D - Escape byte - following byte is escaped
+ // 7E - end of frame
+
+ while (ZigbeeSerial->available()) {
+ yield();
+ uint8_t zigbee_in_byte = ZigbeeSerial->read();
+ AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: ZbInput byte=0x%02X len=%d"), zigbee_in_byte, zigbee_buffer->len());
+
+ // if (0 == zigbee_buffer->len()) { // make sure all variables are correctly initialized
+ // escape = false;
+ // frame_complete = false;
+ // }
+
+ if ((0x11 == zigbee_in_byte) || (0x13 == zigbee_in_byte)) {
+ continue; // ignore reserved bytes XON/XOFF
+ }
+
+ if (ZIGBEE_EZSP_ESCAPE == zigbee_in_byte) {
+ AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: Escape byte received"));
+ escape = true;
+ continue;
+ }
+
+ if (ZIGBEE_EZSP_CANCEL == zigbee_in_byte) {
+ AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: ZbInput byte=0x1A, cancel byte received, discarding %d bytes"), zigbee_buffer->len());
+ zigbee_buffer->setLen(0); // empty buffer
+ escape = false;
+ frame_complete = false;
+ continue; // re-loop
+ }
+
+ if (ZIGBEE_EZSP_EOF == zigbee_in_byte) {
+ // end of frame
+ frame_complete = true;
+ break;
+ }
+
+ if (zigbee_buffer->len() < ZIGBEE_BUFFER_SIZE) {
+ if (escape) {
+ // invert bit 5
+ zigbee_in_byte ^= 0x20;
+ escape = false;
+ }
+
+ zigbee_buffer->add8(zigbee_in_byte);
+ zigbee_polling_window = millis(); // Wait for more data
+ } // adding bytes
+ } // while (ZigbeeSerial->available())
+
+ uint32_t frame_len = zigbee_buffer->len();
+ if (frame_complete || (frame_len && (millis() > (zigbee_polling_window + ZIGBEE_POLLING)))) {
+ char hex_char[frame_len * 2 + 2];
+ ToHex_P((unsigned char*)zigbee_buffer->getBuffer(), zigbee_buffer->len(), hex_char, sizeof(hex_char));
+
+ AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Bytes follow_read_metric = %0d"), ZigbeeSerial->getLoopReadMetric());
+ if ((frame_complete) && (frame_len >= 3)) {
+ // frame received and has at least 3 bytes (without EOF), checking CRC
+ // AddLog_P2(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": received raw frame %s"), hex_char);
+ uint16_t crc = 0xFFFF; // frame CRC
+ // compute CRC
+ for (uint32_t i=0; iget8(i) << 8);
+ for (uint32_t i=0; i<8; i++) {
+ if (crc & 0x8000) {
+ crc = (crc << 1) ^ 0x1021; // polynom is x^16 + x^12 + x^5 + 1, CCITT standard
+ } else {
+ crc <<= 1;
+ }
+ }
+ }
+
+ uint16_t crc_received = zigbee_buffer->get8(frame_len - 2) << 8 | zigbee_buffer->get8(frame_len - 1);
+ // remove 2 last bytes
+
+ if (crc_received != crc) {
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": bad crc (received 0x%04X, computed 0x%04X) %s"), crc_received, crc, hex_char);
+ } else {
+ // copy buffer
+ SBuffer ezsp_buffer = zigbee_buffer->subBuffer(0, frame_len - 2); // CRC
+
+ // CRC is correct, apply de-stuffing if DATA frame
+ if (0 == (ezsp_buffer.get8(0) & 0x80)) {
+ // DATA frame
+ uint8_t rand = 0x42;
+ for (uint32_t i=1; i> 1) ^ 0xB8; }
+ else { rand = (rand >> 1); }
+ }
+ }
+
+ ToHex_P((unsigned char*)ezsp_buffer.getBuffer(), ezsp_buffer.len(), hex_char, sizeof(hex_char));
+ Response_P(PSTR("{\"" D_JSON_ZIGBEE_EZSP_RECEIVED "\":\"%s\"}"), hex_char);
+ if (Settings.flag3.tuya_serial_mqtt_publish) {
+ MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR));
+ XdrvRulesProcess();
+ } else {
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); // TODO move to LOG_LEVEL_DEBUG when stable
+ }
+ // now process the message
+ ZigbeeProcessInput(ezsp_buffer);
+ }
+ } else {
+ // the buffer timed-out, print error and discard
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": time-out, discarding %s, %d"), hex_char);
+ }
+ zigbee_buffer->setLen(0); // empty buffer
+ escape = false;
+ frame_complete = false;
+ }
+
+#endif // USE_ZIGBEE_EZSP
+
}
/********************************************************************************************/
@@ -201,15 +342,20 @@ uint32_t strToUInt(const JsonVariant &val) {
return 0; // couldn't parse anything
}
+#ifdef USE_ZIGBEE_ZNP
// Do a factory reset of the CC2530
const unsigned char ZIGBEE_FACTORY_RESET[] PROGMEM =
{ Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 /* len */, 0x01 /* STARTOPT_CLEAR_CONFIG */};
//"2605030101"; // Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 len, 0x01 STARTOPT_CLEAR_CONFIG
+#endif // USE_ZIGBEE_ZNP
+
void CmndZbReset(void) {
if (ZigbeeSerial) {
switch (XdrvMailbox.payload) {
case 1:
+#ifdef USE_ZIGBEE_ZNP
ZigbeeZNPSend(ZIGBEE_FACTORY_RESET, sizeof(ZIGBEE_FACTORY_RESET));
+#endif // USE_ZIGBEE_ZNP
eraseZigbeeDevices();
restart_flag = 2;
ResponseCmndChar_P(PSTR(D_JSON_ZIGBEE_CC2530 " " D_JSON_RESET_AND_RESTARTING));
@@ -220,6 +366,38 @@ void CmndZbReset(void) {
}
}
+#ifdef USE_ZIGBEE_ZNP
+
+void ZigbeeZNPSend(const uint8_t *msg, size_t len) {
+ if ((len < 2) || (len > 252)) {
+ // abort, message cannot be less than 2 bytes for CMD1 and CMD2
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_JSON_ZIGBEEZNPSENT ": bad message len %d"), len);
+ return;
+ }
+ uint8_t data_len = len - 2; // removing CMD1 and CMD2
+
+ if (ZigbeeSerial) {
+ uint8_t fcs = data_len;
+
+ ZigbeeSerial->write(ZIGBEE_SOF); // 0xFE
+ //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend SOF %02X"), ZIGBEE_SOF);
+ ZigbeeSerial->write(data_len);
+ //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend LEN %02X"), data_len);
+ for (uint32_t i = 0; i < len; i++) {
+ uint8_t b = pgm_read_byte(msg + i);
+ ZigbeeSerial->write(b);
+ fcs ^= b;
+ //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend byt %02X"), b);
+ }
+ ZigbeeSerial->write(fcs); // finally send fcs checksum byte
+ //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend FCS %02X"), fcs);
+ }
+ // Now send a MQTT message to report the sent message
+ char hex_char[(len * 2) + 2];
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZNPSENT " %s"),
+ ToHex_P(msg, len, hex_char, sizeof(hex_char)));
+}
+
//
// Same code for `ZbZNPSend` and `ZbZNPReceive`
// building the complete message (intro, length)
@@ -264,36 +442,138 @@ void CmndZbZNPSend(void)
CmndZbZNPSendOrReceive(true);
}
-void ZigbeeZNPSend(const uint8_t *msg, size_t len) {
- if ((len < 2) || (len > 252)) {
+#endif // USE_ZIGBEE_ZNP
+
+#ifdef USE_ZIGBEE_EZSP
+
+// internal function to output a byte, and escape it (stuffing) if needed
+void ZigbeeEZSPSend_Out(uint8_t out_byte) {
+ switch (out_byte) {
+ case 0x7E: // Flag byte
+ case 0x11: // XON
+ case 0x13: // XOFF
+ case 0x18: // Substitute byte
+ case 0x1A: // Cancel byte
+ case 0x7D: // Escape byte
+ ZigbeeSerial->write(ZIGBEE_EZSP_ESCAPE); // send Escape byte 0x7D
+ ZigbeeSerial->write(out_byte ^ 0x20); // send with bit 5 inverted
+ break;
+ default:
+ ZigbeeSerial->write(out_byte); // send unchanged
+ break;
+ }
+}
+// Send low-level EZSP frames
+//
+// The frame should contain the Control Byte and Data Field
+// The frame shouldn't be escaped, nor randomized
+//
+// Before sending:
+// - send Cancel byte (0x1A) if requested
+// - randomize Data Field if DATA Frame
+// - compute CRC16
+// - escape (stuff) reserved bytes
+// - add EOF (0x7E)
+// - send frame
+// send_cancel: should we first send a EZSP_CANCEL (0x1A) before the message to clear any leftover
+void ZigbeeEZSPSend(const uint8_t *msg, size_t len, bool send_cancel = false) {
+ if ((len < 1) || (len > 252)) {
// abort, message cannot be less than 2 bytes for CMD1 and CMD2
- AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_JSON_ZIGBEEZNPSENT ": bad message len %d"), len);
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_JSON_ZIGBEE_EZSP_SENT ": bad message len %d"), len);
return;
}
uint8_t data_len = len - 2; // removing CMD1 and CMD2
if (ZigbeeSerial) {
- uint8_t fcs = data_len;
+ if (send_cancel) {
+ ZigbeeSerial->write(ZIGBEE_EZSP_CANCEL); // 0x1A
+ }
- ZigbeeSerial->write(ZIGBEE_SOF); // 0xFE
- //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend SOF %02X"), ZIGBEE_SOF);
- ZigbeeSerial->write(data_len);
- //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend LEN %02X"), data_len);
- for (uint32_t i = 0; i < len; i++) {
- uint8_t b = pgm_read_byte(msg + i);
- ZigbeeSerial->write(b);
- fcs ^= b;
- //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend byt %02X"), b);
- }
- ZigbeeSerial->write(fcs); // finally send fcs checksum byte
- //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend FCS %02X"), fcs);
+ bool data_frame = (0 == (msg[0] & 0x80));
+ uint8_t rand = 0x42; // pseudo-randomizer initial value
+ uint16_t crc = 0xFFFF; // CRC16 CCITT initialization
+
+ for (uint32_t i=0; i 0)) {
+ out_byte ^= rand;
+ if (rand & 1) { rand = (rand >> 1) ^ 0xB8; }
+ else { rand = (rand >> 1); }
+ }
+
+ // compute CRC
+ crc = crc ^ ((uint16_t)out_byte << 8);
+ for (uint32_t i=0; i<8; i++) {
+ if (crc & 0x8000) {
+ crc = (crc << 1) ^ 0x1021; // polynom is x^16 + x^12 + x^5 + 1, CCITT standard
+ } else {
+ crc <<= 1;
+ }
+ }
+
+ // output byte
+ ZigbeeEZSPSend_Out(out_byte);
+ }
+ // send CRC16 in big-endian
+ ZigbeeEZSPSend_Out(crc >> 8);
+ ZigbeeEZSPSend_Out(crc & 0xFF);
+
+ // finally send End of Frame
+ ZigbeeSerial->write(ZIGBEE_EZSP_EOF); // 0x1A
}
// Now send a MQTT message to report the sent message
char hex_char[(len * 2) + 2];
- AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZNPSENT " %s"),
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEE_EZSP_SENT " %s"),
ToHex_P(msg, len, hex_char, sizeof(hex_char)));
}
+//
+// Same code for `ZbZNPSend` and `ZbZNPReceive`
+// building the complete message (intro, length)
+//
+void CmndZbEZSPSendOrReceive(bool send)
+{
+ if (ZigbeeSerial && (XdrvMailbox.data_len > 0)) {
+ uint8_t code;
+
+ char *codes = RemoveSpace(XdrvMailbox.data);
+ int32_t size = strlen(XdrvMailbox.data);
+
+ SBuffer buf((size+1)/2);
+
+ while (size > 1) {
+ char stemp[3];
+ strlcpy(stemp, codes, sizeof(stemp));
+ code = strtol(stemp, nullptr, 16);
+ buf.add8(code);
+ size -= 2;
+ codes += 2;
+ }
+ if (send) {
+ // Command was `ZbEZSPSend`
+ ZigbeeEZSPSend(buf.getBuffer(), buf.len());
+ } else {
+ // Command was `ZbEZSPReceive`
+ ZigbeeProcessInput(buf);
+ }
+ }
+ ResponseCmndDone();
+}
+
+// For debug purposes only, simulates a message received
+void CmndZbEZSPReceive(void)
+{
+ CmndZbEZSPSendOrReceive(false);
+}
+
+void CmndZbEZSPSend(void)
+{
+ CmndZbEZSPSendOrReceive(true);
+}
+#endif // USE_ZIGBEE_EZSP
+
//
// Internal function, send the low-level frame
// Input:
@@ -311,6 +591,7 @@ void ZigbeeZNPSend(const uint8_t *msg, size_t len) {
//
void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterId, uint8_t endpoint, uint8_t cmdId, bool clusterSpecific, uint16_t manuf, const uint8_t *msg, size_t len, bool needResponse, uint8_t transacId) {
+#ifdef USE_ZIGBEE_ZNP
SBuffer buf(32+len);
buf.add8(Z_SREQ | Z_AF); // 24
buf.add8(AF_DATA_REQUEST_EXT); // 02
@@ -342,6 +623,7 @@ void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterI
}
ZigbeeZNPSend(buf.getBuffer(), buf.len());
+#endif // USE_ZIGBEE_ZNP
}
/********************************************************************************************/
@@ -914,6 +1196,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
if (&to_group && dstLongAddr) { ResponseCmndChar_P(PSTR("Cannot have both \"ToDevice\" and \"ToGroup\"")); return; }
if (!&to_group && !dstLongAddr) { ResponseCmndChar_P(PSTR("Missing \"ToDevice\" or \"ToGroup\"")); return; }
+#ifdef USE_ZIGBEE_ZNP
SBuffer buf(34);
buf.add8(Z_SREQ | Z_ZDO);
if (unbind) {
@@ -935,6 +1218,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
}
ZigbeeZNPSend(buf.getBuffer(), buf.len());
+#endif // USE_ZIGBEE_ZNP
ResponseCmndDone();
}
@@ -961,6 +1245,7 @@ void CmndZbBindState(void) {
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
+#ifdef USE_ZIGBEE_ZNP
SBuffer buf(10);
buf.add8(Z_SREQ | Z_ZDO); // 25
buf.add8(ZDO_MGMT_BIND_REQ); // 33
@@ -968,6 +1253,7 @@ void CmndZbBindState(void) {
buf.add8(0); // StartIndex = 0
ZigbeeZNPSend(buf.getBuffer(), buf.len());
+#endif // USE_ZIGBEE_ZNP
ResponseCmndDone();
}
@@ -1191,6 +1477,7 @@ void CmndZbPermitJoin(void) {
duration = 0xFF; // unlimited time
}
+#ifdef USE_ZIGBEE_ZNP
SBuffer buf(34);
buf.add8(Z_SREQ | Z_ZDO); // 25
buf.add8(ZDO_MGMT_PERMIT_JOIN_REQ); // 36
@@ -1200,6 +1487,7 @@ void CmndZbPermitJoin(void) {
buf.add8(0x00); // TCSignificance
ZigbeeZNPSend(buf.getBuffer(), buf.len());
+#endif // USE_ZIGBEE_ZNP
ResponseCmndDone();
}
diff --git a/tasmota/xdrv_31_tasmota_client.ino b/tasmota/xdrv_31_tasmota_client.ino
new file mode 100644
index 000000000..27e289373
--- /dev/null
+++ b/tasmota/xdrv_31_tasmota_client.ino
@@ -0,0 +1,585 @@
+/*
+ xdrv_31_tasmota_client.ino - Support for external microcontroller on serial
+
+ Copyright (C) 2020 Andre Thomas and Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifdef USE_TASMOTA_CLIENT
+/*********************************************************************************************\
+ * Tasmota to microcontroller
+\*********************************************************************************************/
+
+#define XDRV_31 31
+
+#define CONST_STK_CRC_EOP 0x20
+
+#define CMND_STK_GET_SYNC 0x30
+#define CMND_STK_SET_DEVICE 0x42
+#define CMND_STK_SET_DEVICE_EXT 0x45
+#define CMND_STK_ENTER_PROGMODE 0x50
+#define CMND_STK_LEAVE_PROGMODE 0x51
+#define CMND_STK_LOAD_ADDRESS 0x55
+#define CMND_STK_PROG_PAGE 0x64
+
+/*************************************************\
+ * Tasmota Client Specific Commands
+\*************************************************/
+
+#define CMND_START 0xFC
+#define CMND_END 0xFD
+
+#define CMND_FEATURES 0x01
+#define CMND_JSON 0x02
+#define CMND_FUNC_EVERY_SECOND 0x03
+#define CMND_FUNC_EVERY_100_MSECOND 0x04
+#define CMND_CLIENT_SEND 0x05
+#define CMND_PUBLISH_TELE 0x06
+#define CMND_EXECUTE_CMND 0x07
+
+#define PARAM_DATA_START 0xFE
+#define PARAM_DATA_END 0xFF
+
+#include
+
+/*
+ * Embedding class in here since its rather specific to Arduino bootloader
+ */
+
+class SimpleHexParse {
+ public:
+ SimpleHexParse(void);
+ uint8_t parseLine(char *hexline);
+ uint8_t ptr_l = 0;
+ uint8_t ptr_h = 0;
+ bool PageIsReady = false;
+ bool firstrun = true;
+ bool EndOfFile = false;
+ uint8_t FlashPage[128];
+ uint8_t FlashPageIdx = 0;
+ uint8_t layoverBuffer[16];
+ uint8_t layoverIdx = 0;
+ uint8_t getByte(char *hexline, uint8_t idx);
+};
+
+SimpleHexParse::SimpleHexParse(void) {
+
+}
+
+uint8_t SimpleHexParse::parseLine(char *hexline) {
+ if (layoverIdx) {
+ memcpy(&FlashPage[0], &layoverBuffer[0], layoverIdx);
+ FlashPageIdx = layoverIdx;
+ layoverIdx = 0;
+ }
+ uint8_t len = getByte(hexline, 1);
+ uint8_t addr_h = getByte(hexline, 2);
+ uint8_t addr_l = getByte(hexline, 3);
+ uint8_t rectype = getByte(hexline, 4);
+ for (uint8_t idx = 0; idx < len; idx++) {
+ if (FlashPageIdx < 128) {
+ FlashPage[FlashPageIdx] = getByte(hexline, idx+5);
+ FlashPageIdx++;
+ } else { // We have layover bytes
+ layoverBuffer[layoverIdx] = getByte(hexline, idx+5);
+ layoverIdx++;
+ }
+ }
+ if (1 == rectype) {
+ EndOfFile = true;
+ while (FlashPageIdx < 128) {
+ FlashPage[FlashPageIdx] = 0xFF;
+ FlashPageIdx++;
+ }
+ }
+ if (FlashPageIdx == 128) {
+ if (firstrun) {
+ firstrun = false;
+ } else {
+ ptr_l += 0x40;
+ if (ptr_l == 0) {
+ ptr_l = 0;
+ ptr_h++;
+ }
+ }
+ firstrun = false;
+ PageIsReady = true;
+ }
+ return 0;
+}
+
+uint8_t SimpleHexParse::getByte(char* hexline, uint8_t idx) {
+ char buff[3];
+ buff[3] = '\0';
+ memcpy(&buff, &hexline[(idx*2)-1], 2);
+ return strtol(buff, 0, 16);
+}
+
+/*
+ * End of embedded class SimpleHexParse
+ */
+
+struct TCLIENT {
+ uint32_t spi_hex_size = 0;
+ uint32_t spi_sector_counter = 0;
+ uint8_t spi_sector_cursor = 0;
+ uint8_t inverted = LOW;
+ bool type = false;
+ bool flashing = false;
+ bool SerialEnabled = false;
+ uint8_t waitstate = 0; // We use this so that features detection does not slow down other stuff on startup
+ bool unsupported = false;
+} TClient;
+
+typedef union {
+ uint32_t data;
+ struct {
+ uint32_t func_json_append : 1; // Client supports providing a JSON for TELEPERIOD
+ uint32_t func_every_second : 1; // Client supports receiving a FUNC_EVERY_SECOND callback with no response
+ uint32_t func_every_100_msecond : 1; // Client supports receiving a FUNC_EVERY_100_MSECOND callback with no response
+ uint32_t func_client_send : 1; // Client supports receiving commands with "client send xxx"
+ uint32_t spare4 : 1;
+ uint32_t spare5 : 1;
+ uint32_t spare6 : 1;
+ uint32_t spare7 : 1;
+ uint32_t spare8 : 1;
+ uint32_t spare9 : 1;
+ uint32_t spare10 : 1;
+ uint32_t spare11 : 1;
+ uint32_t spare12 : 1;
+ uint32_t spare13 : 1;
+ uint32_t spare14 : 1;
+ uint32_t spare15 : 1;
+ uint32_t spare16 : 1;
+ uint32_t spare17 : 1;
+ uint32_t spare18 : 1;
+ uint32_t spare19 : 1;
+ uint32_t spare20 : 1;
+ uint32_t spare21 : 1;
+ uint32_t spare22 : 1;
+ uint32_t spare23 : 1;
+ uint32_t spare24 : 1;
+ uint32_t spare25 : 1;
+ uint32_t spare26 : 1;
+ uint32_t spare27 : 1;
+ uint32_t spare28 : 1;
+ uint32_t spare29 : 1;
+ uint32_t spare30 : 1;
+ uint32_t spare31 : 1;
+ };
+} TClientFeatureCfg;
+
+/*
+ * The structure below must remain 4 byte aligned to be compatible with
+ * Tasmota as master
+ */
+
+struct TCLIENT_FEATURES {
+ uint32_t features_version;
+ TClientFeatureCfg features;
+} TClientSettings;
+
+struct TCLIENT_COMMAND {
+ uint8_t command;
+ uint8_t parameter;
+ uint8_t unused2;
+ uint8_t unused3;
+} TClientCommand;
+
+TasmotaSerial *TasmotaClient_Serial;
+
+uint32_t TasmotaClient_FlashStart(void) {
+ return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
+}
+
+uint8_t TasmotaClient_UpdateInit(void) {
+ TClient.spi_hex_size = 0;
+ TClient.spi_sector_counter = TasmotaClient_FlashStart(); // Reset the pre-defined write address where firmware will temporarily be stored
+ TClient.spi_sector_cursor = 0;
+ return 0;
+}
+
+void TasmotaClient_Reset(void) {
+ if (TClient.SerialEnabled) {
+ digitalWrite(Pin(GPIO_TASMOTACLIENT_RST), !TClient.inverted);
+ delay(1);
+ digitalWrite(Pin(GPIO_TASMOTACLIENT_RST), TClient.inverted);
+ delay(1);
+ digitalWrite(Pin(GPIO_TASMOTACLIENT_RST), !TClient.inverted);
+ delay(5);
+ }
+}
+
+uint8_t TasmotaClient_waitForSerialData(int dataCount, int timeout) {
+ int timer = 0;
+ while (timer < timeout) {
+ if (TasmotaClient_Serial->available() >= dataCount) {
+ return 1;
+ }
+ delay(1);
+ timer++;
+ }
+ return 0;
+}
+
+uint8_t TasmotaClient_sendBytes(uint8_t* bytes, int count) {
+ TasmotaClient_Serial->write(bytes, count);
+ TasmotaClient_waitForSerialData(2, 250);
+ uint8_t sync = TasmotaClient_Serial->read();
+ uint8_t ok = TasmotaClient_Serial->read();
+ if ((sync == 0x14) && (ok == 0x10)) {
+ return 1;
+ }
+ return 0;
+}
+
+uint8_t TasmotaClient_execCmd(uint8_t cmd) {
+ uint8_t bytes[] = { cmd, CONST_STK_CRC_EOP };
+ return TasmotaClient_sendBytes(bytes, 2);
+}
+
+uint8_t TasmotaClient_execParam(uint8_t cmd, uint8_t* params, int count) {
+ uint8_t bytes[32];
+ bytes[0] = cmd;
+ int i = 0;
+ while (i < count) {
+ bytes[i + 1] = params[i];
+ i++;
+ }
+ bytes[i + 1] = CONST_STK_CRC_EOP;
+ return TasmotaClient_sendBytes(bytes, i + 2);
+}
+
+uint8_t TasmotaClient_exitProgMode(void) {
+ return TasmotaClient_execCmd(CMND_STK_LEAVE_PROGMODE); // Exit programming mode
+}
+
+uint8_t TasmotaClient_SetupFlash(void) {
+ uint8_t ProgParams[] = {0x86, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00};
+ uint8_t ExtProgParams[] = {0x05, 0x04, 0xd7, 0xc2, 0x00};
+ TasmotaClient_Serial->begin(USE_TASMOTA_CLIENT_FLASH_SPEED);
+ if (TasmotaClient_Serial->hardwareSerial()) {
+ ClaimSerial();
+ }
+
+ TasmotaClient_Reset();
+
+ uint8_t timeout = 0;
+ uint8_t no_error = 0;
+ while (50 > timeout) {
+ if (TasmotaClient_execCmd(CMND_STK_GET_SYNC)) {
+ timeout = 200;
+ no_error = 1;
+ }
+ timeout++;
+ delay(1);
+ }
+ if (no_error) {
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Found bootloader"));
+ } else {
+ no_error = 0;
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Bootloader could not be found"));
+ }
+ if (no_error) {
+ if (TasmotaClient_execParam(CMND_STK_SET_DEVICE, ProgParams, sizeof(ProgParams))) {
+ } else {
+ no_error = 0;
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Could not configure device for programming (1)"));
+ }
+ }
+ if (no_error) {
+ if (TasmotaClient_execParam(CMND_STK_SET_DEVICE_EXT, ExtProgParams, sizeof(ExtProgParams))) {
+ } else {
+ no_error = 0;
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Could not configure device for programming (2)"));
+ }
+ }
+ if (no_error) {
+ if (TasmotaClient_execCmd(CMND_STK_ENTER_PROGMODE)) {
+ } else {
+ no_error = 0;
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Failed to put bootloader into programming mode"));
+ }
+ }
+ return no_error;
+}
+
+uint8_t TasmotaClient_loadAddress(uint8_t adrHi, uint8_t adrLo) {
+ uint8_t params[] = { adrLo, adrHi };
+ return TasmotaClient_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params));
+}
+
+void TasmotaClient_FlashPage(uint8_t addr_h, uint8_t addr_l, uint8_t* data) {
+ uint8_t Header[] = {CMND_STK_PROG_PAGE, 0x00, 0x80, 0x46};
+ TasmotaClient_loadAddress(addr_h, addr_l);
+ TasmotaClient_Serial->write(Header, 4);
+ for (int i = 0; i < 128; i++) {
+ TasmotaClient_Serial->write(data[i]);
+ }
+ TasmotaClient_Serial->write(CONST_STK_CRC_EOP);
+ TasmotaClient_waitForSerialData(2, 250);
+ TasmotaClient_Serial->read();
+ TasmotaClient_Serial->read();
+}
+
+void TasmotaClient_Flash(void) {
+ bool reading = true;
+ uint32_t read = 0;
+ uint32_t processed = 0;
+ char thishexline[50];
+ uint8_t position = 0;
+ char* flash_buffer;
+
+ SimpleHexParse hexParse = SimpleHexParse();
+
+ if (!TasmotaClient_SetupFlash()) {
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Flashing aborted!"));
+ TClient.flashing = false;
+ restart_flag = 2;
+ return;
+ }
+
+ flash_buffer = new char[SPI_FLASH_SEC_SIZE];
+ uint32_t flash_start = TasmotaClient_FlashStart() * SPI_FLASH_SEC_SIZE;
+ while (reading) {
+ ESP.flashRead(flash_start + read, (uint32_t*)flash_buffer, SPI_FLASH_SEC_SIZE);
+ read = read + SPI_FLASH_SEC_SIZE;
+ if (read >= TClient.spi_hex_size) {
+ reading = false;
+ }
+ for (uint32_t ca = 0; ca < SPI_FLASH_SEC_SIZE; ca++) {
+ processed++;
+ if ((processed <= TClient.spi_hex_size) && (!hexParse.EndOfFile)) {
+ if (':' == flash_buffer[ca]) {
+ position = 0;
+ }
+ if (0x0D == flash_buffer[ca]) {
+ thishexline[position] = 0;
+ hexParse.parseLine(thishexline);
+ if (hexParse.PageIsReady) {
+ TasmotaClient_FlashPage(hexParse.ptr_h, hexParse.ptr_l, hexParse.FlashPage);
+ hexParse.PageIsReady = false;
+ hexParse.FlashPageIdx = 0;
+ }
+ } else {
+ if (0x0A != flash_buffer[ca]) {
+ thishexline[position] = flash_buffer[ca];
+ position++;
+ }
+ }
+ }
+ }
+ }
+ TasmotaClient_exitProgMode();
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Flash done!"));
+ TClient.flashing = false;
+ restart_flag = 2;
+}
+
+void TasmotaClient_SetFlagFlashing(bool value) {
+ TClient.flashing = value;
+}
+
+bool TasmotaClient_GetFlagFlashing(void) {
+ return TClient.flashing;
+}
+
+void TasmotaClient_WriteBuffer(uint8_t *buf, size_t size) {
+ if (0 == TClient.spi_sector_cursor) { // Starting a new sector write so we need to erase it first
+ ESP.flashEraseSector(TClient.spi_sector_counter);
+ }
+ TClient.spi_sector_cursor++;
+ ESP.flashWrite((TClient.spi_sector_counter * SPI_FLASH_SEC_SIZE) + ((TClient.spi_sector_cursor-1)*2048), (uint32_t*)buf, size);
+ TClient.spi_hex_size = TClient.spi_hex_size + size;
+ if (2 == TClient.spi_sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase
+ TClient.spi_sector_cursor = 0;
+ TClient.spi_sector_counter++;
+ }
+}
+
+void TasmotaClient_Init(void) {
+ if (TClient.type) {
+ return;
+ }
+ if (10 > TClient.waitstate) {
+ TClient.waitstate++;
+ return;
+ }
+ if (!TClient.SerialEnabled) {
+ if (PinUsed(GPIO_TASMOTACLIENT_RXD) && PinUsed(GPIO_TASMOTACLIENT_TXD) &&
+ (PinUsed(GPIO_TASMOTACLIENT_RST) || PinUsed(GPIO_TASMOTACLIENT_RST_INV))) {
+ TasmotaClient_Serial = new TasmotaSerial(Pin(GPIO_TASMOTACLIENT_RXD), Pin(GPIO_TASMOTACLIENT_TXD), 1, 0, 200);
+ if (TasmotaClient_Serial->begin(USE_TASMOTA_CLIENT_SERIAL_SPEED)) {
+ if (TasmotaClient_Serial->hardwareSerial()) {
+ ClaimSerial();
+ }
+ TasmotaClient_Serial->setTimeout(100); // Theo 20200502 - increase from 50
+ if (PinUsed(GPIO_TASMOTACLIENT_RST_INV)) {
+ SetPin(Pin(GPIO_TASMOTACLIENT_RST_INV), GPIO_TASMOTACLIENT_RST);
+ TClient.inverted = HIGH;
+ }
+ pinMode(Pin(GPIO_TASMOTACLIENT_RST), OUTPUT);
+ TClient.SerialEnabled = true;
+ TasmotaClient_Reset();
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Enabled"));
+ }
+ }
+ }
+ if (TClient.SerialEnabled) { // All go for hardware now we need to detect features if there are any
+ TasmotaClient_sendCmnd(CMND_FEATURES, 0);
+ char buffer[32] = { 0 };
+ TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer));
+ uint8_t len = TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer));
+
+ if (len) { AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)buffer, len); } // Theo 20200502 - DMP: 99 17 34 01 02 00 00 00
+
+ memcpy(&TClientSettings, &buffer, sizeof(TClientSettings));
+ if (20191129 == TClientSettings.features_version) {
+ TClient.type = true;
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Version %u"), TClientSettings.features_version);
+ } else {
+ if ((!TClient.unsupported) && (TClientSettings.features_version > 0)) {
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Version %u not supported!"), TClientSettings.features_version);
+ TClient.unsupported = true;
+ }
+ }
+ }
+}
+
+void TasmotaClient_Show(void) {
+ if ((TClient.type) && (TClientSettings.features.func_json_append)) {
+ char buffer[100];
+ TasmotaClient_sendCmnd(CMND_JSON, 0);
+ TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)-1);
+ uint8_t len = TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)-1);
+ buffer[len] = '\0';
+ ResponseAppend_P(PSTR(",\"TasmotaClient\":%s"), buffer);
+ }
+}
+
+void TasmotaClient_sendCmnd(uint8_t cmnd, uint8_t param) {
+ TClientCommand.command = cmnd;
+ TClientCommand.parameter = param;
+ char buffer[sizeof(TClientCommand)+2];
+ buffer[0] = CMND_START;
+ memcpy(&buffer[1], &TClientCommand, sizeof(TClientCommand));
+ buffer[sizeof(TClientCommand)+1] = CMND_END;
+
+ TasmotaClient_Serial->flush(); // Theo 20200502
+
+ for (uint8_t ca = 0; ca < sizeof(buffer); ca++) {
+ TasmotaClient_Serial->write(buffer[ca]);
+ }
+}
+
+#define D_PRFX_CLIENT "Client"
+#define D_CMND_CLIENT_RESET "Reset"
+#define D_CMND_CLIENT_SEND "Send"
+
+const char kTasmotaClientCommands[] PROGMEM = D_PRFX_CLIENT "|"
+ D_CMND_CLIENT_RESET "|" D_CMND_CLIENT_SEND;
+
+void (* const TasmotaClientCommand[])(void) PROGMEM = {
+ &CmndClientReset, &CmndClientSend };
+
+void CmndClientReset(void) {
+ TasmotaClient_Reset();
+ TClient.type = false; // Force redetection
+ TClient.waitstate = 7; // give it at least 3 seconds to restart from bootloader
+ TClient.unsupported = false; // Reset unsupported flag
+ ResponseCmndDone();
+}
+
+void CmndClientSend(void) {
+ if (0 < XdrvMailbox.data_len) {
+ TasmotaClient_sendCmnd(CMND_CLIENT_SEND, XdrvMailbox.data_len);
+ TasmotaClient_Serial->write(char(PARAM_DATA_START));
+ for (uint8_t idx = 0; idx < XdrvMailbox.data_len; idx++) {
+ TasmotaClient_Serial->write(XdrvMailbox.data[idx]);
+ }
+ TasmotaClient_Serial->write(char(PARAM_DATA_END));
+ }
+ ResponseCmndDone();
+}
+
+void TasmotaClient_ProcessIn(void) {
+ uint8_t cmnd = TasmotaClient_Serial->read();
+ if (CMND_START == cmnd) {
+ TasmotaClient_waitForSerialData(sizeof(TClientCommand),50);
+ uint8_t buffer[sizeof(TClientCommand)];
+ for (uint8_t idx = 0; idx < sizeof(TClientCommand); idx++) {
+ buffer[idx] = TasmotaClient_Serial->read();
+ }
+ TasmotaClient_Serial->read(); // read trailing byte of command
+ memcpy(&TClientCommand, &buffer, sizeof(TClientCommand));
+ char inbuf[TClientCommand.parameter+1];
+ TasmotaClient_waitForSerialData(TClientCommand.parameter, 50);
+ TasmotaClient_Serial->read(); // Read leading byte
+ for (uint8_t idx = 0; idx < TClientCommand.parameter; idx++) {
+ inbuf[idx] = TasmotaClient_Serial->read();
+ }
+ TasmotaClient_Serial->read(); // Read trailing byte
+ inbuf[TClientCommand.parameter] = '\0';
+
+ if (CMND_PUBLISH_TELE == TClientCommand.command) { // We need to publish stat/ with incoming stream as content
+ Response_P(PSTR("{\"TasmotaClient\":"));
+ ResponseAppend_P("%s", inbuf);
+ ResponseJsonEnd();
+ MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data);
+ XdrvRulesProcess();
+ }
+ if (CMND_EXECUTE_CMND == TClientCommand.command) { // We need to execute the incoming command
+ ExecuteCommand(inbuf, SRC_IGNORE);
+ }
+ }
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xdrv31(uint8_t function) {
+ bool result = false;
+
+ switch (function) {
+ case FUNC_EVERY_100_MSECOND:
+ if (TClient.type) {
+ if (TasmotaClient_Serial->available()) {
+ TasmotaClient_ProcessIn();
+ }
+ if (TClientSettings.features.func_every_100_msecond) {
+ TasmotaClient_sendCmnd(CMND_FUNC_EVERY_100_MSECOND, 0);
+ }
+ }
+ break;
+ case FUNC_EVERY_SECOND:
+ if ((TClient.type) && (TClientSettings.features.func_every_second)) {
+ TasmotaClient_sendCmnd(CMND_FUNC_EVERY_SECOND, 0);
+ }
+ TasmotaClient_Init();
+ break;
+ case FUNC_JSON_APPEND:
+ if ((TClient.type) && (TClientSettings.features.func_json_append)) {
+ TasmotaClient_Show();
+ }
+ break;
+ case FUNC_COMMAND:
+ result = DecodeCommand(kTasmotaClientCommands, TasmotaClientCommand);
+ break;
+ }
+ return result;
+}
+
+#endif // USE_TASMOTA_CLIENT
diff --git a/tasmota/xdrv_31_tasmota_slave.ino b/tasmota/xdrv_31_tasmota_slave.ino
deleted file mode 100644
index 38306a791..000000000
--- a/tasmota/xdrv_31_tasmota_slave.ino
+++ /dev/null
@@ -1,615 +0,0 @@
-/*
- xdrv_31_tasmota_slave.ino - Support for external microcontroller slave on serial
-
- Copyright (C) 2020 Andre Thomas and Theo Arends
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#ifdef USE_TASMOTA_SLAVE
-/*********************************************************************************************\
- * Tasmota slave
-\*********************************************************************************************/
-
-#define XDRV_31 31
-
-#define CONST_STK_CRC_EOP 0x20
-
-#define CMND_STK_GET_SYNC 0x30
-#define CMND_STK_SET_DEVICE 0x42
-#define CMND_STK_SET_DEVICE_EXT 0x45
-#define CMND_STK_ENTER_PROGMODE 0x50
-#define CMND_STK_LEAVE_PROGMODE 0x51
-#define CMND_STK_LOAD_ADDRESS 0x55
-#define CMND_STK_PROG_PAGE 0x64
-
-/*************************************************\
- * Tasmota Slave Specific Commands
-\*************************************************/
-
-#define CMND_START 0xFC
-#define CMND_END 0xFD
-
-#define CMND_FEATURES 0x01
-#define CMND_JSON 0x02
-#define CMND_FUNC_EVERY_SECOND 0x03
-#define CMND_FUNC_EVERY_100_MSECOND 0x04
-#define CMND_SLAVE_SEND 0x05
-#define CMND_PUBLISH_TELE 0x06
-#define CMND_EXECUTE_CMND 0x07
-
-#define PARAM_DATA_START 0xFE
-#define PARAM_DATA_END 0xFF
-
-#include
-
-/*
- * Embedding class in here since its rather specific to Arduino bootloader
- */
-
-class SimpleHexParse {
- public:
- SimpleHexParse(void);
- uint8_t parseLine(char *hexline);
- uint8_t ptr_l = 0;
- uint8_t ptr_h = 0;
- bool PageIsReady = false;
- bool firstrun = true;
- bool EndOfFile = false;
- uint8_t FlashPage[128];
- uint8_t FlashPageIdx = 0;
- uint8_t layoverBuffer[16];
- uint8_t layoverIdx = 0;
- uint8_t getByte(char *hexline, uint8_t idx);
-};
-
-SimpleHexParse::SimpleHexParse(void)
-{
-
-}
-
-uint8_t SimpleHexParse::parseLine(char *hexline)
-{
- if (layoverIdx) {
- memcpy(&FlashPage[0], &layoverBuffer[0], layoverIdx);
- FlashPageIdx = layoverIdx;
- layoverIdx = 0;
- }
- uint8_t len = getByte(hexline, 1);
- uint8_t addr_h = getByte(hexline, 2);
- uint8_t addr_l = getByte(hexline, 3);
- uint8_t rectype = getByte(hexline, 4);
- for (uint8_t idx = 0; idx < len; idx++) {
- if (FlashPageIdx < 128) {
- FlashPage[FlashPageIdx] = getByte(hexline, idx+5);
- FlashPageIdx++;
- } else { // We have layover bytes
- layoverBuffer[layoverIdx] = getByte(hexline, idx+5);
- layoverIdx++;
- }
- }
- if (1 == rectype) {
- EndOfFile = true;
- while (FlashPageIdx < 128) {
- FlashPage[FlashPageIdx] = 0xFF;
- FlashPageIdx++;
- }
- }
- if (FlashPageIdx == 128) {
- if (firstrun) {
- firstrun = false;
- } else {
- ptr_l += 0x40;
- if (ptr_l == 0) {
- ptr_l = 0;
- ptr_h++;
- }
- }
- firstrun = false;
- PageIsReady = true;
- }
- return 0;
-}
-
-uint8_t SimpleHexParse::getByte(char* hexline, uint8_t idx)
-{
- char buff[3];
- buff[3] = '\0';
- memcpy(&buff, &hexline[(idx*2)-1], 2);
- return strtol(buff, 0, 16);
-}
-
-/*
- * End of embedded class SimpleHexParse
- */
-
-struct TSLAVE {
- uint32_t spi_hex_size = 0;
- uint32_t spi_sector_counter = 0;
- uint8_t spi_sector_cursor = 0;
- uint8_t inverted = LOW;
- bool type = false;
- bool flashing = false;
- bool SerialEnabled = false;
- uint8_t waitstate = 0; // We use this so that features detection does not slow down other stuff on startup
- bool unsupported = false;
-} TSlave;
-
-typedef union {
- uint32_t data;
- struct {
- uint32_t func_json_append : 1; // Slave supports providing a JSON for TELEPERIOD
- uint32_t func_every_second : 1; // Slave supports receiving a FUNC_EVERY_SECOND callback with no response
- uint32_t func_every_100_msecond : 1; // Slave supports receiving a FUNC_EVERY_100_MSECOND callback with no response
- uint32_t func_slave_send : 1; // Slave supports receiving commands with "slave send xxx"
- uint32_t spare4 : 1;
- uint32_t spare5 : 1;
- uint32_t spare6 : 1;
- uint32_t spare7 : 1;
- uint32_t spare8 : 1;
- uint32_t spare9 : 1;
- uint32_t spare10 : 1;
- uint32_t spare11 : 1;
- uint32_t spare12 : 1;
- uint32_t spare13 : 1;
- uint32_t spare14 : 1;
- uint32_t spare15 : 1;
- uint32_t spare16 : 1;
- uint32_t spare17 : 1;
- uint32_t spare18 : 1;
- uint32_t spare19 : 1;
- uint32_t spare20 : 1;
- uint32_t spare21 : 1;
- uint32_t spare22 : 1;
- uint32_t spare23 : 1;
- uint32_t spare24 : 1;
- uint32_t spare25 : 1;
- uint32_t spare26 : 1;
- uint32_t spare27 : 1;
- uint32_t spare28 : 1;
- uint32_t spare29 : 1;
- uint32_t spare30 : 1;
- uint32_t spare31 : 1;
- };
-} TSlaveFeatureCfg;
-
-/*
- * The structure below must remain 4 byte aligned to be compatible with
- * Tasmota as master
- */
-
-struct TSLAVE_FEATURES {
- uint32_t features_version;
- TSlaveFeatureCfg features;
-} TSlaveSettings;
-
-struct TSLAVE_COMMAND {
- uint8_t command;
- uint8_t parameter;
- uint8_t unused2;
- uint8_t unused3;
-} TSlaveCommand;
-
-TasmotaSerial *TasmotaSlave_Serial;
-
-uint32_t TasmotaSlave_FlashStart(void)
-{
- return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
-}
-
-uint8_t TasmotaSlave_UpdateInit(void)
-{
- TSlave.spi_hex_size = 0;
- TSlave.spi_sector_counter = TasmotaSlave_FlashStart(); // Reset the pre-defined write address where firmware will temporarily be stored
- TSlave.spi_sector_cursor = 0;
- return 0;
-}
-
-void TasmotaSlave_Reset(void)
-{
- if (TSlave.SerialEnabled) {
- digitalWrite(Pin(GPIO_TASMOTASLAVE_RST), !TSlave.inverted);
- delay(1);
- digitalWrite(Pin(GPIO_TASMOTASLAVE_RST), TSlave.inverted);
- delay(1);
- digitalWrite(Pin(GPIO_TASMOTASLAVE_RST), !TSlave.inverted);
- delay(5);
- }
-}
-
-uint8_t TasmotaSlave_waitForSerialData(int dataCount, int timeout)
-{
- int timer = 0;
- while (timer < timeout) {
- if (TasmotaSlave_Serial->available() >= dataCount) {
- return 1;
- }
- delay(1);
- timer++;
- }
- return 0;
-}
-
-uint8_t TasmotaSlave_sendBytes(uint8_t* bytes, int count)
-{
- TasmotaSlave_Serial->write(bytes, count);
- TasmotaSlave_waitForSerialData(2, 250);
- uint8_t sync = TasmotaSlave_Serial->read();
- uint8_t ok = TasmotaSlave_Serial->read();
- if ((sync == 0x14) && (ok == 0x10)) {
- return 1;
- }
- return 0;
-}
-
-uint8_t TasmotaSlave_execCmd(uint8_t cmd)
-{
- uint8_t bytes[] = { cmd, CONST_STK_CRC_EOP };
- return TasmotaSlave_sendBytes(bytes, 2);
-}
-
-uint8_t TasmotaSlave_execParam(uint8_t cmd, uint8_t* params, int count)
-{
- uint8_t bytes[32];
- bytes[0] = cmd;
- int i = 0;
- while (i < count) {
- bytes[i + 1] = params[i];
- i++;
- }
- bytes[i + 1] = CONST_STK_CRC_EOP;
- return TasmotaSlave_sendBytes(bytes, i + 2);
-}
-
-uint8_t TasmotaSlave_exitProgMode(void)
-{
- return TasmotaSlave_execCmd(CMND_STK_LEAVE_PROGMODE); // Exit programming mode
-}
-
-uint8_t TasmotaSlave_SetupFlash(void)
-{
- uint8_t ProgParams[] = {0x86, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00};
- uint8_t ExtProgParams[] = {0x05, 0x04, 0xd7, 0xc2, 0x00};
- TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_FLASH_SPEED);
- if (TasmotaSlave_Serial->hardwareSerial()) {
- ClaimSerial();
- }
-
- TasmotaSlave_Reset();
-
- uint8_t timeout = 0;
- uint8_t no_error = 0;
- while (50 > timeout) {
- if (TasmotaSlave_execCmd(CMND_STK_GET_SYNC)) {
- timeout = 200;
- no_error = 1;
- }
- timeout++;
- delay(1);
- }
- if (no_error) {
- AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Found bootloader"));
- } else {
- no_error = 0;
- AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Bootloader could not be found"));
- }
- if (no_error) {
- if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE, ProgParams, sizeof(ProgParams))) {
- } else {
- no_error = 0;
- AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (1)"));
- }
- }
- if (no_error) {
- if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE_EXT, ExtProgParams, sizeof(ExtProgParams))) {
- } else {
- no_error = 0;
- AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (2)"));
- }
- }
- if (no_error) {
- if (TasmotaSlave_execCmd(CMND_STK_ENTER_PROGMODE)) {
- } else {
- no_error = 0;
- AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Failed to put bootloader into programming mode"));
- }
- }
- return no_error;
-}
-
-uint8_t TasmotaSlave_loadAddress(uint8_t adrHi, uint8_t adrLo)
-{
- uint8_t params[] = { adrLo, adrHi };
- return TasmotaSlave_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params));
-}
-
-void TasmotaSlave_FlashPage(uint8_t addr_h, uint8_t addr_l, uint8_t* data)
-{
- uint8_t Header[] = {CMND_STK_PROG_PAGE, 0x00, 0x80, 0x46};
- TasmotaSlave_loadAddress(addr_h, addr_l);
- TasmotaSlave_Serial->write(Header, 4);
- for (int i = 0; i < 128; i++) {
- TasmotaSlave_Serial->write(data[i]);
- }
- TasmotaSlave_Serial->write(CONST_STK_CRC_EOP);
- TasmotaSlave_waitForSerialData(2, 250);
- TasmotaSlave_Serial->read();
- TasmotaSlave_Serial->read();
-}
-
-void TasmotaSlave_Flash(void)
-{
- bool reading = true;
- uint32_t read = 0;
- uint32_t processed = 0;
- char thishexline[50];
- uint8_t position = 0;
- char* flash_buffer;
-
- SimpleHexParse hexParse = SimpleHexParse();
-
- if (!TasmotaSlave_SetupFlash()) {
- AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Flashing aborted!"));
- TSlave.flashing = false;
- restart_flag = 2;
- return;
- }
-
- flash_buffer = new char[SPI_FLASH_SEC_SIZE];
- uint32_t flash_start = TasmotaSlave_FlashStart() * SPI_FLASH_SEC_SIZE;
- while (reading) {
- ESP.flashRead(flash_start + read, (uint32_t*)flash_buffer, SPI_FLASH_SEC_SIZE);
- read = read + SPI_FLASH_SEC_SIZE;
- if (read >= TSlave.spi_hex_size) {
- reading = false;
- }
- for (uint32_t ca = 0; ca < SPI_FLASH_SEC_SIZE; ca++) {
- processed++;
- if ((processed <= TSlave.spi_hex_size) && (!hexParse.EndOfFile)) {
- if (':' == flash_buffer[ca]) {
- position = 0;
- }
- if (0x0D == flash_buffer[ca]) {
- thishexline[position] = 0;
- hexParse.parseLine(thishexline);
- if (hexParse.PageIsReady) {
- TasmotaSlave_FlashPage(hexParse.ptr_h, hexParse.ptr_l, hexParse.FlashPage);
- hexParse.PageIsReady = false;
- hexParse.FlashPageIdx = 0;
- }
- } else {
- if (0x0A != flash_buffer[ca]) {
- thishexline[position] = flash_buffer[ca];
- position++;
- }
- }
- }
- }
- }
- TasmotaSlave_exitProgMode();
- AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Flash done!"));
- TSlave.flashing = false;
- restart_flag = 2;
-}
-
-void TasmotaSlave_SetFlagFlashing(bool value)
-{
- TSlave.flashing = value;
-}
-
-bool TasmotaSlave_GetFlagFlashing(void)
-{
- return TSlave.flashing;
-}
-
-void TasmotaSlave_WriteBuffer(uint8_t *buf, size_t size)
-{
- if (0 == TSlave.spi_sector_cursor) { // Starting a new sector write so we need to erase it first
- ESP.flashEraseSector(TSlave.spi_sector_counter);
- }
- TSlave.spi_sector_cursor++;
- ESP.flashWrite((TSlave.spi_sector_counter * SPI_FLASH_SEC_SIZE) + ((TSlave.spi_sector_cursor-1)*2048), (uint32_t*)buf, size);
- TSlave.spi_hex_size = TSlave.spi_hex_size + size;
- if (2 == TSlave.spi_sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase
- TSlave.spi_sector_cursor = 0;
- TSlave.spi_sector_counter++;
- }
-}
-
-void TasmotaSlave_Init(void)
-{
- if (TSlave.type) {
- return;
- }
- if (10 > TSlave.waitstate) {
- TSlave.waitstate++;
- return;
- }
- if (!TSlave.SerialEnabled) {
- if (PinUsed(GPIO_TASMOTASLAVE_RXD) && PinUsed(GPIO_TASMOTASLAVE_TXD) &&
- (PinUsed(GPIO_TASMOTASLAVE_RST) || PinUsed(GPIO_TASMOTASLAVE_RST_INV))) {
- TasmotaSlave_Serial = new TasmotaSerial(Pin(GPIO_TASMOTASLAVE_RXD), Pin(GPIO_TASMOTASLAVE_TXD), 1, 0, 200);
- if (TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_SERIAL_SPEED)) {
- if (TasmotaSlave_Serial->hardwareSerial()) {
- ClaimSerial();
- }
- TasmotaSlave_Serial->setTimeout(100); // Theo 20200502 - increase from 50
- if (PinUsed(GPIO_TASMOTASLAVE_RST_INV)) {
- SetPin(Pin(GPIO_TASMOTASLAVE_RST_INV), GPIO_TASMOTASLAVE_RST);
- TSlave.inverted = HIGH;
- }
- pinMode(Pin(GPIO_TASMOTASLAVE_RST), OUTPUT);
- TSlave.SerialEnabled = true;
- TasmotaSlave_Reset();
- AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Enabled"));
- }
- }
- }
- if (TSlave.SerialEnabled) { // All go for hardware now we need to detect features if there are any
- TasmotaSlave_sendCmnd(CMND_FEATURES, 0);
- char buffer[32] = { 0 };
- TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer));
- uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer));
-
- if (len) { AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)buffer, len); } // Theo 20200502 - DMP: 99 17 34 01 02 00 00 00
-
- memcpy(&TSlaveSettings, &buffer, sizeof(TSlaveSettings));
- if (20191129 == TSlaveSettings.features_version) {
- TSlave.type = true;
- AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Version %u"), TSlaveSettings.features_version);
- } else {
- if ((!TSlave.unsupported) && (TSlaveSettings.features_version > 0)) {
- AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Version %u not supported!"), TSlaveSettings.features_version);
- TSlave.unsupported = true;
- }
- }
- }
-}
-
-void TasmotaSlave_Show(void)
-{
- if ((TSlave.type) && (TSlaveSettings.features.func_json_append)) {
- char buffer[100];
- TasmotaSlave_sendCmnd(CMND_JSON, 0);
- TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)-1);
- uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)-1);
- buffer[len] = '\0';
- ResponseAppend_P(PSTR(",\"TasmotaSlave\":%s"), buffer);
- }
-}
-
-void TasmotaSlave_sendCmnd(uint8_t cmnd, uint8_t param)
-{
- TSlaveCommand.command = cmnd;
- TSlaveCommand.parameter = param;
- char buffer[sizeof(TSlaveCommand)+2];
- buffer[0] = CMND_START;
- memcpy(&buffer[1], &TSlaveCommand, sizeof(TSlaveCommand));
- buffer[sizeof(TSlaveCommand)+1] = CMND_END;
-
- TasmotaSlave_Serial->flush(); // Theo 20200502
-
- for (uint8_t ca = 0; ca < sizeof(buffer); ca++) {
- TasmotaSlave_Serial->write(buffer[ca]);
- }
-}
-
-#define D_PRFX_SLAVE "Slave"
-#define D_CMND_SLAVE_RESET "Reset"
-#define D_CMND_SLAVE_SEND "Send"
-
-const char kTasmotaSlaveCommands[] PROGMEM = D_PRFX_SLAVE "|"
- D_CMND_SLAVE_RESET "|" D_CMND_SLAVE_SEND;
-
-void (* const TasmotaSlaveCommand[])(void) PROGMEM = {
- &CmndTasmotaSlaveReset, &CmndTasmotaSlaveSend };
-
-void CmndTasmotaSlaveReset(void)
-{
- TasmotaSlave_Reset();
- TSlave.type = false; // Force redetection
- TSlave.waitstate = 7; // give it at least 3 seconds to restart from bootloader
- TSlave.unsupported = false; // Reset unsupported flag
- ResponseCmndDone();
-}
-
-void CmndTasmotaSlaveSend(void)
-{
- if (0 < XdrvMailbox.data_len) {
- TasmotaSlave_sendCmnd(CMND_SLAVE_SEND, XdrvMailbox.data_len);
- TasmotaSlave_Serial->write(char(PARAM_DATA_START));
- for (uint8_t idx = 0; idx < XdrvMailbox.data_len; idx++) {
- TasmotaSlave_Serial->write(XdrvMailbox.data[idx]);
- }
- TasmotaSlave_Serial->write(char(PARAM_DATA_END));
- }
- ResponseCmndDone();
-}
-
-void TasmotaSlave_ProcessIn(void)
-{
- uint8_t cmnd = TasmotaSlave_Serial->read();
- switch (cmnd) {
- case CMND_START:
- TasmotaSlave_waitForSerialData(sizeof(TSlaveCommand),50);
- uint8_t buffer[sizeof(TSlaveCommand)];
- for (uint8_t idx = 0; idx < sizeof(TSlaveCommand); idx++) {
- buffer[idx] = TasmotaSlave_Serial->read();
- }
- TasmotaSlave_Serial->read(); // read trailing byte of command
- memcpy(&TSlaveCommand, &buffer, sizeof(TSlaveCommand));
- char inbuf[TSlaveCommand.parameter+1];
- TasmotaSlave_waitForSerialData(TSlaveCommand.parameter, 50);
- TasmotaSlave_Serial->read(); // Read leading byte
- for (uint8_t idx = 0; idx < TSlaveCommand.parameter; idx++) {
- inbuf[idx] = TasmotaSlave_Serial->read();
- }
- TasmotaSlave_Serial->read(); // Read trailing byte
- inbuf[TSlaveCommand.parameter] = '\0';
-
- if (CMND_PUBLISH_TELE == TSlaveCommand.command) { // We need to publish stat/ with incoming stream as content
- Response_P(PSTR("{\"TasmotaSlave\":"));
- ResponseAppend_P("%s", inbuf);
- ResponseJsonEnd();
- MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data);
- XdrvRulesProcess();
- }
- if (CMND_EXECUTE_CMND == TSlaveCommand.command) { // We need to execute the incoming command
- ExecuteCommand(inbuf, SRC_IGNORE);
- }
- break;
- default:
- break;
- }
-}
-
-
-/*********************************************************************************************\
- * Interface
-\*********************************************************************************************/
-
-bool Xdrv31(uint8_t function)
-{
- bool result = false;
-
- switch (function) {
- case FUNC_EVERY_100_MSECOND:
- if (TSlave.type) {
- if (TasmotaSlave_Serial->available()) {
- TasmotaSlave_ProcessIn();
- }
- if (TSlaveSettings.features.func_every_100_msecond) {
- TasmotaSlave_sendCmnd(CMND_FUNC_EVERY_100_MSECOND, 0);
- }
- }
- break;
- case FUNC_EVERY_SECOND:
- if ((TSlave.type) && (TSlaveSettings.features.func_every_second)) {
- TasmotaSlave_sendCmnd(CMND_FUNC_EVERY_SECOND, 0);
- }
- TasmotaSlave_Init();
- break;
- case FUNC_JSON_APPEND:
- if ((TSlave.type) && (TSlaveSettings.features.func_json_append)) {
- TasmotaSlave_Show();
- }
- break;
- case FUNC_COMMAND:
- result = DecodeCommand(kTasmotaSlaveCommands, TasmotaSlaveCommand);
- break;
- }
- return result;
-}
-
-#endif // USE_TASMOTA_SLAVE
diff --git a/tasmota/xdrv_39_thermostat.ino b/tasmota/xdrv_39_thermostat.ino
index 79e842dc5..768088117 100644
--- a/tasmota/xdrv_39_thermostat.ino
+++ b/tasmota/xdrv_39_thermostat.ino
@@ -1331,7 +1331,7 @@ void ThermostatGetLocalSensor(uint8_t ctr_output) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((const char*)mqtt_data);
if (root.success()) {
- const char* value_c = root["THERMOSTAT_SENSOR_NAME"]["Temperature"];
+ const char* value_c = root[THERMOSTAT_SENSOR_NAME]["Temperature"];
if (value_c != NULL && strlen(value_c) > 0 && (isdigit(value_c[0]) || (value_c[0] == '-' && isdigit(value_c[1])) ) ) {
int16_t value = (int16_t)(CharToFloat(value_c) * 10);
if ( (value >= -1000)
diff --git a/tasmota/xdrv_40_telegram.ino b/tasmota/xdrv_40_telegram.ino
new file mode 100644
index 000000000..a7beb5005
--- /dev/null
+++ b/tasmota/xdrv_40_telegram.ino
@@ -0,0 +1,470 @@
+/*
+ xdrv_40_telegram.ino - telegram for Tasmota
+
+ Copyright (C) 2020 Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifdef USE_TELEGRAM
+/*********************************************************************************************\
+ * Telegram bot
+ *
+ * Supported commands:
+ * TmToken - Add your BotFather created bot token (default none)
+ * TmChatId - Add your BotFather created bot chat id (default none)
+ * TmPoll - Telegram receive poll time (default 10 seconds)
+ * TmState 0 - Disable telegram sending (default)
+ * TmState 1 - Enable telegram sending
+ * TmState 2 - Disable telegram listener (default)
+ * TmState 3 - Enable telegram listener
+ * TmState 4 - Disable telegram response echo (default)
+ * TmState 5 - Enable telegram response echo
+ * TmSend - If telegram sending is enabled AND a chat id is present then send data
+ *
+ * Tested with defines
+ * #define USE_TELEGRAM // Support for Telegram protocol
+ * #define USE_TELEGRAM_FINGERPRINT "\xB2\x72\x47\xA6\x69\x8C\x3C\x69\xF9\x58\x6C\xF3\x60\x02\xFB\x83\xFA\x8B\x1F\x23" // Telegram api.telegram.org TLS public key fingerpring
+\*********************************************************************************************/
+
+#define XDRV_40 40
+
+#define TELEGRAM_SEND_RETRY 4 // Retries
+#define TELEGRAM_LOOP_WAIT 10 // Seconds
+
+#ifdef USE_MQTT_TLS_CA_CERT
+ static const uint32_t tls_rx_size = 2048; // since Telegram CA is bigger than 1024 bytes, we need to increase rx buffer
+ static const uint32_t tls_tx_size = 1024;
+#else
+ static const uint32_t tls_rx_size = 1024;
+ static const uint32_t tls_tx_size = 1024;
+#endif
+
+#include "WiFiClientSecureLightBearSSL.h"
+BearSSL::WiFiClientSecure_light *telegramClient = nullptr;
+
+static const uint8_t Telegram_Fingerprint[] PROGMEM = USE_TELEGRAM_FINGERPRINT;
+
+struct {
+ String message[3][6]; // amount of messages read per time (update_id, name_id, name, lastname, chat_id, text)
+ uint8_t state = 0;
+ uint8_t index = 0;
+ uint8_t retry = 0;
+ uint8_t poll = TELEGRAM_LOOP_WAIT;
+ uint8_t wait = 0;
+ bool send_enable = false;
+ bool recv_enable = false;
+ bool echo_enable = false;
+ bool recv_busy = false;
+} Telegram;
+
+bool TelegramInit(void) {
+ bool init_done = false;
+ if (strlen(SettingsText(SET_TELEGRAM_TOKEN))) {
+ if (!telegramClient) {
+ telegramClient = new BearSSL::WiFiClientSecure_light(tls_rx_size, tls_tx_size);
+#ifdef USE_MQTT_TLS_CA_CERT
+ telegramClient->setTrustAnchor(&GoDaddyCAG2_TA);
+#else
+ telegramClient->setPubKeyFingerprint(Telegram_Fingerprint, Telegram_Fingerprint, false); // check server fingerprint
+#endif
+
+ Telegram.message[0][0]="0"; // Number of received messages
+ Telegram.message[1][0]="";
+ Telegram.message[0][1]="0"; // Code of last read Message
+
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("TGM: Started"));
+ }
+
+ init_done = true;
+ }
+ return init_done;
+}
+
+String TelegramConnectToTelegram(String command) {
+// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Cmnd %s"), command.c_str());
+
+ if (!TelegramInit()) { return ""; }
+
+ String response = "";
+ uint32_t tls_connect_time = millis();
+
+ if (telegramClient->connect("api.telegram.org", 443)) {
+// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Connected in %d ms, max ThunkStack used %d"), millis() - tls_connect_time, telegramClient->getMaxThunkStackUse());
+
+ telegramClient->println("GET /"+command);
+
+ String a = "";
+ char c;
+ int ch_count=0;
+ uint32_t now = millis();
+ bool avail = false;
+ while (millis() -now < 1500) {
+ while (telegramClient->available()) {
+ char c = telegramClient->read();
+ if (ch_count < 700) {
+ response = response + c;
+ ch_count++;
+ }
+ avail = true;
+ }
+ if (avail) {
+ break;
+ }
+ }
+
+ telegramClient->stop();
+ }
+
+ return response;
+}
+
+void TelegramGetUpdates(String offset) {
+ AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: getUpdates"));
+
+ if (!TelegramInit()) { return; }
+
+ String _token = SettingsText(SET_TELEGRAM_TOKEN);
+ String command = "bot" + _token + "/getUpdates?offset=" + offset;
+ String response = TelegramConnectToTelegram(command); //recieve reply from telegram.org
+
+ // {"ok":true,"result":[]}
+ // or
+ // {"ok":true,"result":[
+ // {"update_id":973125394,
+ // "message":{"message_id":25,
+ // "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"},
+ // "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"},
+ // "date":1591877503,
+ // "text":"M1"
+ // }
+ // },
+ // {"update_id":973125395,
+ // "message":{"message_id":26,
+ // "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"},
+ // "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"},
+ // "date":1591877508,
+ // "text":"M2"
+ // }
+ // }
+ // ]}
+ // or
+ // {"ok":true,"result":[
+ // {"update_id":973125396,
+ // "message":{"message_id":29,
+ // "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"},
+ // "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"},
+ // "date":1591879753,
+ // "text":"/power toggle",
+ // "entities":[{"offset":0,"length":6,"type":"bot_command"}]
+ // }
+ // }
+ // ]}
+
+// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str());
+
+ // parsing of reply from Telegram into separate received messages
+ int i = 0; //messages received counter
+ if (response != "") {
+
+// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Sent Update request messages up to %s"), offset.c_str());
+
+ String a = "";
+ int ch_count = 0;
+ String c;
+ for (uint32_t n = 1; n < response.length() +1; n++) { //Search for each message start
+ ch_count++;
+ c = response.substring(n -1, n);
+ a = a + c;
+ if (ch_count > 8) {
+ if (a.substring(ch_count -9) == "update_id") {
+ if (i > 1) { break; }
+ Telegram.message[i][0] = a.substring(0, ch_count -11);
+ a = a.substring(ch_count-11);
+ i++;
+ ch_count = 11;
+ }
+ }
+ }
+ if (1 == i) {
+ Telegram.message[i][0] = a.substring(0, ch_count); //Assign of parsed message into message matrix if only 1 message)
+ }
+ if (i > 1) { i = i -1; }
+ }
+ //check result of parsing process
+ if (response == "") {
+// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Failed to update"));
+ return;
+ }
+ if (0 == i) {
+// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: No new messages"));
+ Telegram.message[0][0] = "0";
+ } else {
+ Telegram.message[0][0] = String(i); //returns how many messages are in the array
+ for (int b = 1; b < i+1; b++) {
+// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Msg %d %s"), b, Telegram.message[b][0].c_str());
+ }
+
+ TelegramAnalizeMessage();
+ }
+}
+
+void TelegramAnalizeMessage(void) {
+ for (uint32_t i = 1; i < Telegram.message[0][0].toInt() +1; i++) {
+ Telegram.message[i][5] = "";
+
+ DynamicJsonBuffer jsonBuffer;
+ JsonObject &root = jsonBuffer.parseObject(Telegram.message[i][0]);
+ if (root.success()) {
+ Telegram.message[i][0] = root["update_id"].as();
+ Telegram.message[i][1] = root["message"]["from"]["id"].as();
+ Telegram.message[i][2] = root["message"]["from"]["first_name"].as();
+ Telegram.message[i][3] = root["message"]["from"]["last_name"].as();
+ Telegram.message[i][4] = root["message"]["chat"]["id"].as();
+ Telegram.message[i][5] = root["message"]["text"].as();
+ }
+
+ int id = Telegram.message[Telegram.message[0][0].toInt()][0].toInt() +1;
+ Telegram.message[0][1] = id; // Write id of last read message
+
+ for (int j = 0; j < 6; j++) {
+// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Parsed%d \"%s\""), j, Telegram.message[i][j].c_str());
+ }
+ }
+}
+
+bool TelegramSendMessage(String chat_id, String text) {
+ AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: sendMessage"));
+
+ if (!TelegramInit()) { return false; }
+
+ bool sent = false;
+ if (text != "") {
+ String _token = SettingsText(SET_TELEGRAM_TOKEN);
+ String command = "bot" + _token + "/sendMessage?chat_id=" + chat_id + "&text=" + text;
+ String response = TelegramConnectToTelegram(command);
+
+// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str());
+
+ if (response.startsWith("{\"ok\":true")) {
+// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Message sent"));
+ sent = true;
+ }
+
+ }
+
+ return sent;
+}
+
+/*
+void TelegramSendGetMe(void) {
+ AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: getMe"));
+
+ if (!TelegramInit()) { return; }
+
+ String _token = SettingsText(SET_TELEGRAM_TOKEN);
+ String command = "bot" + _token + "/getMe";
+ String response = TelegramConnectToTelegram(command);
+
+ // {"ok":true,"result":{"id":1179906608,"is_bot":true,"first_name":"Tasmota","username":"tasmota_bot","can_join_groups":true,"can_read_all_group_messages":false,"supports_inline_queries":false}}
+
+// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str());
+}
+*/
+
+String TelegramExecuteCommand(const char *svalue) {
+ String response = "";
+
+ uint32_t curridx = web_log_index;
+ ExecuteCommand(svalue, SRC_CHAT);
+ if (web_log_index != curridx) {
+ uint32_t counter = curridx;
+ response = F("{");
+ bool cflg = false;
+ do {
+ char* tmp;
+ size_t len;
+ GetLog(counter, &tmp, &len);
+ if (len) {
+ // [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
+ char* JSON = (char*)memchr(tmp, '{', len);
+ if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
+ size_t JSONlen = len - (JSON - tmp);
+ if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); }
+ char stemp[JSONlen];
+ strlcpy(stemp, JSON +1, JSONlen -2);
+ if (cflg) { response += F(","); }
+ response += stemp;
+ cflg = true;
+ }
+ }
+ counter++;
+ counter &= 0xFF;
+ if (!counter) counter++; // Skip 0 as it is not allowed
+ } while (counter != web_log_index);
+ response += F("}");
+ } else {
+ response = F("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}");
+ }
+
+ return response;
+}
+
+void TelegramLoop(void) {
+ if (!global_state.network_down && (Telegram.recv_enable || Telegram.echo_enable)) {
+ switch (Telegram.state) {
+ case 0:
+ TelegramInit();
+ Telegram.state++;
+ break;
+ case 1:
+ TelegramGetUpdates(Telegram.message[0][1]); // launch API GetUpdates up to xxx message
+ Telegram.index = 1;
+ Telegram.retry = TELEGRAM_SEND_RETRY;
+ Telegram.state++;
+ break;
+ case 2:
+ if (Telegram.echo_enable) {
+ if (Telegram.retry && (Telegram.index < Telegram.message[0][0].toInt() + 1)) {
+ if (TelegramSendMessage(Telegram.message[Telegram.index][4], Telegram.message[Telegram.index][5])) {
+ Telegram.index++;
+ Telegram.retry = TELEGRAM_SEND_RETRY;
+ } else {
+ Telegram.retry--;
+ }
+ } else {
+ Telegram.message[0][0] = ""; // All messages have been replied - reset new messages
+ Telegram.wait = Telegram.poll;
+ Telegram.state++;
+ }
+ } else {
+ if (Telegram.message[0][0].toInt() && (Telegram.message[Telegram.index][5].length() > 0)) {
+ String logging = TelegramExecuteCommand(Telegram.message[Telegram.index][5].c_str());
+ if (logging.length() > 0) {
+ TelegramSendMessage(Telegram.message[Telegram.index][4], logging);
+ }
+ }
+ Telegram.message[0][0] = ""; // All messages have been replied - reset new messages
+ Telegram.wait = Telegram.poll;
+ Telegram.state++;
+ }
+ break;
+ case 3:
+ if (Telegram.wait) {
+ Telegram.wait--;
+ } else {
+ Telegram.state = 1;
+ }
+ }
+ }
+}
+
+/*********************************************************************************************\
+ * Commands
+\*********************************************************************************************/
+
+#define D_CMND_TMSTATE "State"
+#define D_CMND_TMPOLL "Poll"
+#define D_CMND_TMSEND "Send"
+#define D_CMND_TMTOKEN "Token"
+#define D_CMND_TMCHATID "ChatId"
+
+const char kTelegramCommands[] PROGMEM = "Tm|" // Prefix
+ D_CMND_TMSTATE "|" D_CMND_TMPOLL "|" D_CMND_TMTOKEN "|" D_CMND_TMCHATID "|" D_CMND_TMSEND;
+
+void (* const TelegramCommand[])(void) PROGMEM = {
+ &CmndTmState, &CmndTmPoll, &CmndTmToken, &CmndTmChatId, &CmndTmSend };
+
+void CmndTmState(void) {
+ if (XdrvMailbox.data_len > 0) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6)) {
+ switch (XdrvMailbox.payload) {
+ case 0: // Off
+ case 1: // On
+ Telegram.send_enable = XdrvMailbox.payload &1;
+ break;
+ case 2: // Off
+ case 3: // On
+ Telegram.recv_enable = XdrvMailbox.payload &1;
+ break;
+ case 4: // Off
+ case 5: // On
+ Telegram.echo_enable = XdrvMailbox.payload &1;
+ break;
+ }
+ }
+ }
+ snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"Send\":\"%s\",\"Receive\":\"%s\",\"Echo\":\"%s\"}}"),
+ XdrvMailbox.command, GetStateText(Telegram.send_enable), GetStateText(Telegram.recv_enable), GetStateText(Telegram.echo_enable));
+}
+
+void CmndTmPoll(void) {
+ if ((XdrvMailbox.payload >= 4) && (XdrvMailbox.payload <= 300)) {
+ Telegram.poll = XdrvMailbox.payload;
+ if (Telegram.poll < Telegram.wait) {
+ Telegram.wait = Telegram.poll;
+ }
+ }
+ ResponseCmndNumber(Telegram.poll);
+}
+
+void CmndTmToken(void) {
+ if (XdrvMailbox.data_len > 0) {
+ SettingsUpdateText(SET_TELEGRAM_TOKEN, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data);
+ }
+ ResponseCmndChar(SettingsText(SET_TELEGRAM_TOKEN));
+}
+
+void CmndTmChatId(void) {
+ if (XdrvMailbox.data_len > 0) {
+ SettingsUpdateText(SET_TELEGRAM_CHATID, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data);
+ }
+ ResponseCmndChar(SettingsText(SET_TELEGRAM_CHATID));
+}
+
+void CmndTmSend(void) {
+ if (!Telegram.send_enable || !strlen(SettingsText(SET_TELEGRAM_CHATID))) {
+ ResponseCmndChar(D_JSON_FAILED);
+ return;
+ }
+ if (XdrvMailbox.data_len > 0) {
+ String message = XdrvMailbox.data;
+ String chat_id = SettingsText(SET_TELEGRAM_CHATID);
+ if (!TelegramSendMessage(chat_id, message)) {
+ ResponseCmndChar(D_JSON_FAILED);
+ return;
+ }
+ }
+ ResponseCmndDone();
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xdrv40(uint8_t function)
+{
+ bool result = false;
+
+ switch (function) {
+ case FUNC_EVERY_SECOND:
+ TelegramLoop();
+ break;
+ case FUNC_COMMAND:
+ result = DecodeCommand(kTelegramCommands, TelegramCommand);
+ break;
+ }
+ return result;
+}
+#endif // USE_TELEGRAM
diff --git a/tasmota/xdrv_41_tcp_bridge.ino b/tasmota/xdrv_41_tcp_bridge.ino
new file mode 100644
index 000000000..a6513ec46
--- /dev/null
+++ b/tasmota/xdrv_41_tcp_bridge.ino
@@ -0,0 +1,205 @@
+/*
+ xdrv_41_tcp_bridge.ino - TCP to serial bridge
+
+ Copyright (C) 2020 Theo Arends and 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 .
+*/
+
+#ifdef USE_TCP_BRIDGE
+
+#define XDRV_41 41
+
+#ifndef TCP_BRIDGE_CONNECTIONS
+#define TCP_BRIDGE_CONNECTIONS 2 // number of maximum parallel connections
+#endif
+
+#ifndef TCP_BRIDGE_BUF_SIZE
+#define TCP_BRIDGE_BUF_SIZE 255 // size of the buffer, above 132 required for efficient XMODEM
+#endif
+
+//const uint16_t tcp_port = 8880;
+WiFiServer *server_tcp = nullptr;
+//WiFiClient client_tcp1, client_tcp2;
+WiFiClient client_tcp[TCP_BRIDGE_CONNECTIONS];
+uint8_t client_next = 0;
+uint8_t *tcp_buf = nullptr; // data transfer buffer
+
+#include
+TasmotaSerial *TCPSerial = nullptr;
+
+const char kTCPCommands[] PROGMEM = "TCP" "|" // prefix
+ "Start" "|" "Baudrate"
+ ;
+
+void (* const TCPCommand[])(void) PROGMEM = {
+ &CmndTCPStart, &CmndTCPBaudrate
+ };
+
+//
+// Called at event loop, checks for incoming data from the CC2530
+//
+void TCPLoop(void)
+{
+ uint8_t c;
+ bool busy; // did we transfer some data?
+ int32_t buf_len;
+
+ if (!TCPSerial) return;
+
+ // check for a new client connection
+ if ((server_tcp) && (server_tcp->hasClient())) {
+ // find an empty slot
+ uint32_t i;
+ for (i=0; iavailable();
+ break;
+ }
+ }
+ if (i >= ARRAY_SIZE(client_tcp)) {
+ i = client_next++ % ARRAY_SIZE(client_tcp);
+ WiFiClient &client = client_tcp[i];
+ client.stop();
+ client = server_tcp->available();
+ }
+ }
+
+ do {
+ busy = false; // exit loop if no data was transferred
+
+ // start reading the UART, this buffer can quickly overflow
+ buf_len = 0;
+ while ((buf_len < TCP_BRIDGE_BUF_SIZE) && (TCPSerial->available())) {
+ c = TCPSerial->read();
+ if (c >= 0) {
+ tcp_buf[buf_len++] = c;
+ busy = true;
+ }
+ }
+ if (buf_len > 0) {
+ char hex_char[TCP_BRIDGE_BUF_SIZE+1];
+ ToHex_P(tcp_buf, buf_len, hex_char, 256);
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_TCP "from MCU: %s"), hex_char);
+
+ for (uint32_t i=0; i= 0) {
+ tcp_buf[buf_len++] = c;
+ busy = true;
+ }
+ }
+ if (buf_len > 0) {
+ char hex_char[TCP_BRIDGE_BUF_SIZE+1];
+ ToHex_P(tcp_buf, buf_len, hex_char, 256);
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_TCP "to MCU/%d: %s"), i+1, hex_char);
+ TCPSerial->write(tcp_buf, buf_len);
+ }
+ }
+
+ yield(); // avoid WDT if heavy traffic
+ } while (busy);
+}
+
+/********************************************************************************************/
+void TCPInit(void) {
+ if (PinUsed(GPIO_TCP_RX) && PinUsed(GPIO_TCP_TX)) {
+ tcp_buf = (uint8_t*) malloc(TCP_BRIDGE_BUF_SIZE);
+ if (!tcp_buf) { AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_TCP "could not allocate buffer")); return; }
+
+ if (!Settings.tcp_baudrate) { Settings.tcp_baudrate = 115200 / 1200; }
+ TCPSerial = new TasmotaSerial(Pin(GPIO_TCP_RX), Pin(GPIO_TCP_TX), seriallog_level ? 1 : 2, 0, TCP_BRIDGE_BUF_SIZE); // set a receive buffer of 256 bytes
+ TCPSerial->begin(Settings.tcp_baudrate * 1200);
+ if (TCPSerial->hardwareSerial()) {
+ ClaimSerial();
+ }
+ }
+}
+
+/*********************************************************************************************\
+ * Commands
+\*********************************************************************************************/
+
+//
+// Command `ZbConfig`
+//
+void CmndTCPStart(void) {
+
+ if (!TCPSerial) { return; }
+ int32_t tcp_port = XdrvMailbox.payload;
+
+ if (server_tcp) {
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_TCP "Stopping TCP server"));
+ server_tcp->stop();
+ delete server_tcp;
+ server_tcp = nullptr;
+
+ for (uint32_t i=0; i 0) {
+ AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_TCP "Starting TCP server on port %d"), tcp_port);
+ server_tcp = new WiFiServer(tcp_port);
+ server_tcp->begin(); // start TCP server
+ server_tcp->setNoDelay(true);
+ }
+
+ ResponseCmndDone();
+}
+
+void CmndTCPBaudrate(void) {
+ if ((XdrvMailbox.payload >= 1200) && (XdrvMailbox.payload <= 115200)) {
+ XdrvMailbox.payload /= 1200; // Make it a valid baudrate
+ Settings.tcp_baudrate = XdrvMailbox.payload;
+ TCPSerial->begin(Settings.tcp_baudrate * 1200); // Reinitialize serial port with new baud rate
+ }
+ ResponseCmndNumber(Settings.tcp_baudrate * 1200);
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xdrv41(uint8_t function)
+{
+ bool result = false;
+
+ switch (function) {
+ case FUNC_LOOP:
+ TCPLoop();
+ break;
+ case FUNC_PRE_INIT:
+ TCPInit();
+ break;
+ case FUNC_COMMAND:
+ result = DecodeCommand(kTCPCommands, TCPCommand);
+ break;
+ }
+ return result;
+}
+
+#endif // USE_TCP_BRIDGE
diff --git a/tasmota/xdrv_81_webcam.ino b/tasmota/xdrv_81_webcam.ino
index 9cbeb4133..b0dab47b7 100644
--- a/tasmota/xdrv_81_webcam.ino
+++ b/tasmota/xdrv_81_webcam.ino
@@ -23,7 +23,7 @@
* ESP32 webcam based on example in Arduino-ESP32 library
*
* Template as used on ESP32-CAM WiFi + bluetooth Camera Module Development Board ESP32 With Camera Module OV2640 Geekcreit for Arduino
- * {"NAME":"AITHINKER CAM No SPI","GPIO":[4992,65504,65504,65504,65504,5088,65504,65504,65504,65504,65504,65504,65504,65504,5089,5090,0,5091,5184,5152,0,5120,5024,5056,0,0,0,0,4928,65504,5094,5095,5092,0,0,5093],"FLAG":0,"BASE":1}
+ * {"NAME":"AITHINKER CAM","GPIO":[4992,1,1,1,1,5088,1,1,1,1,1,1,1,1,5089,5090,0,5091,5184,5152,0,5120,5024,5056,0,0,0,0,4928,1,5094,5095,5092,0,0,5093],"FLAG":0,"BASE":1}
*
* Supported commands:
* WcStream = Control streaming, 0 = stop, 1 = start
@@ -792,7 +792,7 @@ void HandleWebcamRoot(void) {
/*********************************************************************************************/
uint32_t WcSetStreamserver(uint32_t flag) {
- if (global_state.wifi_down) { return 0; }
+ if (global_state.network_down) { return 0; }
Wc.stream_active = 0;
diff --git a/tasmota/xdrv_82_ethernet.ino b/tasmota/xdrv_82_ethernet.ino
new file mode 100644
index 000000000..cccac57b7
--- /dev/null
+++ b/tasmota/xdrv_82_ethernet.ino
@@ -0,0 +1,205 @@
+/*
+ xdrv_82_ethernet.ino - ESP32 (PoE) ethernet support for Tasmota
+
+ Copyright (C) 2020 Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifdef ESP32
+#ifdef USE_ETHERNET
+/*********************************************************************************************\
+ * Ethernet support for ESP32
+ *
+ * Dedicated fixed Phy pins
+ * GPIO17 - EMAC_CLK_OUT_180
+ * GPIO19 - EMAC_TXD0(RMII)
+ * GPIO21 - EMAC_TX_EN(RMII)
+ * GPIO22 - EMAC_TXD1(RMII)
+ * GPIO25 - EMAC_RXD0(RMII)
+ * GPIO26 - EMAC_RXD1(RMII)
+ * GPIO27 - EMAC_RX_CRS_DV
+ *
+ * {"NAME":"Olimex ESP32-PoE","GPIO":[1,1,1,1,1,1,0,0,5536,1,1,1,1,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
+ * {"NAME":"wESP32","GPIO":[1,1,1,1,1,1,0,0,0,1,1,1,5568,5600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
+ *
+\*********************************************************************************************/
+
+#define XDRV_82 82
+
+/*
+// Olimex ESP32-PoE
+#define ETH_CLKMODE ETH_CLOCK_GPIO17_OUT
+#define ETH_POWER_PIN 12
+
+//********************************************************************************************
+
+#ifndef ETH_ADDR
+#define ETH_ADDR 0 // esp_eth.h eth_phy_base_t: 0 = PHY0 .. 31 = PHY31
+#endif
+
+#ifndef ETH_TYPE
+#define ETH_TYPE ETH_PHY_LAN8720 // ETH.h eth_phy_type_t: 0 = ETH_PHY_LAN8720, 1 = ETH_PHY_TLK110, 2 = ETH_PHY_IP101
+#endif
+
+#ifndef ETH_CLKMODE
+#define ETH_CLKMODE ETH_CLOCK_GPIO0_IN // esp_eth.h eth_clock_mode_t: 0 = ETH_CLOCK_GPIO0_IN, 1 = ETH_CLOCK_GPIO0_OUT, 2 = ETH_CLOCK_GPIO16_OUT, 3 = ETH_CLOCK_GPIO17_OUT
+#endif
+*/
+
+#include
+
+char eth_hostname[sizeof(my_hostname)];
+
+void EthernetEvent(WiFiEvent_t event) {
+ switch (event) {
+ case SYSTEM_EVENT_ETH_START:
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ETH: " D_ATTEMPTING_CONNECTION));
+ ETH.setHostname(eth_hostname);
+ break;
+ case SYSTEM_EVENT_ETH_CONNECTED:
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("ETH: " D_CONNECTED));
+ break;
+ case SYSTEM_EVENT_ETH_GOT_IP:
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ETH: Mac %s, IPAddress %s, Hostname %s"),
+ ETH.macAddress().c_str(), ETH.localIP().toString().c_str(), eth_hostname);
+/*
+ if (ETH.fullDuplex()) {
+ Serial.print(", FULL_DUPLEX");
+ }
+ Serial.print(", ");
+ Serial.print(ETH.linkSpeed());
+ Serial.println("Mbps");
+*/
+ Settings.ip_address[1] = (uint32_t)ETH.gatewayIP();
+ Settings.ip_address[2] = (uint32_t)ETH.subnetMask();
+ Settings.ip_address[3] = (uint32_t)ETH.dnsIP();
+ global_state.eth_down = 0;
+ break;
+ case SYSTEM_EVENT_ETH_DISCONNECTED:
+ AddLog_P2(LOG_LEVEL_INFO, PSTR("ETH: Disconnected"));
+ global_state.eth_down = 1;
+ break;
+ case SYSTEM_EVENT_ETH_STOP:
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ETH: Stopped"));
+ global_state.eth_down = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+void EthernetInit(void) {
+ if (!Settings.flag4.network_ethernet) { return; }
+ if (!PinUsed(GPIO_ETH_PHY_MDC) && !PinUsed(GPIO_ETH_PHY_MDIO)) {
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ETH: No ETH MDC and/or ETH MDIO GPIO defined"));
+ return;
+ }
+
+// snprintf_P(Eth.hostname, sizeof(Eth.hostname), PSTR("%s_eth"), my_hostname);
+ strlcpy(eth_hostname, my_hostname, sizeof(eth_hostname) -5); // Make sure there is room for "_eth"
+ strcat(eth_hostname, "_eth");
+
+ WiFi.onEvent(EthernetEvent);
+
+ int eth_power = (PinUsed(GPIO_ETH_PHY_POWER)) ? Pin(GPIO_ETH_PHY_POWER) : -1;
+ int eth_mdc = Pin(GPIO_ETH_PHY_MDC);
+ int eth_mdio = Pin(GPIO_ETH_PHY_MDIO);
+ if (!ETH.begin(Settings.eth_address, eth_power, eth_mdc, eth_mdio, (eth_phy_type_t)Settings.eth_type, (eth_clock_mode_t)Settings.eth_clk_mode)) {
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ETH: Bad PHY type or init error"));
+ };
+}
+
+IPAddress EthernetLocalIP(void) {
+ return ETH.localIP();
+}
+
+char* EthernetHostname(void) {
+ return eth_hostname;
+}
+
+String EthernetMacAddress(void) {
+ return ETH.macAddress();
+}
+
+/*********************************************************************************************\
+ * Commands
+\*********************************************************************************************/
+
+#define D_CMND_ETHADDRESS "EthAddress"
+#define D_CMND_ETHTYPE "EthType"
+#define D_CMND_ETHCLOCKMODE "EthClockMode"
+
+const char kEthernetCommands[] PROGMEM = "|" // No prefix
+ D_CMND_ETHERNET "|" D_CMND_ETHADDRESS "|" D_CMND_ETHTYPE "|" D_CMND_ETHCLOCKMODE;
+
+void (* const EthernetCommand[])(void) PROGMEM = {
+ &CmndEthernet, &CmndEthAddress, &CmndEthType, &CmndEthClockMode };
+
+void CmndEthernet(void)
+{
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
+ Settings.flag4.network_ethernet = XdrvMailbox.payload;
+ restart_flag = 2;
+ }
+ ResponseCmndStateText(Settings.flag4.network_ethernet);
+}
+
+void CmndEthAddress(void)
+{
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 31)) {
+ Settings.eth_address = XdrvMailbox.payload;
+ restart_flag = 2;
+ }
+ ResponseCmndNumber(Settings.eth_address);
+}
+
+void CmndEthType(void)
+{
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {
+ Settings.eth_type = XdrvMailbox.payload;
+ restart_flag = 2;
+ }
+ ResponseCmndNumber(Settings.eth_type);
+}
+
+void CmndEthClockMode(void)
+{
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
+ Settings.eth_clk_mode = XdrvMailbox.payload;
+ restart_flag = 2;
+ }
+ ResponseCmndNumber(Settings.eth_clk_mode);
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xdrv82(uint8_t function) {
+ bool result = false;
+
+ switch (function) {
+ case FUNC_COMMAND:
+ result = DecodeCommand(kEthernetCommands, EthernetCommand);
+ break;
+ case FUNC_INIT:
+ EthernetInit();
+ break;
+ }
+ return result;
+}
+
+#endif // USE_ETHERNET
+#endif // ESP32
diff --git a/tasmota/xdsp_04_ili9341.ino b/tasmota/xdsp_04_ili9341.ino
index f755314c8..21981ff76 100644
--- a/tasmota/xdsp_04_ili9341.ino
+++ b/tasmota/xdsp_04_ili9341.ino
@@ -90,7 +90,11 @@ void Ili9341InitDriver(void)
if (Settings.display_height != ILI9341_TFTHEIGHT) {
Settings.display_height = ILI9341_TFTHEIGHT;
}
+#ifdef ESP8266
tft = new Adafruit_ILI9341(Pin(GPIO_SPI_CS), Pin(GPIO_SPI_DC));
+#else // ESP32
+ tft = new Adafruit_ILI9341(Pin(GPIO_SPI_CS), Pin(GPIO_SPI_DC), Pin(GPIO_SPI_MOSI), Pin(GPIO_SPI_CLK), -1, Pin(GPIO_SPI_MISO));
+#endif
tft->begin();
#ifdef USE_DISPLAY_MODES1TO5
diff --git a/tasmota/xnrg_02_cse7766.ino b/tasmota/xnrg_02_cse7766.ino
index f0aa210d1..9c8417bc6 100644
--- a/tasmota/xnrg_02_cse7766.ino
+++ b/tasmota/xnrg_02_cse7766.ino
@@ -59,8 +59,7 @@ struct CSE {
bool received = false;
} Cse;
-void CseReceived(void)
-{
+void CseReceived(void) {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// F2 5A 02 F7 60 00 03 61 00 40 10 05 72 40 51 A6 58 63 10 1B E1 7F 4D 4E - F2 = Power cycle exceeds range - takes too long - No load
// 55 5A 02 F7 60 00 03 5A 00 40 10 04 8B 9F 51 A6 58 18 72 75 61 AC A1 30 - 55 = Ok, 61 = Power not valid (load below 5W)
@@ -69,7 +68,7 @@ void CseReceived(void)
uint8_t header = Cse.rx_buffer[0];
if ((header & 0xFC) == 0xFC) {
- AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Abnormal hardware"));
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CSE: Abnormal hardware"));
return;
}
@@ -142,8 +141,7 @@ void CseReceived(void)
}
}
-bool CseSerialInput(void)
-{
+bool CseSerialInput(void) {
while (CseSerial->available()) {
yield();
uint8_t serial_in_byte = CseSerial->read();
@@ -162,12 +160,12 @@ bool CseSerialInput(void)
Cse.received = false;
return true;
} else {
- AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE));
do { // Sync buffer with data (issue #1907 and #3425)
memmove(Cse.rx_buffer, Cse.rx_buffer +1, 24);
Cse.byte_counter--;
} while ((Cse.byte_counter > 2) && (0x5A != Cse.rx_buffer[1]));
if (0x5A != Cse.rx_buffer[1]) {
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE));
Cse.received = false;
Cse.byte_counter = 0;
}
@@ -186,34 +184,31 @@ bool CseSerialInput(void)
/********************************************************************************************/
-void CseEverySecond(void)
-{
+void CseEverySecond(void) {
if (Energy.data_valid[0] > ENERGY_WATCHDOG) {
Cse.voltage_cycle = 0;
Cse.current_cycle = 0;
Cse.power_cycle = 0;
} else {
- long cf_frequency = 0;
-
if (CSE_PULSES_NOT_INITIALIZED == Cse.cf_pulses_last_time) {
Cse.cf_pulses_last_time = Cse.cf_pulses; // Init after restart
} else {
- if (Cse.cf_pulses < Cse.cf_pulses_last_time) { // Rolled over after 65535 pulses
- cf_frequency = (65536 - Cse.cf_pulses_last_time) + Cse.cf_pulses;
+ uint32_t cf_pulses = 0;
+ if (Cse.cf_pulses < Cse.cf_pulses_last_time) { // Rolled over after 0xFFFF (65535) pulses
+ cf_pulses = (0x10000 - Cse.cf_pulses_last_time) + Cse.cf_pulses;
} else {
- cf_frequency = Cse.cf_pulses - Cse.cf_pulses_last_time;
+ cf_pulses = Cse.cf_pulses - Cse.cf_pulses_last_time;
}
- if (cf_frequency && Energy.active_power[0]) {
- unsigned long delta = (cf_frequency * Settings.energy_power_calibration) / 36;
+ if (cf_pulses && Energy.active_power[0]) {
+ uint32_t delta = (cf_pulses * Settings.energy_power_calibration) / 36;
// prevent invalid load delta steps even checksum is valid (issue #5789):
-// if (delta <= (3680*100/36) * 10 ) { // max load for S31/Pow R2: 3.68kW
// prevent invalid load delta steps even checksum is valid but allow up to 4kW (issue #7155):
- if (delta <= (4000*100/36) * 10 ) { // max load for S31/Pow R2: 4.00kW
+ if (delta <= (4000 * 1000 / 36)) { // max load for S31/Pow R2: 4.00kW
Cse.cf_pulses_last_time = Cse.cf_pulses;
Energy.kWhtoday_delta += delta;
}
else {
- AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Load overflow"));
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CSE: Overload"));
Cse.cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED;
}
EnergyUpdateToday();
@@ -222,8 +217,7 @@ void CseEverySecond(void)
}
}
-void CseSnsInit(void)
-{
+void CseSnsInit(void) {
// Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions
// CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), Pin(GPIO_CSE7766_TX), 1);
CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), -1, 1);
@@ -241,8 +235,7 @@ void CseSnsInit(void)
}
}
-void CseDrvInit(void)
-{
+void CseDrvInit(void) {
// if (PinUsed(GPIO_CSE7766_RX) && PinUsed(GPIO_CSE7766_TX)) {
if (PinUsed(GPIO_CSE7766_RX)) {
Cse.rx_buffer = (uint8_t*)(malloc(CSE_BUFFER_SIZE));
@@ -252,8 +245,7 @@ void CseDrvInit(void)
}
}
-bool CseCommand(void)
-{
+bool CseCommand(void) {
bool serviced = true;
if (CMND_POWERSET == Energy.command_code) {
@@ -280,15 +272,14 @@ bool CseCommand(void)
* Interface
\*********************************************************************************************/
-bool Xnrg02(uint8_t function)
-{
+bool Xnrg02(uint8_t function) {
bool result = false;
switch (function) {
case FUNC_LOOP:
if (CseSerial) { CseSerialInput(); }
break;
- case FUNC_ENERGY_EVERY_SECOND:
+ case FUNC_EVERY_SECOND:
CseEverySecond();
break;
case FUNC_COMMAND:
diff --git a/tasmota/xnrg_13_fif_le01mr.ino b/tasmota/xnrg_13_fif_le01mr.ino
index 71e77793a..f8d25e06f 100644
--- a/tasmota/xnrg_13_fif_le01mr.ino
+++ b/tasmota/xnrg_13_fif_le01mr.ino
@@ -127,15 +127,15 @@ void FifLEEvery250ms(void)
} else {
Energy.data_valid[0] = 0;
- // SA=Slave Address, FC=Function Code, BC=Byte Count, B3..B0=Data byte, Ch Cl = crc16 checksum
+ // CA=Client Address, FC=Function Code, BC=Byte Count, B3..B0=Data byte, Ch Cl = crc16 checksum
// U32 registers:
// 00 01 02 03 04 05 06 07 08
- // SA FC BC B3 B2 B1 B0 Cl Ch
+ // CA FC BC B3 B2 B1 B0 Cl Ch
// 01 03 04 00 00 00 72 7A 16 = REG[B3..B2=0x0139,B1..B0=0x013A] 114 = 0.114 A
// 01 03 04 00 00 00 B0 FB 87 = REG[B3..B2=0xA01E,B1..B0=0xA01F] 176 = 1.76 kvarh
// U16/S16 registers:
// 00 01 02 03 04 05 06
- // SA FC BC B1 B0 Cl Ch
+ // CA FC BC B1 B0 Cl Ch
// 01 03 02 5B 02 02 B5 = REG[B1..B0=0x0131] 23298 = 232.98 V
// 01 03 02 03 E8 B8 FA = REG[B1..B0=0x0158] 1000 = 1.000 (power factor)
// there are 3 data types used:
diff --git a/tasmota/xnrg_14_bl0940.ino b/tasmota/xnrg_14_bl0940.ino
index 655f3d8df..fae36ea3a 100644
--- a/tasmota/xnrg_14_bl0940.ino
+++ b/tasmota/xnrg_14_bl0940.ino
@@ -33,6 +33,8 @@
#define BL0940_UREF 33000
#define BL0940_IREF 2750
+#define BL0940_PULSES_NOT_INITIALIZED -1
+
#define BL0940_BUFFER_SIZE 36
#define BL0940_WRITE_COMMAND 0xA0 // 0xA8 according to documentation
@@ -55,11 +57,13 @@ struct BL0940 {
long voltage = 0;
long current = 0;
long power = 0;
-// long power_cycle_first = 0;
-// long cf_pulses = 0;
+ long power_cycle_first = 0;
+ long cf_pulses = 0;
+ long cf_pulses_last_time = BL0940_PULSES_NOT_INITIALIZED;
float temperature;
int byte_counter = 0;
+ uint16_t tps1 = 0;
uint8_t *rx_buffer = nullptr;
bool received = false;
} Bl0940;
@@ -78,22 +82,31 @@ void Bl0940Received(void) {
// 55 B9 33 00 DE 45 00 94 02 00 CF E4 70 63 02 00 6C 4C 00 13 01 00 09 00 00 00 00 00 E4 01 00 FE 03 00 72
// Hd IFRms--- Current- Reserved Voltage- Reserved Power--- Reserved CF------ Reserved TPS1---- TPS2---- Ck
- if (Bl0940.rx_buffer[0] != BL0940_PACKET_HEADER) {
- AddLog_P(LOG_LEVEL_DEBUG, PSTR("BL9: Invalid data"));
+ uint16_t tps1 = Bl0940.rx_buffer[29] << 8 | Bl0940.rx_buffer[28]; // TPS1 unsigned
+ if ((Bl0940.rx_buffer[0] != BL0940_PACKET_HEADER) || // Bad header
+ (Bl0940.tps1 && ((tps1 < (Bl0940.tps1 -10)) || (tps1 > (Bl0940.tps1 +10)))) // Invalid temperature change
+ ) {
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: Invalid data"));
return;
}
- Bl0940.voltage = Bl0940.rx_buffer[12] << 16 | Bl0940.rx_buffer[11] << 8 | Bl0940.rx_buffer[10];
- Bl0940.current = Bl0940.rx_buffer[6] << 16 | Bl0940.rx_buffer[5] << 8 | Bl0940.rx_buffer[4];
- Bl0940.power = Bl0940.rx_buffer[18] << 16 | Bl0940.rx_buffer[17] << 8 | Bl0940.rx_buffer[16];
-// Bl0940.cf_pulses = Bl0940.rx_buffer[24] << 16 | Bl0940.rx_buffer[23] << 8 | Bl0940.rx_buffer[22];
- uint16_t tps1 = Bl0940.rx_buffer[29] << 8 | Bl0940.rx_buffer[28];
- float t = ((170.0f/448.0f)*(((float)tps1/2.0f)-32.0f))-45.0f;
+ Bl0940.tps1 = tps1;
+ float t = ((170.0f/448.0f)*(((float)Bl0940.tps1/2.0f)-32.0f))-45.0f;
Bl0940.temperature = ConvertTemp(t);
+ Bl0940.voltage = Bl0940.rx_buffer[12] << 16 | Bl0940.rx_buffer[11] << 8 | Bl0940.rx_buffer[10]; // V_RMS unsigned
+ Bl0940.current = Bl0940.rx_buffer[6] << 16 | Bl0940.rx_buffer[5] << 8 | Bl0940.rx_buffer[4]; // I_RMS unsigned
+ int32_t power = Bl0940.rx_buffer[18] << 24 | Bl0940.rx_buffer[17] << 16 | Bl0940.rx_buffer[16] << 8; // WATT signed
+ Bl0940.power = abs(power) >> 8; // WATT unsigned
+ int32_t cf_cnt = Bl0940.rx_buffer[24] << 24 | Bl0940.rx_buffer[23] << 16 | Bl0940.rx_buffer[22] << 8; // CF_CNT signed
+ Bl0940.cf_pulses = abs(cf_cnt) >> 8;
+
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: U %d, I %d, P %d, C %d, T %d"),
+ Bl0940.voltage, Bl0940.current, Bl0940.power, Bl0940.cf_pulses, Bl0940.tps1);
+
if (Energy.power_on) { // Powered on
Energy.voltage[0] = (float)Bl0940.voltage / Settings.energy_voltage_calibration;
- if (power != 0) {
+ if (power && (Bl0940.power > Settings.energy_power_calibration)) { // We need at least 1W
Energy.active_power[0] = (float)Bl0940.power / Settings.energy_power_calibration;
Energy.current[0] = (float)Bl0940.current / (Settings.energy_current_calibration * 100);
} else {
@@ -131,13 +144,12 @@ bool Bl0940SerialInput(void) {
Bl0940.received = false;
return true;
} else {
-// AddLog_P(LOG_LEVEL_DEBUG, PSTR("BL9: " D_CHECKSUM_FAILURE));
do { // Sync buffer with data (issue #1907 and #3425)
memmove(Bl0940.rx_buffer, Bl0940.rx_buffer +1, BL0940_BUFFER_SIZE -1);
Bl0940.byte_counter--;
} while ((Bl0940.byte_counter > 1) && (BL0940_PACKET_HEADER != Bl0940.rx_buffer[0]));
if (BL0940_PACKET_HEADER != Bl0940.rx_buffer[0]) {
- AddLog_P(LOG_LEVEL_DEBUG, PSTR("BL9: " D_CHECKSUM_FAILURE));
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: " D_CHECKSUM_FAILURE));
Bl0940.received = false;
Bl0940.byte_counter = 0;
}
@@ -155,12 +167,41 @@ void Bl0940EverySecond(void) {
Bl0940.current = 0;
Bl0940.power = 0;
} else {
+/*
+ // Calculate energy by using active power
if (Energy.active_power[0]) {
Energy.kWhtoday_delta += (Energy.active_power[0] * 1000) / 36;
EnergyUpdateToday();
}
+*/
+ // Calculate energy by using active energy pulse count
+ if (BL0940_PULSES_NOT_INITIALIZED == Bl0940.cf_pulses_last_time) {
+ Bl0940.cf_pulses_last_time = Bl0940.cf_pulses; // Init after restart
+ } else {
+ uint32_t cf_pulses = 0;
+ if (Bl0940.cf_pulses < Bl0940.cf_pulses_last_time) { // Rolled over after 0xFFFFFF (16777215) pulses
+ cf_pulses = (0x1000000 - Bl0940.cf_pulses_last_time) + Bl0940.cf_pulses;
+ } else {
+ cf_pulses = Bl0940.cf_pulses - Bl0940.cf_pulses_last_time;
+ }
+ if (cf_pulses && Energy.active_power[0]) {
+ uint32_t watt256 = (1638400 * 256) / Settings.energy_power_calibration;
+ uint32_t delta = (cf_pulses * watt256) / 36;
+ if (delta <= (4000 * 1000 / 36)) { // max load for SHP10: 4.00kW (3.68kW)
+ Bl0940.cf_pulses_last_time = Bl0940.cf_pulses;
+ Energy.kWhtoday_delta += delta;
+ } else {
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: Overload"));
+ Bl0940.cf_pulses_last_time = BL0940_PULSES_NOT_INITIALIZED;
+ }
+ EnergyUpdateToday();
+ }
+ }
+
}
+// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: Poll"));
+
Bl0940Serial->flush();
Bl0940Serial->write(BL0940_READ_COMMAND);
Bl0940Serial->write(BL0940_FULL_PACKET);
@@ -169,7 +210,7 @@ void Bl0940EverySecond(void) {
void Bl0940SnsInit(void) {
// Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions
Bl0940Serial = new TasmotaSerial(Pin(GPIO_BL0940_RX), Pin(GPIO_TXD), 1);
- if (Bl0940Serial->begin(4800, 2)) {
+ if (Bl0940Serial->begin(4800, 1)) {
if (Bl0940Serial->hardwareSerial()) {
ClaimSerial();
}
@@ -226,8 +267,7 @@ bool Bl0940Command(void) {
return serviced;
}
-void Bl0940Show(bool json)
-{
+void Bl0940Show(bool json) {
char temperature[33];
dtostrfd(Bl0940.temperature, Settings.flag2.temperature_resolution, temperature);
@@ -252,15 +292,14 @@ void Bl0940Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xnrg14(uint8_t function)
-{
+bool Xnrg14(uint8_t function) {
bool result = false;
switch (function) {
case FUNC_LOOP:
if (Bl0940Serial) { Bl0940SerialInput(); }
break;
- case FUNC_ENERGY_EVERY_SECOND:
+ case FUNC_EVERY_SECOND:
Bl0940EverySecond();
break;
case FUNC_JSON_APPEND:
diff --git a/tasmota/xsns_21_sgp30.ino b/tasmota/xsns_21_sgp30.ino
index ab417a8c3..ec1e85258 100644
--- a/tasmota/xsns_21_sgp30.ino
+++ b/tasmota/xsns_21_sgp30.ino
@@ -87,7 +87,7 @@ void Sgp30Update(void) // Perform every second to ensure proper operation of th
if (!sgp.IAQmeasure()) {
return; // Measurement failed
}
- if (global_update && (global_humidity > 0) && (global_temperature != 9999)) {
+ if (global_update && (global_humidity > 0) && !isnan(global_temperature)) {
// abs hum in mg/m3
sgp30_abshum=sgp30_AbsoluteHumidity(global_temperature,global_humidity,TempUnit());
sgp.setHumidity(sgp30_abshum*1000);
@@ -118,14 +118,14 @@ void Sgp30Show(bool json)
{
if (sgp30_ready) {
char abs_hum[33];
-
- if (global_update && global_humidity>0 && global_temperature!=9999) {
+
+ if (global_update && (global_humidity > 0) && !isnan(global_temperature)) {
// has humidity + temperature
dtostrfd(sgp30_abshum,4,abs_hum);
}
if (json) {
ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d"), sgp.eCO2, sgp.TVOC);
- if (global_update && global_humidity>0 && global_temperature!=9999) {
+ if (global_update && global_humidity>0 && !isnan(global_temperature)) {
ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"),abs_hum);
}
ResponseJsonEnd();
diff --git a/tasmota/xsns_31_ccs811.ino b/tasmota/xsns_31_ccs811.ino
index a968319cb..aada03d04 100644
--- a/tasmota/xsns_31_ccs811.ino
+++ b/tasmota/xsns_31_ccs811.ino
@@ -65,7 +65,9 @@ void CCS811Update(void) // Perform every n second
TVOC = ccs.getTVOC();
eCO2 = ccs.geteCO2();
CCS811_ready = 1;
- if (global_update && global_humidity>0 && global_temperature!=9999) { ccs.setEnvironmentalData((uint8_t)global_humidity, global_temperature); }
+ if (global_update && (global_humidity > 0) && !isnan(global_temperature)) {
+ ccs.setEnvironmentalData((uint8_t)global_humidity, global_temperature);
+ }
ecnt = 0;
}
} else {
diff --git a/tasmota/xsns_48_chirp.ino b/tasmota/xsns_48_chirp.ino
index 9606b419c..934dff205 100644
--- a/tasmota/xsns_48_chirp.ino
+++ b/tasmota/xsns_48_chirp.ino
@@ -20,6 +20,8 @@
Version Date Action Description
--------------------------------------------------------------------------------------------
+ 1.0.0.2 20200611 changed - bugfix: decouple restart of the work loop from FUNC_JSON_APPEND callback
+ ---
1.0.0.1 20190917 changed - rework of the inner loop to enable delays in the middle of I2C-reads
changed - double send address change only for fw>0x25
changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS
@@ -300,7 +302,7 @@ void ChirpServiceAllSensors(uint8_t job){
void ChirpEvery100MSecond(void)
{
- // DEBUG_SENSOR_LOG(PSTR("CHIRP: every second"));
+ // DEBUG_SENSOR_LOG(PSTR("CHIRP: every 100 mseconds, counter: %u, next job: %u"),chirp_timeout_count,chirp_next_job);
if(chirp_timeout_count == 0) { //countdown complete, now do something
switch(chirp_next_job) {
case 0: //this should only be called after driver initialization
@@ -377,10 +379,11 @@ void ChirpEvery100MSecond(void)
break;
case 13:
DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE"));
+ chirp_next_job++;
break;
case 14:
if (Settings.tele_period > 16){
- chirp_timeout_count = (Settings.tele_period - 17) * 10; // sync it with the TELEPERIOD, we need about up to 17 seconds to measure
+ chirp_timeout_count = (Settings.tele_period - 16) * 10; // sync it with the TELEPERIOD, we need about up to 16 seconds to measure
DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout 1/10 sec: %u, tele: %u"), chirp_timeout_count, Settings.tele_period);
}
else{
@@ -533,7 +536,6 @@ bool Xsns48(uint8_t function)
break;
case FUNC_JSON_APPEND:
ChirpShow(1);
- chirp_next_job = 14; // TELE done, now compute time for next measure cycle
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR:
diff --git a/tasmota/xsns_52_ibeacon.ino b/tasmota/xsns_52_ibeacon.ino
index 5f9c0f3ba..6a33d94a0 100755
--- a/tasmota/xsns_52_ibeacon.ino
+++ b/tasmota/xsns_52_ibeacon.ino
@@ -87,6 +87,9 @@ struct IBEACON {
struct IBEACON_UID {
char MAC[12];
char RSSI[4];
+ char UID[32];
+ char MAJOR[4];
+ char MINOR[4];
uint8_t FLAGS;
uint8_t TIME;
} ibeacons[MAX_IBEACONS];
@@ -132,7 +135,7 @@ void hm17_every_second(void) {
ibeacons[cnt].TIME++;
if (ibeacons[cnt].TIME>IB_TIMEOUT_TIME) {
ibeacons[cnt].FLAGS=0;
- ibeacon_mqtt(ibeacons[cnt].MAC,"0000");
+ ibeacon_mqtt(ibeacons[cnt].MAC,"0000",ibeacons[cnt].UID,ibeacons[cnt].MAJOR,ibeacons[cnt].MINOR);
}
}
}
@@ -210,6 +213,9 @@ uint32_t ibeacon_add(struct IBEACON *ib) {
if (!ibeacons[cnt].FLAGS) {
memcpy(ibeacons[cnt].MAC,ib->MAC,12);
memcpy(ibeacons[cnt].RSSI,ib->RSSI,4);
+ memcpy(ibeacons[cnt].UID,ib->UID,32);
+ memcpy(ibeacons[cnt].MAJOR,ib->MAJOR,4);
+ memcpy(ibeacons[cnt].MINOR,ib->MINOR,4);
ibeacons[cnt].FLAGS=1;
ibeacons[cnt].TIME=0;
return 1;
@@ -400,7 +406,7 @@ hm17_v110:
memcpy(ib.RSSI,&hm17_sbuffer[8+8+1+32+1+4+4+2+1+12+1],4);
if (ibeacon_add(&ib)) {
- ibeacon_mqtt(ib.MAC,ib.RSSI);
+ ibeacon_mqtt(ib.MAC,ib.RSSI,ib.UID,ib.MAJOR,ib.MINOR);
}
hm17_sbclr();
hm17_result=1;
@@ -560,15 +566,30 @@ void ib_sendbeep(void) {
hm17_sendcmd(HM17_CON);
}
-void ibeacon_mqtt(const char *mac,const char *rssi) {
+void ibeacon_mqtt(const char *mac,const char *rssi,const char *uid,const char *major,const char *minor) {
char s_mac[14];
+ char s_uid[34];
+ char s_major[6];
+ char s_minor[6];
char s_rssi[6];
memcpy(s_mac,mac,12);
s_mac[12]=0;
+ memcpy(s_uid,uid,32);
+ s_uid[32]=0;
+ memcpy(s_major,major,4);
+ s_major[4]=0;
+ memcpy(s_minor,minor,4);
+ s_minor[4]=0;
memcpy(s_rssi,rssi,4);
s_rssi[4]=0;
int16_t n_rssi=atoi(s_rssi);
- ResponseTime_P(PSTR(",\"" D_CMND_IBEACON "_%s\":{\"RSSI\":%d}}"),s_mac,n_rssi);
+ // if uid == all zeros, take mac
+ if (!strncmp_P(s_uid,PSTR("00000000000000000000000000000000"),32)) {
+ ResponseTime_P(PSTR(",\"" D_CMND_IBEACON "_%s\":{\"UID\":\"%s\",\"MAJOR\":\"%s\",\"MINOR\":\"%s\",\"RSSI\":%d}}"),s_mac,s_uid,s_major,s_minor,n_rssi);
+ } else {
+ ResponseTime_P(PSTR(",\"" D_CMND_IBEACON "_%s\":{\"MAJOR\":\"%s\",\"MINOR\":\"%s\",\"RSSI\":%d}}"),s_uid,s_major,s_minor,n_rssi);
+ }
+
MqttPublishTeleSensor();
}
diff --git a/tasmota/xsns_53_sml.ino b/tasmota/xsns_53_sml.ino
index cb51bcc82..18fd53bf5 100755
--- a/tasmota/xsns_53_sml.ino
+++ b/tasmota/xsns_53_sml.ino
@@ -2405,12 +2405,13 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
if (!rflg) {
*ucp++=0;
*ucp++=2;
+ slen+=2;
}
// append crc
- uint16_t crc = MBUS_calculateCRC(sbuff,6);
+ uint16_t crc = MBUS_calculateCRC(sbuff,slen);
*ucp++=lowByte(crc);
*ucp++=highByte(crc);
- slen+=4;
+ slen+=2;
}
if (script_meter_desc[meter].type=='o') {
for (uint32_t cnt=0;cntaddress, INA226_REG_CALIBRATION, si->calibrationValue);
@@ -167,10 +167,10 @@ bool Ina226TestPresence(uint8_t device)
// Read config
- uint16_t config = I2cRead16( slaveInfo[device].address, INA226_REG_CONFIG );
+ uint16_t config = I2cRead16( Ina226Info[device].address, INA226_REG_CONFIG );
//AddLog_P2( LOG_LEVEL_NONE, PSTR("Config register %04x" ), config);
- if (config != slaveInfo[device].config)
+ if (config != Ina226Info[device].config)
return false;
return true;
@@ -179,10 +179,10 @@ bool Ina226TestPresence(uint8_t device)
void Ina226ResetActive(void)
{
- Ina226SlaveInfo_t *p = slaveInfo;
+ Ina226Info_t *p = Ina226Info;
for (uint32_t i = 0; i < INA226_MAX_ADDRESSES; i++) {
- p = &slaveInfo[i];
+ p = &Ina226Info[i];
// Address
uint8_t addr = p->address;
if (addr) {
@@ -199,9 +199,9 @@ void Ina226Init()
{
uint32_t i;
- slavesFound = 0;
+ Ina226sFound = 0;
- Ina226SlaveInfo_t *p = slaveInfo;
+ Ina226Info_t *p = Ina226Info;
//AddLog_P2( LOG_LEVEL_NONE, "Ina226Init");
// AddLog_P2( LOG_LEVEL_NONE, "Size of Settings: %d bytes", sizeof(Settings));
@@ -210,7 +210,7 @@ void Ina226Init()
// AddLog_P2(LOG_LEVEL_DEBUG, "INA226: Initialization failed: No I2C support");
- // Clear slave info data
+ // Clear Ina226 info data
for (i = 0; i < 4; i++){
*p = {0};
@@ -232,7 +232,7 @@ void Ina226Init()
continue;
- //AddLog_P2( LOG_LEVEL_NONE, PSTR("INA226 trying slave address %02x" ), addr );
+ //AddLog_P2( LOG_LEVEL_NONE, PSTR("INA226 trying address %02x" ), addr );
// Try Resetting the device
@@ -257,8 +257,8 @@ void Ina226Init()
if (!I2cWrite16( addr, INA226_REG_CONFIG, config))
continue; // No device
- // store data in slave info struct.
- p = &slaveInfo[i];
+ // store data in info struct.
+ p = &Ina226Info[i];
// Address
p->address = addr;
// Configuration
@@ -282,7 +282,7 @@ void Ina226Init()
I2cSetActiveFound(addr, Ina226Str);
- slavesFound++;
+ Ina226sFound++;
}
}
@@ -292,7 +292,7 @@ void Ina226Init()
float Ina226ReadBus_v(uint8_t device)
{
- uint8_t addr = slaveInfo[device].address;
+ uint8_t addr = Ina226Info[device].address;
int16_t reg_bus_v = I2cReadS16( addr, INA226_REG_BUSVOLTAGE);
float result = ((float) reg_bus_v) * 0.00125f;
@@ -307,10 +307,10 @@ float Ina226ReadBus_v(uint8_t device)
float Ina226ReadShunt_i(uint8_t device)
{
- uint8_t addr = slaveInfo[device].address;
+ uint8_t addr = Ina226Info[device].address;
int16_t reg_shunt_i = I2cReadS16( addr, INA226_REG_CURRENT);
- float result = ((float) reg_shunt_i) * slaveInfo[device].i_lsb;
+ float result = ((float) reg_shunt_i) * Ina226Info[device].i_lsb;
return result;
}
@@ -321,10 +321,10 @@ float Ina226ReadShunt_i(uint8_t device)
float Ina226ReadPower_w(uint8_t device)
{
- uint8_t addr = slaveInfo[device].address;
+ uint8_t addr = Ina226Info[device].address;
int16_t reg_shunt_i = I2cReadS16( addr, INA226_REG_POWER);
- float result = ((float) reg_shunt_i) * (slaveInfo[device].i_lsb * 25.0);
+ float result = ((float) reg_shunt_i) * (Ina226Info[device].i_lsb * 25.0);
return result;
}
@@ -354,19 +354,19 @@ void Ina226EverySecond()
{
//AddLog_P2( LOG_LEVEL_NONE, "Ina226EverySecond");
for (uint8_t device = 0; device < INA226_MAX_ADDRESSES; device++){
- // If there are slaves, and the device was present, and the device still is present, read its registers
- if (slavesFound && slaveInfo[device].present && Ina226TestPresence(device)){
+ // If there are Ina226s, and the device was present, and the device still is present, read its registers
+ if (Ina226sFound && Ina226Info[device].present && Ina226TestPresence(device)){
Ina226Read(device);
}
else {
powers[device] = currents[device] = voltages[device] = 0.0f;
// If device was present, note that it dropped off here
- //if(slaveInfo[device].present){
+ //if(Ina226Info[device].present){
//reinit_count[device]++;
//AddLog_P2( LOG_LEVEL_DEBUG, "INA226 Device %d dropped off, count: %d", device, reinit_count[device]);
//}
// Device no longer present
- slaveInfo[device].present = false;
+ Ina226Info[device].present = false;
}
}
}
@@ -413,7 +413,7 @@ bool Ina226CommandSensor()
case 1: // Rerun init
Ina226ResetActive();
Ina226Init();
- Response_P(PSTR("{\"Sensor54-Command-Result\":{\"SlavesFound\":%d}}"),slavesFound);
+ Response_P(PSTR("{\"Sensor54-Command-Result\":{\"Ina226sFound\":%d}}"),Ina226sFound);
break;
case 2: // Save and restart
@@ -497,7 +497,7 @@ void Ina226Show(bool json)
int i, num_found;
for (num_found = 0, i = 0; i < INA226_MAX_ADDRESSES; i++) {
// Skip uninstalled sensors
- if (!slaveInfo[i].present)
+ if (!Ina226Info[i].present)
continue;
num_found++;
diff --git a/tasmota/xsns_61_MI_NRF24.ino b/tasmota/xsns_61_MI_NRF24.ino
index 5dd82f3a5..4fb261751 100644
--- a/tasmota/xsns_61_MI_NRF24.ino
+++ b/tasmota/xsns_61_MI_NRF24.ino
@@ -21,6 +21,8 @@
Version yyyymmdd Action Description
--------------------------------------------------------------------------------------------
+ 0.9.6.0 20200618 integrate - add decryption for LYWSD03
+ ---
0.9.5.0 20200328 integrate - add dew point, multi-page-web ui, refactoring, command interface,
simple beacon
---
@@ -62,6 +64,7 @@
#define XSNS_61 61
#include
+#include
#define FLORA 1
#define MJ_HT_V1 2
@@ -74,14 +77,15 @@
const char S_JSON_NRF_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_NRF "%s\":%d}";
const char S_JSON_NRF_COMMAND[] PROGMEM = "{\"" D_CMND_NRF "%s\":\"%s\"}";
-const char kNRF_Commands[] PROGMEM = "Ignore|Page|Scan|Beacon|Chan";
+const char kNRF_Commands[] PROGMEM = "Ignore|Page|Scan|Beacon|Chan|Key";
enum NRF_Commands { // commands useable in console or rules
CMND_NRF_IGNORE, // ignore specific sensor type (1-6)
CMND_NRF_PAGE, // sensor entries per web page, which will be shown alternated
CMND_NRF_SCAN, // simplified passive BLE adv scan
CMND_NRF_BEACON, // even more simplified Beacon, reports time since last sighting
- CMND_NRF_CHAN // ignore channel 0-2 (translates to 37-39)
+ CMND_NRF_CHAN, // ignore channel 0-2 (translates to 37-39)
+ CMND_NRF_KEY // add bind_key to a MAC for payload decryption
};
const uint16_t kMINRFSlaveID[6]={ 0x0098, // Flora
@@ -104,8 +108,8 @@ const char * kMINRFSlaveType[] PROGMEM = {kMINRFSlaveType1,kMINRFSlaveType2,kMIN
const uint32_t kMINRFFloPDU[3] = {0x3eaa857d,0xef3b8730,0x71da7b46};
const uint32_t kMINRFMJPDU[3] = {0x4760cd66,0xdbcc0cd3,0x33048df5};
const uint32_t kMINRFL2PDU[3] = {0x3eaa057d,0xef3b0730,0x71dafb46};
-// const uint32_t kMINRFL3PDU[3] = {0x4760dd78,0xdbcc1ccd,0xffffffff}; //encrypted - 58 58
-const uint32_t kMINRFL3PDU[3] = {0x4760cb78,0xdbcc0acd,0x33048beb}; //unencrypted - 30 58
+const uint32_t kMINRFL3PDU[3] = {0x4760dd78,0xdbcc1ccd,0x33049deb}; //encrypted - 58 58
+// const uint32_t kMINRFL3PDU[3] = {0x4760cb78,0xdbcc0acd,0x33048beb}; //unencrypted - 30 58
const uint32_t kMINRFCGGPDU[3] = {0x4760cd6e,0xdbcc0cdb,0x33048dfd};
const uint32_t kMINRFCGDPDU[3] = {0x5da0d752,0xc10c16e7,0x29c497c1};
@@ -155,6 +159,28 @@ struct bleAdvPacket_t { // for nRF24L01 max 32 bytes = 2+6+24
uint8_t mac[6];
};
+struct encPayload_t {
+ uint8_t cipher[5];
+ uint8_t ExtCnt[3];
+ uint8_t tag[4];
+};
+
+struct encPacket_t{
+ // the packet is longer, but this part is enough to decrypt
+ uint16_t PID;
+ uint8_t frameCnt;
+ uint8_t MAC[6];
+ encPayload_t payload;
+};
+
+union mi_bindKey_t{
+ struct{
+ uint8_t key[16];
+ uint8_t MAC[6];
+ };
+ uint8_t buf[22];
+};
+
union FIFO_t{
bleAdvPacket_t bleAdv;
mi_beacon_t miBeacon;
@@ -223,6 +249,7 @@ struct scan_entry_t {
std::vector MIBLEsensors;
std::vector MINRFscanResult;
+std::vector MIBLEbindKeys;
static union{
scan_entry_t MINRFdummyEntry;
@@ -564,6 +591,61 @@ void MINRFcomputeBeaconPDU(void){
}
}
+int MINRFdecryptPacket(char *_buf){
+ encPacket_t *packet = (encPacket_t*)_buf;
+ // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("to decrypt: %02x %02x %02x %02x %02x %02x %02x %02x"),(uint8_t)_buf[0],(uint8_t)_buf[1],(uint8_t)_buf[2],(uint8_t)_buf[3],(uint8_t)_buf[4],(uint8_t)_buf[5],(uint8_t)_buf[6],(uint8_t)_buf[7]);
+
+ int ret = 0;
+ unsigned char output[10] = {0};
+ uint8_t nonce[12];
+ const unsigned char authData[1] = {0x11};
+
+ // nonce: device MAC, device type, frame cnt, ext. cnt
+ for (uint32_t i = 0; i<6; i++){
+ nonce[i] = packet->MAC[5-i];
+ }
+ memcpy((uint8_t*)&nonce+6,(uint8_t*)&packet->PID,2);
+ nonce[8] = packet->frameCnt;
+ memcpy((uint8_t*)&nonce+9,(uint8_t*)&packet->payload.ExtCnt,3);
+
+ uint8_t _bindkey[16] = {0x0};
+ for(uint32_t i=0; iMAC,MIBLEbindKeys[i].MAC,sizeof(packet->MAC))==0){
+ AddLog_P2(LOG_LEVEL_DEBUG,PSTR("have key"));
+ memcpy(_bindkey,MIBLEbindKeys[i].key,sizeof(_bindkey));
+ break;
+ }
+ // else{
+ // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mac in packet: %02x %02x %02x %02x %02x %02x"), packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]);
+ // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mac in vector: %02x %02x %02x %02x %02x %02x"), MIBLEbindKeys[i].MAC[0], MIBLEbindKeys[i].MAC[1], MIBLEbindKeys[i].MAC[2], MIBLEbindKeys[i].MAC[3], MIBLEbindKeys[i].MAC[4], MIBLEbindKeys[i].MAC[5]);
+ // }
+ }
+ // init
+ mbedtls_ccm_context ctx;
+ mbedtls_ccm_init(&ctx);
+
+ // set bind key
+ ret = mbedtls_ccm_setkey(&ctx,
+ MBEDTLS_CIPHER_ID_AES,
+ _bindkey,
+ 16 * 8 //bits
+ );
+
+ ret = mbedtls_ccm_auth_decrypt(&ctx,5,
+ (const unsigned char*)&nonce, sizeof(nonce),
+ authData, sizeof(authData),
+ packet->payload.cipher, output,
+ packet->payload.tag,sizeof(packet->payload.tag));
+
+ AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Err:%i, Decrypted : %02x %02x %02x %02x %02x "), ret, output[0],output[1],output[2],output[3],output[4]);
+ // put decrypted data in place
+ memcpy((uint8_t*)(packet->payload.cipher)+1,output,sizeof(packet->payload.cipher));
+ // clean up
+ mbedtls_ccm_free(&ctx);
+ return ret;
+}
+
+
/*********************************************************************************************\
* helper functions
\*********************************************************************************************/
@@ -581,6 +663,46 @@ void MINRFreverseMAC(uint8_t _mac[]){
memcpy(_mac,_reversedMAC, sizeof(_reversedMAC));
}
+void MINRFAddKey(char* payload){
+ mi_bindKey_t keyMAC;
+ memset(keyMAC.buf,0,sizeof(keyMAC));
+ MINRFKeyMACStringToBytes(payload,keyMAC.buf);
+ bool unknownKey = true;
+ for(uint32_t i=0; i= '0' && c <= '9')
+ value = (c - '0');
+ else if (c >= 'A' && c <= 'F')
+ value = (10 + (c - 'A'));
+ _keyMac[(index/2)] += value << (((index + 1) % 2) * 4);
+ index++;
+ }
+ DEBUG_SENSOR_LOG(PSTR("MINRF: %s to:"),_string);
+ DEBUG_SENSOR_LOG(PSTR("MINRF: key-array: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"),_keyMac[0],_keyMac[1],_keyMac[2],_keyMac[3],_keyMac[4],_keyMac[5],_keyMac[6],_keyMac[7],_keyMac[8],_keyMac[9],_keyMac[10],_keyMac[11],_keyMac[12],_keyMac[13],_keyMac[14],_keyMac[15]);
+ DEBUG_SENSOR_LOG(PSTR("MINRF: MAC-array: %02X%02X%02X%02X%02X%02X"),_keyMac[16],_keyMac[17],_keyMac[18],_keyMac[19],_keyMac[20],_keyMac[21]);
+}
+
/**
* @brief
*
@@ -754,14 +876,19 @@ void MINRFhandleMiBeaconPacket(void){
uint32_t _slot = MINRFgetSensorSlot(MINRF.buffer.miBeacon.Mac, MINRF.buffer.miBeacon.productID);
if(_slot==0xff) return;
DEBUG_SENSOR_LOG(PSTR("MINRF: slot %u, size vector: %u %u"),_slot,MIBLEsensors.size());
-
mi_sensor_t *_sensorVec = &MIBLEsensors.at(_slot);
+ DEBUG_SENSOR_LOG(PSTR("MINRF: %u %u %u"),_slot,_sensorVec->type,MINRF.buffer.miBeacon.type);
float _tempFloat;
if (_sensorVec->type==MJ_HT_V1 || _sensorVec->type==CGG1){
memcpy(MINRFtempBuf,(uint8_t*)&MINRF.buffer.miBeacon.spare, 32-9); // shift by one byte for the MJ_HT_V1 and CGG1
memcpy((uint8_t*)&MINRF.buffer.miBeacon.type,MINRFtempBuf, 32-9); // shift by one byte for the MJ_HT_V1 and CGG1
}
+ if(_sensorVec->type==LYWSD03){
+ int decryptRet = -1;
+ decryptRet = MINRFdecryptPacket((char*)&MINRF.buffer); //start with PID
+ if(decryptRet==0) _sensorVec->showedUp=255; // if decryption worked, this must be a valid sensor
+ }
DEBUG_SENSOR_LOG(PSTR("%s at slot %u"), kNRFSlaveType[_sensorVec->type-1],_slot);
switch(MINRF.buffer.miBeacon.type){
@@ -823,21 +950,6 @@ void MINRFhandleMiBeaconPacket(void){
break;
}
}
-/**
- * @brief more or less a placeholder, at least it is technically possible to really decrypt data, but
- * the bind_key must be retrieved with 3rd-party-tools -> TODO
- */
-void MINRFhandleLYWSD03Packet(void){
- // not much to do ATM, just show the sensor without data
- MINRFreverseMAC(MINRF.buffer.miBeacon.Mac);
- uint32_t _slot = MINRFgetSensorSlot(MINRF.buffer.miBeacon.Mac, MINRF.buffer.miBeacon.productID);
- DEBUG_SENSOR_LOG(PSTR("MINRF: Sensor slot: %u"), _slot);
- if(_slot==0xff) return;
-
- MINRF_LOG_BUFFER(MINRF.streamBuffer);
- MINRF_LOG_BUFFER(MINRF.lsfrBuffer);
- MINRF_LOG_BUFFER(MINRF.buffer.raw);
-}
/**
* @brief parse the Cleargrass-packet
@@ -901,12 +1013,9 @@ void MINRF_EVERY_50_MSECOND() { // Every 50mseconds
}
else MINRFhandleScan();
break;
- case FLORA: case MJ_HT_V1: case LYWSD02: case CGG1:
+ case FLORA: case MJ_HT_V1: case LYWSD02: case CGG1: case LYWSD03:
MINRFhandleMiBeaconPacket();
break;
- case LYWSD03:
- MINRFhandleLYWSD03Packet();
- break;
case CGD1:
MINRFhandleCGD1Packet();
break;
@@ -1026,6 +1135,12 @@ bool NRFCmd(void) {
}
Response_P(S_JSON_NRF_COMMAND_NVALUE, command, MINRF.channelIgnore);
break;
+ case CMND_NRF_KEY:
+ if (XdrvMailbox.data_len==44){ // a KEY-MAC-string
+ MINRFAddKey(XdrvMailbox.data);
+ Response_P(S_JSON_NRF_COMMAND, command, XdrvMailbox.data);
+ }
+ break;
default:
// else for Unknown command
serviced = false;
@@ -1191,5 +1306,3 @@ bool Xsns61(uint8_t function)
#endif // USE_MIBLE
#endif // USE_NRF24
#endif // USE_SPI
-
-
diff --git a/tasmota/xsns_71_veml7700.ino b/tasmota/xsns_71_veml7700.ino
index 3869e72d6..695e35824 100644
--- a/tasmota/xsns_71_veml7700.ino
+++ b/tasmota/xsns_71_veml7700.ino
@@ -40,27 +40,27 @@ const char JSON_SNS_VEML7700[] PROGMEM = ",\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d
#define D_CMND_VEML7700_PWR "power"
#define D_CMND_VEML7700_GAIN "gain"
#define D_CMND_VEML7700_INTTIME "inttime"
+#define D_CMND_VEML7700_PERSIST "persist"
const char S_JSON_VEML7700_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_VEML7700 "\":{\"%s\":%d}}";
-const char kVEML7700_Commands[] PROGMEM = D_CMND_VEML7700_PWR "|" D_CMND_VEML7700_GAIN "|" D_CMND_VEML7700_INTTIME;
+const char kVEML7700_Commands[] PROGMEM = D_CMND_VEML7700_PWR "|" D_CMND_VEML7700_GAIN "|" D_CMND_VEML7700_INTTIME "|" D_CMND_VEML7700_PERSIST;
enum VEML7700_Commands { // commands for Console
CMND_VEML7700_PWR,
CMND_VEML7700_GAIN,
CMND_VEML7700_SET_IT,
- };
+ CMND_VEML7700_PERSIST,
+};
struct VEML7700STRUCT
{
+ bool active = 0;
char types[9] = D_NAME_VEML7700;
uint8_t address = VEML7700_I2CADDR_DEFAULT;
- //uint16_t lux = 0;
- //uint16_t white = 0;
- uint16_t lux_normalized = 0;
- uint16_t white_normalized = 0;
+ uint32_t lux_normalized = 0;
+ uint32_t white_normalized = 0;
} veml7700_sensor;
-uint8_t veml7700_active = 0;
/********************************************************************************************/
@@ -68,7 +68,7 @@ void VEML7700Detect(void) {
if (!I2cSetDevice(veml7700_sensor.address)) return;
if (veml7700.begin()) {
I2cSetActiveFound(veml7700_sensor.address, veml7700_sensor.types);
- veml7700_active = 1;
+ veml7700_sensor.active = 1;
}
}
@@ -97,10 +97,8 @@ uint8_t VEML7700TranslateItInt (uint16_t ittimems){
}
void VEML7700EverySecond(void) {
- veml7700_sensor.lux_normalized = (uint16_t) veml7700.readLuxNormalized();
- veml7700_sensor.white_normalized = (uint16_t) veml7700.readWhiteNormalized();
- //veml7700_sensor.lux = (uint16_t) veml7700.readLux();
- //veml7700_sensor.white = (uint16_t) veml7700.readWhite();
+ veml7700_sensor.lux_normalized = (uint32_t) veml7700.readLuxNormalized();
+ veml7700_sensor.white_normalized = (uint32_t) veml7700.readWhiteNormalized();
}
void VEML7700Show(bool json)
@@ -152,6 +150,14 @@ bool VEML7700Cmd(void) {
Response_P(S_JSON_VEML7700_COMMAND_NVALUE, command, dataret);
}
break;
+ case CMND_VEML7700_PERSIST:
+ if (XdrvMailbox.data_len) {
+ if (4 >= XdrvMailbox.payload) {
+ veml7700.setPersistence(XdrvMailbox.payload);
+ }
+ }
+ Response_P(S_JSON_VEML7700_COMMAND_NVALUE, command, veml7700.getPersistence());
+ break;
default:
return false;
}
@@ -174,7 +180,7 @@ bool Xsns71(uint8_t function)
if (FUNC_INIT == function) {
VEML7700Detect();
}
- else if (veml7700_active) {
+ else if (veml7700_sensor.active) {
switch (function) {
case FUNC_EVERY_SECOND:
VEML7700EverySecond();
diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino
new file mode 100644
index 000000000..0d9363409
--- /dev/null
+++ b/tasmota/xsns_73_hp303b.ino
@@ -0,0 +1,178 @@
+/*
+ xsns_72_hp303b.ino - HP303B digital barometric air pressure sensor support for Tasmota
+
+ Copyright (C) 2020 Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifdef USE_I2C
+#ifdef USE_HP303B
+/*********************************************************************************************\
+ * HP303B - Pressure and temperature sensor
+ *
+ * Source: Lolin LOLIN_HP303B_Library
+ *
+ * I2C Address: 0x77 or 0x76
+\*********************************************************************************************/
+
+#define XSNS_73 73
+#define XI2C_52 52 // See I2CDEVICES.md
+
+#define HP303B_MAX_SENSORS 2
+#define HP303B_START_ADDRESS 0x76
+
+#include
+// HP303B Object
+LOLIN_HP303B HP303BSensor = LOLIN_HP303B();
+
+struct {
+ int16_t oversampling = 7;
+ char types[7] = "HP303B";
+ uint8_t count = 0;
+} hp303b_cfg;
+
+struct BHP303B {
+ float temperature = NAN;
+ float pressure = NAN;
+ uint8_t address;
+ uint8_t valid = 0;
+} hp303b_sensor[HP303B_MAX_SENSORS];
+
+/*********************************************************************************************/
+
+bool HP303B_Read(uint32_t hp303b_idx) {
+ if (hp303b_sensor[hp303b_idx].valid) { hp303b_sensor[hp303b_idx].valid--; }
+
+ float t;
+ if (HP303BSensor.measureTempOnce(t, hp303b_sensor[hp303b_idx].address, hp303b_cfg.oversampling) != 0) {
+ return false;
+ }
+
+ float p;
+ if (HP303BSensor.measurePressureOnce(p, hp303b_sensor[hp303b_idx].address, hp303b_cfg.oversampling) != 0) {
+ return false;
+ }
+
+ hp303b_sensor[hp303b_idx].temperature = (float)ConvertTemp(t);
+ hp303b_sensor[hp303b_idx].pressure = (float)ConvertPressure(p / 100); // Conversion to hPa
+
+ hp303b_sensor[hp303b_idx].valid = SENSOR_MAX_MISS;
+ return true;
+}
+
+/********************************************************************************************/
+
+void HP303B_Detect(void) {
+ for (uint32_t i = 0; i < HP303B_MAX_SENSORS; i++) {
+ if (!I2cSetDevice(HP303B_START_ADDRESS + i)) { continue; }
+
+ if (HP303BSensor.begin(HP303B_START_ADDRESS + i)) {
+ hp303b_sensor[hp303b_cfg.count].address = HP303B_START_ADDRESS + i;
+ I2cSetActiveFound(hp303b_sensor[hp303b_cfg.count].address, hp303b_cfg.types);
+ hp303b_cfg.count++;
+ }
+ }
+}
+
+void HP303B_EverySecond(void) {
+ for (uint32_t i = 0; i < hp303b_cfg.count; i++) {
+ if (uptime &1) {
+ if (!HP303B_Read(i)) {
+ AddLogMissed(hp303b_cfg.types, hp303b_sensor[i].valid);
+ }
+ }
+ }
+}
+
+void HP303B_Show(bool json) {
+ for (uint32_t i = 0; i < hp303b_cfg.count; i++) {
+ if (hp303b_sensor[i].valid) {
+ char sensor_name[12];
+ strlcpy(sensor_name, hp303b_cfg.types, sizeof(sensor_name));
+ if (hp303b_cfg.count > 1) {
+ snprintf_P(sensor_name, sizeof(sensor_name), PSTR("%s%c%02X"), sensor_name, IndexSeparator(), hp303b_sensor[i].address); // HP303B-76, HP303B-77
+ }
+
+ float sealevel = 0.0;
+ if (hp303b_sensor[i].pressure != 0.0) {
+ sealevel = (hp303b_sensor[i].pressure / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0), 5.255)) - 21.6;
+ sealevel = ConvertPressure(sealevel);
+ }
+
+ char str_temperature[33];
+ dtostrfd(hp303b_sensor[i].temperature, Settings.flag2.temperature_resolution, str_temperature);
+ char str_pressure[33];
+ dtostrfd(hp303b_sensor[i].pressure, Settings.flag2.pressure_resolution, str_pressure);
+ char sea_pressure[33];
+ dtostrfd(sealevel, Settings.flag2.pressure_resolution, sea_pressure);
+
+ if (json) {
+ ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_PRESSURE "\":%s"), sensor_name, str_temperature, str_pressure);
+ if (Settings.altitude != 0) {
+ ResponseAppend_P(PSTR(",\"" D_JSON_PRESSUREATSEALEVEL "\":%s"), sea_pressure);
+ }
+ ResponseJsonEnd();
+#ifdef USE_DOMOTICZ
+ // Domoticz and knx only support one temp sensor
+ if ((0 == tele_period) && (0 == i)) {
+ DomoticzSensor(DZ_TEMP, hp303b_sensor[i].temperature);
+ }
+#endif // USE_DOMOTICZ
+#ifdef USE_WEBSERVER
+ } else {
+ WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, str_temperature, TempUnit());
+ WSContentSend_PD(HTTP_SNS_PRESSURE, sensor_name, str_pressure, PressureUnit().c_str());
+ if (Settings.altitude != 0) {
+ WSContentSend_PD(HTTP_SNS_SEAPRESSURE, sensor_name, sea_pressure, PressureUnit().c_str());
+ }
+#endif // USE_WEBSERVER
+ }
+ }
+ }
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xsns73(uint8_t function)
+{
+ if (!I2cEnabled(XI2C_52)) { return false; }
+
+ bool result = false;
+
+ if (FUNC_INIT == function) {
+ HP303B_Detect();
+ }
+ else if (hp303b_cfg.count) {
+ switch (function) {
+ case FUNC_EVERY_SECOND:
+ HP303B_EverySecond();
+ break;
+ case FUNC_JSON_APPEND:
+ HP303B_Show(1);
+ break;
+#ifdef USE_WEBSERVER
+ case FUNC_WEB_SENSOR:
+ HP303B_Show(0);
+ break;
+#endif // USE_WEBSERVER
+ }
+ }
+ return result;
+}
+
+#endif // USE_HP303B
+#endif // USE_I2C
diff --git a/tasmota/xsns_74_lmt01.ino b/tasmota/xsns_74_lmt01.ino
new file mode 100644
index 000000000..8bd23ca4a
--- /dev/null
+++ b/tasmota/xsns_74_lmt01.ino
@@ -0,0 +1,142 @@
+/*
+ xns_74_lmt01.ino - Support for single wire LMT01 Temperature Sensor
+
+ Copyright (C) 2020 Theo Arends, Justifiably
+
+ 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 .
+*/
+
+#ifdef USE_LMT01
+/*********************************************************************************************\
+ * LMT01 - 0.5°C Accurate 2-Pin Digital Output Temperature Sensor With Pulse Count Interface
+ *
+ * Uses fragments of public domain code LMT01_Example.ino released by Texas Instruments, July 10th 2017.
+ * See https://training.ti.com/how-interface-lmt01-temperature-sensor-arduino
+\*********************************************************************************************/
+
+#define XSNS_74 74
+
+#define LMT01_TIMEOUT 200 // ms timeout for a reading cycle
+
+bool lmt01_initialized = false;
+float lmt01_temperature = NAN;
+
+void LMT01_Init(void) {
+ if (PinUsed(GPIO_LMT01)) {
+ pinMode(Pin(GPIO_LMT01), INPUT);
+ attachInterrupt(Pin(GPIO_LMT01), LMT01_countPulse, FALLING);
+ lmt01_initialized = true;
+ }
+}
+
+#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 // Fix core 2.5.x ISR not in IRAM Exception
+void LMT01_countPulse(void) ICACHE_RAM_ATTR;
+#endif // ARDUINO_ESP8266_RELEASE_2_3_0
+
+volatile int lmt01_pulseCount = 0;
+
+void LMT01_countPulse(void) {
+ lmt01_pulseCount++;
+}
+
+void LMT01_GetTemperature(void) {
+ int pulses = 0;
+ pulses = LMT01_getPulses();
+ if (pulses >= 0) {
+ // simple linear conversion, datasheet has a look-up table alternative
+ // which is accurate over a wider temperature range
+ lmt01_temperature = ConvertTemp(0.0625 * pulses - 50);
+ } else {
+ lmt01_temperature = NAN; // Timeout
+ }
+}
+
+int LMT01_getPulses(void) {
+ int timeout = LMT01_TIMEOUT;
+ int hold = -1;
+ // complete current pulse cycle (50ms max)
+ while(lmt01_pulseCount != hold && --timeout > 0) {
+ hold = lmt01_pulseCount;
+ delay(1);
+ }
+ lmt01_pulseCount = 0;
+ // wait for start of next (54ms max)
+ while(lmt01_pulseCount == 0 && --timeout > 0) {
+ delay(1);
+ }
+ hold = -1;
+ // take this count (up to 50ms)
+ while(lmt01_pulseCount != hold && --timeout > 0) {
+ hold = lmt01_pulseCount;
+ delay(1);
+ }
+ if (timeout > 0) {
+ return hold;
+ }
+ return -1;
+}
+
+void LMT01_Show(bool Json) {
+ char temp[33];
+ dtostrfd(lmt01_temperature, Settings.flag2.temperature_resolution, temp);
+
+ if (Json) {
+ ResponseAppend_P(JSON_SNS_TEMP, "LMT01", temp);
+#ifdef USE_DOMOTICZ
+ if (0 == tele_period) {
+ DomoticzSensor(DZ_TEMP, temp);
+ }
+#endif // USE_DOMOTICZ
+#ifdef USE_KNX
+ if (0 == tele_period) {
+ KnxSensor(KNX_TEMPERATURE, lmt01_temperature);
+ }
+#endif // USE_KNX
+#ifdef USE_WEBSERVER
+ } else {
+ WSContentSend_PD(HTTP_SNS_TEMP, "LMT01", temp, TempUnit());
+#endif // USE_WEBSERVER
+ }
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xsns74(uint8_t function)
+{
+ bool result = false;
+
+ if (FUNC_INIT == function) {
+ LMT01_Init();
+ }
+ else if (lmt01_initialized) {
+ switch (function) {
+ case FUNC_EVERY_SECOND:
+ LMT01_GetTemperature();
+ break;
+ case FUNC_JSON_APPEND:
+ LMT01_Show(true);
+ break;
+#ifdef USE_WEBSERVER
+ case FUNC_WEB_SENSOR:
+ LMT01_Show(false);
+ break;
+#endif // USE_WEBSERVER
+ }
+ }
+ return result;
+}
+
+#endif // USE_LMT01
diff --git a/tasmota/xsns_91_prometheus.ino b/tasmota/xsns_91_prometheus.ino
index f5b0eba9d..2a361b550 100644
--- a/tasmota/xsns_91_prometheus.ino
+++ b/tasmota/xsns_91_prometheus.ino
@@ -37,7 +37,7 @@ void HandleMetrics(void)
char parameter[FLOATSZ];
- if (global_temperature != 9999) {
+ if (!isnan(global_temperature)) {
dtostrfd(global_temperature, Settings.flag2.temperature_resolution, parameter);
WSContentSend_P(PSTR("# TYPE global_temperature gauge\nglobal_temperature %s\n"), parameter);
}
diff --git a/tools/decode-status.py b/tools/decode-status.py
index 1ce04951e..cdceced48 100755
--- a/tools/decode-status.py
+++ b/tools/decode-status.py
@@ -205,11 +205,11 @@ a_features = [[
"USE_KEELOQ","USE_HRXL","USE_SONOFF_D1","USE_HDC1080",
"USE_IAQ","USE_DISPLAY_SEVENSEG","USE_AS3935","USE_PING",
"USE_WINDMETER","USE_OPENTHERM","USE_THERMOSTAT","USE_VEML6075",
- "USE_VEML7700","USE_MCP9808","USE_BL0940","",
+ "USE_VEML7700","USE_MCP9808","USE_BL0940","USE_TELEGRAM",
+ "USE_HP303B","USE_TCP_BRIDGE","USE_TELEINFO","USE_LMT01",
"","","","",
"","","","",
- "","","","",
- "","","","USE_WEBCAM"
+ "","","USE_ETHERNET","USE_WEBCAM"
]]
usage = "usage: decode-status {-d | -f} arg"
@@ -243,7 +243,7 @@ else:
obj = json.load(fp)
def StartDecode():
- print ("\n*** decode-status.py v20200607 by Theo Arends and Jacek Ziolkowski ***")
+ print ("\n*** decode-status.py v20200617 by Theo Arends and Jacek Ziolkowski ***")
# print("Decoding\n{}".format(obj))