Skip to content

Commit

Permalink
Sanyo A/C: Basic send/decode support
Browse files Browse the repository at this point in the history
* `sendSanyoAc()` & `decodeSanyoAc()` support
* Update unit tests.
* Add basic send and decode unit tests for new protocol.

For #1211
  • Loading branch information
crankyoldgit committed Jul 10, 2020
1 parent 5a007a8 commit c21abb7
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Zepeal decode");
if (decodeZepeal(results, offset)) return true;
#endif // DECODE_ZEPEAL
#if DECODE_SANYO_AC
DPRINTLN("Attempting Sanyo AC decode");
if (decodeSanyoAc(results, offset)) return true;
#endif // DECODE_SANYO_AC
// Typically new protocols are added above this line.
}
#if DECODE_HASH
Expand Down
8 changes: 7 additions & 1 deletion src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,14 @@ class IRrecv {
bool decodeSanyoLC7461(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kSanyoLC7461Bits,
bool strict = true);
const bool strict = true);
#endif
#if DECODE_SANYO_AC
bool decodeSanyoAc(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kSanyoAcBits,
const bool strict = true);
#endif // DECODE_SANYO_AC
#if DECODE_MITSUBISHI
bool decodeMitsubishi(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kMitsubishiBits,
Expand Down
14 changes: 12 additions & 2 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,13 @@
#define SEND_SANYO _IR_ENABLE_DEFAULT_
#endif // SEND_SANYO

#ifndef DECODE_SANYO_AC
#define DECODE_SANYO_AC _IR_ENABLE_DEFAULT_
#endif // DECODE_SANYO_AC
#ifndef SEND_SANYO_AC
#define SEND_SANYO_AC _IR_ENABLE_DEFAULT_
#endif // SEND_SANYO_AC

#ifndef DECODE_MITSUBISHI
#define DECODE_MITSUBISHI _IR_ENABLE_DEFAULT_
#endif // DECODE_MITSUBISHI
Expand Down Expand Up @@ -674,7 +681,7 @@
DECODE_NEOCLIMA || DECODE_DAIKIN176 || DECODE_DAIKIN128 || \
DECODE_AMCOR || DECODE_DAIKIN152 || DECODE_MITSUBISHI136 || \
DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424 || DECODE_HITACHI_AC3 || \
DECODE_HITACHI_AC344 || DECODE_CORONA_AC)
DECODE_HITACHI_AC344 || DECODE_CORONA_AC || DECODE_SANYO_AC)
// Add any DECODE to the above if it uses result->state (see kStateSizeMax)
// you might also want to add the protocol to hasACState function
#define DECODE_AC true // We need some common infrastructure for decoding A/Cs.
Expand Down Expand Up @@ -802,8 +809,9 @@ enum decode_type_t {
CORONA_AC,
MIDEA24,
ZEPEAL,
SANYO_AC,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = ZEPEAL,
kLastDecodeType = SANYO_AC,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -971,6 +979,8 @@ const uint16_t kSamsungAcBits = kSamsungAcStateLength * 8;
const uint16_t kSamsungAcExtendedStateLength = 21;
const uint16_t kSamsungAcExtendedBits = kSamsungAcExtendedStateLength * 8;
const uint16_t kSamsungAcDefaultRepeat = kNoRepeat;
const uint16_t kSanyoAcStateLength = 9;
const uint16_t kSanyoAcBits = kSanyoAcStateLength * 8;
const uint16_t kSanyoSA8650BBits = 12;
const uint16_t kSanyoLC7461AddressBits = 13;
const uint16_t kSanyoLC7461CommandBits = 8;
Expand Down
7 changes: 7 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kNeoclimaBits;
case SAMSUNG_AC:
return kSamsungAcBits;
case SANYO_AC:
return kSanyoAcBits;
case SHARP_AC:
return kSharpAcBits;
case TCL112AC:
Expand Down Expand Up @@ -1152,6 +1154,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendSamsungAC(state, nbytes);
break;
#endif // SEND_SAMSUNG_AC
#if SEND_SANYO_AC
case SANYO_AC:
sendSanyoAc(state, nbytes);
break;
#endif // SEND_SANYO_AC
#if SEND_SHARP_AC
case SHARP_AC:
sendSharpAc(state, nbytes);
Expand Down
5 changes: 5 additions & 0 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,11 @@ class IRsend {
const uint16_t nbits = kSanyoLC7461Bits,
const uint16_t repeat = kNoRepeat);
#endif
#if SEND_SANYO_AC
void sendSanyoAc(const uint8_t *data,
const uint16_t nbytes = kSanyoAcStateLength,
const uint16_t repeat = kNoRepeat);
#endif // SEND_SANYO_AC
#if SEND_DISH
// sendDISH() should typically be called with repeat=3 as DISH devices
// expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes)
Expand Down
1 change: 1 addition & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,5 +265,6 @@ const PROGMEM char *kAllProtocolNamesStr =
D_STR_CORONA_AC "\x0"
D_STR_MIDEA24 "\x0"
D_STR_ZEPEAL "\x0"
D_STR_SANYO_AC "\x0"
///< New protocol strings should be added just above this line.
"\x0"; ///< This string requires double null termination.
1 change: 1 addition & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ bool hasACState(const decode_type_t protocol) {
case NEOCLIMA:
case PANASONIC_AC:
case SAMSUNG_AC:
case SANYO_AC:
case SHARP_AC:
case TCL112AC:
case TOSHIBA_AC:
Expand Down
67 changes: 66 additions & 1 deletion src/ir_Sanyo.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2009 Ken Shirriff
// Copyright 2016 marcosamarinho
// Copyright 2017 David Conran
// Copyright 2017-2020 David Conran

/// @file
/// @brief Support for Sanyo protocols.
Expand All @@ -11,10 +11,15 @@
/// @see http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf
/// @see https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp
/// @see http://slydiman.narod.ru/scr/kb/sanyo.htm
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1211

// Supports:
// Brand: Sanyo, Model: SA 8650B - disabled
// Brand: Sanyo, Model: LC7461 transmitter IC (SANYO_LC7461)
// Brand: Sanyo, Model: SAP-K121AHA A/C (SANYO_AC)
// Brand: Sanyo, Model: RCS-2HS4E remote (SANYO_AC)
// Brand: Sanyo, Model: SAP-K242AH A/C (SANYO_AC)
// Brand: Sanyo, Model: RCS-2S4E remote (SANYO_AC)

#include <algorithm>
#include "IRrecv.h"
Expand Down Expand Up @@ -48,6 +53,13 @@ const uint16_t kSanyoLc7461MinGap =
(kSanyoLc7461OneSpace + kSanyoLc7461ZeroSpace) / 2) +
kSanyoLc7461BitMark);

