Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental basic support for Sanyo AC 152 bit protocol. #1828

Merged
merged 2 commits into from
Jun 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting TCL AC 96-bit decode");
if (decodeTcl96Ac(results, offset)) return true;
#endif // DECODE_TCL96AC
#if DECODE_SANYO_AC152
DPRINTLN("Attempting Sanyo AC 152-bit decode");
if (decodeSanyoAc152(results, offset)) return true;
#endif // DECODE_SANYO_AC152
// Typically new protocols are added above this line.
}
#if DECODE_HASH
Expand Down
6 changes: 6 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,12 @@ class IRrecv {
const uint16_t nbits = kSanyoAc88Bits,
const bool strict = true);
#endif // DECODE_SANYO_AC88
#if DECODE_SANYO_AC152
bool decodeSanyoAc152(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kSanyoAc152Bits,
const bool strict = true);
#endif // DECODE_SANYO_AC152
#if DECODE_MITSUBISHI
bool decodeMitsubishi(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kMitsubishiBits,
Expand Down
15 changes: 13 additions & 2 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,13 @@
#define SEND_SANYO_AC88 _IR_ENABLE_DEFAULT_
#endif // SEND_SANYO_AC88

#ifndef DECODE_SANYO_AC152
#define DECODE_SANYO_AC152 _IR_ENABLE_DEFAULT_
#endif // DECODE_SANYO_AC152
#ifndef SEND_SANYO_AC152
#define SEND_SANYO_AC152 _IR_ENABLE_DEFAULT_
#endif // SEND_SANYO_AC152

#ifndef DECODE_MITSUBISHI
#define DECODE_MITSUBISHI _IR_ENABLE_DEFAULT_
#endif // DECODE_MITSUBISHI
Expand Down Expand Up @@ -927,7 +934,7 @@
DECODE_SANYO_AC88 || DECODE_RHOSS || DECODE_HITACHI_AC264 || \
DECODE_KELON168 || DECODE_HITACHI_AC296 || DECODE_CARRIER_AC128 || \
DECODE_DAIKIN200 || DECODE_HAIER_AC160 || DECODE_TCL96AC || \
DECODE_BOSCH144 || \
DECODE_BOSCH144 || DECODE_SANYO_AC152 || \
false)
// Add any DECODE to the above if it uses result->state (see kStateSizeMax)
// you might also want to add the protocol to hasACState function
Expand Down Expand Up @@ -1088,8 +1095,9 @@ enum decode_type_t {
CLIMABUTLER,
TCL96AC,
BOSCH144, // 120
SANYO_AC152,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = BOSCH144,
kLastDecodeType = SANYO_AC152,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -1299,6 +1307,9 @@ const uint16_t kSanyoAcBits = kSanyoAcStateLength * 8;
const uint16_t kSanyoAc88StateLength = 11;
const uint16_t kSanyoAc88Bits = kSanyoAc88StateLength * 8;
const uint16_t kSanyoAc88MinRepeat = 2;
const uint16_t kSanyoAc152StateLength = 19;
const uint16_t kSanyoAc152Bits = kSanyoAc152StateLength * 8;
const uint16_t kSanyoAc152MinRepeat = kNoRepeat;
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 @@ -768,6 +768,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kSanyoAcBits;
case SANYO_AC88:
return kSanyoAc88Bits;
case SANYO_AC152:
return kSanyoAc152Bits;
case SHARP_AC:
return kSharpAcBits;
case TCL96AC:
Expand Down Expand Up @@ -1353,6 +1355,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendSanyoAc88(state, nbytes);
break;
#endif // SEND_SANYO_AC88
#if SEND_SANYO_AC152
case SANYO_AC152:
sendSanyoAc152(state, nbytes);
break;
#endif // SEND_SANYO_AC152
#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 @@ -346,6 +346,11 @@ class IRsend {
const uint16_t nbytes = kSanyoAc88StateLength,
const uint16_t repeat = kSanyoAc88MinRepeat);
#endif // SEND_SANYO_AC88
#if SEND_SANYO_AC152
void sendSanyoAc152(const uint8_t *data,
const uint16_t nbytes = kSanyoAc152StateLength,
const uint16_t repeat = kSanyoAc152MinRepeat);
#endif // SEND_SANYO_AC152
#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 @@ -404,6 +404,7 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
D_STR_CLIMABUTLER "\x0"
D_STR_TCL96AC "\x0"
D_STR_BOSCH144 "\x0"
D_STR_SANYO_AC152 "\x0"
///< New protocol strings should be added just above this line.
"\x0" ///< This string requires double null termination.
};
Expand Down
1 change: 1 addition & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ bool hasACState(const decode_type_t protocol) {
case SAMSUNG_AC:
case SANYO_AC:
case SANYO_AC88:
case SANYO_AC152:
case SHARP_AC:
case TCL96AC:
case TCL112AC:
Expand Down
68 changes: 67 additions & 1 deletion src/ir_Sanyo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ const uint32_t kSanyoAc88Gap = 3675; ///< uSeconds
const uint16_t kSanyoAc88Freq = 38000; ///< Hz. (Guess only)
const uint8_t kSanyoAc88ExtraTolerance = 5; /// (%) Extra tolerance to use.

const uint16_t kSanyoAc152HdrMark = 3300; ///< uSeconds
const uint16_t kSanyoAc152BitMark = 440; ///< uSeconds
const uint16_t kSanyoAc152HdrSpace = 1725; ///< uSeconds
const uint16_t kSanyoAc152OneSpace = 1290; ///< uSeconds
const uint16_t kSanyoAc152ZeroSpace = 405; ///< uSeconds
const uint16_t kSanyoAc152Freq = 38000; ///< Hz. (Guess only)
const uint8_t kSanyoAc152ExtraTolerance = 13; /// (%) Extra tolerance to use.

#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 @@ -687,7 +695,7 @@ void IRsend::sendSanyoAc88(const uint8_t data[], const uint16_t nbytes,
#endif // SEND_SANYO_AC88

#if DECODE_SANYO_AC88
/// Decode the supplied SanyoAc message.
/// Decode the supplied SanyoAc88 message.
/// Status: ALPHA / Untested.
/// @param[in,out] results Ptr to the data to decode & where to store the decode
/// @warning data's bit order may change. It is not yet confirmed.
Expand Down Expand Up @@ -976,3 +984,61 @@ String IRSanyoAc88::toString(void) const {
result += addLabeledString(minsToString(getClock()), kClockStr);
return result;
}

#if SEND_SANYO_AC152
/// Send a SanyoAc152 formatted message.
/// Status: BETA / Probably works.
/// @param[in] data An array of bytes containing the IR command.
/// @warning data's bit order may change. It is not yet confirmed.
/// @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/1826
void IRsend::sendSanyoAc152(const uint8_t data[], const uint16_t nbytes,
const uint16_t repeat) {
// (Header + Data + Footer) per repeat
sendGeneric(kSanyoAc152HdrMark, kSanyoAc152HdrSpace,
kSanyoAc152BitMark, kSanyoAc152OneSpace,
kSanyoAc152BitMark, kSanyoAc152ZeroSpace,
kSanyoAc152BitMark, kDefaultMessageGap,
data, nbytes, kSanyoAc152Freq, false, repeat, kDutyDefault);
space(kDefaultMessageGap); // Make a guess at a post message gap.
}
#endif // SEND_SANYO_AC152

#if DECODE_SANYO_AC152
/// Decode the supplied SanyoAc152 message.
/// Status: BETA / Probably works.
/// @param[in,out] results Ptr to the data to decode & where to store the decode
/// @warning data's bit order may change. It is not yet confirmed.
/// @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/1503
bool IRrecv::decodeSanyoAc152(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kSanyoAc152Bits)
return false;

// Header + Data + Footer
if (!matchGeneric(results->rawbuf + offset, results->state,
results->rawlen - offset, nbits,
kSanyoAc152HdrMark, kSanyoAc152HdrSpace,
kSanyoAc152BitMark, kSanyoAc152OneSpace,
kSanyoAc152BitMark, kSanyoAc152ZeroSpace,
kSanyoAc152BitMark,
kDefaultMessageGap, // Just a guess.
false, _tolerance + kSanyoAc152ExtraTolerance,
kMarkExcess, false))
return false; // No match!

// Success
results->decode_type = decode_type_t::SANYO_AC152;
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_AC152
3 changes: 3 additions & 0 deletions src/ir_Sanyo.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
/// @see https://docs.google.com/spreadsheets/d/1dYfLsnYvpjV-SgO8pdinpfuBIpSzm8Q1R5SabrLeskw/edit?usp=sharing
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1503
/// @see https://docs.google.com/spreadsheets/d/1weUmGAsEpfX38gg5rlDN69Uchnbr6gQl9FqHffLBIRk/edit#gid=0
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1826

// Supports:
// Brand: Sanyo, Model: SA 8650B - disabled
Expand All @@ -21,6 +22,8 @@
// 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)
// Brand: Sanyo, Model: RCS-4MHVPIS4EE remote (SANYO_AC152)
// Brand: Sanyo, Model: SAP-KMRV124EHE A/C (SANYO_AC152)

#ifndef IR_SANYO_H_
#define IR_SANYO_H_
Expand Down
9 changes: 6 additions & 3 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -980,13 +980,16 @@ D_STR_INDIRECT " " D_STR_MODE
#define D_STR_SANYO "SANYO"
#endif // D_STR_SANYO
#ifndef D_STR_SANYO_AC
#define D_STR_SANYO_AC "SANYO_AC"
#define D_STR_SANYO_AC D_STR_SANYO "_AC"
#endif // D_STR_SANYO_AC
#ifndef D_STR_SANYO_AC88
#define D_STR_SANYO_AC88 "SANYO_AC88"
#define D_STR_SANYO_AC88 D_STR_SANYO_AC "88"
#endif // D_STR_SANYO_AC88
#ifndef D_STR_SANYO_AC152
#define D_STR_SANYO_AC152 D_STR_SANYO_AC "152"
#endif // D_STR_SANYO_AC152
#ifndef D_STR_SANYO_LC7461
#define D_STR_SANYO_LC7461 "SANYO_LC7461"
#define D_STR_SANYO_LC7461 D_STR_SANYO "_LC7461"
#endif // D_STR_SANYO_LC7461
#ifndef D_STR_SHARP
#define D_STR_SHARP "SHARP"
Expand Down
75 changes: 75 additions & 0 deletions test/ir_Sanyo_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,14 @@ TEST(TestUtils, Housekeeping) {
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::SANYO_AC88));
ASSERT_EQ(kSanyoAc88Bits, IRsend::defaultBits(decode_type_t::SANYO_AC88));
ASSERT_EQ(kSanyoAc88MinRepeat, IRsend::minRepeats(decode_type_t::SANYO_AC88));
// Sanyo A/C 152 Bit.
ASSERT_EQ("SANYO_AC152", typeToString(decode_type_t::SANYO_AC152));
ASSERT_EQ(decode_type_t::SANYO_AC152, strToDecodeType("SANYO_AC152"));
ASSERT_TRUE(hasACState(decode_type_t::SANYO_AC152));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::SANYO_AC152));
ASSERT_EQ(kSanyoAc152Bits, IRsend::defaultBits(decode_type_t::SANYO_AC152));
ASSERT_EQ(kSanyoAc152MinRepeat,
IRsend::minRepeats(decode_type_t::SANYO_AC152));
}

