Skip to content

Commit

Permalink
Experimental support for Samsung 36 bit protocol (#625)
Browse files Browse the repository at this point in the history
* sendSamsung36() & decodeSamsung36() added.
* Unit test coverage for those routines.
* Update examples.

Fixes #621
  • Loading branch information
crankyoldgit authored Feb 26, 2019
1 parent 66e09b0 commit 24e7278
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 3 deletions.
10 changes: 9 additions & 1 deletion examples/IRMQTTServer/IRMQTTServer.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -467,6 +467,7 @@ void handleRoot() {
"<option value='2'>RC-6</option>"
"<option value='21'>RC-MM</option>"
"<option value='7'>Samsung</option>"
"<option value='56'>Samsung36</option>"
"<option value='11'>Sanyo</option>"
"<option value='22'>Sanyo LC7461</option>"
"<option value='14'>Sharp</option>"
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -285,6 +288,8 @@ enum decode_type_t {
MWM,
DAIKIN2,
VESTEL_AC,
TECO, // (55)
SAMSUNG36,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
123 changes: 122 additions & 1 deletion src/ir_Samsung.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017 David Conran
// Copyright 2017, 2018, 2019 David Conran

#include "ir_Samsung.h"
#include <algorithm>
Expand Down Expand Up @@ -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.
//
Expand Down
Loading

0 comments on commit 24e7278

Please sign in to comment.