const uint16_t kSanyoAcHdrMark = 8500; ///< uSeconds
const uint16_t kSanyoAcHdrSpace = 4200; ///< uSeconds
const uint16_t kSanyoAcBitMark = 575; ///< uSeconds
const uint16_t kSanyoAcOneSpace = 1500; ///< uSeconds
const uint16_t kSanyoAcZeroSpace = 500; ///< uSeconds
const uint16_t kSanyoAcFreq = 38000; ///< Hz. (Guess only)

#if SEND_SANYO
/// Construct a Sanyo LC7461 message.
/// @param[in] address The 13 bit value of the address(Custom) portion of the
Expand Down Expand Up @@ -221,3 +233,56 @@ bool IRrecv::decodeSanyo(decode_results *results, uint16_t nbits, bool strict) {
}
*/
#endif // DECODE_SANYO


#if SEND_SANYO_AC
/// Send a SanyoAc formatted message.
/// Status: ALPHA / Untested.
/// @param[in] data An array of bytes containing the IR command.
/// @param[in] nbytes Nr. of bytes of data in the array.
/// @param[in] repeat Nr. of times the message is to be repeated.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1211
void IRsend::sendSanyoAc(const uint8_t data[], const uint16_t nbytes,
const uint16_t repeat) {
// Header + Data + Footer
sendGeneric(kSanyoAcHdrMark, kSanyoAcHdrSpace,
kSanyoAcBitMark, kSanyoAcOneSpace,
kSanyoAcBitMark, kSanyoAcZeroSpace,
kSanyoAcBitMark, kDefaultMessageGap,
data, nbytes, kSanyoAcFreq, false, repeat, kDutyDefault);
}
#endif // SEND_SANYO_AC

#if DECODE_SANYO_AC
/// Decode the supplied SanyoAc message.
/// Status: BETA / Probably works.
/// @param[in,out] results Ptr to the data to decode & where to store the decode
/// @param[in] offset The starting index to use when attempting to decode the
/// raw data. Typically/Defaults to kStartOffset.
/// @param[in] nbits The number of data bits to expect.
/// @param[in] strict Flag indicating if we should perform strict matching.
/// @return A boolean. True if it can decode it, false if it can't.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1211
bool IRrecv::decodeSanyoAc(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kSanyoAcBits)
return false;

// Header + Data + Footer
if (!matchGeneric(results->rawbuf + offset, results->state,
results->rawlen - offset, nbits,
kSanyoAcHdrMark, kSanyoAcHdrSpace,
kSanyoAcBitMark, kSanyoAcOneSpace,
kSanyoAcBitMark, kSanyoAcZeroSpace,
kSanyoAcBitMark, kDefaultMessageGap,
true, kUseDefTol, kMarkExcess, false)) return false;

// Success
results->decode_type = decode_type_t::SANYO_AC;
results->bits = nbits;
// No need to record the state as we stored it as we decoded it.
// As we use result->state, we don't record value, address, or command as it
// is a union data type.
return true;
}
#endif // DECODE_SANYO_AC
3 changes: 3 additions & 0 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,9 @@
#ifndef D_STR_SANYO
#define D_STR_SANYO "SANYO"
#endif // D_STR_SANYO
#ifndef D_STR_SANYO_AC
#define D_STR_SANYO_AC "SANYO_AC"
#endif // D_STR_SANYO_AC
#ifndef D_STR_SANYO_LC7461
#define D_STR_SANYO_LC7461 "SANYO_LC7461"
#endif // D_STR_SANYO_LC7461
Expand Down
90 changes: 89 additions & 1 deletion test/ir_Sanyo_test.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// Copyright 2017 David Conran
// Copyright 2017-2020 David Conran

