From ee25464c26245ff79b697260390479c7caa96c01 Mon Sep 17 00:00:00 2001
From: openshwprojects <85486843+openshwprojects@users.noreply.github.com>
Date: Mon, 15 Dec 2025 19:56:10 +0100
Subject: [PATCH] RF driver (receiver RF directly with SYN590R or similar)
* test
* T
* T
* W
* Update RCSwitch.cpp
* t
* w
* Update RCSwitch.h
* Update RCSwitch.cpp
* w
* ww
* Update RCSwitch.cpp
* t
* ttt
* test
* dbg
* Update RCSwitch.cpp
* Update RCSwitch.cpp
* ww
* Update drv_rc.cpp
* c
* Update RCSwitch.h
* make
* fix
* Update drv_rc.cpp
* wwww
* wwwwwwwwwww
* Update drv_rc.cpp
* fix
* dsfsdsd
* IOR_RCRecv
* Update RCSwitch.cpp
* test
* ffffffffffffx
* sds
* try
* fx
* tttttttt
* fixes
* fx
* hold
* hide debug vars
---
platforms/obk_main.mk | 2 +
src/cmnds/cmd_eventHandlers.c | 2 +
src/cmnds/cmd_public.h | 2 +
src/driver/drv_main.c | 17 +
src/driver/drv_rc.cpp | 101 ++
src/driver/drv_rc.h | 17 +
src/httpserver/new_http.c | 2 +
src/libraries/rc-switch/.gitignore | 17 +
src/libraries/rc-switch/README.md | 16 +
.../ReceiveDemo_Advanced.ino | 24 +
.../examples/ReceiveDemo_Advanced/output.ino | 70 ++
.../ReceiveDemo_Simple/ReceiveDemo_Simple.ino | 29 +
.../rc-switch/examples/SendDemo/SendDemo.ino | 57 +
.../TypeA_WithDIPSwitches.ino | 40 +
.../TypeA_WithDIPSwitches_Lightweight.ino | 43 +
.../TypeB_WithRotaryOrSlidingSwitches.ino | 40 +
.../TypeC_Intertechno/TypeC_Intertechno.ino | 40 +
.../examples/TypeD_REV/TypeD_REV.ino | 41 +
.../examples/Webserver/Webserver.ino | 154 +++
src/libraries/rc-switch/keywords.txt | 57 +
src/libraries/rc-switch/library.json | 19 +
src/libraries/rc-switch/library.properties | 10 +
src/libraries/rc-switch/platformio.ini | 103 ++
src/libraries/rc-switch/src/RCSwitch.cpp | 1039 +++++++++++++++++
src/libraries/rc-switch/src/RCSwitch.h | 212 ++++
src/new_pins.h | 14 +
src/obk_config.h | 1 +
27 files changed, 2169 insertions(+)
create mode 100644 src/driver/drv_rc.cpp
create mode 100644 src/driver/drv_rc.h
create mode 100644 src/libraries/rc-switch/.gitignore
create mode 100644 src/libraries/rc-switch/README.md
create mode 100644 src/libraries/rc-switch/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.ino
create mode 100644 src/libraries/rc-switch/examples/ReceiveDemo_Advanced/output.ino
create mode 100644 src/libraries/rc-switch/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.ino
create mode 100644 src/libraries/rc-switch/examples/SendDemo/SendDemo.ino
create mode 100644 src/libraries/rc-switch/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.ino
create mode 100644 src/libraries/rc-switch/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino
create mode 100644 src/libraries/rc-switch/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.ino
create mode 100644 src/libraries/rc-switch/examples/TypeC_Intertechno/TypeC_Intertechno.ino
create mode 100644 src/libraries/rc-switch/examples/TypeD_REV/TypeD_REV.ino
create mode 100644 src/libraries/rc-switch/examples/Webserver/Webserver.ino
create mode 100644 src/libraries/rc-switch/keywords.txt
create mode 100644 src/libraries/rc-switch/library.json
create mode 100644 src/libraries/rc-switch/library.properties
create mode 100644 src/libraries/rc-switch/platformio.ini
create mode 100644 src/libraries/rc-switch/src/RCSwitch.cpp
create mode 100644 src/libraries/rc-switch/src/RCSwitch.h
diff --git a/platforms/obk_main.mk b/platforms/obk_main.mk
index f6db33ad9..fc32ae59f 100644
--- a/platforms/obk_main.mk
+++ b/platforms/obk_main.mk
@@ -171,7 +171,9 @@ OBKM_SRC += $(OBK_SRCS)i2c/drv_i2c_mcp23017.c
OBKM_SRC += $(OBK_SRCS)i2c/drv_i2c_tc74.c
OBKM_SRC_CXX += $(OBK_SRCS)driver/drv_ir.cpp
+OBKM_SRC_CXX += $(OBK_SRCS)driver/drv_rc.cpp
OBKM_SRC_CXX += $(OBK_SRCS)driver/drv_ir_new.cpp
+OBKM_SRC_CXX += $(OBK_SRCS)libraries/rc-switch/src/RCSwitch.cpp
OBKM_SRC_CXX += $(OBK_SRCS)libraries/IRremoteESP8266/src/IRac.cpp
OBKM_SRC_CXX += $(OBK_SRCS)libraries/IRremoteESP8266/src/IRproto.cpp
OBKM_SRC_CXX += $(OBK_SRCS)libraries/IRremoteESP8266/src/IRrecv.cpp
diff --git a/src/cmnds/cmd_eventHandlers.c b/src/cmnds/cmd_eventHandlers.c
index 95697d1f1..faa0812b2 100644
--- a/src/cmnds/cmd_eventHandlers.c
+++ b/src/cmnds/cmd_eventHandlers.c
@@ -234,6 +234,8 @@ int EVENT_ParseEventName(const char *s) {
return CMD_EVENT_ON_HTTP;
if (!stricmp(s, "OnDiscovery"))
return CMD_EVENT_ON_DISCOVERY;
+ if (!stricmp(s, "RC"))
+ return CMD_EVENT_RC;
if (isdigit((unsigned char)*s)) {
return atoi(s);
}
diff --git a/src/cmnds/cmd_public.h b/src/cmnds/cmd_public.h
index 09e8c06d8..c3f7cc2b4 100644
--- a/src/cmnds/cmd_public.h
+++ b/src/cmnds/cmd_public.h
@@ -172,6 +172,8 @@ enum EventCode {
CMD_EVENT_ON_DISCOVERY,
+ CMD_EVENT_RC,
+
// must be lower than 256
CMD_EVENT_MAX_TYPES
};
diff --git a/src/driver/drv_main.c b/src/driver/drv_main.c
index 1f480c4fb..217ec6f74 100644
--- a/src/driver/drv_main.c
+++ b/src/driver/drv_main.c
@@ -5,6 +5,7 @@
#include "drv_bl_shared.h"
#include "drv_cse7766.h"
#include "drv_ir.h"
+#include "drv_rc.h"
#include "drv_local.h"
#include "drv_ntp.h"
#include "drv_deviceclock.h"
@@ -757,6 +758,22 @@ static driver_t g_drivers[] = {
false, // loaded
},
#endif
+#if ENABLE_DRIVER_RC
+ //drvdetail:{"name":"RC",
+ //drvdetail:"title":"TODO",
+ //drvdetail:"descr":"",
+ //drvdetail:"requires":""}
+ { "RC", // Driver Name
+ DRV_RC_Init, // Init
+ NULL, // onEverySecond
+ RC_AppendInformationToHTTPIndexPage, // appendInformationToHTTPIndexPage
+ DRV_RC_RunFrame, // runQuickTick
+ NULL, // stopFunction
+ NULL, // onChannelChanged
+ NULL, // onHassDiscovery
+ false, // loaded
+ },
+#endif
#if ENABLE_DRIVER_IR2
//drvdetail:{"name":"IR2",
//drvdetail:"title":"TODO",
diff --git a/src/driver/drv_rc.cpp b/src/driver/drv_rc.cpp
new file mode 100644
index 000000000..6f91b809d
--- /dev/null
+++ b/src/driver/drv_rc.cpp
@@ -0,0 +1,101 @@
+
+#include "../obk_config.h"
+
+#if ENABLE_DRIVER_RC
+
+extern "C" {
+ // these cause error: conflicting declaration of 'int bk_wlan_mcu_suppress_and_sleep(unsigned int)' with 'C' linkage
+#include "../new_common.h"
+#include "../httpserver/new_http.h"
+#include "../logging/logging.h"
+#include "../new_pins.h"
+#include "../new_cfg.h"
+#include "../cmnds/cmd_public.h"
+
+}
+
+#include "drv_rc.h"
+#include "../libraries/rc-switch/src/RCSwitch.h"
+
+RCSwitch mySwitch = RCSwitch();
+void DRV_RC_Init() {
+ // allow user to change them
+ int pin = -1;
+ bool pup = true;
+ pin = PIN_FindPinIndexForRole(IOR_RCRecv, pin);
+ if (pin == -1)
+ {
+ pin = PIN_FindPinIndexForRole(IOR_RCRecv_nPup, pin);
+ if (pin >= 0)
+ pup = false;
+ }
+ ADDLOG_INFO(LOG_FEATURE_IR, "DRV_RC_Init: passing pin %i\n", pin);
+ mySwitch.enableReceive(pin, pup); // Receiver on interrupt 0 => that is pin #2
+}
+//extern long g_micros;
+//extern int rc_triggers;
+//extern int g_rcpin;
+//extern int rc_checkedProtocols;
+//extern int rc_singleRepeats;
+//extern int rc_repeats;
+static int rc_totalDecoded = 0;
+
+void RC_AppendInformationToHTTPIndexPage(http_request_t *request, int bPreState) {
+
+ if (bPreState) {
+ }
+ else {
+ hprintf255(request, "
RC signals decoded: %i
", rc_totalDecoded);
+ //hprintf255(request, "Triggers: %i
", (int)rc_triggers);
+ //hprintf255(request, "Micros: %i
", (int)g_micros);
+ //hprintf255(request, "g_rcpin: %i
", (int)g_rcpin);
+ //hprintf255(request, "rc_checkedProtocols: %i
", (int)rc_checkedProtocols);
+ //hprintf255(request, "rc_singleRepeats: %i
", (int)rc_singleRepeats);
+ //hprintf255(request, "rc_repeats: %i
", (int)rc_repeats);
+ }
+}
+unsigned long rc_prev = 0;
+int loopsUntilClear = 0;
+void DRV_RC_RunFrame() {
+ if (loopsUntilClear) {
+ loopsUntilClear--;
+ if (loopsUntilClear <= 0) {
+ rc_prev = 0;
+ ADDLOG_INFO(LOG_FEATURE_IR, "Clearing hold timer\n");
+ }
+ }
+ if (mySwitch.available()) {
+ rc_totalDecoded++;
+
+ unsigned long rc_now = mySwitch.getReceivedValue();
+ int bHold = 0;
+ if (rc_now != rc_prev) {
+ rc_prev = rc_now;
+ }
+ else {
+ bHold = 1;
+ }
+ loopsUntilClear = 15;
+ // TODO 64 bit
+ // generic
+ // addEventHandler RC 1234 toggleChannel 5 123
+ // on first receive
+ // addEventHandler2 RC 1234 0 toggleChannel 5 123
+ // on hold
+ // addEventHandler2 RC 1234 1 toggleChannel 5 123
+ ADDLOG_INFO(LOG_FEATURE_IR, "Received %lu / %u bit protocol %u, hold %i\n",
+ rc_now,
+ mySwitch.getReceivedBitlength(),
+ mySwitch.getReceivedProtocol(),
+ bHold);
+ EventHandlers_FireEvent2(CMD_EVENT_RC, mySwitch.getReceivedValue(), bHold);
+
+
+ mySwitch.resetAvailable();
+ }
+}
+
+
+#endif
+
+
diff --git a/src/driver/drv_rc.h b/src/driver/drv_rc.h
new file mode 100644
index 000000000..482bdddc1
--- /dev/null
+++ b/src/driver/drv_rc.h
@@ -0,0 +1,17 @@
+#ifndef __DRV_RC_H__
+#define __DRV_RC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void DRV_RC_Init();
+void DRV_RC_RunFrame();
+void RC_AppendInformationToHTTPIndexPage(http_request_t *request, int bPreState);
+
+#ifdef __cplusplus
+}
+
+#endif
+#endif
+
diff --git a/src/httpserver/new_http.c b/src/httpserver/new_http.c
index c80bc494d..e927cc153 100644
--- a/src/httpserver/new_http.c
+++ b/src/httpserver/new_http.c
@@ -558,6 +558,8 @@ const char* htmlPinRoleNames[] = {
"StripState",
"StripState_n",
"HLW_8112_SCSN",
+ "RCRecv",
+ "RCRecv_nPup",
"error",
"error",
"error",
diff --git a/src/libraries/rc-switch/.gitignore b/src/libraries/rc-switch/.gitignore
new file mode 100644
index 000000000..d0972bb47
--- /dev/null
+++ b/src/libraries/rc-switch/.gitignore
@@ -0,0 +1,17 @@
+# Mac stuff
+.DS_Store
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+
diff --git a/src/libraries/rc-switch/README.md b/src/libraries/rc-switch/README.md
new file mode 100644
index 000000000..8debb6d7d
--- /dev/null
+++ b/src/libraries/rc-switch/README.md
@@ -0,0 +1,16 @@
+**Modified Tasmota Fork of RC-SWITCH by @sui77 and @1technophile**
+
+## Info
+
+This will most likely work with all popular low cost power outlet sockets.
+
+All you need is a 315/433MHz AM transmitter and one
+or more devices with one of the supported chipsets:
+
+ - SC5262 / SC5272
+ - HX2262 / HX2272
+ - PT2262 / PT2272
+ - EV1527 / RT1527 / FP1527 / HS1527
+ - Intertechno outlets
+ - HT6P20X
+
diff --git a/src/libraries/rc-switch/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.ino b/src/libraries/rc-switch/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.ino
new file mode 100644
index 000000000..18380d336
--- /dev/null
+++ b/src/libraries/rc-switch/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.ino
@@ -0,0 +1,24 @@
+/*
+ Example for receiving
+
+ https://github.com/sui77/rc-switch/
+
+ If you want to visualize a telegram copy the raw data and
+ paste it into http://test.sui.li/oszi/
+*/
+
+#include
+
+RCSwitch mySwitch = RCSwitch();
+
+void setup() {
+ Serial.begin(9600);
+ mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
+}
+
+void loop() {
+ if (mySwitch.available()) {
+ output(mySwitch.getReceivedValue(), mySwitch.getReceivedBitlength(), mySwitch.getReceivedDelay(), mySwitch.getReceivedRawdata(),mySwitch.getReceivedProtocol());
+ mySwitch.resetAvailable();
+ }
+}
diff --git a/src/libraries/rc-switch/examples/ReceiveDemo_Advanced/output.ino b/src/libraries/rc-switch/examples/ReceiveDemo_Advanced/output.ino
new file mode 100644
index 000000000..31e61ba69
--- /dev/null
+++ b/src/libraries/rc-switch/examples/ReceiveDemo_Advanced/output.ino
@@ -0,0 +1,70 @@
+static const char* bin2tristate(const char* bin);
+static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength);
+
+void output(unsigned long decimal, unsigned int length, unsigned int delay, unsigned int* raw, unsigned int protocol) {
+
+ const char* b = dec2binWzerofill(decimal, length);
+ Serial.print("Decimal: ");
+ Serial.print(decimal);
+ Serial.print(" (");
+ Serial.print( length );
+ Serial.print("Bit) Binary: ");
+ Serial.print( b );
+ Serial.print(" Tri-State: ");
+ Serial.print( bin2tristate( b) );
+ Serial.print(" PulseLength: ");
+ Serial.print(delay);
+ Serial.print(" microseconds");
+ Serial.print(" Protocol: ");
+ Serial.println(protocol);
+
+ Serial.print("Raw data: ");
+ for (unsigned int i=0; i<= length*2; i++) {
+ Serial.print(raw[i]);
+ Serial.print(",");
+ }
+ Serial.println();
+ Serial.println();
+}
+
+static const char* bin2tristate(const char* bin) {
+ static char returnValue[50];
+ int pos = 0;
+ int pos2 = 0;
+ while (bin[pos]!='\0' && bin[pos+1]!='\0') {
+ if (bin[pos]=='0' && bin[pos+1]=='0') {
+ returnValue[pos2] = '0';
+ } else if (bin[pos]=='1' && bin[pos+1]=='1') {
+ returnValue[pos2] = '1';
+ } else if (bin[pos]=='0' && bin[pos+1]=='1') {
+ returnValue[pos2] = 'F';
+ } else {
+ return "not applicable";
+ }
+ pos = pos+2;
+ pos2++;
+ }
+ returnValue[pos2] = '\0';
+ return returnValue;
+}
+
+static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) {
+ static char bin[64];
+ unsigned int i=0;
+
+ while (Dec > 0) {
+ bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0';
+ Dec = Dec >> 1;
+ }
+
+ for (unsigned int j = 0; j< bitLength; j++) {
+ if (j >= bitLength - i) {
+ bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
+ } else {
+ bin[j] = '0';
+ }
+ }
+ bin[bitLength] = '\0';
+
+ return bin;
+}
diff --git a/src/libraries/rc-switch/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.ino b/src/libraries/rc-switch/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.ino
new file mode 100644
index 000000000..bb1076387
--- /dev/null
+++ b/src/libraries/rc-switch/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.ino
@@ -0,0 +1,29 @@
+/*
+ Simple example for receiving
+
+ https://github.com/sui77/rc-switch/
+*/
+
+#include
+
+RCSwitch mySwitch = RCSwitch();
+
+void setup() {
+ Serial.begin(9600);
+ mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
+}
+
+void loop() {
+ if (mySwitch.available()) {
+
+ Serial.print("Received ");
+ Serial.print( mySwitch.getReceivedValue() );
+ Serial.print(" / ");
+ Serial.print( mySwitch.getReceivedBitlength() );
+ Serial.print("bit ");
+ Serial.print("Protocol: ");
+ Serial.println( mySwitch.getReceivedProtocol() );
+
+ mySwitch.resetAvailable();
+ }
+}
diff --git a/src/libraries/rc-switch/examples/SendDemo/SendDemo.ino b/src/libraries/rc-switch/examples/SendDemo/SendDemo.ino
new file mode 100644
index 000000000..5acb4958c
--- /dev/null
+++ b/src/libraries/rc-switch/examples/SendDemo/SendDemo.ino
@@ -0,0 +1,57 @@
+/*
+ Example for different sending methods
+
+ https://github.com/sui77/rc-switch/
+
+*/
+
+#include
+
+RCSwitch mySwitch = RCSwitch();
+
+void setup() {
+
+ Serial.begin(9600);
+
+ // Transmitter is connected to Arduino Pin #10
+ mySwitch.enableTransmit(10);
+
+ // Optional set protocol (default is 1, will work for most outlets)
+ // mySwitch.setProtocol(2);
+
+ // Optional set pulse length.
+ // mySwitch.setPulseLength(320);
+
+ // Optional set number of transmission repetitions.
+ // mySwitch.setRepeatTransmit(15);
+
+}
+
+void loop() {
+
+ /* See Example: TypeA_WithDIPSwitches */
+ mySwitch.switchOn("11111", "00010");
+ delay(1000);
+ mySwitch.switchOff("11111", "00010");
+ delay(1000);
+
+ /* Same switch as above, but using decimal code */
+ mySwitch.send(5393, 24);
+ delay(1000);
+ mySwitch.send(5396, 24);
+ delay(1000);
+
+ /* Same switch as above, but using binary code */
+ mySwitch.send("000000000001010100010001");
+ delay(1000);
+ mySwitch.send("000000000001010100010100");
+ delay(1000);
+
+ /* Same switch as above, but tri-state code */
+ mySwitch.sendTriState("00000FFF0F0F");
+ delay(1000);
+ mySwitch.sendTriState("00000FFF0FF0");
+ delay(1000);
+
+ delay(20000);
+}
diff --git a/src/libraries/rc-switch/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.ino b/src/libraries/rc-switch/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.ino
new file mode 100644
index 000000000..14f7d2a6c
--- /dev/null
+++ b/src/libraries/rc-switch/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.ino
@@ -0,0 +1,40 @@
+/*
+ Example for outlets which are configured with a 10 pole DIP switch.
+
+ https://github.com/sui77/rc-switch/
+*/
+
+#include
+
+RCSwitch mySwitch = RCSwitch();
+
+void setup() {
+
+ // Transmitter is connected to Arduino Pin #10
+ mySwitch.enableTransmit(10);
+
+ // Optional set pulse length.
+ // mySwitch.setPulseLength(320);
+
+}
+
+void loop() {
+
+ // Switch on:
+ // The first parameter represents the setting of the first 5 DIP switches.
+ // In this example it's ON-ON-OFF-OFF-ON.
+ //
+ // The second parameter represents the setting of the last 5 DIP switches.
+ // In this example the last 5 DIP switches are OFF-ON-OFF-ON-OFF.
+ mySwitch.switchOn("11001", "01010");
+
+ // Wait a second
+ delay(1000);
+
+ // Switch off
+ mySwitch.switchOff("11001", "01010");
+
+ // Wait another second
+ delay(1000);
+
+}
diff --git a/src/libraries/rc-switch/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino b/src/libraries/rc-switch/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino
new file mode 100644
index 000000000..214daf41a
--- /dev/null
+++ b/src/libraries/rc-switch/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino
@@ -0,0 +1,43 @@
+/*
+ This is a minimal sketch without using the library at all but only works for
+ the 10 pole dip switch sockets. It saves a lot of memory and thus might be
+ very useful to use with ATTinys :)
+
+ https://github.com/sui77/rc-switch/
+*/
+
+int RCLpin = 7;
+
+void setup() {
+ pinMode(RCLpin, OUTPUT);
+}
+
+void loop() {
+ RCLswitch(0b010001000001); // DIPs an Steckdose: 0100010000 An:01
+ delay(2000);
+
+ RCLswitch(0b010001000010); // DIPs an Steckdose: 0100010000 Aus:10
+ delay(2000);
+}
+
+void RCLswitch(uint16_t code) {
+ for (int nRepeat=0; nRepeat<6; nRepeat++) {
+ for (int i=4; i<16; i++) {
+ RCLtransmit(1,3);
+ if (((code << (i-4)) & 2048) > 0) {
+ RCLtransmit(1,3);
+ } else {
+ RCLtransmit(3,1);
+ }
+ }
+ RCLtransmit(1,31);
+ }
+}
+
+void RCLtransmit(int nHighPulses, int nLowPulses) {
+ digitalWrite(RCLpin, HIGH);
+ delayMicroseconds( 350 * nHighPulses);
+ digitalWrite(RCLpin, LOW);
+ delayMicroseconds( 350 * nLowPulses);
+}
+
diff --git a/src/libraries/rc-switch/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.ino b/src/libraries/rc-switch/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.ino
new file mode 100644
index 000000000..e8568e25b
--- /dev/null
+++ b/src/libraries/rc-switch/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.ino
@@ -0,0 +1,40 @@
+/*
+ Example for outlets which are configured with two rotary/sliding switches.
+
+ https://github.com/sui77/rc-switch/
+*/
+
+#include
+
+RCSwitch mySwitch = RCSwitch();
+
+void setup() {
+
+ // Transmitter is connected to Arduino Pin #10
+ mySwitch.enableTransmit(10);
+
+ // Optional set pulse length.
+ // mySwitch.setPulseLength(320);
+
+}
+
+void loop() {
+
+ // Switch on:
+ // The first parameter represents the setting of the first rotary switch.
+ // In this example it's switched to "1" or "A" or "I".
+ //
+ // The second parameter represents the setting of the second rotary switch.
+ // In this example it's switched to "4" or "D" or "IV".
+ mySwitch.switchOn(1, 4);
+
+ // Wait a second
+ delay(1000);
+
+ // Switch off
+ mySwitch.switchOff(1, 4);
+
+ // Wait another second
+ delay(1000);
+
+}
diff --git a/src/libraries/rc-switch/examples/TypeC_Intertechno/TypeC_Intertechno.ino b/src/libraries/rc-switch/examples/TypeC_Intertechno/TypeC_Intertechno.ino
new file mode 100644
index 000000000..0fc69c7c8
--- /dev/null
+++ b/src/libraries/rc-switch/examples/TypeC_Intertechno/TypeC_Intertechno.ino
@@ -0,0 +1,40 @@
+/*
+ Example for Intertechno outlets
+
+ https://github.com/sui77/rc-switch/
+*/
+
+#include
+
+RCSwitch mySwitch = RCSwitch();
+
+void setup() {
+
+ // Transmitter is connected to Arduino Pin #10
+ mySwitch.enableTransmit(10);
+
+ // Optional set pulse length.
+ // mySwitch.setPulseLength(320);
+
+}
+
+void loop() {
+
+ // Switch on:
+ // The first parameter represents the familycode (a, b, c, ... f)
+ // The second parameter represents the group number
+ // The third parameter represents the device number
+ //
+ // In this example it's family 'b', group #3, device #2
+ mySwitch.switchOn('b', 3, 2);
+
+ // Wait a second
+ delay(1000);
+
+ // Switch off
+ mySwitch.switchOff('b', 3, 2);
+
+ // Wait another second
+ delay(1000);
+
+}
\ No newline at end of file
diff --git a/src/libraries/rc-switch/examples/TypeD_REV/TypeD_REV.ino b/src/libraries/rc-switch/examples/TypeD_REV/TypeD_REV.ino
new file mode 100644
index 000000000..878272945
--- /dev/null
+++ b/src/libraries/rc-switch/examples/TypeD_REV/TypeD_REV.ino
@@ -0,0 +1,41 @@
+/*
+ Example for REV outlets (e.g. 8342L)
+
+ https://github.com/sui77/rc-switch/
+
+ Need help? http://forum.ardumote.com
+*/
+
+#include
+
+RCSwitch mySwitch = RCSwitch();
+
+void setup() {
+
+ // Transmitter is connected to Arduino Pin #10
+ mySwitch.enableTransmit(10);
+
+ // set pulse length.
+ mySwitch.setPulseLength(360);
+
+}
+
+void loop() {
+
+ // Switch on:
+ // The first parameter represents the channel (a, b, c, d)
+ // The second parameter represents the device number
+ //
+ // In this example it's family 'd', device #2
+ mySwitch.switchOn('d', 2);
+
+ // Wait a second
+ delay(1000);
+
+ // Switch off
+ mySwitch.switchOff('d', 2);
+
+ // Wait another second
+ delay(1000);
+
+}
diff --git a/src/libraries/rc-switch/examples/Webserver/Webserver.ino b/src/libraries/rc-switch/examples/Webserver/Webserver.ino
new file mode 100644
index 000000000..66668e76a
--- /dev/null
+++ b/src/libraries/rc-switch/examples/Webserver/Webserver.ino
@@ -0,0 +1,154 @@
+/*
+ A simple RCSwitch/Ethernet/Webserver demo
+
+ https://github.com/sui77/rc-switch/
+*/
+
+#include
+#include
+#include
+
+// Ethernet configuration
+uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // MAC Address
+uint8_t ip[] = { 192,168,0, 2 }; // IP Address
+EthernetServer server(80); // Server Port 80
+
+// RCSwitch configuration
+RCSwitch mySwitch = RCSwitch();
+int RCTransmissionPin = 7;
+
+// More to do...
+// You should also modify the processCommand() and
+// httpResponseHome() functions to fit your needs.
+
+
+
+/**
+ * Setup
+ */
+void setup() {
+ Ethernet.begin(mac, ip);
+ server.begin();
+ mySwitch.enableTransmit( RCTransmissionPin );
+}
+
+/**
+ * Loop
+ */
+void loop() {
+ char* command = httpServer();
+}
+
+/**
+ * Command dispatcher
+ */
+void processCommand(char* command) {
+ if (strcmp(command, "1-on") == 0) {
+ mySwitch.switchOn(1,1);
+ } else if (strcmp(command, "1-off") == 0) {
+ mySwitch.switchOff(1,1);
+ } else if (strcmp(command, "2-on") == 0) {
+ mySwitch.switchOn(1,2);
+ } else if (strcmp(command, "2-off") == 0) {
+ mySwitch.switchOff(1,2);
+ }
+}
+
+/**
+ * HTTP Response with homepage
+ */
+void httpResponseHome(EthernetClient c) {
+ c.println("HTTP/1.1 200 OK");
+ c.println("Content-Type: text/html");
+ c.println();
+ c.println("");
+ c.println("");
+ c.println( "RCSwitch Webserver Demo");
+ c.println( "");
+ c.println("");
+ c.println("");
+ c.println( "RCSwitch Webserver Demo
");
+ c.println( "");
+ c.println( "");
+ c.println( "
");
+ c.println( "https://github.com/sui77/rc-switch/");
+ c.println("");
+ c.println("");
+}
+
+/**
+ * HTTP Redirect to homepage
+ */
+void httpResponseRedirect(EthernetClient c) {
+ c.println("HTTP/1.1 301 Found");
+ c.println("Location: /");
+ c.println();
+}
+
+/**
+ * HTTP Response 414 error
+ * Command must not be longer than 30 characters
+ **/
+void httpResponse414(EthernetClient c) {
+ c.println("HTTP/1.1 414 Request URI too long");
+ c.println("Content-Type: text/plain");
+ c.println();
+ c.println("414 Request URI too long");
+}
+
+/**
+ * Process HTTP requests, parse first request header line and
+ * call processCommand with GET query string (everything after
+ * the ? question mark in the URL).
+ */
+char* httpServer() {
+ EthernetClient client = server.available();
+ if (client) {
+ char sReturnCommand[32];
+ int nCommandPos=-1;
+ sReturnCommand[0] = '\0';
+ while (client.connected()) {
+ if (client.available()) {
+ char c = client.read();
+ if ((c == '\n') || (c == ' ' && nCommandPos>-1)) {
+ sReturnCommand[nCommandPos] = '\0';
+ if (strcmp(sReturnCommand, "\0") == 0) {
+ httpResponseHome(client);
+ } else {
+ processCommand(sReturnCommand);
+ httpResponseRedirect(client);
+ }
+ break;
+ }
+ if (nCommandPos>-1) {
+ sReturnCommand[nCommandPos++] = c;
+ }
+ if (c == '?' && nCommandPos == -1) {
+ nCommandPos = 0;
+ }
+ }
+ if (nCommandPos > 30) {
+ httpResponse414(client);
+ sReturnCommand[0] = '\0';
+ break;
+ }
+ }
+ if (nCommandPos!=-1) {
+ sReturnCommand[nCommandPos] = '\0';
+ }
+ // give the web browser time to receive the data
+ delay(1);
+ client.stop();
+
+ return sReturnCommand;
+ }
+ return '\0';
+}
\ No newline at end of file
diff --git a/src/libraries/rc-switch/keywords.txt b/src/libraries/rc-switch/keywords.txt
new file mode 100644
index 000000000..2474367c4
--- /dev/null
+++ b/src/libraries/rc-switch/keywords.txt
@@ -0,0 +1,57 @@
+#######################################
+# Syntax Coloring Map For RCSwitch
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+RCSwitch KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+##########
+#SENDS Begin
+##########
+switchOn KEYWORD2
+switchOff KEYWORD2
+sendTriState KEYWORD2
+send KEYWORD2
+##########
+#SENDS End
+##########
+
+##########
+#RECEIVE Begin
+##########
+enableReceive KEYWORD2
+disableReceive KEYWORD2
+available KEYWORD2
+resetAvailable KEYWORD2
+setReceiveTolerance KEYWORD2
+getReceivedValue KEYWORD2
+getReceivedBitlength KEYWORD2
+getReceivedDelay KEYWORD2
+getReceivedProtocol KEYWORD2
+getReceivedRawdata KEYWORD2
+##########
+#RECEIVE End
+##########
+
+##########
+#OTHERS Begin
+##########
+enableTransmit KEYWORD2
+disableTransmit KEYWORD2
+setPulseLength KEYWORD2
+setProtocol KEYWORD2
+setRepeatTransmit KEYWORD2
+##########
+#OTHERS End
+##########
+
+#######################################
+# Constants (LITERAL1)
+#######################################
diff --git a/src/libraries/rc-switch/library.json b/src/libraries/rc-switch/library.json
new file mode 100644
index 000000000..0d6a337f4
--- /dev/null
+++ b/src/libraries/rc-switch/library.json
@@ -0,0 +1,19 @@
+{
+ "name": "rc-switch",
+ "description": "Use ESP8266/ESP32 to operate remote radio controlled devices",
+ "keywords": "rf, radio, wireless",
+ "authors":
+ {
+ "name": "Theo Arends"
+ },
+ "repository":
+ {
+ "type": "git",
+ "url": "https://github.com/arendst/Tasmota.git"
+ },
+ "version": "1.0.0",
+ "frameworks": [
+ "arduino"
+ ],
+ "platforms": "*"
+}
diff --git a/src/libraries/rc-switch/library.properties b/src/libraries/rc-switch/library.properties
new file mode 100644
index 000000000..09a0193fe
--- /dev/null
+++ b/src/libraries/rc-switch/library.properties
@@ -0,0 +1,10 @@
+name=rc-switch
+version=1.0.0
+author=@sui77 @1technophile and more
+maintainer=Theo Arends
+sentence=Operate 433/315Mhz devices.
+paragraph=Use ESP8266/ESP32 to operate remote radio controlled devices.
+category=Device Control
+url=https://github.com/arendst/Tasmota
+architectures=esp8266,esp32
+includes=RCSwitch.h
diff --git a/src/libraries/rc-switch/platformio.ini b/src/libraries/rc-switch/platformio.ini
new file mode 100644
index 000000000..74999c992
--- /dev/null
+++ b/src/libraries/rc-switch/platformio.ini
@@ -0,0 +1,103 @@
+; PlatformIO Project Configuration File
+;
+; Build options: build flags, source filter
+; Upload options: custom upload port, speed and extra flags
+; Library options: dependencies, extra library storages
+; Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[platformio]
+src_dir = examples/ReceiveDemo_Advanced
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ENVIRONMENT CHOICE ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;Uncomment the env line corresponding to your board and modules required, ;
+;you can also adapt the modules by removing the corresponding lines in the env detail ;
+; if you go to the build flag section of your env you will see that some user_config.h ;
+; parameters can be overwritten here, for example the gateway name. ;
+; If you want to avoid the lost of your environments at each update you can put them ;
+; into a separate file called prod_env.ini, it will be automatically read by pio ;
+; an example (prod_env.ini.example) is available into the same folder as this file. ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;default_envs = sonoff-basic-rfr3
+;default_envs = esp32dev-rf
+;default_envs = nodemcuv2-rf
+;default_envs = rf-wifi-gateway
+;default_envs = uno-rf
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ENVIRONMENTS PARAMETERS ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;Libraries and parameters shared accross environements ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+
+[env]
+lib_extra_dirs = .
+framework = arduino
+build_flags =
+ -w ; supress all warnings
+monitor_speed = 115200
+
+[com]
+esp8266_platform = espressif8266@2.2.3
+esp32_platform = espressif32@1.11.1
+atmelavr_platform = atmelavr@1.13.0
+
+[com-esp]
+build_flags =
+ ${env.build_flags}
+
+[com-arduino]
+build_flags =
+ ${env.build_flags}
+
+[com-arduino-low-memory]
+build_flags =
+ ${env.build_flags}
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ENVIRONMENTS LIST ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;List of environments that can be build ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[env:esp32dev-rf]
+platform = ${com.esp32_platform}
+board = esp32dev
+build_flags =
+ ${com-esp.build_flags}
+
+[env:nodemcuv2-rf]
+platform = ${com.esp8266_platform}
+board = nodemcuv2
+build_flags =
+ ${com-esp.build_flags}
+board_build.flash_mode = dout
+
+[env:rf-wifi-gateway]
+platform = ${com.esp8266_platform}
+board = nodemcuv2
+build_flags =
+ ${com-esp.build_flags}
+board_build.flash_mode = dout
+
+
+[env:sonoff-basic-rfr3]
+platform = ${com.esp8266_platform}
+board = esp8285
+build_flags =
+ ${com-esp.build_flags}
+board_build.flash_mode = dout
+
+[env:uno-rf]
+platform = ${com.atmelavr_platform}
+board = uno
+build_flags =
+ ${com-arduino-low-memory.build_flags}
diff --git a/src/libraries/rc-switch/src/RCSwitch.cpp b/src/libraries/rc-switch/src/RCSwitch.cpp
new file mode 100644
index 000000000..45d2abf31
--- /dev/null
+++ b/src/libraries/rc-switch/src/RCSwitch.cpp
@@ -0,0 +1,1039 @@
+/*
+ RCSwitch - Arduino libary for remote control outlet switches
+ Copyright (c) 2011 Suat Özgür. All right reserved.
+
+ Contributors:
+ - Andre Koehler / info(at)tomate-online(dot)de
+ - Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
+ - Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
+ - Dominik Fischer / dom_fischer(at)web(dot)de
+ - Frank Oltmanns / .(at)gmail(dot)com
+ - Andreas Steinel / A.(at)gmail(dot)com
+ - Max Horn / max(at)quendi(dot)de
+ - Robert ter Vehn / .(at)gmail(dot)com
+ - Johann Richard / .(at)gmail(dot)com
+ - Vlad Gheorghe / .(at)gmail(dot)com https://github.com/vgheo
+
+ Project home: https://github.com/sui77/rc-switch/
+
+ 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 "RCSwitch.h"
+
+#ifdef RaspberryPi
+ // PROGMEM and _P functions are for AVR based microprocessors,
+ // so we must normalize these for the ARM processor:
+ #define PROGMEM
+ #define memcpy(dest, src, num) memcpy((dest), (src), (num))
+#endif
+
+#if defined(ESP8266)
+ // interrupt handler and related code must be in RAM on ESP8266,
+ // according to issue #46.
+ #define RECEIVE_ATTR ICACHE_RAM_ATTR
+ #define VAR_ISR_ATTR
+#elif defined(ESP32)
+ #define RECEIVE_ATTR IRAM_ATTR
+ #define VAR_ISR_ATTR DRAM_ATTR
+#else
+ #define RECEIVE_ATTR
+ #define VAR_ISR_ATTR
+
+
+#endif
+
+
+
+#if PLATFORM_BEKEN
+
+extern "C" {
+#include "include.h"
+#include "arm_arch.h"
+#include "bk_timer_pub.h"
+#include "drv_model_pub.h"
+
+#include
+//#include "pwm.h"
+#include "pwm_pub.h"
+
+#include "../../beken378/func/include/net_param_pub.h"
+#include "../../beken378/func/user_driver/BkDriverPwm.h"
+#include "../../beken378/func/user_driver/BkDriverI2c.h"
+#include "../../beken378/driver/i2c/i2c1.h"
+#include "../../beken378/driver/gpio/gpio.h"
+#include "../../beken378/driver/pwm/pwm.h"
+#if PLATFORM_BK7231N
+#if PLATFORM_BEKEN_NEW
+#include "pwm_bk7231n.h"
+#else
+#include "../../beken378/driver/pwm/pwm_new.h"
+#endif
+#endif
+}
+
+
+#endif
+
+
+/* Protocol description format
+ *
+ * {
+ * Pulse length,
+ *
+ * PreambleFactor,
+ * Preamble {high,low},
+ *
+ * HeaderFactor,
+ * Header {high,low},
+ *
+ * "0" bit {high,low},
+ * "1" bit {high,low},
+ *
+ * Inverted Signal,
+ * Guard time
+ * }
+ *
+ * Pulse length: pulse duration (Te) in microseconds,
+ * for example 350
+ * PreambleFactor: Number of high and low states to send
+ * (One pulse = 2 states, in orther words, number of pulses is
+ * ceil(PreambleFactor/2).)
+ * Preamble: Pulse shape which defines a preamble bit.
+ * Sent ceil(PreambleFactor/2) times.
+ * For example, {1, 2} with factor 3 would send
+ * _ _
+ * | |__| |__ (each horizontal bar has a duration of Te,
+ * vertical bars are ignored)
+ * HeaderFactor: Number of times to send the header pulse.
+ * Header: Pulse shape which defines a header (or "sync"/"clock") pulse.
+ * {1, 31} means one pulse of duration 1 Te high and 31 Te low
+ * _
+ * | |_______________________________ (don't count the vertical bars)
+ *
+ * "0" bit: pulse shape defining a data bit, which is a logical "0"
+ * {1, 3} means 1 pulse duration Te high level and 3 low
+ * _
+ * | |___
+ *
+ * "1" bit: pulse shape that defines the data bit, which is a logical "1"
+ * {3, 1} means 3 pulses with a duration of Te high level and 1 low
+ * ___
+ * | |_
+ *
+ * (note: to form the state bit Z (Tri-State bit), two codes are combined)
+ *
+ * Inverted Signal: Signal inversion - if true the signal is inverted
+ * replacing high to low in a transmitted / received packet
+ * Guard time: Separation time between two retries. It will be followed by the
+ * next preamble of the next packet. In number of Te.
+ * e.g. 39 pulses of duration Te low level
+ */
+
+#if defined(ESP8266) || defined(ESP32)
+static const VAR_ISR_ATTR RCSwitch::Protocol proto[] = {
+#else
+static const RCSwitch::Protocol proto[] = {
+#endif
+ { 350, 0, { 0, 0 }, 1, { 1, 31 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 01 (Princeton, PT-2240)
+ { 650, 0, { 0, 0 }, 1, { 1, 10 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 02
+ { 100, 0, { 0, 0 }, 1, { 30, 71 }, { 4, 11 }, { 9, 6 }, false, 0 }, // 03
+ { 380, 0, { 0, 0 }, 1, { 1, 6 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 04
+ { 500, 0, { 0, 0 }, 1, { 6, 14 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 05
+ { 450, 0, { 0, 0 }, 1, { 23, 1 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 06 (HT6P20B)
+ { 150, 0, { 0, 0 }, 1, { 2, 62 }, { 1, 6 }, { 6, 1 }, false, 0 }, // 07 (HS2303-PT, i. e. used in AUKEY Remote)
+ { 320, 0, { 0, 0 }, 1, { 36, 1 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 08 (Came 12bit, HT12E)
+ { 700, 0, { 0, 0 }, 1, { 32, 1 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 09 (Nice_Flo 12bit)
+ { 420, 0, { 0, 0 }, 1, { 60, 6 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 10 (V2 phoenix)
+ { 500, 2, { 3, 3 }, 0, { 0, 0 }, { 1, 2 }, { 2, 1 }, false, 37 }, // 11 (Nice_FloR-S 52bit)
+ { 400, 23, { 1, 1 }, 1, { 0, 9 }, { 2, 1 }, { 1, 2 }, false, 39 }, // 12 Placeholder not working! (Keeloq 64/66)
+ { 300, 6, { 2, 2 }, 3, { 8, 3 }, { 2, 2 }, { 3, 3 }, false, 0 }, // 13 test (CFM)
+ { 250, 12, { 4, 4 }, 0, { 0, 0 }, { 1, 1 }, { 2, 2 }, false, 0 }, // 14 test (StarLine)
+ { 500, 0, { 0, 0 }, 0, { 100, 1 }, { 1, 2 }, { 2, 1 }, false, 35 }, // 15
+
+ { 361, 0, { 0, 0 }, 1, { 52, 1 }, { 1, 3 }, { 3, 1 }, true, 0 }, // 16 (Einhell)
+ { 500, 0, { 0, 0 }, 1, { 1, 23 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 17 (InterTechno PAR-1000)
+ { 180, 0, { 0, 0 }, 1, { 1, 15 }, { 1, 1 }, { 1, 8 }, false, 0 }, // 18 (Intertechno ITT-1500)
+ { 350, 0, { 0, 0 }, 1, { 1, 2 }, { 0, 2 }, { 3, 2 }, false, 0 }, // 19 (Murcury)
+ { 150, 0, { 0, 0 }, 1, { 34, 3 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 20 (AC114)
+ { 360, 0, { 0, 0 }, 1, { 13, 4 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 21 (DC250)
+ { 650, 0, { 0, 0 }, 1, { 1, 10 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 22 (Mandolyn/Lidl TR-502MSV/RC-402/RC-402DX)
+ { 641, 0, { 0, 0 }, 1, { 115, 1 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 23 (Lidl TR-502MSV/RC-402 - Flavien)
+ { 620, 0, { 0, 0 }, 1, { 0, 64 }, { 0, 1 }, { 1, 0 }, false, 0 }, // 24 (Lidl TR-502MSV/RC701)
+ { 560, 0, { 0, 0 }, 1, { 16, 8 }, { 1, 1 }, { 1, 3 }, false, 0 }, // 25 (NEC)
+ { 385, 0, { 0, 0 }, 1, { 1, 17 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 26 (Arlec RC210)
+ { 188, 0, { 0, 0 }, 1, { 1, 31 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 27 (Zap, FHT-7901)
+
+ { 700, 1, { 0, 1 }, 1, { 116, 0 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 28 (Quigg GT-7000) from @Tho85 https://github.com/sui77/rc-switch/pull/115
+ { 220, 0, { 0, 0 }, 1, { 1, 46 }, { 1, 6 }, { 1, 1 }, false, 2 }, // 29 (NEXA)
+ { 260, 0, { 0, 0 }, 1, { 1, 8 }, { 1, 4 }, { 4, 1 }, true, 0 }, // 30 (Anima)
+
+ { 400, 0, { 0, 0 }, 1, { 1, 1 }, { 1, 2 }, { 2, 1 }, false, 43 }, // 31 (Mertik Maxitrol G6R-H4T1)
+ { 365, 0, { 0, 0 }, 1, { 18, 1 }, { 3, 1 }, { 1, 3 }, true, 0 }, // 32 (1ByOne Doorbell) from @Fatbeard https://github.com/sui77/rc-switch/pull/277
+ { 340, 0, { 0, 0 }, 1, { 14, 4 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 33 (Dooya Control DC2708L)
+ { 120, 0, { 0, 0 }, 1, { 1, 28 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 34 DIGOO SD10 - so as to use this protocol RCSWITCH_SEPARATION_LIMIT must be set to 2600
+ { 20, 0, { 0, 0 }, 1, { 239, 78 }, {20, 35 }, {35, 20}, false, 10000},// 35 Dooya 5-Channel blinds remote DC1603
+ { 250, 0, { 0, 0 }, 1, { 18, 6 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 36 Dooya remote DC2700AC for Dooya DT82TV curtains motor
+ { 200, 0, { 0, 0 }, 0, { 0, 0 }, { 1, 3 }, { 3, 1 }, false, 20 }, // 37 DEWENWILS Power Strip
+ { 500, 0, { 0, 0 }, 1, { 7, 1 }, { 2, 1 }, { 4, 1 }, true, 0 }, // 38 temperature and humidity sensor, various brands, nexus protocol, 36 bits + start impulse
+ { 560, 0, { 0, 0 }, 1, { 15, 1 }, { 3, 1 }, { 7, 1 }, true, 0 } // 39 Hyundai WS Senzor 77/77TH, 36 bits (requires disabled protocol 38: 'RfProtocol38 0')
+};
+
+int numProto = sizeof(proto) / sizeof(proto[0]);
+
+#if not defined( RCSwitchDisableReceiving )
+volatile unsigned long long RCSwitch::nReceivedValue = 0;
+volatile unsigned long long RCSwitch::nReceiveProtocolMask;
+volatile unsigned int RCSwitch::nReceivedBitlength = 0;
+volatile unsigned int RCSwitch::nReceivedDelay = 0;
+volatile unsigned int RCSwitch::nReceivedProtocol = 0;
+int RCSwitch::nReceiveTolerance = 60;
+unsigned int RCSwitch::nSeparationLimit = RCSWITCH_SEPARATION_LIMIT;
+unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES];
+unsigned int RCSwitch::buftimings[4];
+#endif
+
+RCSwitch::RCSwitch() {
+ this->nTransmitterPin = -1;
+ this->setRepeatTransmit(5);
+ this->setProtocol(1);
+ #if not defined( RCSwitchDisableReceiving )
+ this->nReceiverInterrupt = -1;
+ this->setReceiveTolerance(60);
+ RCSwitch::nReceivedValue = 0;
+ RCSwitch::nReceiveProtocolMask = (1ULL << numProto)-1; //pow(2,numProto)-1;
+ #endif
+ RCSwitch::nReceiveProtocolMask = -1;
+}
+
+uint8_t RCSwitch::getNumProtos() {
+ return numProto;
+}
+/**
+ * Sets the protocol to send.
+ */
+void RCSwitch::setProtocol(Protocol protocol) {
+ this->protocol = protocol;
+}
+
+/**
+ * Sets the protocol to send, from a list of predefined protocols
+ */
+void RCSwitch::setProtocol(int nProtocol) {
+ if (nProtocol < 1 || nProtocol > numProto) {
+ nProtocol = 1; // TODO: trigger an error, e.g. "bad protocol" ???
+ }
+#if defined(ESP8266) || defined(ESP32)
+ this->protocol = proto[nProtocol-1];
+#else
+ memcpy(&this->protocol, &proto[nProtocol-1], sizeof(Protocol));
+#endif
+}
+
+/**
+ * Sets the protocol to send with pulse length in microseconds.
+ */
+void RCSwitch::setProtocol(int nProtocol, int nPulseLength) {
+ setProtocol(nProtocol);
+ this->setPulseLength(nPulseLength);
+}
+
+
+/**
+ * Sets pulse length in microseconds
+ */
+void RCSwitch::setPulseLength(int nPulseLength) {
+ this->protocol.pulseLength = nPulseLength;
+}
+
+/**
+ * Sets Repeat Transmits
+ */
+void RCSwitch::setRepeatTransmit(int nRepeatTransmit) {
+ this->nRepeatTransmit = nRepeatTransmit;
+}
+
+/**
+ * Set Receiving Tolerance
+ */
+#if not defined( RCSwitchDisableReceiving )
+void RCSwitch::setReceiveTolerance(int nPercent) {
+ RCSwitch::nReceiveTolerance = nPercent;
+}
+
+bool RCSwitch::setReceiveProtocolMask(unsigned long long mask) {
+ RCSwitch::nReceiveProtocolMask = mask;
+ return updateSeparationLimit();
+}
+
+bool RCSwitch::updateSeparationLimit()
+{
+ unsigned int longestPulseTime = UINT_MAX;
+ unsigned int shortestPulseTime = 0;
+
+ unsigned long long thisMask = 1;
+ for(unsigned int i = 0; i < numProto; i++) {
+ //if (RCSwitch::nReceiveProtocolMask & thisMask)
+ {
+ const unsigned int headerShortPulseCount = MIN(proto[i].Header.high, proto[i].Header.low);
+ const unsigned int headerLongPulseCount = MAX(proto[i].Header.high, proto[i].Header.low);
+
+ // This must be the longest pulse-length of this protocol. nSeparationLimit must of this length or shorter.
+ // This pulse will be used to detect the beginning of a transmission.
+ const unsigned int headerLongPulseTime = proto[i].pulseLength * headerLongPulseCount;
+
+ // nSeparationLimit must be longer than any of the following pulses to avoid detecting a new transmission in the middle of a frame.
+ unsigned int longestDataPulseCount = headerShortPulseCount;
+ longestDataPulseCount = MAX(longestDataPulseCount, proto[i].zero.high);
+ longestDataPulseCount = MAX(longestDataPulseCount, proto[i].zero.low);
+ longestDataPulseCount = MAX(longestDataPulseCount, proto[i].one.high);
+ longestDataPulseCount = MAX(longestDataPulseCount, proto[i].one.low);
+
+ const unsigned int longestDataPulseTime = proto[i].pulseLength * longestDataPulseCount;
+
+ longestPulseTime = MIN(longestPulseTime, headerLongPulseTime);
+ shortestPulseTime = MAX(shortestPulseTime, longestDataPulseTime);
+ }
+ thisMask <<= 1;
+ }
+
+ if (longestPulseTime <= shortestPulseTime) {
+ // incompatible protocols enabled, fall back to default value
+ nSeparationLimit = RCSWITCH_SEPARATION_LIMIT;
+ return false;
+ }
+
+ const unsigned int timeDiff = longestPulseTime - shortestPulseTime;
+ nSeparationLimit = longestPulseTime - (timeDiff / 2);
+ return true;
+}
+#endif
+
+
+/**
+ * Enable transmissions
+ *
+ * @param nTransmitterPin Arduino Pin to which the sender is connected to
+ */
+void RCSwitch::enableTransmit(int nTransmitterPin) {
+ this->nTransmitterPin = nTransmitterPin;
+ HAL_PIN_Setup_Output(this->nTransmitterPin);
+}
+
+/**
+ * Disable transmissions
+ */
+void RCSwitch::disableTransmit() {
+ this->nTransmitterPin = -1;
+}
+
+/**
+ * Switch a remote switch on (Type D REV)
+ *
+ * @param sGroup Code of the switch group (A,B,C,D)
+ * @param nDevice Number of the switch itself (1..3)
+ */
+void RCSwitch::switchOn(char sGroup, int nDevice) {
+ this->sendTriState( this->getCodeWordD(sGroup, nDevice, true) );
+}
+
+/**
+ * Switch a remote switch off (Type D REV)
+ *
+ * @param sGroup Code of the switch group (A,B,C,D)
+ * @param nDevice Number of the switch itself (1..3)
+ */
+void RCSwitch::switchOff(char sGroup, int nDevice) {
+ this->sendTriState( this->getCodeWordD(sGroup, nDevice, false) );
+}
+
+/**
+ * Switch a remote switch on (Type C Intertechno)
+ *
+ * @param sFamily Familycode (a..f)
+ * @param nGroup Number of group (1..4)
+ * @param nDevice Number of device (1..4)
+ */
+void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) {
+ this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) );
+}
+
+/**
+ * Switch a remote switch off (Type C Intertechno)
+ *
+ * @param sFamily Familycode (a..f)
+ * @param nGroup Number of group (1..4)
+ * @param nDevice Number of device (1..4)
+ */
+void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) {
+ this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) );
+}
+
+/**
+ * Switch a remote switch on (Type B with two rotary/sliding switches)
+ *
+ * @param nAddressCode Number of the switch group (1..4)
+ * @param nChannelCode Number of the switch itself (1..4)
+ */
+void RCSwitch::switchOn(int nAddressCode, int nChannelCode) {
+ this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) );
+}
+
+/**
+ * Switch a remote switch off (Type B with two rotary/sliding switches)
+ *
+ * @param nAddressCode Number of the switch group (1..4)
+ * @param nChannelCode Number of the switch itself (1..4)
+ */
+void RCSwitch::switchOff(int nAddressCode, int nChannelCode) {
+ this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) );
+}
+
+/**
+ * Deprecated, use switchOn(const char* sGroup, const char* sDevice) instead!
+ * Switch a remote switch on (Type A with 10 pole DIP switches)
+ *
+ * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
+ * @param nChannelCode Number of the switch itself (1..5)
+ */
+void RCSwitch::switchOn(const char* sGroup, int nChannel) {
+ const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
+ this->switchOn(sGroup, code[nChannel]);
+}
+
+/**
+ * Deprecated, use switchOff(const char* sGroup, const char* sDevice) instead!
+ * Switch a remote switch off (Type A with 10 pole DIP switches)
+ *
+ * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
+ * @param nChannelCode Number of the switch itself (1..5)
+ */
+void RCSwitch::switchOff(const char* sGroup, int nChannel) {
+ const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
+ this->switchOff(sGroup, code[nChannel]);
+}
+
+/**
+ * Switch a remote switch on (Type A with 10 pole DIP switches)
+ *
+ * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
+ * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
+ */
+void RCSwitch::switchOn(const char* sGroup, const char* sDevice) {
+ this->sendTriState( this->getCodeWordA(sGroup, sDevice, true) );
+}
+
+/**
+ * Switch a remote switch off (Type A with 10 pole DIP switches)
+ *
+ * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
+ * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
+ */
+void RCSwitch::switchOff(const char* sGroup, const char* sDevice) {
+ this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) );
+}
+
+
+/**
+ * Returns a char[13], representing the code word to be send.
+ *
+ */
+char* RCSwitch::getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus) {
+ static char sReturn[13];
+ int nReturnPos = 0;
+
+ for (int i = 0; i < 5; i++) {
+ sReturn[nReturnPos++] = (sGroup[i] == '0') ? 'F' : '0';
+ }
+
+ for (int i = 0; i < 5; i++) {
+ sReturn[nReturnPos++] = (sDevice[i] == '0') ? 'F' : '0';
+ }
+
+ sReturn[nReturnPos++] = bStatus ? '0' : 'F';
+ sReturn[nReturnPos++] = bStatus ? 'F' : '0';
+
+ sReturn[nReturnPos] = '\0';
+ return sReturn;
+}
+
+/**
+ * Encoding for type B switches with two rotary/sliding switches.
+ *
+ * The code word is a tristate word and with following bit pattern:
+ *
+ * +-----------------------------+-----------------------------+----------+------------+
+ * | 4 bits address | 4 bits address | 3 bits | 1 bit |
+ * | switch group | switch number | not used | on / off |
+ * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | FFF | on=F off=0 |
+ * +-----------------------------+-----------------------------+----------+------------+
+ *
+ * @param nAddressCode Number of the switch group (1..4)
+ * @param nChannelCode Number of the switch itself (1..4)
+ * @param bStatus Whether to switch on (true) or off (false)
+ *
+ * @return char[13], representing a tristate code word of length 12
+ */
+char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) {
+ static char sReturn[13];
+ int nReturnPos = 0;
+
+ if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) {
+ return 0;
+ }
+
+ for (int i = 1; i <= 4; i++) {
+ sReturn[nReturnPos++] = (nAddressCode == i) ? '0' : 'F';
+ }
+
+ for (int i = 1; i <= 4; i++) {
+ sReturn[nReturnPos++] = (nChannelCode == i) ? '0' : 'F';
+ }
+
+ sReturn[nReturnPos++] = 'F';
+ sReturn[nReturnPos++] = 'F';
+ sReturn[nReturnPos++] = 'F';
+
+ sReturn[nReturnPos++] = bStatus ? 'F' : '0';
+
+ sReturn[nReturnPos] = '\0';
+ return sReturn;
+}
+
+/**
+ * Like getCodeWord (Type C = Intertechno)
+ */
+char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) {
+ static char sReturn[13];
+ int nReturnPos = 0;
+
+ int nFamily = (int)sFamily - 'a';
+ if ( nFamily < 0 || nFamily > 15 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) {
+ return 0;
+ }
+
+ // encode the family into four bits
+ sReturn[nReturnPos++] = (nFamily & 1) ? 'F' : '0';
+ sReturn[nReturnPos++] = (nFamily & 2) ? 'F' : '0';
+ sReturn[nReturnPos++] = (nFamily & 4) ? 'F' : '0';
+ sReturn[nReturnPos++] = (nFamily & 8) ? 'F' : '0';
+
+ // encode the device and group
+ sReturn[nReturnPos++] = ((nDevice-1) & 1) ? 'F' : '0';
+ sReturn[nReturnPos++] = ((nDevice-1) & 2) ? 'F' : '0';
+ sReturn[nReturnPos++] = ((nGroup-1) & 1) ? 'F' : '0';
+ sReturn[nReturnPos++] = ((nGroup-1) & 2) ? 'F' : '0';
+
+ // encode the status code
+ sReturn[nReturnPos++] = '0';
+ sReturn[nReturnPos++] = 'F';
+ sReturn[nReturnPos++] = 'F';
+ sReturn[nReturnPos++] = bStatus ? 'F' : '0';
+
+ sReturn[nReturnPos] = '\0';
+ return sReturn;
+}
+
+/**
+ * Encoding for the REV Switch Type
+ *
+ * The code word is a tristate word and with following bit pattern:
+ *
+ * +-----------------------------+-------------------+----------+--------------+
+ * | 4 bits address | 3 bits address | 3 bits | 2 bits |
+ * | switch group | device number | not used | on / off |
+ * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FF 2=F0F 3=FF0 | 000 | on=10 off=01 |
+ * +-----------------------------+-------------------+----------+--------------+
+ *
+ * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/
+ *
+ * @param sGroup Name of the switch group (A..D, resp. a..d)
+ * @param nDevice Number of the switch itself (1..3)
+ * @param bStatus Whether to switch on (true) or off (false)
+ *
+ * @return char[13], representing a tristate code word of length 12
+ */
+char* RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus) {
+ static char sReturn[13];
+ int nReturnPos = 0;
+
+ // sGroup must be one of the letters in "abcdABCD"
+ int nGroup = (sGroup >= 'a') ? (int)sGroup - 'a' : (int)sGroup - 'A';
+ if ( nGroup < 0 || nGroup > 3 || nDevice < 1 || nDevice > 3) {
+ return 0;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ sReturn[nReturnPos++] = (nGroup == i) ? '1' : 'F';
+ }
+
+ for (int i = 1; i <= 3; i++) {
+ sReturn[nReturnPos++] = (nDevice == i) ? '1' : 'F';
+ }
+
+ sReturn[nReturnPos++] = '0';
+ sReturn[nReturnPos++] = '0';
+ sReturn[nReturnPos++] = '0';
+
+ sReturn[nReturnPos++] = bStatus ? '1' : '0';
+ sReturn[nReturnPos++] = bStatus ? '0' : '1';
+
+ sReturn[nReturnPos] = '\0';
+ return sReturn;
+}
+
+/**
+ * @param sCodeWord a tristate code word consisting of the letter 0, 1, F
+ */
+void RCSwitch::sendTriState(const char* sCodeWord) {
+ // turn the tristate code word into the corresponding bit pattern, then send it
+ unsigned long long code = 0;
+ unsigned int length = 0;
+ for (const char* p = sCodeWord; *p; p++) {
+ code <<= 2L;
+ switch (*p) {
+ case '0':
+ // bit pattern 00
+ break;
+ case 'F':
+ // bit pattern 01
+ code |= 1ULL;
+ break;
+ case '1':
+ // bit pattern 11
+ code |= 3ULL;
+ break;
+ }
+ length += 2;
+ }
+ this->sendGeneric(code, length);
+}
+
+/**
+ * @param duration no. of microseconds to delay
+ */
+static inline void safeDelayMicroseconds(unsigned long duration) {
+#if defined(ESP8266) || defined(ESP32)
+ if (duration > 10000) {
+ // if delay > 10 milliseconds, use yield() to avoid wdt reset
+ unsigned long start = micros();
+ while ((micros() - start) < duration) {
+ yield();
+ }
+ }
+ else {
+ usleep(duration);
+ }
+#else
+ usleep(duration);
+#endif
+}
+
+/**
+ * @param sCodeWord a binary code word consisting of the letter 0, 1
+ */
+void RCSwitch::sendGeneric(const char* sCodeWord) {
+ // turn the tristate code word into the corresponding bit pattern, then send it
+ unsigned long long code = 0;
+ unsigned int length = 0;
+ for (const char* p = sCodeWord; *p; p++) {
+ code <<= 1ULL;
+ if (*p != '0')
+ code |= 1ULL;
+ length++;
+ }
+ this->sendGeneric(code, length);
+}
+
+/**
+ * Transmit the first 'length' bits of the integer 'code'. The
+ * bits are sent from MSB to LSB, i.e., first the bit at position length-1,
+ * then the bit at position length-2, and so on, till finally the bit at position 0.
+ */
+void RCSwitch::sendGeneric(unsigned long long code, unsigned int length) {
+ if (this->nTransmitterPin == -1)
+ return;
+
+#if not defined( RCSwitchDisableReceiving )
+ // make sure the receiver is disabled while we transmit
+ int nReceiverInterrupt_backup = nReceiverInterrupt;
+ if (nReceiverInterrupt_backup != -1) {
+ this->disableReceive();
+ }
+#endif
+
+ // repeat sending the packet nRepeatTransmit times
+ for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) {
+ // send the preamble
+ for (int i = 0; i < ((protocol.PreambleFactor / 2) + (protocol.PreambleFactor %2 )); i++) {
+ this->transmit({protocol.Preamble.high, protocol.Preamble.low});
+ }
+ // send the header
+ if (protocol.HeaderFactor > 0) {
+ for (int i = 0; i < protocol.HeaderFactor; i++) {
+ this->transmit(protocol.Header);
+ }
+ }
+ // send the code
+ for (int i = length - 1; i >= 0; i--) {
+ if (code & (1ULL << i))
+ this->transmit(protocol.one);
+ else
+ this->transmit(protocol.zero);
+ }
+ // Set the guard Time
+ if (protocol.Guard > 0) {
+ HAL_PIN_SetOutputValue(this->nTransmitterPin, 0);
+ safeDelayMicroseconds(this->protocol.pulseLength * protocol.Guard);
+ }
+ }
+
+ // Disable transmit after sending (i.e., for inverted protocols)
+ HAL_PIN_SetOutputValue(this->nTransmitterPin, 0);
+
+#if not defined( RCSwitchDisableReceiving )
+ // enable receiver again if we just disabled it
+ if (nReceiverInterrupt_backup != -1) {
+ this->enableReceive(nReceiverInterrupt_backup, bUsePullUp);
+ }
+#endif
+}
+
+/**
+ * Transmit a single high-low pulse.
+ */
+void RCSwitch::transmit(HighLow pulses) {
+ uint8_t firstLogicLevel = (this->protocol.invertedSignal) ? 0 : 1;
+ uint8_t secondLogicLevel = (this->protocol.invertedSignal) ? 1 : 0;
+
+ if (pulses.high > 0) {
+ HAL_PIN_SetOutputValue(this->nTransmitterPin, firstLogicLevel);
+ usleep( this->protocol.pulseLength * pulses.high);
+ }
+ if (pulses.low > 0) {
+ HAL_PIN_SetOutputValue(this->nTransmitterPin, secondLogicLevel);
+ usleep( this->protocol.pulseLength * pulses.low);
+ }
+}
+
+
+#if not defined( RCSwitchDisableReceiving )
+/**
+ * Enable receiving data
+ */
+void RCSwitch::enableReceive(int interrupt, bool pup) {
+ this->nReceiverInterrupt = interrupt;
+ this->bUsePullUp = pup;
+ this->enableReceive();
+}
+
+
+/**
+ * Disable receiving data
+ */
+void RCSwitch::disableReceive() {
+#if not defined(RaspberryPi) // Arduino
+ HAL_DetachInterrupt(this->nReceiverInterrupt);
+#endif // For Raspberry Pi (wiringPi) you can't unregister the ISR
+ this->nReceiverInterrupt = -1;
+}
+
+bool RCSwitch::available() {
+ return RCSwitch::nReceivedValue != 0;
+}
+
+void RCSwitch::resetAvailable() {
+ RCSwitch::nReceivedValue = 0;
+}
+
+unsigned long long RCSwitch::getReceivedValue() {
+ return RCSwitch::nReceivedValue;
+}
+
+unsigned int RCSwitch::getReceivedBitlength() {
+ return RCSwitch::nReceivedBitlength;
+}
+
+unsigned int RCSwitch::getReceivedDelay() {
+ return RCSwitch::nReceivedDelay;
+}
+
+unsigned int RCSwitch::getReceivedProtocol() {
+ return RCSwitch::nReceivedProtocol;
+}
+
+unsigned int* RCSwitch::getReceivedRawdata() {
+ return RCSwitch::timings;
+}
+
+/* helper function for the receiveProtocol method */
+static inline unsigned int diff(int A, int B) {
+ return abs(A - B);
+}
+
+/**
+ *
+ */
+bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCount) {
+#if defined(ESP8266) || defined(ESP32)
+ const Protocol &pro = proto[p-1];
+#else
+ Protocol pro;
+ memcpy(&pro, &proto[p-1], sizeof(Protocol));
+#endif
+
+ unsigned long long code = 0;
+ unsigned int FirstTiming = 0;
+ if (pro.PreambleFactor > 0) {
+ FirstTiming = pro.PreambleFactor + 1;
+ }
+ unsigned int BeginData = 0;
+ if (pro.HeaderFactor > 0) {
+ BeginData = (pro.invertedSignal) ? (2) : (1);
+ // Header pulse count correction for more than one
+ if (pro.HeaderFactor > 1) {
+ BeginData += (pro.HeaderFactor - 1) * 2;
+ }
+ }
+ //Assuming the longer pulse length is the pulse captured in timings[FirstTiming]
+ // берем наибольшее значение из Header
+ const unsigned int syncLengthInPulses = ((pro.Header.low) > (pro.Header.high)) ? (pro.Header.low) : (pro.Header.high);
+ // определяем длительность Te как длительность первого импульса header деленную на количество импульсов в нем
+ // или как длительность импульса preamble деленную на количество Te в нем
+ unsigned int sdelay = 0;
+ if (syncLengthInPulses > 0) {
+ sdelay = RCSwitch::timings[FirstTiming] / syncLengthInPulses;
+ } else if (pro.PreambleFactor > 0) {
+ sdelay = RCSwitch::timings[FirstTiming-2] / pro.PreambleFactor;
+ }
+ const unsigned int delay = sdelay;
+ // nReceiveTolerance = 60
+ // допустимое отклонение длительностей импульсов на 60 %
+ const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100;
+
+ // 0 - sync перед preamble или data
+ // BeginData - сдвиг на 1 или 2 от sync к preamble/data
+ // FirstTiming - сдвиг на preamble к header
+ // firstDataTiming первый импульс data
+ // bitChangeCount - количество импульсов в data
+
+ /* For protocols that start low, the sync period looks like
+ * _________
+ * _____________| |XXXXXXXXXXXX|
+ *
+ * |--1st dur--|-2nd dur-|-Start data-|
+ *
+ * The 3rd saved duration starts the data.
+ *
+ * For protocols that start high, the sync period looks like
+ *
+ * ______________
+ * | |____________|XXXXXXXXXXXXX|
+ *
+ * |-filtered out-|--1st dur--|--Start data--|
+ *
+ * The 2nd saved duration starts the data
+ */
+ // если invertedSignal=false, то сигнал начинается с 1 элемента массива (высокий уровень)
+ // если invertedSignal=true, то сигнал начинается со 2 элемента массива (низкий уровень)
+ // добавляем поправку на Преамбулу и Хедер
+ const unsigned int firstDataTiming = BeginData + FirstTiming;
+ unsigned int bitChangeCount = changeCount - firstDataTiming - 1 + pro.invertedSignal;
+ if (bitChangeCount > 128) {
+ bitChangeCount = 128;
+ }
+
+ for (unsigned int i = firstDataTiming; i < firstDataTiming + bitChangeCount; i += 2) {
+ code <<= 1;
+ if (diff(RCSwitch::timings[i], delay * pro.zero.high) < delayTolerance &&
+ diff(RCSwitch::timings[i + 1], delay * pro.zero.low) < delayTolerance) {
+ // zero
+ } else if (diff(RCSwitch::timings[i], delay * pro.one.high) < delayTolerance &&
+ diff(RCSwitch::timings[i + 1], delay * pro.one.low) < delayTolerance) {
+ // one
+ code |= 1;
+ } else {
+ // Failed
+ return false;
+ }
+ }
+
+ if (bitChangeCount > 14) { // ignore very short transmissions: no device sends them, so this must be noise
+ RCSwitch::nReceivedValue = code;
+ RCSwitch::nReceivedBitlength = bitChangeCount / 2;
+ RCSwitch::nReceivedDelay = delay;
+ RCSwitch::nReceivedProtocol = p;
+ return true;
+ }
+
+ return false;
+}
+
+volatile long g_micros = 0;
+volatile int rc_triggers = 0;
+int prev = 0;
+int g_rcpin = 0;
+static const uint32_t ir_periodus = 50;
+void RC_ISR(uint8_t t) {
+ g_micros += ir_periodus;
+ int n = HAL_PIN_ReadDigitalInput(g_rcpin);
+ if (n != prev) {
+ prev = n;
+ rc_triggers++;
+ RCSwitch::handleInterrupt(0);
+ }
+}
+static uint32_t ir_chan
+#if PLATFORM_BEKEN
+= BKTIMER0
+#endif
+;
+static uint32_t ir_div = 1;
+void obk_startTimer() {
+#if PLATFORM_BEKEN
+ timer_param_t params = {
+ (unsigned char)ir_chan,
+ (unsigned char)ir_div, // div
+ ir_periodus, // us
+ RC_ISR
+ };
+ //GLOBAL_INT_DECLARATION();
+
+
+ UINT32 res;
+ // test what error we get with an invalid command
+ res = sddev_control((char *)TIMER_DEV_NAME, -1, 0);
+
+
+
+
+ //ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer init");
+ // do not need to do this
+ //bk_timer_init();
+ //ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer init done");
+ //ADDLOG_INFO(LOG_FEATURE_IR, (char *)"will ir timer setup %u", res);
+ res = sddev_control((char *)TIMER_DEV_NAME, CMD_TIMER_INIT_PARAM_US, ¶ms);
+ //ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer setup %u", res);
+ res = sddev_control((char *)TIMER_DEV_NAME, CMD_TIMER_UNIT_ENABLE, &ir_chan);
+ //ADDLOG_INFO(LOG_FEATURE_IR, (char *)"ir timer enabled %u", res);
+#endif
+}
+void RCSwitch::enableReceive() {
+ if (this->nReceiverInterrupt != -1) {
+ RCSwitch::nReceivedValue = 0;
+ RCSwitch::nReceivedBitlength = 0;
+ // attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE);
+ //HAL_AttachInterrupt(this->nReceiverInterrupt, INTERRUPT_CHANGE, handleInterrupt);
+ if (bUsePullUp) {
+ HAL_PIN_Setup_Input_Pullup(this->nReceiverInterrupt);
+ ADDLOG_INFO(LOG_FEATURE_IR, "RC: Using pin %i (with pullup)\n", this->nReceiverInterrupt);
+ }
+ else {
+ HAL_PIN_Setup_Input(this->nReceiverInterrupt);
+ ADDLOG_INFO(LOG_FEATURE_IR, "RC: Using pin %i (no pullup)\n", this->nReceiverInterrupt);
+ }
+ g_rcpin = this->nReceiverInterrupt;
+ obk_startTimer();
+ }
+}
+int rc_checkedProtocols = 0;
+int rc_singleRepeats = 0;
+int rc_repeats = 0;
+void RECEIVE_ATTR RCSwitch::handleInterrupt(int xyz) {
+
+ static unsigned int changeCount = 0;
+ static unsigned long lastTime = 0;
+ static unsigned char repeatCount = 0;
+
+ const long time = g_micros; // micros();
+ const unsigned int duration = time - lastTime;
+
+ RCSwitch::buftimings[3]=RCSwitch::buftimings[2];
+ RCSwitch::buftimings[2]=RCSwitch::buftimings[1];
+ RCSwitch::buftimings[1]=RCSwitch::buftimings[0];
+ RCSwitch::buftimings[0]=duration;
+
+ if (duration > RCSwitch::nSeparationLimit ||
+ changeCount == 156 ||
+ (diff(RCSwitch::buftimings[3], RCSwitch::buftimings[2]) < 50 &&
+ diff(RCSwitch::buftimings[2], RCSwitch::buftimings[1]) < 50 &&
+ changeCount > 25)) {
+ // принят длинный импульс продолжительностью более nSeparationLimit (4300)
+ // A long stretch without signal level change occurred. This could
+ // be the gap between two transmission.
+ if (diff(duration, RCSwitch::timings[0]) < 400 ||
+ changeCount == 156 ||
+ (diff(RCSwitch::buftimings[3], RCSwitch::timings[1]) < 50 &&
+ diff(RCSwitch::buftimings[2], RCSwitch::timings[2]) < 50 &&
+ diff(RCSwitch::buftimings[1], RCSwitch::timings[3]) < 50 &&
+ changeCount > 25)) {
+ // если его длительность отличается от первого импульса,
+ // который приняли раньше, менее чем на +-200 (исходно 200)
+ // то считаем это повторным пакетом и игнорируем его
+ // This long signal is close in length to the long signal which
+ // started the previously recorded timings; this suggests that
+ // it may indeed by a a gap between two transmissions (we assume
+ // here that a sender will send the signal multiple times,
+ // with roughly the same gap between them).
+
+ // количество повторных пакетов
+ repeatCount++;
+ rc_repeats++;
+ // при приеме второго повторного начинаем анализ принятого первым
+ if (repeatCount == 1) {
+ rc_singleRepeats++;
+ unsigned long long thismask = 1;
+ for(unsigned int i = 1; i <= numProto; i++) {
+ //if (RCSwitch::nReceiveProtocolMask & thismask)
+ {
+ rc_checkedProtocols++;
+ if (receiveProtocol(i, changeCount)) {
+ // receive succeeded for protocol i
+ break;
+ }
+ }
+ thismask <<= 1;
+ }
+ // очищаем количество повторных пакетов
+ repeatCount = 0;
+ }
+ }
+ // дительность отличается более чем на +-200 от первого
+ // принятого ранее, очищаем счетчик для приема нового пакета
+ changeCount = 0;
+ if (diff(RCSwitch::buftimings[3], RCSwitch::buftimings[2]) < 50 &&
+ diff(RCSwitch::buftimings[2], RCSwitch::buftimings[1]) < 50) {
+ RCSwitch::timings[1]=RCSwitch::buftimings[3];
+ RCSwitch::timings[2]=RCSwitch::buftimings[2];
+ RCSwitch::timings[3]=RCSwitch::buftimings[1];
+ changeCount = 4;
+ }
+ }
+
+ // detect overflow
+ if (changeCount >= RCSWITCH_MAX_CHANGES) {
+ changeCount = 0;
+ repeatCount = 0;
+ }
+
+ // заносим в массив длительность очередного принятого импульса
+ if (changeCount > 0 && duration < 100) { // игнорируем шумовые всплески менее 100 мкс
+ RCSwitch::timings[changeCount-1] += duration;
+ } else {
+ RCSwitch::timings[changeCount++] = duration;
+ }
+ lastTime = time;
+}
+#endif
diff --git a/src/libraries/rc-switch/src/RCSwitch.h b/src/libraries/rc-switch/src/RCSwitch.h
new file mode 100644
index 000000000..ac7dda38d
--- /dev/null
+++ b/src/libraries/rc-switch/src/RCSwitch.h
@@ -0,0 +1,212 @@
+/*
+ RCSwitch - Arduino libary for remote control outlet switches
+ Copyright (c) 2011 Suat Özgür. All right reserved.
+
+ Contributors:
+ - Andre Koehler / info(at)tomate-online(dot)de
+ - Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
+ - Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
+ - Dominik Fischer / dom_fischer(at)web(dot)de
+ - Frank Oltmanns / .(at)gmail(dot)com
+ - Max Horn / max(at)quendi(dot)de
+ - Robert ter Vehn / .(at)gmail(dot)com
+
+ Project home: https://github.com/sui77/rc-switch/
+
+ 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 _RCSwitch_h
+#define _RCSwitch_h
+
+#if defined(ARDUINO) && ARDUINO >= 100
+ #include "Arduino.h"
+#elif defined(ENERGIA) // LaunchPad, FraunchPad and StellarPad specific
+ #include "Energia.h"
+#elif defined(RPI) // Raspberry Pi
+ #define RaspberryPi
+
+ // Include libraries for RPi:
+ #include /* memcpy */
+ #include /* abs */
+ #include
+#elif defined(SPARK)
+ #include "application.h"
+#else
+ // #include "WProgram.h"
+ #include /* memcpy */
+ #include /* abs */
+extern "C" {
+#include "../../../obk_config.h"
+#include "../../../new_common.h"
+#include "../../../logging/logging.h"
+#include "../../../hal/hal_pins.h"
+}
+#endif
+
+#include
+
+
+// At least for the ATTiny X4/X5, receiving has to be disabled due to
+// missing libm depencies (udivmodhi4)
+#if defined( __AVR_ATtinyX5__ ) or defined ( __AVR_ATtinyX4__ )
+#define RCSwitchDisableReceiving
+#endif
+
+// Number of maximum high/Low changes per packet.
+// We can handle up to 36 bit * 2 H/L changes per bit + 2 for sync
+// Для keeloq нужно увеличить RCSWITCH_MAX_CHANGES до 23+1+66*2+1=157
+//#define RCSWITCH_MAX_CHANGES 75 // default 75 - longest protocol that requires this buffer size is 38/nexus
+#define RCSWITCH_MAX_CHANGES 131 // default 75 - Supports 64 too
+
+// separationLimit: minimum microseconds between received codes, closer codes are ignored.
+// according to discussion on issue #14 it might be more suitable to set the separation
+// limit to the same time as the 'low' part of the sync signal for the current protocol.
+// should be set to the minimum value of pulselength * the sync signal
+#define RCSWITCH_SEPARATION_LIMIT 3600
+
+class RCSwitch {
+
+ public:
+ RCSwitch();
+
+ void switchOn(int nGroupNumber, int nSwitchNumber);
+ void switchOff(int nGroupNumber, int nSwitchNumber);
+ void switchOn(const char* sGroup, int nSwitchNumber);
+ void switchOff(const char* sGroup, int nSwitchNumber);
+ void switchOn(char sFamily, int nGroup, int nDevice);
+ void switchOff(char sFamily, int nGroup, int nDevice);
+ void switchOn(const char* sGroup, const char* sDevice);
+ void switchOff(const char* sGroup, const char* sDevice);
+ void switchOn(char sGroup, int nDevice);
+ void switchOff(char sGroup, int nDevice);
+
+ void sendTriState(const char* sCodeWord);
+ void sendGeneric(unsigned long long code, unsigned int length);
+ void sendGeneric(const char* sCodeWord);
+
+ #if not defined( RCSwitchDisableReceiving )
+ void enableReceive(int interrupt, bool pup);
+ void enableReceive();
+ void disableReceive();
+ bool available();
+ void resetAvailable();
+
+ unsigned long long getReceivedValue();
+ unsigned int getReceivedBitlength();
+ unsigned int getReceivedDelay();
+ unsigned int getReceivedProtocol();
+ unsigned int* getReceivedRawdata();
+ uint8_t getNumProtos();
+ #endif
+
+ void enableTransmit(int nTransmitterPin);
+ void disableTransmit();
+ void setPulseLength(int nPulseLength);
+ void setRepeatTransmit(int nRepeatTransmit);
+ #if not defined( RCSwitchDisableReceiving )
+ void setReceiveTolerance(int nPercent);
+ bool setReceiveProtocolMask(unsigned long long mask);
+ #endif
+
+ /**
+ * Description of a single pule, which consists of a high signal
+ * whose duration is "high" times the base pulse length, followed
+ * by a low signal lasting "low" times the base pulse length.
+ * Thus, the pulse overall lasts (high+low)*pulseLength
+ */
+ struct HighLow {
+ uint8_t high;
+ uint8_t low;
+ };
+
+ /**
+ * A "protocol" describes how zero and one bits are encoded into high/low
+ * pulses.
+ */
+ struct Protocol {
+ /** base pulse length in microseconds, e.g. 350 */
+ uint16_t pulseLength;
+ uint8_t PreambleFactor;
+ HighLow Preamble;
+ uint8_t HeaderFactor;
+ HighLow Header;
+
+ HighLow zero;
+ HighLow one;
+
+ /**
+ * If true, interchange high and low logic levels in all transmissions.
+ *
+ * By default, RCSwitch assumes that any signals it sends or receives
+ * can be broken down into pulses which start with a high signal level,
+ * followed by a a low signal level. This is e.g. the case for the
+ * popular PT 2260 encoder chip, and thus many switches out there.
+ *
+ * But some devices do it the other way around, and start with a low
+ * signal level, followed by a high signal level, e.g. the HT6P20B. To
+ * accommodate this, one can set invertedSignal to true, which causes
+ * RCSwitch to change how it interprets any HighLow struct FOO: It will
+ * then assume transmissions start with a low signal lasting
+ * FOO.high*pulseLength microseconds, followed by a high signal lasting
+ * FOO.low*pulseLength microseconds.
+ */
+ bool invertedSignal;
+ uint16_t Guard;
+ };
+
+ void setProtocol(Protocol protocol);
+ void setProtocol(int nProtocol);
+ void setProtocol(int nProtocol, int nPulseLength);
+
+ private:
+ char* getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus);
+ char* getCodeWordB(int nGroupNumber, int nSwitchNumber, bool bStatus);
+ char* getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus);
+ char* getCodeWordD(char group, int nDevice, bool bStatus);
+ void transmit(HighLow pulses);
+
+ #if not defined( RCSwitchDisableReceiving )
+public:
+ static void handleInterrupt(int xyz);
+private:
+ static bool receiveProtocol(const int p, unsigned int changeCount);
+ static bool updateSeparationLimit();
+ int nReceiverInterrupt;
+ bool bUsePullUp;
+ #endif
+ int nTransmitterPin;
+ int nRepeatTransmit;
+ Protocol protocol;
+
+ #if not defined( RCSwitchDisableReceiving )
+ static int nReceiveTolerance;
+ volatile static unsigned long long nReceivedValue;
+ volatile static unsigned long long nReceiveProtocolMask;
+ volatile static unsigned int nReceivedBitlength;
+ volatile static unsigned int nReceivedDelay;
+ volatile static unsigned int nReceivedProtocol;
+ static unsigned int nSeparationLimit;
+ /*
+ * timings[0] contains sync timing, followed by a number of bits
+ */
+ static unsigned int timings[RCSWITCH_MAX_CHANGES];
+ // буфер длительностей последних четырех пакетов, [0] - последний
+ static unsigned int buftimings[4];
+ #endif
+
+
+};
+
+#endif
diff --git a/src/new_pins.h b/src/new_pins.h
index 06bb63da2..6f9239f97 100644
--- a/src/new_pins.h
+++ b/src/new_pins.h
@@ -616,6 +616,20 @@ typedef enum ioRole_e {
//iodetail:"file":"new_pins.h",
//iodetail:"driver":"HLW8112SPI"}
IOR_HLW8112_SCSN,
+ //iodetail:{"name":"IOR_RCRecv",
+ //iodetail:"title":"IOR_RCRecv Pin",
+ //iodetail:"descr":"IOR_RCRecv.",
+ //iodetail:"enum":"IOR_RCRecv",
+ //iodetail:"file":"new_pins.h",
+ //iodetail:"driver":"RC"}
+ IOR_RCRecv,
+ //iodetail:{"name":"IOR_RCRecv_nPup",
+ //iodetail:"title":"IOR_RCRecv_nPup Pin",
+ //iodetail:"descr":"IOR_RCRecv_nPup.",
+ //iodetail:"enum":"IOR_RCRecv_nPup",
+ //iodetail:"file":"new_pins.h",
+ //iodetail:"driver":"RC"}
+ IOR_RCRecv_nPup,
//iodetail:{"name":"Total_Options",
//iodetail:"title":"TODO",
//iodetail:"descr":"Current total number of available IOR roles",
diff --git a/src/obk_config.h b/src/obk_config.h
index 87444eded..815af035f 100644
--- a/src/obk_config.h
+++ b/src/obk_config.h
@@ -289,6 +289,7 @@
#define ENABLE_DRIVER_DDP 1
#define ENABLE_DRIVER_SSDP 1
#define ENABLE_DRIVER_IR 1
+#define ENABLE_DRIVER_RC 1
// #define ENABLE_DRIVER_IR2 1
#define ENABLE_DRIVER_DS1820 1
#define ENABLE_DRIVER_CHT83XX 1