diff --git a/examples/IRMQTTServer/IRMQTTServer.ino b/examples/IRMQTTServer/IRMQTTServer.ino
index 250e8b6ba..13e68c948 100644
--- a/examples/IRMQTTServer/IRMQTTServer.ino
+++ b/examples/IRMQTTServer/IRMQTTServer.ino
@@ -261,7 +261,7 @@ const uint16_t kMinUnknownSize = 2 * 10;
// ----------------- End of User Configuration Section -------------------------
// Globals
-#define _MY_VERSION_ "v0.8.3"
+#define _MY_VERSION_ "v0.8.4"
// HTML arguments we will parse for IR code information.
#define argType "type"
#define argData "code"
@@ -467,6 +467,7 @@ void handleRoot() {
""
""
""
+ ""
""
""
""
@@ -1413,6 +1414,13 @@ bool sendIRCode(int const ir_type, uint64_t const code, char const * code_str,
irsend.sendSAMSUNG(code, bits, repeat);
break;
#endif
+#if SEND_SAMSUNG36
+ case SAMSUNG36: // 56
+ if (bits == 0)
+ bits = kSamsung36Bits;
+ irsend.sendSamsung36(code, bits, repeat);
+ break;
+#endif
#if SEND_WHYNTER
case WHYNTER: // 8
if (bits == 0)
diff --git a/src/IRrecv.cpp b/src/IRrecv.cpp
index 9e926de4a..a52a63f18 100644
--- a/src/IRrecv.cpp
+++ b/src/IRrecv.cpp
@@ -364,6 +364,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
DPRINTLN("Attempting SAMSUNG decode");
if (decodeSAMSUNG(results)) return true;
#endif
+#if DECODE_SAMSUNG36
+ DPRINTLN("Attempting Samsung36 decode");
+ if (decodeSamsung36(results)) return true;
+#endif
#if DECODE_WHYNTER
DPRINTLN("Attempting Whynter decode");
if (decodeWhynter(results)) return true;
diff --git a/src/IRrecv.h b/src/IRrecv.h
index 24df9b960..c0bb38055 100644
--- a/src/IRrecv.h
+++ b/src/IRrecv.h
@@ -216,6 +216,11 @@ class IRrecv {
bool decodeSAMSUNG(decode_results *results, uint16_t nbits = kSamsungBits,
bool strict = true);
#endif
+#if DECODE_SAMSUNG
+ bool decodeSamsung36(decode_results *results,
+ const uint16_t nbits = kSamsung36Bits,
+ const bool strict = true);
+#endif
#if DECODE_SAMSUNG_AC
bool decodeSamsungAC(decode_results *results, uint16_t nbits = kSamsungAcBits,
bool strict = true);
diff --git a/src/IRremoteESP8266.h b/src/IRremoteESP8266.h
index 8912d5883..4a80d0301 100644
--- a/src/IRremoteESP8266.h
+++ b/src/IRremoteESP8266.h
@@ -86,6 +86,9 @@
#define DECODE_SAMSUNG true
#define SEND_SAMSUNG true
+#define DECODE_SAMSUNG36 true
+#define SEND_SAMSUNG36 true
+
#define DECODE_SAMSUNG_AC true
#define SEND_SAMSUNG_AC true
@@ -285,6 +288,8 @@ enum decode_type_t {
MWM,
DAIKIN2,
VESTEL_AC,
+ TECO, // (55)
+ SAMSUNG36,
};
// Message lengths & required repeat values
@@ -373,6 +378,7 @@ const uint16_t kRC6Mode0Bits = 20; // Excludes the 'start' bit.
const uint16_t kRC6_36Bits = 36; // Excludes the 'start' bit.
const uint16_t kRCMMBits = 24;
const uint16_t kSamsungBits = 32;
+const uint16_t kSamsung36Bits = 36;
const uint16_t kSamsungAcStateLength = 14;
const uint16_t kSamsungAcBits = kSamsungAcStateLength * 8;
const uint16_t kSamsungAcExtendedStateLength = 21;
diff --git a/src/IRsend.h b/src/IRsend.h
index fddbb8f89..b0131ac88 100644
--- a/src/IRsend.h
+++ b/src/IRsend.h
@@ -92,6 +92,10 @@ class IRsend {
uint16_t repeat = kNoRepeat);
uint32_t encodeSAMSUNG(uint8_t customer, uint8_t command);
#endif
+#if SEND_SAMSUNG36
+ void sendSamsung36(const uint64_t data, const uint16_t nbits = kSamsung36Bits,
+ const uint16_t repeat = kNoRepeat);
+#endif
#if SEND_SAMSUNG_AC
void sendSamsungAC(unsigned char data[],
uint16_t nbytes = kSamsungAcStateLength,
diff --git a/src/IRutils.cpp b/src/IRutils.cpp
index 7c9347d88..da43d5814 100644
--- a/src/IRutils.cpp
+++ b/src/IRutils.cpp
@@ -231,6 +231,9 @@ std::string typeToString(const decode_type_t protocol, const bool isRepeat) {
case SAMSUNG:
result = "SAMSUNG";
break;
+ case SAMSUNG36:
+ result = "SAMSUNG36";
+ break;
case SAMSUNG_AC:
result = "SAMSUNG_AC";
break;
diff --git a/src/ir_Samsung.cpp b/src/ir_Samsung.cpp
index d70e571c0..6c90e7481 100644
--- a/src/ir_Samsung.cpp
+++ b/src/ir_Samsung.cpp
@@ -1,5 +1,5 @@
// Copyright 2009 Ken Shirriff
-// Copyright 2017 David Conran
+// Copyright 2017, 2018, 2019 David Conran
#include "ir_Samsung.h"
#include
@@ -168,6 +168,127 @@ bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits,
}
#endif
+#if SEND_SAMSUNG36
+// Send a Samsung 36-bit formatted message.
+//
+// Args:
+// data: The message to be sent.
+// nbits: The bit size of the message being sent. typically kSamsung36Bits.
+// repeat: The number of times the message is to be repeated.
+//
+// Status: Alpha / Experimental.
+//
+// Note:
+// Protocol is used by Samsung Bluray Remote: ak59-00167a
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/621
+void IRsend::sendSamsung36(const uint64_t data, const uint16_t nbits,
+ const uint16_t repeat) {
+ if (nbits < 16) return; // To small to send.
+ for (uint16_t r = 0; r <= repeat; r++) {
+ // Block #1 (16 bits)
+ sendGeneric(kSamsungHdrMark, kSamsungHdrSpace,
+ kSamsungBitMark, kSamsungOneSpace,
+ kSamsungBitMark, kSamsungZeroSpace,
+ kSamsungBitMark, kSamsungHdrSpace,
+ data >> (nbits - 16), 16, 38, true, 0, kDutyDefault);
+ // Block #2 (The rest, typically 20 bits)
+ sendGeneric(0, 0, // No header
+ kSamsungBitMark, kSamsungOneSpace,
+ kSamsungBitMark, kSamsungZeroSpace,
+ kSamsungBitMark, kSamsungMinGap, // Gap is just a guess.
+ // Mask off the rest of the bits.
+ data & ((1ULL << (nbits - 16)) - 1),
+ nbits - 16, 38, true, 0, kDutyDefault);
+ }
+}
+#endif // SEND_SAMSUNG36
+
+#if DECODE_SAMSUNG36
+// Decode the supplied Samsung36 message.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: Nr. of bits to expect in the data portion.
+// Typically kSamsung36Bits.
+// strict: Flag to indicate if we strictly adhere to the specification.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: Alpha / Experimental
+//
+// Note:
+// Protocol is used by Samsung Bluray Remote: ak59-00167a
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/621
+bool IRrecv::decodeSamsung36(decode_results *results, const uint16_t nbits,
+ const bool strict) {
+ if (results->rawlen < 2 * nbits + kHeader + kFooter * 2 - 1)
+ return false; // Can't possibly be a valid Samsung message.
+ // We need to be looking for > 16 bits to make sense.
+ if (nbits <= 16) return false;
+ if (strict && nbits != kSamsung36Bits)
+ return false; // We expect nbits to be 36 bits of message.
+
+ uint64_t data = 0;
+ uint16_t offset = kStartOffset;
+
+ // Header
+ if (!matchMark(results->rawbuf[offset], kSamsungHdrMark)) return false;
+ // Calculate how long the common tick time is based on the header mark.
+ uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kSamsungHdrMarkTicks;
+ if (!matchSpace(results->rawbuf[offset], kSamsungHdrSpace)) return false;
+ // Calculate how long the common tick time is based on the header space.
+ uint32_t s_tick =
+ results->rawbuf[offset++] * kRawTick / kSamsungHdrSpaceTicks;
+ // Data (Block #1)
+ match_result_t data_result =
+ matchData(&(results->rawbuf[offset]), 16,
+ kSamsungBitMarkTicks * m_tick, kSamsungOneSpaceTicks * s_tick,
+ kSamsungBitMarkTicks * m_tick, kSamsungZeroSpaceTicks * s_tick);
+ if (data_result.success == false) return false;
+ data = data_result.data;
+ offset += data_result.used;
+ uint16_t bitsSoFar = data_result.used / 2;
+ // Footer (Block #1)
+ if (!matchMark(results->rawbuf[offset++], kSamsungBitMarkTicks * m_tick))
+ return false;
+ if (!matchSpace(results->rawbuf[offset++], kSamsungHdrSpaceTicks * s_tick))
+ return false;
+ // Data (Block #2)
+ data_result = matchData(&(results->rawbuf[offset]),
+ nbits - 16,
+ kSamsungBitMarkTicks * m_tick,
+ kSamsungOneSpaceTicks * s_tick,
+ kSamsungBitMarkTicks * m_tick,
+ kSamsungZeroSpaceTicks * s_tick);
+ if (data_result.success == false) return false;
+ data <<= (nbits - 16);
+ data += data_result.data;
+ offset += data_result.used;
+ bitsSoFar += data_result.used / 2;
+ // Footer (Block #2)
+ if (!matchMark(results->rawbuf[offset++], kSamsungBitMarkTicks * m_tick))
+ return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kSamsungMinGapTicks * s_tick))
+ return false;
+
+ // Compliance
+ if (nbits != bitsSoFar) return false;
+
+ // Success
+ results->bits = bitsSoFar;
+ results->value = data;
+ results->decode_type = SAMSUNG36;
+ results->command = data & ((1ULL << (nbits - 16)) - 1);
+ results->address = data >> (nbits - 16);
+ return true;
+}
+#endif // DECODE_SAMSUNG36
+
#if SEND_SAMSUNG_AC
// Send a Samsung A/C message.
//
diff --git a/test/ir_Samsung_test.cpp b/test/ir_Samsung_test.cpp
index 4c798036b..390e86e79 100644
--- a/test/ir_Samsung_test.cpp
+++ b/test/ir_Samsung_test.cpp
@@ -1,4 +1,4 @@
-// Copyright 2017 David Conran
+// Copyright 2017, 2018, 2019 David Conran
#include "ir_Samsung.h"
#include "IRrecv.h"
@@ -7,6 +7,13 @@
#include "IRsend_test.h"
#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestSamsung, Housekeeping) {
+ ASSERT_EQ("SAMSUNG", typeToString(SAMSUNG));
+ ASSERT_FALSE(hasACState(SAMSUNG));
+}
+
// Tests for sendSAMSUNG().
// Test sending typical data only.
@@ -281,6 +288,12 @@ TEST(TestDecodeSamsung, FailToDecodeNonSamsungExample) {
ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, false));
}
+// General housekeeping
+TEST(TestSamsungAC, Housekeeping) {
+ ASSERT_EQ("SAMSUNG_AC", typeToString(SAMSUNG_AC));
+ ASSERT_TRUE(hasACState(SAMSUNG_AC));
+}
+
// Tests for sendSamsungAC().
// Test sending typical data only.
@@ -976,3 +989,133 @@ TEST(TestDecodeSamsungAC, Issue604DecodeExtended) {
"Beep: Off, Clean: Off, Quiet: Off",
samsung.toString());
}
+
+TEST(TestSendSamsung36, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendSamsung36(0);
+ EXPECT_EQ(
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560"
+ "m560s26880",
+ irsend.outputStr());
+ irsend.sendSamsung36(0x400E00FF);
+ EXPECT_EQ(
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880",
+ irsend.outputStr());
+ irsend.reset();
+}
+
+// General housekeeping
+TEST(TestSamsung36, Housekeeping) {
+ ASSERT_EQ("SAMSUNG36", typeToString(SAMSUNG36));
+ ASSERT_FALSE(hasACState(SAMSUNG36));
+}
+
+// Test sending with different repeats.
+TEST(TestSendSamsung36, SendWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendSamsung36(0x400E00FF, kSamsung36Bits, 1); // 1 repeat.
+ EXPECT_EQ(
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880",
+ irsend.outputStr());
+ irsend.sendSamsung36(0x400E00FF, kSamsung36Bits, 2); // 2 repeats.
+ EXPECT_EQ(
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880",
+ irsend.outputStr());
+}
+
+TEST(TestDecodeSamsung36, RealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ uint16_t rawData[77] = {
+ 4542, 4438, 568, 432, 562, 436, 536, 462, 538, 460, 538, 460, 564, 1434,
+ 564, 434, 534, 464, 536, 462, 562, 436, 536, 464, 564, 432, 538, 462, 536,
+ 464, 534, 464, 564, 420, 566, 4414, 538, 1462, 566, 1432, 562, 1436, 536,
+ 462, 564, 436, 562, 436, 560, 436, 562, 436, 562, 436, 560, 438, 536, 462,
+ 562, 436, 562, 1436, 562, 1434, 536, 1462, 564, 1434, 562, 1436, 564,
+ 1436, 534, 1462, 534, 1464, 536}; // UNKNOWN E4CD1208
+
+ irsend.sendRaw(rawData, 77, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(SAMSUNG36, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsung36Bits, irsend.capture.bits);
+ EXPECT_EQ(0x400E00FF, irsend.capture.value);
+ EXPECT_EQ(0xE00FF, irsend.capture.command);
+ EXPECT_EQ(0x400, irsend.capture.address);
+}
+
+TEST(TestDecodeSamsung36, SyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+ irsend.reset();
+
+ irsend.sendSamsung36(0x400E00FF);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decodeSamsung36(&irsend.capture));
+ ASSERT_EQ(SAMSUNG36, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsung36Bits, irsend.capture.bits);
+ EXPECT_EQ(0x400E00FF, irsend.capture.value);
+ EXPECT_EQ(0xE00FF, irsend.capture.command);
+ EXPECT_EQ(0x400, irsend.capture.address);
+}