#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
Expand Down Expand Up @@ -257,3 +260,88 @@ TEST(TestDecodeSanyoLC7461, FailToDecodeNonSanyoLC7461Example) {
irrecv.decodeSanyoLC7461(&irsend.capture, kStartOffset, kSanyoLC7461Bits,
false));
}

TEST(TestUtils, Housekeeping) {
// Sanyo LC7461
ASSERT_EQ("SANYO_LC7461", typeToString(decode_type_t::SANYO_LC7461));
ASSERT_EQ(decode_type_t::SANYO_LC7461, strToDecodeType("SANYO_LC7461"));
ASSERT_FALSE(hasACState(decode_type_t::SANYO_LC7461));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::SANYO_LC7461));
ASSERT_EQ(kSanyoLC7461Bits, IRsend::defaultBits(decode_type_t::SANYO_LC7461));
ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::SANYO_LC7461));
// Sanyo A/C
ASSERT_EQ("SANYO_AC", typeToString(decode_type_t::SANYO_AC));
ASSERT_EQ(decode_type_t::SANYO_AC, strToDecodeType("SANYO_AC"));
ASSERT_TRUE(hasACState(decode_type_t::SANYO_AC));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::SANYO_AC));
ASSERT_EQ(kSanyoAcBits, IRsend::defaultBits(decode_type_t::SANYO_AC));
ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::SANYO_AC));
}

TEST(TestDecodeSanyoAc, DecodeRealExamples) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
// Ref: "On" from https://github.com/crankyoldgit/IRremoteESP8266/issues/1211#issue-650997449
const uint16_t rawData[148] = {
8456, 4192,
624, 448, 584, 1508, 608, 452, 580, 1512, 628, 452, 604, 1468, 560, 1552,
600, 472, 584, 1532, 580, 472, 528, 516, 512, 540, 576, 1516, 628, 1472,
612, 1508, 612, 452, 580, 1512, 628, 1468, 612, 1496, 632, 444, 580, 480,
580, 476, 580, 1496, 564, 508, 576, 480, 576, 480, 580, 476, 584, 472,
584, 468, 584, 480, 520, 512, 580, 480, 576, 480, 580, 476, 584, 472,
584, 472, 528, 508, 524, 1568, 600, 480, 576, 480, 584, 1492, 560, 512,
580, 1536, 576, 480, 580, 476, 580, 476, 528, 528, 524, 1568, 580, 476,
584, 476, 580, 476, 580, 472, 528, 512, 520, 536, 576, 480, 580, 480,
576, 480, 576, 476, 532, 528, 520, 512, 576, 480, 584, 476, 580, 476,
580, 480, 576, 472, 528, 1548, 600, 480, 576, 480, 576, 1520, 592, 1496,
600, 476, 580, 480, 576};
const uint8_t expectedState[kSanyoAcStateLength] = {
0x6A, 0x71, 0x47, 0x00, 0x20, 0x85, 0x00, 0x00, 0x32};
irsend.begin();
irsend.reset();
irsend.sendRaw(rawData, 148, 38000);
irsend.makeDecodeResult();

ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SANYO_AC, irsend.capture.decode_type);
EXPECT_EQ(kSanyoAcBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_FALSE(irsend.capture.repeat);
EXPECT_EQ(
"",
IRAcUtils::resultAcToString(&irsend.capture));
}

TEST(TestDecodeSanyoAc, SyntheticSelfDecode) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
const uint8_t expectedState[kSanyoAcStateLength] = {
0x6A, 0x71, 0x47, 0x00, 0x20, 0x85, 0x00, 0x00, 0x32};
irsend.begin();
irsend.reset();
irsend.sendSanyoAc(expectedState);
irsend.makeDecodeResult();

ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SANYO_AC, irsend.capture.decode_type);
EXPECT_EQ(kSanyoAcBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_FALSE(irsend.capture.repeat);
EXPECT_EQ(
"",
IRAcUtils::resultAcToString(&irsend.capture));
EXPECT_EQ(
"f38000d50"
"m8500s4200"
"m575s500m575s1500m575s500m575s1500m575s500m575s1500m575s1500m575s500"
"m575s1500m575s500m575s500m575s500m575s1500m575s1500m575s1500m575s500"
"m575s1500m575s1500m575s1500m575s500m575s500m575s500m575s1500m575s500"
"m575s500m575s500m575s500m575s500m575s500m575s500m575s500m575s500m575s500"
"m575s500m575s500m575s500m575s500m575s1500m575s500m575s500m575s1500"
"m575s500m575s1500m575s500m575s500m575s500m575s500m575s1500m575s500"
"m575s500m575s500m575s500m575s500m575s500m575s500m575s500m575s500m575s500"
"m575s500m575s500m575s500m575s500m575s500m575s500m575s500m575s1500"
"m575s500m575s500m575s1500m575s1500m575s500m575s500"
"m575s100000",
irsend.outputStr());
}

0 comments on commit c21abb7

Please sign in to comment.