Skip to content

Commit

Permalink
Experimental Bose remote support (#1579)
Browse files Browse the repository at this point in the history
* Experimental Bose remote support
* Unit tests.

Co-authored-by: crankyoldgit <[email protected]>
  • Loading branch information
parsnip42 and crankyoldgit authored Aug 28, 2021
1 parent f026c5c commit b1b9277
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting SanyoAc88 decode");
if (decodeSanyoAc88(results, offset)) return true;
#endif // DECODE_SANYO_AC88
#if DECODE_BOSE
DPRINTLN("Attempting Bose decode");
if (decodeBose(results, offset)) return true;
#endif // DECODE_BOSE
// Typically new protocols are added above this line.
}
#if DECODE_HASH
Expand Down
4 changes: 4 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,10 @@ class IRrecv {
bool decodeKelon(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kKelonBits, const bool strict = true);
#endif // DECODE_KELON
#if DECODE_BOSE
bool decodeBose(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kBoseBits, const bool strict = true);
#endif // DECODE_BOSE
};

#endif // IRRECV_H_
11 changes: 10 additions & 1 deletion src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,13 @@
#define SEND_KELON _IR_ENABLE_DEFAULT_
#endif // SEND_KELON

#ifndef DECODE_BOSE
#define DECODE_BOSE _IR_ENABLE_DEFAULT_
#endif // DECODE_BOSE
#ifndef SEND_BOSE
#define SEND_BOSE _IR_ENABLE_DEFAULT_
#endif // SEND_BOSE

#if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \
DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \
DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \
Expand Down Expand Up @@ -943,8 +950,9 @@ enum decode_type_t {
KELON,
TROTEC_3550,
SANYO_AC88, // 105
BOSE,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = SANYO_AC88,
kLastDecodeType = BOSE,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -1186,6 +1194,7 @@ const uint16_t kVoltasStateLength = 10;
const uint16_t kMilesTag2ShotBits = 14;
const uint16_t kMilesTag2MsgBits = 24;
const uint16_t kMilesMinRepeat = 0;
const uint16_t kBoseBits = 16;


// Legacy defines. (Deprecated)
Expand Down
6 changes: 6 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
case DENON:
case SHARP:
return 15;
case BOSE:
case DISH:
case GICABLE:
case JVC:
Expand Down Expand Up @@ -790,6 +791,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendAiwaRCT501(data, nbits, min_repeat);
break;
#endif
#if SEND_BOSE
case BOSE:
sendBose(data, nbits, min_repeat);
break;
#endif // SEND_BOSE
#if SEND_CARRIER_AC
case CARRIER_AC:
sendCarrierAC(data, nbits, min_repeat);
Expand Down
4 changes: 4 additions & 0 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,10 @@ class IRsend {
void sendKelon(const uint64_t data, const uint16_t nbits = kKelonBits,
const uint16_t repeat = kNoRepeat);
#endif // SEND_KELON
#if SEND_BOSE
void sendBose(const uint64_t data, const uint16_t nbits = kBoseBits,
const uint16_t repeat = kNoRepeat);
#endif // SEND_BOSE

protected:
#ifdef UNIT_TEST
Expand Down
1 change: 1 addition & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,5 +292,6 @@ const PROGMEM char *kAllProtocolNamesStr =
D_STR_KELON "\x0"
D_STR_TROTEC_3550 "\x0"
D_STR_SANYO_AC88 "\x0"
D_STR_BOSE "\x0"
///< New protocol strings should be added just above this line.
"\x0"; ///< This string requires double null termination.
69 changes: 69 additions & 0 deletions src/ir_Bose.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2021 parsnip42
// Copyright 2021 David Conran

/// @file
/// @brief Support for Bose protocols.
/// @note Currently only tested against Bose TV Speaker.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/pull/1579

// Supports:
// Brand: Bose, Model: Bose TV Speaker

#include "IRrecv.h"
#include "IRsend.h"

const uint16_t kBoseHdrMark = 1100;
const uint16_t kBoseHdrSpace = 1350;
const uint16_t kBoseBitMark = 555;
const uint16_t kBoseOneSpace = 1435;
const uint16_t kBoseZeroSpace = 500;
const uint32_t kBoseGap = kDefaultMessageGap;
const uint16_t kBoseFreq = 38;

#if SEND_BOSE
/// Send a Bose formatted message.
/// Status: STABLE / Known working.
/// @param[in] data The message to be sent.
/// @param[in] nbits The number of bits of message to be sent.
/// @param[in] repeat The number of times the command is to be repeated.
void IRsend::sendBose(const uint64_t data, const uint16_t nbits,
const uint16_t repeat) {
sendGeneric(kBoseHdrMark, kBoseHdrSpace,
kBoseBitMark, kBoseOneSpace,
kBoseBitMark, kBoseZeroSpace,
kBoseBitMark, kBoseGap,
data, nbits, kBoseFreq, false,
repeat, kDutyDefault);
}
#endif // SEND_BOSE

#if DECODE_BOSE
/// Decode the supplied Bose formatted message.
/// Status: STABLE / Known working.
/// @param[in,out] results Ptr to the data to decode & where to store the result
/// @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.
bool IRrecv::decodeBose(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kBoseBits) return false;

if (!matchGeneric(results->rawbuf + offset, &(results->value),
results->rawlen - offset, nbits,
kBoseHdrMark, kBoseHdrSpace,
kBoseBitMark, kBoseOneSpace,
kBoseBitMark, kBoseZeroSpace,
kBoseBitMark, kBoseGap, true,
kUseDefTol, 0, false)) {
return false;
}

//
results->decode_type = decode_type_t::BOSE;
results->bits = nbits;
results->address = 0;
results->command = 0;
return true;
}
#endif // DECODE_BOSE
3 changes: 3 additions & 0 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,9 @@
#ifndef D_STR_ARGO
#define D_STR_ARGO "ARGO"
#endif // D_STR_ARGO
#ifndef D_STR_BOSE
#define D_STR_BOSE "BOSE"
#endif // D_STR_BOSE
#ifndef D_STR_CARRIER_AC
#define D_STR_CARRIER_AC "CARRIER_AC"
#endif // D_STR_CARRIER_AC
Expand Down
108 changes: 108 additions & 0 deletions test/ir_Bose_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2021 parsnip42
// Copyright 2021 David Conran

#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"


TEST(TestUtils, Housekeeping) {
ASSERT_EQ("BOSE", typeToString(decode_type_t::BOSE));
ASSERT_EQ(decode_type_t::BOSE, strToDecodeType("BOSE"));
ASSERT_FALSE(hasACState(decode_type_t::BOSE));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::BOSE));
ASSERT_EQ(kBoseBits, IRsend::defaultBits(decode_type_t::BOSE));
ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::BOSE));
}

