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

Add support of Toshiba Remote Control B #2094

Merged
merged 9 commits into from
Jul 25, 2024
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
7 changes: 7 additions & 0 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@ enum argo_ac_remote_model_t {
SAC_WREM3 // (2) ARGO WREM3 remote (touch buttons), bit-len vary by cmd
};

/// Toshiba A/C model numbers
enum toshiba_ac_remote_model_t {
kToshibaGenericRemote_A = 0, // Default from existing codebase
kToshibaGenericRemote_B = 1, // Newly discovered remote control b, applies to
// many remote models such as WA-TH03A, WA-TH04A etc.
};

// Classes

/// Class for sending all basic IR protocols.
Expand Down
4 changes: 4 additions & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@ IRTEXT_CONST_STRING(kDg11j104Str, D_STR_DG11J104); ///< "DG11J104"
IRTEXT_CONST_STRING(kDg11j191Str, D_STR_DG11J191); ///< "DG11J191"
IRTEXT_CONST_STRING(kArgoWrem2Str, D_STR_ARGO_WREM2); ///< "WREM3"
IRTEXT_CONST_STRING(kArgoWrem3Str, D_STR_ARGO_WREM3); ///< "WREM3"
IRTEXT_CONST_STRING(kToshibaGenericRemoteAStr, D_STR_TOSHIBAGENERICREMOTEA);
// "TOSHIBA REMOTE A"
IRTEXT_CONST_STRING(kToshibaGenericRemoteBStr, D_STR_TOSHIBAGENERICREMOTEB);
// "TOSHIBA REMOTE B"

#define D_STR_UNSUPPORTED "?" // Unsupported protocols will be showing as
// a question mark, check for length > 1
Expand Down
2 changes: 2 additions & 0 deletions src/IRtext.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ extern IRTEXT_CONST_PTR(kSetTimerCommandStr);
extern IRTEXT_CONST_PTR(kTimerStr);
extern IRTEXT_CONST_PTR(kToggleStr);
extern IRTEXT_CONST_PTR(kTopStr);
extern IRTEXT_CONST_PTR(kToshibaGenericRemoteAStr);
extern IRTEXT_CONST_PTR(kToshibaGenericRemoteBStr);
extern IRTEXT_CONST_PTR(kTrueStr);
extern IRTEXT_CONST_PTR(kTurboStr);
extern IRTEXT_CONST_PTR(kTurboToggleStr);
Expand Down
9 changes: 9 additions & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,15 @@ namespace irutils {
default: return kUnknownStr;
}
break;
case decode_type_t::TOSHIBA_AC:
switch (model) {
case toshiba_ac_remote_model_t::kToshibaGenericRemote_A:
return kToshibaGenericRemoteAStr;
case toshiba_ac_remote_model_t::kToshibaGenericRemote_B:
return kToshibaGenericRemoteBStr;
default:
return kUnknownStr;
}
default: return kUnknownStr;
}
}
Expand Down
33 changes: 30 additions & 3 deletions src/ir_Toshiba.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ using irutils::addModeToString;
using irutils::addTempToString;
using irutils::checkInvertedBytePairs;
using irutils::invertBytePairs;
using irutils::addModelToString;