TEST(TestDecodeSanyoAc, DecodeRealExamples) {
Expand Down Expand Up @@ -820,3 +828,70 @@ TEST(TestSanyoAc88Class, Clock) {
ac.setClock(25 * 60 + 61);
EXPECT_EQ(23 * 60 + 59, ac.getClock());
}

TEST(TestDecodeSanyoAc152, DecodeRealExamples) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
// Ref: "16c" from https://github.com/crankyoldgit/IRremoteESP8266/issues/1826#issuecomment-1160708653
const uint16_t rawData[307] = {
3294, 1726, 420, 330, 458, 462, 382, 452, 438, 330, 456, 458, 384, 454,
384, 1312, 422, 324, 512, 336, 454, 458, 384, 450, 438, 358, 436, 464,
424, 326, 458, 476, 372, 458, 430, 328, 458, 464, 382, 1308, 424, 326,
510, 1264, 424, 268, 520, 460, 380, 460, 436, 324, 462, 400, 436, 474,
372, 456, 430, 342, 452, 450, 388, 446, 442, 1262, 422, 266, 520, 1314,
372, 1306, 424, 1258, 370, 390, 448, 1314, 372, 1310, 426, 308, 522, 338,
454, 470, 370, 454, 438, 330, 456, 468, 370, 456, 384, 464, 384, 1306,
422, 328, 460, 472, 374, 448, 442, 1258, 426, 1256, 426, 268, 520, 464,
382, 460, 430, 328, 508, 1264, 426, 262, 572, 1262, 424, 228, 604, 1262,
372, 1312, 372, 1310, 426, 1256, 422, 1258, 424, 262, 524, 418, 428, 456,
382, 1308, 372, 456, 386, 456, 382, 464, 378, 1308, 424, 360, 436, 454,
430, 344, 450, 1306, 372, 1310, 424, 326, 510, 338, 452, 456, 384, 456,
436, 328, 510, 1258, 372, 1310, 422, 338, 454, 466, 424, 328, 460, 1310,
372, 1312, 424, 1258, 450, 262, 496, 1310, 372, 1310, 426, 1260, 424, 260,
526, 442, 442, 1264, 426, 268, 520, 458, 380, 450, 386, 462, 436, 320,
518, 1256, 372, 394, 446, 398, 494, 334, 506, 326, 510, 276, 518, 460,
430, 332, 508, 326, 510, 356, 440, 448, 444, 264, 572, 336, 456, 408, 434,
454, 438, 332, 506, 336, 454, 460, 384, 448, 444, 326, 510, 332, 456, 442,
400, 456, 384, 456, 386, 452, 388, 454, 440, 326, 512, 272, 518, 450, 440,
334, 454, 458, 440, 320, 516, 268, 570, 340, 452, 468, 424, 260, 574, 336,
456, 394, 444, 458, 438, 328, 508, 1258, 370, 1312, 372, 1312, 424, 314,
468, 1312, 450, 1232, 370, 1314, 420, 324, 514}; // UNKNOWN 584FBE80

const uint8_t expectedState[kSanyoAc152StateLength] = {
0x40, 0x00, 0x14, 0x80, 0x6E, 0x80, 0x18, 0xEA, 0x23, 0x62,
0x30, 0xEE, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77};
irsend.begin();
irsend.reset();
irsend.sendRaw(rawData, 307, 38000);
irsend.makeDecodeResult();

ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(SANYO_AC152, irsend.capture.decode_type);
EXPECT_EQ(kSanyoAc152Bits, 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(TestDecodeSanyoAc152, SyntheticSelfDecode) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
const uint8_t expectedState[kSanyoAc152StateLength] = {
0x40, 0x00, 0x14, 0x80, 0x6E, 0x80, 0x18, 0xEA, 0x23, 0x62,
0x30, 0xEE, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77};
irsend.begin();
irsend.reset();
irsend.sendSanyoAc152(expectedState);
irsend.makeDecodeResult();

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