// Tests for sendBose().

// Test sending typical data only.
TEST(TestSendBose, SendDataOnly) {
IRsendTest irsend(kGpioUnused);
irsend.begin();
irsend.sendBose(0xCD32);
EXPECT_EQ("f38000d50"
"m1100s1350m555s500m555s1435m555s500m555s500m555s1435m555s1435"
"m555s500m555s500m555s1435m555s500m555s1435m555s1435m555s500"
"m555s500m555s1435m555s1435m555s100000",
irsend.outputStr());
}

// Decode normal Bose messages.
TEST(TestDecodeBose, SyntheticSelfDecode) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();

// Synthesised 16-bit Bose message (TV Speaker Power On).
irsend.reset();
irsend.sendBose(0xCD32);
irsend.makeDecodeResult();

EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(BOSE, irsend.capture.decode_type);
EXPECT_EQ(kBoseBits, irsend.capture.bits);
EXPECT_EQ(0xCD32, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
}

// Decode normal Bose messages.
TEST(TestDecodeBose, RealMessageDecode1) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);

irsend.begin();

// Real-life Bose code from an actual capture/decode (TV Speaker Power On).
irsend.reset();

const uint16_t rawData_0[35] = {
942, 1558,
442, 558, 442, 1502, 494, 534, 466, 560, 440, 1530, 468, 1532, 466,
558, 440, 504, 496, 1558, 440, 534, 466, 1556, 442, 1558, 440, 558,
440, 534, 466, 1556, 442, 1558, 440
};

irsend.sendRaw(rawData_0, 35, 38000);
irsend.makeDecodeResult();

EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(BOSE, irsend.capture.decode_type);
EXPECT_EQ(kBoseBits, irsend.capture.bits);
EXPECT_EQ(0xCD32, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
}

// Decode normal Bose messages.
TEST(TestDecodeBose, RealMessageDecode2) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);

irsend.begin();

// Real-life Bose code from an actual capture/decode (TV Speaker Mute).
irsend.reset();

const uint16_t rawData_0[35] = {
1024, 1504,
496, 528, 472, 480, 520, 502, 496, 506, 494, 502, 496, 502, 498,
502, 498, 1500, 498, 1502, 496, 1504, 496, 1502, 496, 1504, 494,
1472, 524, 1504, 468, 1556, 442, 532, 468,
};

irsend.sendRaw(rawData_0, 35, 38000);
irsend.makeDecodeResult();

EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(BOSE, irsend.capture.decode_type);
EXPECT_EQ(kBoseBits, irsend.capture.bits);
EXPECT_EQ(0x7F80, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
}

0 comments on commit b1b9277

Please sign in to comment.