#if SEND_TOSHIBA_AC
/// Send a Toshiba A/C message.
Expand Down Expand Up @@ -104,8 +105,9 @@ void IRToshibaAC::send(const uint16_t repeat) {
uint16_t IRToshibaAC::getInternalStateLength(const uint8_t state[],
const uint16_t size) {
if (size < kToshibaAcLengthByte) return 0;
return std::min((uint16_t)(state[kToshibaAcLengthByte] + kToshibaAcMinLength),
kToshibaACStateLengthLong);
// Fix: Extract the last 4 bits instead
return std::min((uint16_t)((state[kToshibaAcLengthByte] & 0xF)
+ kToshibaAcMinLength), kToshibaACStateLengthLong);
}

/// Get the length of the current internal state per the protocol structure.
Expand Down Expand Up @@ -462,7 +464,8 @@ stdAc::state_t IRToshibaAC::toCommon(const stdAc::state_t *prev) const {
String IRToshibaAC::toString(void) const {
String result = "";
result.reserve(95);
result += addTempToString(getTemp(), true, false);
result += addModelToString(decode_type_t::TOSHIBA_AC, getModel(), false);
result += addTempToString(getTemp(), true);
switch (getStateLength()) {
case kToshibaACStateLengthShort:
result += addIntToString(getSwing(true), kSwingVStr);
Expand Down Expand Up @@ -493,6 +496,30 @@ String IRToshibaAC::toString(void) const {
return result;
}

/// Get the model information currently known.
/// @return The known model number.
toshiba_ac_remote_model_t IRToshibaAC::getModel(void) const {
switch (_.Model) {
case kToshibaAcRemoteB:
return toshiba_ac_remote_model_t::kToshibaGenericRemote_B;
default:
return toshiba_ac_remote_model_t::kToshibaGenericRemote_A;
}
}

/// Set the current model for the remote.
/// @param[in] model The model number.
void IRToshibaAC::setModel(const toshiba_ac_remote_model_t model) {
switch (model) {
case toshiba_ac_remote_model_t::kToshibaGenericRemote_B:
_.Model = kToshibaAcRemoteB;
break;
default:
_.Model = kToshibaAcRemoteA;
break;
}
}

#if DECODE_TOSHIBA_AC
/// Decode the supplied Toshiba A/C message.
/// Status: STABLE / Working.
Expand Down
11 changes: 10 additions & 1 deletion src/ir_Toshiba.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ union ToshibaProtocol{
///< 1 (56 bit message)
///< 3 (72 bit message)
///< 4 (80 bit message)
uint8_t Length :8;
uint8_t Length :4;
// Toshiba remote type
// 0 - Remote control A
// 1 - Remote control B
uint8_t Model :4;
// Byte[3] - The bit-inverted value of the "length" byte.
uint8_t :8;
// Byte[4]
Expand Down Expand Up @@ -111,6 +115,9 @@ const uint8_t kToshibaAcFanMax = 5; // 0b101
const uint8_t kToshibaAcTurboOn = 1; // 0b01
const uint8_t kToshibaAcEconoOn = 3; // 0b11

const uint8_t kToshibaAcRemoteA = 0; // 0b0000
const uint8_t kToshibaAcRemoteB = 1; // 0b0001

// Legacy defines. (Deprecated)
#define TOSHIBA_AC_AUTO kToshibaAcAuto
#define TOSHIBA_AC_COOL kToshibaAcCool
Expand Down Expand Up @@ -140,6 +147,8 @@ class IRToshibaAC {
void begin(void);
void on(void);
void off(void);
void setModel(const toshiba_ac_remote_model_t model);
toshiba_ac_remote_model_t getModel() const;
void setPower(const bool on);
bool getPower(void) const;
void setTemp(const uint8_t degrees);
Expand Down
6 changes: 6 additions & 0 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,12 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_ZEPEAL
#define D_STR_ZEPEAL "ZEPEAL"
#endif // D_STR_ZEPEAL
#ifndef D_STR_TOSHIBAGENERICREMOTEA
#define D_STR_TOSHIBAGENERICREMOTEA "TOSHIBA REMOTE A"
#endif // D_STR_TOSHIBAGENERICREMOTEA
#ifndef D_STR_TOSHIBAGENERICREMOTEB
#define D_STR_TOSHIBAGENERICREMOTEB "TOSHIBA REMOTE B"
#endif // D_STR_TOSHIBAGENERICREMOTEB

// IRrecvDumpV2+
#ifndef D_STR_TIMESTAMP
Expand Down
12 changes: 6 additions & 6 deletions test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2158,8 +2158,8 @@ TEST(TestIRac, Toshiba) {
IRac irac(kGpioUnused);
IRrecv capture(kGpioUnused);
char expected[] =
"Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), "
"Turbo: Off, Econo: On, Filter: Off";
"Model: 0 (TOSHIBA REMOTE A), Temp: 29C, Power: On, Mode: 2 (Dry), "
"Fan: 2 (UNKNOWN), Turbo: Off, Econo: On, Filter: Off";

ac.begin();
irac.toshiba(&ac,
Expand Down Expand Up @@ -3145,8 +3145,8 @@ TEST(TestIRac, Issue1250) {

// Now send the state so we can actually decode/capture what we sent.
char expected_on[] =
"Temp: 19C, Power: On, Mode: 4 (Fan), Fan: 0 (Auto), "
"Turbo: Off, Econo: Off, Filter: Off";
"Model: 0 (TOSHIBA REMOTE A), Temp: 19C, Power: On, Mode: 4 (Fan), "
"Fan: 0 (Auto), Turbo: Off, Econo: Off, Filter: Off";
ac._irsend.reset();
irac.toshiba(&ac,
irac.next.power, // Power
Expand All @@ -3172,8 +3172,8 @@ TEST(TestIRac, Issue1250) {
irac.sendAc();
// Now send the state so we can actually decode/capture what we sent.
char expected_off[] =
"Temp: 19C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, "
"Filter: Off";
"Model: 0 (TOSHIBA REMOTE A), Temp: 19C, Power: Off, Fan: 0 (Auto), "
"Turbo: Off, Econo: Off, Filter: Off";
ac._irsend.reset();
irac.toshiba(&ac,
irac.next.power, // Power
Expand Down
43 changes: 23 additions & 20 deletions test/ir_Toshiba_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,22 +311,25 @@ TEST(TestToshibaACClass, HumanReadableOutput) {
0x00, 0xC1, 0x00, 0xC0};

ac.setRaw(initial_state);
EXPECT_EQ("Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), "
"Turbo: Off, Econo: Off, Filter: Off",
EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Power: On, "
"Mode: 0 (Auto), Fan: 0 (Auto), Turbo: Off, Econo: Off, "
"Filter: Off",
ac.toString());
ac.setRaw(modified_state);
EXPECT_EQ("Temp: 17C, Power: On, Mode: 1 (Cool), Fan: 5 (High), "
"Turbo: Off, Econo: Off, Filter: Off",
EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Power: On, "
"Mode: 1 (Cool), Fan: 5 (High), Turbo: Off, Econo: Off, "
"Filter: Off",
ac.toString());
ac.setTemp(25);
ac.setFan(3);
ac.setMode(kToshibaAcDry);
EXPECT_EQ("Temp: 25C, Power: On, Mode: 2 (Dry), Fan: 3 (Medium), "
"Turbo: Off, Econo: Off, Filter: Off",
EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 25C, Power: On, "
"Mode: 2 (Dry), Fan: 3 (Medium), Turbo: Off, Econo: Off, "
"Filter: Off",
ac.toString());
ac.off();
EXPECT_EQ("Temp: 25C, Power: Off, Fan: 3 (Medium), Turbo: Off, Econo: Off, "
"Filter: Off",
EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 25C, Power: Off, "
"Fan: 3 (Medium), Turbo: Off, Econo: Off, Filter: Off",
ac.toString());
}

Expand Down Expand Up @@ -379,8 +382,8 @@ TEST(TestDecodeToshibaAC, SyntheticExample) {
ASSERT_EQ(kToshibaACBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: Off, "
"Econo: Off, Filter: Off",
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Power: On, Mode: 0 (Auto), "
"Fan: 0 (Auto), Turbo: Off, Econo: Off, Filter: Off",
IRAcUtils::resultAcToString(&irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
Expand Down Expand Up @@ -627,8 +630,8 @@ TEST(TestDecodeToshibaAC, RealLongExample) {
EXPECT_EQ(kToshibaACBitsLong, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"Temp: 22C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: On, "
"Econo: Off, Filter: Off",
"Model: 0 (TOSHIBA REMOTE A), Temp: 22C, Power: On, Mode: 0 (Auto), "
"Fan: 0 (Auto), Turbo: On, Econo: Off, Filter: Off",
IRAcUtils::resultAcToString(&irsend.capture));
}

Expand Down Expand Up @@ -718,7 +721,7 @@ TEST(TestDecodeToshibaAC, RealShortExample) {
EXPECT_EQ(kToshibaACBitsShort, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"Temp: 17C, Swing(V): 0 (Step)",
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 0 (Step)",
IRAcUtils::resultAcToString(&irsend.capture));
}

Expand All @@ -732,8 +735,8 @@ TEST(TestToshibaACClass, ConstructLongState) {
ac.setTurbo(false);
ac.setEcono(true);
EXPECT_EQ(
"Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), "
"Turbo: Off, Econo: On, Filter: Off",
"Model: 0 (TOSHIBA REMOTE A), Temp: 29C, Power: On, Mode: 2 (Dry), "
"Fan: 2 (UNKNOWN), Turbo: Off, Econo: On, Filter: Off",
ac.toString());
EXPECT_EQ(kToshibaACStateLengthLong, ac.getStateLength());
const uint8_t expectedState[kToshibaACStateLengthLong] = {
Expand Down Expand Up @@ -783,8 +786,8 @@ TEST(TestDecodeToshibaAC, RealExample_WHUB03NJ) {
EXPECT_EQ(kToshibaACBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"Temp: 20C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, "
"Filter: Off",
"Model: 0 (TOSHIBA REMOTE A), Temp: 20C, Power: Off, Fan: 0 (Auto), "
"Turbo: Off, Econo: Off, Filter: Off",
IRAcUtils::resultAcToString(&irsend.capture));
}

Expand All @@ -805,7 +808,7 @@ TEST(TestToshibaACClass, SwingCodes) {
ac.setSwing(kToshibaAcSwingOn);

EXPECT_EQ(
"Temp: 17C, Swing(V): 1 (On)",
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 1 (On)",
ac.toString());
EXPECT_EQ(kToshibaACStateLengthShort, ac.getStateLength());
const uint8_t swingOnState[kToshibaACStateLengthShort] = {
Expand All @@ -815,7 +818,7 @@ TEST(TestToshibaACClass, SwingCodes) {

ac.setSwing(kToshibaAcSwingOff);
EXPECT_EQ(
"Temp: 17C, Swing(V): 2 (Off)",
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 2 (Off)",
ac.toString());
EXPECT_EQ(kToshibaACStateLengthShort, ac.getStateLength());
const uint8_t swingOffState[kToshibaACStateLengthShort] = {
Expand All @@ -828,7 +831,7 @@ TEST(TestToshibaACClass, SwingCodes) {
ac.setRaw(swingToggleState, kToshibaACStateLengthShort);
EXPECT_EQ(kToshibaAcSwingToggle, ac.getSwing());
EXPECT_EQ(
"Temp: 17C, Swing(V): 4 (Toggle)",
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 4 (Toggle)",
ac.toString());
}

Expand Down
Loading